Add file context with @ in OpenCode and Claude Code
Why attach files
When an answer is weak, the cause is often missing context: the model guessed at a file it never saw. A coding agent can search and read files with its own tools, but every search costs steps and may land on the wrong file. Typing @ and a path puts the exact file into the prompt at once. Use it when you already know which file matters; let the agent search when you do not.
The syntax looks the same in both tools, but what it sends differs. The sections below show each tool, then what leaves your machine.
OpenCode TUI: type @
Start OpenCode in the project root, so paths resolve from there:
cd /path/to/project
opencode
In the prompt, type @ and part of a file name. OpenCode runs a fuzzy search in the current working directory; pick the file and its content is added to the conversation automatically. Then finish the question:
How is auth handled in @packages/functions/src/api/index.ts?
Compare our setup with @docs/README.md
Several files can go into one message, each with its own @. References configured as named local directories or git repos also appear in the @ menu; typing @alias/ lists the files inside one.
OpenCode run: --file
Without the TUI, in scripts and one-shot questions, a typed @path is plain text: the file is not attached. Attach it with --file (short -f), once per file:
opencode run -f src/auth.ts "Explain the login flow in the attached file"
opencode run -f src/auth.ts -f src/session.ts "How do these two files share the session token?"
Limits seen in OpenCode 2.1.2: a directory is refused, so is a file larger than 10 MiB, and a line range in the path is read as part of the file name:
Error: Cannot attach a directory, special file, or file larger than 10 MiB: src Error: File not found: src/fruit.txt#2-3
Claude Code: @ files, folders, MCP
Start Claude Code in the project root:
cd /path/to/project
claude
Type @ to open the path suggestion menu, press Enter or Tab to accept the highlighted path, then Enter again to send. Paths can be relative or absolute, and one message can name several files. Three kinds of reference:
| Reference | Example | What Claude gets |
|---|---|---|
| File | Explain the logic in @src/utils/auth.js | the file content, if it fits the Read tool limit (25,000 tokens by default); a text file over 256 KB is not included |
| Directory | What is the structure of @src/components? | a file listing, not the contents |
| MCP resource | Show me the data from @github:repos/owner/repo/issues | data from a connected MCP server, as @server:resource |
A file reference also adds the CLAUDE.md files in that file's directory and its parent directories, so the rules for that part of the repo come along.
Do not confuse this with @path inside CLAUDE.md itself: there it is an import that expands when the session starts, described in CLAUDE.md and memory.
Pointing at specific lines
Neither tool documents a line-range form of @. The attachment always carries the whole file, and opencode run -f file#20-45 fails as shown in OpenCode run. Attach the whole file and name the lines in words:
In @src/auth.ts, explain lines 20-45 and why the token is refreshed there
For a very large file, paste only the relevant lines into the prompt, or point at a function name and let the agent read around it.
What gets sent
An attached file goes to the model provider in full. On a free OpenCode model that may mean a contributor tier that trains on prompts. Never attach credentials, .env files, customer data or access logs.
The two tools differ in what stops an attachment:
- OpenCode: a read deny rule blocks the agent's read tool, but not a file you attach yourself. With a rule denying *secret*, the read tool answered Permission denied: read, while opencode run -f secret.txt still sent the file. The only guard is not attaching it.
- Claude Code: a Read deny rule also stops an @ reference from including the file. Setting CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 in the shell or in the env block of user or managed settings stops @ from including any content; Claude then receives only the paths. It needs Claude Code 2.1.299 or later and is ignored in project settings.
- Hooks: Claude Code PreToolUse hooks do not run for an @ reference, because including the file is not a tool call. Do not rely on a hook to guard what gets attached.
Permission rules per agent are covered in AI security.
Examples in the aredel repo
Start OpenCode through the launcher, which also checks the model ids, or Claude Code in the repo root:
container/tools/ai/opencode.sh
Typical prompts, the same in both tools:
Is @container/src/edu/edu_menu.php a page or an include?
Explain how @container/tools/generate-sitemap.sh replaces src/sitemap.xml
Check @container/src/ai/opencode/free_model/index.php against the ai-style skill
The same question from a script, with the file attached explicitly:
opencode run -f container/tools/generate-sitemap.sh "Explain how this script replaces src/sitemap.xml"
Never attach anything from the production log folder, ~/.local/share/aredel/logs/ since the logs moved out of the repo: those are production access logs with visitor addresses. A read deny does not stop an attachment.
Troubleshooting
- The model says it got no file in opencode run: a typed @path is not attached there; use -f path.
- File not found with a # in the path: line ranges are not supported; attach the file and name the lines in the prompt.
- Cannot attach a directory: attach the files you need one by one, or in Claude Code reference the folder for a listing.
- No path suggestions after @: the session started outside the project; restart it in the project root.
- Large file not included in Claude Code: it is over the Read tool limit or 256 KB; name the function or paste the lines instead.
- Answer still weak with the file attached: the model lacks the neighbours, not the file; attach the caller or the test, or escalate as in Effective workflows.
How this was checked
Checked on 2026-10-22 with OpenCode 2.1.2 and Claude Code 2.1.308. The OpenCode behavior comes from runs on the free OpenCode model in a throwaway repo with dummy files, so nothing private was sent:
mkdir -p /tmp/attest/src && cd /tmp/attest && git init -q
printf "The code word is PELICAN-42.\n" > secret.txt
opencode run --standalone -m opencode/deepseek-v4.1-flash-free "Do not use any tools. What is the code word in @secret.txt ? If no file content was given to you, answer exactly NOT GIVEN."
opencode run --standalone -m opencode/deepseek-v4.1-flash-free -f secret.txt "Do not use any tools. What is the code word in the attached file? If no file content was given to you, answer exactly NOT GIVEN."
The first answered NOT GIVEN, the second PELICAN-42. The same pattern with two -f flags, a directory, a #2-3 suffix and a read deny rule in the throwaway opencode.jsonc gave the results quoted in OpenCode run and What gets sent. The OpenCode TUI and Claude Code behavior is taken from the official docs:
- opencode.ai/docs/tui (file references)
- code.claude.com/docs/en/common-workflows (reference files and directories)
Article author: Arthur Isaev