Docs
Jan Agent
Working with Files

Working with Files

The agent operates on the folder you launched it in. Reads happen freely; anything that changes the folder asks first.

Reading and searching

ToolWhat it does
readRead a UTF-8 text file. Truncated to 2000 lines or 64KB, with offset/limit for the rest
lsList a directory, dotfiles included, / suffix on directories
findFind files by glob - *.ts, **/*.json, src/**/*.rs
grepSearch file contents. Returns paths and line numbers, respects .gitignore

None of these prompt. Truncation is deliberate: a tool that dumps a 40MB file would spend the context window in one call, so large results come back bounded and the agent pages through them.

Referencing paths in a message

Type @path in a message and the console resolves it before the model sees the text:

  • @src/parser.rs reads the file and injects its content (UTF-8, capped at 1MB).
  • @src/ injects a listing of the directory's immediate children (capped at 20KB).
  • @image.png is noted inline as (image: image/png) rather than dumped - the model reads it if it supports vision.
  • A missing or unreadable path becomes an inline error notice, so the agent sees that the lookup failed instead of silently losing the reference.

The @token is removed after resolution, so the model sees the injected content directly, not the raw @ text. Typing @ opens a path-hint popup filtered as you type; Tab accepts the highlighted suggestion.

References are path-shaped only. @http:// and @https:// URLs are left alone, and user@host, emails, and bare IPv4 addresses like @1.2.3.4 pass through untouched - ssh user@host stays intact.

Changing files

ToolWhat it does
writeCreate or overwrite a file
editOne or more exact text replacements, applied in order

Both prompt, and both show a diff of the change before you decide:


edit src/parser.rs
- fn parse(input: &str) -> Result<Ast> {
+ fn parse(input: &str) -> Result<Ast, ParseError> {
y yes, once
a yes, and don't ask again this session
n no

edit requires each old_string to match exactly once in the current file. That's a safety property, not a limitation: an edit that could match two places is ambiguous, and the agent is made to disambiguate rather than guess.

For a large write, the console previews the file as it streams in, so you can see what's being produced before it lands.

Running commands

ToolWhat it does
bashRun a shell command in the project root

Output is combined stdout and stderr, followed by a final [exit N] line. That last part matters: it's how the agent knows a command actually failed rather than assuming it worked.

Commands prompt with the exact command shown:


$ cargo test --all
y yes, once
a yes, and don't ask again this session
n no

⚠️

a on a shell command allows further commands for the rest of the session - not just that one command. If you only meant to allow this one, use y.

Staying inside the project

Path arguments are checked against the project root, so a write outside the project is caught before it happens rather than silently allowed. bash runs with the project root as its working directory.

This is a guard, not a jail: a shell command can still reach outside if you approve it. Plan mode blocks the whole category, and that's the control to reach for when you want a hard boundary. See Run modes.

Images

The agent can read images if your model supports vision:


jan --image screenshot.png --task "why does this layout break?"

Repeat --image for more than one, or paste from the clipboard with Ctrl+V while the console is open.