Rich input — references, images, URLs and pipes
By the end you can
- Reference files and MCP resources with @ and predict what each reference actually loads
- Know that an @ reference to a directory lists it rather than reading it
- Get a screenshot, a design or an error image into a session three different ways
- Pipe a log, a diff or command output into claude -p and redirect the answer back out
- Choose between naming input, pasting it, and letting the agent fetch it itself
There is a habit that survives from chat interfaces and costs you badly here: describing your material instead of handing it over.
"There's a function in the auth module that refreshes the token, I think it takes
the session object" is a paraphrase. You wrote it from memory, it is probably
slightly wrong, and it cost you thirty seconds. @src/auth/refresh.ts is the
actual thing, it is exact, and it cost you a tab-complete.
Four ways to get material in, and they differ in one respect worth understanding: who does the reading.
@ references — you name it, the agent reads it
Type @ and a path-suggestion menu opens. A file reference pulls the file's
contents into the conversation before Claude responds (Common
workflows):
Explain the logic in @src/utils/auth.jsTwo behaviours here are not obvious and both catch people:
A reference to a directory lists it — it does not read it. @src/components
gives Claude the file listing for that directory, not the contents of the files
in it. This is a feature: it is how you say "here is what exists, pick what you
need" without loading twenty components into the window. It becomes a bug the
moment you assume you have shown Claude the code and it has only seen the names.
A reference drags CLAUDE.md along with it. Referencing a file also adds the
CLAUDE.md from that file's directory and its parent directories to context.
That is usually what you want — the conventions that apply to a file arrive with
the file — and it is also why an @ into a deeply nested package can pull in
more than the one file you had in mind.
You can also reference resources exposed by a connected MCP server with
@server:resource, which is the same idea pointed at something that is not on
your disk.
Images — three ways in
A screenshot is often the shortest correct description of a UI bug. There are three documented ways to get one in:
- drag and drop the image into the prompt
- copy it and paste with
Ctrl+V— on Windows and WSL,Alt+V - give the file path and ask Claude to look at it
The pattern that pays for itself is the comparison loop: paste the design, ask for the implementation, then ask for a screenshot of the result compared against the original with the differences listed and fixed. That turns "make the dashboard look better" — a request with no possible pass condition — into one that closes on its own.
That loop has a ceiling, and it is worth knowing before you reach it. Images
accumulate in the conversation, and the raw request body carries a 32MB limit
that is separate from the context window. Cross it and Claude Code measures the
conversation for you — Request too large (max 32MB; 20.1MB of about 33.4MB is images or documents). — then retries with the images stripped. Through a proxy,
gateway or cloud provider you get the general message instead: the same two
remedies, without the measurement that tells you which of them applies. Either
way, /compact clears that backlog deliberately. When the messages alone are
over the limit there is nothing to strip: the error says compacting cannot make it fit, and the way out is to press Esc twice and step back past the turn that
added the bulk. Before v2.1.212, conversations with enough accumulated images
failed on every turn with Request too large (max 32MB). Double press esc to go back and try with a smaller file.
(Errors).
Compression on the way in is on your side too. Claude Code resizes oversized images before sending them, and since v2.1.196 anything still over 500KB after that resize is re-encoded as a reduced-quality JPEG with its pixel dimensions unchanged (Tools reference). The bytes go down; the fine pixel detail goes with them, which is why the documented fix for "Claude missed something in that screenshot" is to crop the region of interest and ask again: send what you are actually asking about, not the whole screen.
URLs — for documentation, not for facts you should own
You can paste a URL and ask Claude to fetch and use it, which is the right move
for an API reference or a library's changelog. Frequently-used domains can be
allowlisted with /permissions so you stop approving the same fetch
(Best practices).
Pipes — for anything already in a terminal
Non-interactive mode reads stdin, so Claude behaves like any other command-line tool: data in one end, answer out the other (Run Claude Code programmatically).
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txtThe same shape covers most of what you would otherwise copy out of a scrollback buffer by hand:
git log --oneline -20 | claude -p "summarize these recent commits"git diff main | claude -p "you are a typo linter. report filename:line for each typo."That second one is worth reading twice. Piping the diff in means Claude never needs Bash permission to go and get the diff itself — the data arrives as input rather than as the result of a tool call. Narrowing what a run is allowed to do by changing how the data reaches it is a real technique, and Level 10 spends a while on it.
Two constraints to know before you build a habit on this:
- Piped stdin is capped at 10MB. Over the cap, the run exits with an error and a non-zero status. The documented answer for bigger inputs is to write the content to a file and name the path in your prompt instead of piping it.
--output-format jsonreturns a structured object with the text in aresultfield, which is what you want the moment something downstream is parsing the answer rather than a human reading it (CLI reference).
Or: let it fetch its own context
The fifth option is to supply nothing and say where to look — "read the failing test and the module it imports" — letting Claude pull what it needs with Bash, MCP tools and file reads. This is the cheapest option to type and the least predictable in cost, which is the trade the whole next level is about.
| Method | Who reads | Exact? | You should reach for it when |
|---|---|---|---|
@path | The agent | Yes | You know which file |
@dir | The agent, names only | Listing only | You want it to choose from what exists |
| Paste / image | You | Yes | The thing is not a file — a screenshot, an error, a design |
| Pipe | The shell | Yes | It is already terminal output |
| "Go find it" | The agent, unbounded | Depends | You genuinely do not know where it lives |
Checkpoint
You should be able to take a bug you would normally describe in a paragraph and
deliver it instead as: one @ reference, one pasted screenshot, and one
sentence — and to say what @src/components would and would not have put in the
window.