Skip to content

feat: send files to Depot agents and chat in attach - #607

Closed
robstolarz wants to merge 15 commits into
rob/depot-agents-clifrom
rob/depot-agents-cli-files
Closed

robstolarz wants to merge 15 commits into
rob/depot-agents-clifrom
rob/depot-agents-cli-files

Conversation

@robstolarz

@robstolarz robstolarz commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Lets depot agent session send files, directories, piped output and images to an agent, and turns attach into a chat whose input stays usable while output streams.

  • create and send take --file <path> (repeatable; a file or a directory) and --stdin-file <name>, e.g. some-cmd | depot agent session send <id> --stdin-file out.txt "look at this". In attach, /file <path> [message] adds a file to the next message.
  • Every source goes through one upload: the CLI hashes locally, then PUTs each file to the signed URL the API returns for its hash, with the signed headers as given. The media type comes from the content, then the extension, so a piped screenshot reaches the model as an image.
  • Limits on file count, per-file size and message total come from the API and are checked before anything is read in full or uploaded. Each send shows the file count and size.
  • A directory sends what git would track, so .gitignore applies, and is refused if git fails inside a work tree; outside one it skips .git. Names are flattened to dir_sub_file, with a ~N suffix to keep them unique, within 255 bytes. Each file is read once, so the upload matches its hash.
  • In a terminal, attach prints the conversation above an editable input line. Each user message names its sender and lists its files.
  • Depends on an API that is not released yet. Part of DEP-7247.

Test plan

  • go test -race ./pkg/cmd/agent/, golangci-lint run, go vet ./... clean
  • Fake-server tests: only the returned URLs are PUT, with the signed headers; over-limit, over-count and empty-directory refusals; .gitignore honoured; a piped PNG without an extension sent as image/png; unique names; /file queueing and the cumulative limit in attach
  • Once the API ships: depot agent session send <id> --file ./src "review this" and cat shot.png | depot agent session send <id> --stdin-file shot, then confirm the agent sees both
Stack, decisions, and deferred / known-open
  1. feat: add depot agent session commands #606 depot agent session commands
  2. this PR: files and chat attach
  3. feat: add depot agent pull and push #610 depot agent pull and push (on this PR)

#608 plugin views is also based on #606.

Decisions made without Rob:

  • A directory sends git ls-files --cached --others --exclude-standard inside a work tree, and is refused if git fails there, rather than falling back to sending everything.
  • Directory files are flattened to dir_sub_file, since attachment names are base names; collisions get ~N, and long names lose leading characters of the stem to fit 255 bytes.
  • A symlinked directory is followed; symlinks inside a directory are skipped.
  • The media type comes from the content first. The extension is used only when it narrows a generic result: zip to .docx, text to any type that isn't image, video, audio or font (.md, .rtf; .svg is allowed), MP4/WebM to an audio type (.m4a), or bytes the sniffer can't place. The system MIME table differs by machine (.ts can map to video/mp2t), so text always stays text.
  • The narrowing is by family, not an allowlist of aliases: a name that contradicts its bytes (a zip named .pdf, a text file named .wasm) keeps the name's type. The CLI only guarantees that a machine's MIME table cannot relabel a correctly named file.
  • Message attachments are field 8, leaving 6 and 7 for the author and sender fields on the same message.
  • attach keeps an editable input line while output streams, rather than plain stdin lines.
  • A sender shows as name (kind) for any kind but user, so a new kind like subagent needs no CLI change.

Deferred / known-open:

  • A file queued with /file in attach is uploaded at once, and the stored copy is kept for at least 24 hours. If the next message comes after that, the send fails with the API's error instead of re-uploading. The queued files are then dropped and the chat says to /file them again. Holding the bytes to re-upload would keep up to 64 MiB in memory for the whole chat, for a rare case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm

robstolarz and others added 9 commits October 2, 2026 13:27
The transcript prints above an input line that stays editable while output streams.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`--file` (repeatable) on `session create` and `session send`, and `/file <path> [message]`
in attach, hash each file locally, upload only the contents Depot does not already store,
and send the attachments with the message. The size shows before upload, and a file over
the server's limit is refused before anything is uploaded.

The transcript names the sender of each user message and queued input, including people
on connected services such as Slack, and lists attached files.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… upload

Directories send the files git would track, so .gitignore applies; --stdin-file
names piped input; media types are sniffed so piped images reach the model as
images. Every path is checked against the server's count, per-file and total
limits before anything uploads. DEP-7247

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…for every hash

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…input by what the message has left

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ashed, and fit names in 255 bytes

Inside a work tree a git failure no longer falls back to a plain walk that would
send ignored files. Each file is read once, so a file that changes mid-attach
cannot upload under the wrong hash. Flattened names keep their tail and extension.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ders

A send that fails after retries leaves attach unable to send while the bad
file stays queued, so the chat drops the queue and says so. Subagent reports
render as "name (subagent)" like other non-user senders.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ent notices

Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
@linear-code

linear-code Bot commented Oct 2, 2026

Copy link
Copy Markdown

DEP-7247

robstolarz and others added 2 commits October 2, 2026 15:11
Linux maps .log to text/x-log; macOS to text/plain. Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
Matches the API's numbering. Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment: Cursor Bugbot was present but did not finish within the wait window, so this run is not approved. Human review is needed and no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Risk: medium. Left a non-blocking comment: Cursor Bugbot was present but did not finish within the wait window, so this run is not approved. Human review is needed and no reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f2281f. Configure here.

Comment thread pkg/cmd/agent/files.go
robstolarz and others added 2 commits October 2, 2026 16:05
The system MIME table varies by machine and can label TypeScript as
video/mp2t, so the extension is consulted only for bytes the sniffer
cannot place. Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
A .docx still sniffs as a zip and an .svg or .md as text, so the
extension's type wins when it refines what the bytes say, and is
ignored when it contradicts them. Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
robstolarz and others added 2 commits October 2, 2026 18:42
RTF and other text-based application formats sniff as text, so a text
sniff now keeps the extension's type unless it names binary media.
Part of DEP-7247.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
Go sniffs any MP4 container as video/mp4, so .m4a audio lost its type.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NdhqP6oGqJMRJLwBU5Zepm
@robstolarz robstolarz mentioned this pull request Oct 3, 2026
2 of 3 tasks

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: medium. Approved: Cursor Bugbot completed successfully and the prior finding is resolved, so this run does not need human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@robstolarz

Copy link
Copy Markdown
Contributor Author

Superseded by #613 in the per-feature Depot agents stack (DEP-7247). Closing.

@robstolarz robstolarz closed this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant