You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Prior art, same root cause in another harness: anthropics/claude-code#65181 — a file shared via the macOS shared pasteboard lands on a path the agent cannot read (EPERM); the requested remedy is to copy it somewhere readable before substituting the path into the prompt.
Describe the enhancement you want to request
Summary
Dropping a non-image file into the TUI works from Finder and silently fails from every other application. The cause is not the file type — it's that the dropped path is ephemeral, and the TUI resolves it lazily, long after it has been reaped.
Request: classify the path at drop time and, when it is ephemeral or unreadable, capture the file immediately rather than storing a reference that is already dying.
Root cause
There is no drag-and-drop code in the TUI. Dropping a file on a terminal is handled by the emulator, which types the path into the tty; it arrives as an ordinary bracketed paste. Drop and paste therefore share one path: onPaste (packages/tui/src/component/prompt/index.tsx:1396) → pasteInputText → readLocalAttachment.
Raw bytes never arrive. A terminal injects text and nothing else. Any fix that hopes to receive the dropped bytes in the TUI cannot work — the only input is a path, and the only question is whether it still resolves when a tool finally reads it.
What differs between file types is when the bytes are read:
Drop source
Behavior
Why
Image, any app
works
bytes read at drop time into a data: URL (index.tsx:1195-1201); the source path expiring never matters
Non-image, Finder
works
rejected as an attachment, so the path falls through as literal text (index.tsx:1215); Finder paths are durable, so Read resolves it later
Non-image, non-Finder
silently fails
same fall-through, but the path is a promise/pasteboard file that is gone or EPERM by the time the agent reads it
The rejection is one line, packages/tui/src/component/prompt/local-attachment.ts:44:
Observed: the read fails — ENOENT once the promise file is reaped, or EPERM on the sandboxed shared-pasteboard path. Expected: readable, exactly as the identical drop of a .png already is.
Verified on macOS (Darwin 25.x, Terminal.app / iTerm2). The $TMPDIR/TemporaryItems and shared-pasteboard directories are the two macOS sources I confirmed. Linux (XDG document portal) and Windows (INetCache) are likely equivalent but I have not verified them, so I'm not claiming them.
Proposed behavior
At drop/paste time, once a path is recognized:
Durable and readable — Finder, a project file, anything outside the pasteboard/TemporaryItems/portal dirs that passes an access() probe → keep current behavior, insert the real path. This is strictly better than copying: the agent can edit the original in place, and there's nothing to clean up.
Ephemeral or unreadable → capture the bytes immediately and attach the captured copy.
Detection should be location plus an access probe, never extension.
For step 2's destination, the managed store in #46173 is the natural home rather than a second parallel mechanism — but it currently expects upload at submit, and a drop can precede submit by minutes, which the source file will not survive. Failing that, a session-scoped temp dir referenced by file:// works today: packages/opencode/src/session/prompt.ts:808-889 already reads a file: FilePart through the Read tool with extra: { bypassCwdCheck: true } (line 822), so a path outside the project is explicitly permitted, and ?start=/?end= ranges already work. @file autocomplete builds exactly this shape (autocomplete.tsx:247-267).
Prefer file:// over data: for captured non-images: a data: URL inflates the prompt store, prompt-history.jsonl, and the wire payload by 4/3 for a file the model would rather read on demand.
Implementation notes
pasteAttachment (index.tsx:1224-1270) needs generalizing: virtualText is hardcoded to [PDF n]/[Image n] (line 1233) and the URL to data: (line 1251). A [File n] variant plus a matching counter predicate at lines 1228-1232.
Temp lifetime is the one genuinely new problem. The two existing TUI temp writes (clipboard.ts:50, editor.ts:49) both delete in a finally; a captured attachment must outlive submit, because the server reads it lazily. Session-scoped, cleaned on session end/exit.
History replay.PromptInfo.parts is persisted to prompt-history.jsonl, and restoreExtmarksFromParts (index.tsx:658-700) will restore a placeholder pointing at a file deleted days ago. Recall should degrade visibly rather than silently attach nothing.
The canary test is packages/tui/test/prompt/local-attachment.test.ts:32, which asserts text/plain → undefined; it should fail the moment the gate widens.
The failure is silent and misattributed. The path lands in the prompt, the prompt submits, and the agent reports it cannot find a file the user is looking at on their own screen. Nothing errors at drop time, and nothing in the UI distinguishes the durable path from the doomed one. Users conclude drag-and-drop "only works for images" — when in fact it works for everything from Finder and nothing else from anywhere else.
#46173 will make the file types work. Without capture-at-drop-time in the TUI, this specific case still fails afterward, because by the time anything uploads, the file is gone.
Feature hasn't been suggested before.
Describe the enhancement you want to request
Feature hasn't been suggested before.
Searched existing issues; several are adjacent, none covers this. Specifically:
data:→file://. Explicitly states "non-image attachments are unaffected"..docx/.xlsxdrops rejected. Type-allowlist framing; superseded by [FEATURE]: upload attachments to the server so agent tools can read them (managed per-session store) #46173's sniffing.application/octet-streamattachments crash the session. Server-side crash, not TUI intake.Prior art, same root cause in another harness: anthropics/claude-code#65181 — a file shared via the macOS shared pasteboard lands on a path the agent cannot read (
EPERM); the requested remedy is to copy it somewhere readable before substituting the path into the prompt.Describe the enhancement you want to request
Summary
Dropping a non-image file into the TUI works from Finder and silently fails from every other application. The cause is not the file type — it's that the dropped path is ephemeral, and the TUI resolves it lazily, long after it has been reaped.
Request: classify the path at drop time and, when it is ephemeral or unreadable, capture the file immediately rather than storing a reference that is already dying.
Root cause
There is no drag-and-drop code in the TUI. Dropping a file on a terminal is handled by the emulator, which types the path into the tty; it arrives as an ordinary bracketed paste. Drop and paste therefore share one path:
onPaste(packages/tui/src/component/prompt/index.tsx:1396) →pasteInputText→readLocalAttachment.Raw bytes never arrive. A terminal injects text and nothing else. Any fix that hopes to receive the dropped bytes in the TUI cannot work — the only input is a path, and the only question is whether it still resolves when a tool finally reads it.
What differs between file types is when the bytes are read:
data:URL (index.tsx:1195-1201); the source path expiring never mattersindex.tsx:1215); Finder paths are durable, soReadresolves it laterEPERMby the time the agent reads itThe rejection is one line,
packages/tui/src/component/prompt/local-attachment.ts:44:MIME comes from an 8-entry extension map with no sniffing (
local-attachment.ts:25-34). #46173 addresses that half; this issue is about the other half.Steps to reproduce
.csv,.yaml, or.txtinto the TUI prompt.Observed: the read fails —
ENOENTonce the promise file is reaped, orEPERMon the sandboxed shared-pasteboard path.Expected: readable, exactly as the identical drop of a
.pngalready is.Verified on macOS (Darwin 25.x, Terminal.app / iTerm2). The
$TMPDIR/TemporaryItemsand shared-pasteboard directories are the two macOS sources I confirmed. Linux (XDG document portal) and Windows (INetCache) are likely equivalent but I have not verified them, so I'm not claiming them.Proposed behavior
At drop/paste time, once a path is recognized:
TemporaryItems/portal dirs that passes anaccess()probe → keep current behavior, insert the real path. This is strictly better than copying: the agent can edit the original in place, and there's nothing to clean up.Detection should be location plus an access probe, never extension.
For step 2's destination, the managed store in #46173 is the natural home rather than a second parallel mechanism — but it currently expects upload at submit, and a drop can precede submit by minutes, which the source file will not survive. Failing that, a session-scoped temp dir referenced by
file://works today:packages/opencode/src/session/prompt.ts:808-889already reads afile:FilePart through theReadtool withextra: { bypassCwdCheck: true }(line 822), so a path outside the project is explicitly permitted, and?start=/?end=ranges already work.@fileautocomplete builds exactly this shape (autocomplete.tsx:247-267).Prefer
file://overdata:for captured non-images: adata:URL inflates the prompt store,prompt-history.jsonl, and the wire payload by 4/3 for a file the model would rather read on demand.Implementation notes
pasteAttachment(index.tsx:1224-1270) needs generalizing:virtualTextis hardcoded to[PDF n]/[Image n](line 1233) and the URL todata:(line 1251). A[File n]variant plus a matching counter predicate at lines 1228-1232.clipboard.ts:50,editor.ts:49) both delete in afinally; a captured attachment must outlive submit, because the server reads it lazily. Session-scoped, cleaned on session end/exit.PromptInfo.partsis persisted toprompt-history.jsonl, andrestoreExtmarksFromParts(index.tsx:658-700) will restore a placeholder pointing at a file deleted days ago. Recall should degrade visibly rather than silently attach nothing.packages/tui/test/prompt/local-attachment.test.ts:32, which assertstext/plain→undefined; it should fail the moment the gate widens.Why this is worth doing separately from #46173
The failure is silent and misattributed. The path lands in the prompt, the prompt submits, and the agent reports it cannot find a file the user is looking at on their own screen. Nothing errors at drop time, and nothing in the UI distinguishes the durable path from the doomed one. Users conclude drag-and-drop "only works for images" — when in fact it works for everything from Finder and nothing else from anywhere else.
#46173 will make the file types work. Without capture-at-drop-time in the TUI, this specific case still fails afterward, because by the time anything uploads, the file is gone.