Repository navigation
Chat: a file dropped into an ssh peer's chat goes to that peer (_acpmux/file_put) - #23324
Conversation
…s the chat
A file the person drops into a chat that the composer can't attach is
saved owner-only by the daemon that owns the session, under
<ACPMUX_HOME>/uploads/<session>/<random>/<name>, answered {path}. A peer's
chat is forwarded to that peer, only when its initialize lists filePut
(else Method not found, reason filePut.unsupported), and the 10 MiB cap is
checked before the link: an older peer reads at most 16 MiB frames. Web
connections are refused (filePut.remote); a purge deletes the uploads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
A chat of this Mac's acpmux whose agent runs on an ssh peer (a chat named huge-blue/<name>) took its dropped files into this Mac's Chat Uploads, whose paths that agent cannot open. Its chat.upload now sends each file through this Mac's acpmux to the peer (_acpmux/file_put, AgentPeerUploads) and answers the paths there; an acpmux without the method, here or on the peer, answers unsupported, so the composer keeps its note. Files over 10 MiB are refused before any is sent, and Finder drops in a peer chat are never linked as this Mac's paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
… put on its own line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
…ame (a session key) The two-daemon test caught it: forwarding a peer's session strips session, name and sessionId aliases, so the peer saw no name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
…t Uploads Deleting them on purge was a new delete of user files; leave cleanup to a follow-up that covers both upload folders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
- AgentPaneFilePutFailure.init(_:) is public: CmuxNextApp calls it. - AcpmuxChiefSessionRouter publicly imports Foundation for putFile's Data. - A file name must be one plain path component, and on Windows has no ':', so a drive prefix (C:x) can't take the write out of the uploads folder. - The size check reads the decoded length from the base64 length and padding, so MAX_BYTES+1 is refused before it is forwarded to a peer. - remote_guard's note says a LocalApp page can send file_put itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
|
Owned by attachments-matrix on cosmic-gray · session |
|
Bead |
…-peer-put # Conflicts: # cmux-tui/crates/acpmux/src/server/requests.rs
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Probably yours: CI failed on
Failures:
Matched log linesNot re-run automatically: Written by red: web / Web status; NEW: green on the base 1a71fc9; do not merge until green; see lane-rules
Agents: Tour of The path-selected recorder failed for agent-pane, core; see the run artifact and failed manifests. Path-selected interactions
Agent pane (before): PASS — 3 ok
Screenshots (15)1. Launch
Screenshots (15)1. Launch Tours are data in |
|
Found 4 test failures on Blacksmith runners: Failures
|
The @Concurrent putFile(sessionId:name:data:send:) took a non-Sendable closure, so a main-actor test that passed one failed to compile (SendingRisksDataRace). Every closure passed captures only actors and values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d3d-4bad-7860-b096-c54282b4bec4&host=cosmic-gray
…-peer-put # Conflicts: # cmux-tui/crates/acpmux/src/hub/mod.rs # tests/test-execution.toml
|
|
|
|
|
Review (subagent, correctness first): SHIP at 460daf2 Reviews, all by independent subagents:
Evidence:
Non-green checks, none from this PR:
|
|
Shipped in:
|
The base merge brought +1103 more App lines from 26 commits since fee17be; the cap is the count at the merged head, and the baseline names the largest (#23651 +305, #23155 +285, #23527 +132, #23324 +92, #23638 +82, #23492 +57, #23588 +53, #23109 +48). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bd2-60d2-70e1-8179-d3aa717c8828&host=cosmic-gray
…h (app size base red) (#23540) * cmux-next: raise the CmuxNextApp size cap to 134745, naming the growth (app size base red) check-app-size.sh is red on every feat-cmux-next push: "CmuxNextApp is capped at 128667 lines (now 134745, +6078)". The cap was set at 7817f10; since then 203 first-parent commits changed the target, net +6078. None of it is generated or dead (types checked for references across Packages/macOS); it is feature code, +4040 of it direct pushes (Files and Find +1795) and +2038 from PRs. The baseline comment names the largest. Follow-ups that would pay it back (SW14): FileExplorer/ (22 files, 1647 lines) into its own target with CmuxNextFiles.FolderWatcher instead of its own FSEvents stream, and BrowserDownloadsPopup.swift (468) out of the App target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bd2-60d2-70e1-8179-d3aa717c8828&host=cosmic-gray * cmux-next: the App size cap is the count at ae0d9b7 (135848) The base merge brought +1103 more App lines from 26 commits since fee17be; the cap is the count at the merged head, and the baseline names the largest (#23651 +305, #23155 +285, #23527 +132, #23324 +92, #23638 +82, #23492 +57, #23588 +53, #23109 +48). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bd2-60d2-70e1-8179-d3aa717c8828&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>








































Some chats run their agent on an ssh peer: this Mac's acpmux mirrors them, named like
huge-blue/<name>. Until now, a file dropped or pasted into such a chat that the composer couldn't attach (a binary, a zip, a large text file) got the note that the chat takes no uploads. The Cloud uploader only serves moved chats. The local uploader would save the file on this Mac, where the agent can't open it. Now the file goes to the machine that runs the chat.How
_acpmux/file_put {sessionId, fileName, data}→{path}.<ACPMUX_HOME>/uploads/<session id>/<uuid v7>/<fileName>. Two files with the same name never overwrite each other.peer_forward.rscarries it to the peer.fileNamebecause the forward dropsname, which is a session key.AgentPaneUpload.isFileNamerules (filePut.name).filePut.tooLarge). That is 13.4 MiB of base64, under an older peer's 16 MiB WebSocket frame limit. A bigger frame resets the whole link and every chat on it.initializelistsfilePut, and the peer handshake records whether the peer has it. A peer without it gets -32601 with reasonfilePut.unsupported, and no bytes are sent.AgentPeerUploads, tried after Cloud and before local.AgentLaneStorelists the session with apeer.AgentPaneHostProviding.putFile, which goes over this Mac's acpmux unix socket and requires thefilePutfeature.unsupported, so the page shows its existing note. Size refusals answertoo_large; anything else answersupload_failed.localPathsis false for peer chats, so their Finder drops go as bytes.chat.uploadand puts the returned paths in the prompt asresource_links.Remote access analysis (remote_guard)
via=web(filePut.remote).uploads/<session>/<random>/. The caller picks neither the folder nor any path; the name is one plain file name (no/, no dot file, no control or bidi characters). The name must be one plain path component (on Windows also no:, so a drive prefix can't leave the folder). The session must be one this daemon owns or forwards.Not in this PR
attachment_put: that PR sends images and PDFs as prompt blocks by reference, which is a separate path fromchat.upload. If both land, the two paths have no overlap to reconcile in code.Tests
Rust (
cargo test -p acpmux --test file_put). The cases:Also run:
peer_integration,remote_guard,remote_guard_refused_families,peer_origin,local_app_origin,prompt_images. Results at this head are in a comment below.Swift:
AgentPaneFilePutTestscovers the failure mapping, the size cap before send, and the params.AgentPeerUploadsTestscovers the per-file replies, the size refusal, and theunsupportedmapping. CI is their first compile.Observed / Not run
cargo check --target x86_64-pc-windows-gnu -p acpmuxpassed at 5afc7d1 (run 39586149383).Changelog
Added: Files dropped into a chat that runs on an ssh peer now reach that machine, so the agent can open them.
No capture: no new UI. The only visible change is two error strings in the composer's existing upload note.
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Files dropped into a chat whose agent runs on an ssh peer now land on that machine, where the agent can open them. Previously the composer refused them or saved them on this Mac, where the peer's agent can't read them.
The new
_acpmux/file_putmethod saves the bytes owner-only under<ACPMUX_HOME>/uploads/<session>/<random>/<name>on the daemon that owns the session, andAgentPeerUploads(the app's third uploader, tried after Cloud and before local) sends a peer chat'schat.uploadfiles through this Mac's acpmux unix socket. Refusals map to the existing composer notes: an acpmux without the method answers unsupported (chat takes no uploads), oversize is refused before any bytes go, and the page is unchanged.Checks run before anything is decoded or forwarded: plain file name, 10 MiB cap (an older peer reads 16 MiB frames), existing session, peer advertising the
filePutfeature. The method is allowed only from the unix socket, LocalApp, and peers forwarding for either; Web is refused. Uploads are kept on purge, like the app's local Chat Uploads; cleanup is a follow-up.Written for commit 460daf2. Summary will update on new commits.