Summary
Make chat attachments explicitly session-owned local resources with a lifecycle tied to the conversation.
OpenWork already gets very close to this: attachments are copied into the workspace under a per-session path such as:
.opencode/openwork/inbox/chat-attachments/<sessionId>/<attachmentId>-<filename>
The proposal is to formalize that behavior so that files dropped into a chat remain locally available to that session for its entire lifetime, and are cleaned up when the chat/session is deleted.
The main file types I would like to treat as first-class drag-and-drop attachments are:
Problem / goal
A desktop agent should be able to treat files attached to a conversation as persistent local working context rather than ephemeral model uploads.
Desired lifecycle:
- The user drags one or more supported files into the chat composer.
- OpenWork immediately copies the original bytes into storage owned by the current session.
- The transcript keeps a durable reference to that local file.
- The agent and tools can continue using the local path later in the same conversation, including after app restart.
- Archiving or renaming the conversation keeps the files.
- Deleting an individual message should not unexpectedly invalidate files already used by later steps in the session.
- Deleting the conversation/session removes its attachment storage (and any session-owned derived attachment data) from disk.
This would provide a simple invariant:
If the chat exists, its attached files exist locally. If the chat is deleted, its session-owned files are deleted too.
Today the attachment materialization path is already session-scoped (chat-attachments/<sessionId>/...), but session deletion appears to call the OpenCode session deletion API independently. I could not find an explicit lifecycle cleanup tying deletion of the session to deletion of the corresponding attachment directory and derived attachment data.
Primary user(s)
OpenCode primitive alignment
This should stay a thin OpenWork lifecycle layer around existing primitives rather than introduce a parallel document store.
Relevant existing behavior/code:
apps/app/src/react-app/domains/session/sync/attachment-file-part.ts already builds paths under chat-attachments/<sessionId>/... and materializes them below .opencode/openwork/inbox/.
- Office attachment handling already recognizes DOCX/PPTX/XLSX and preserves the original materialized file for tool access.
- PDF attachment handling already materializes originals and creates derived page/text data.
- Session deletion ultimately calls
client.session.delete(...) through the existing OpenCode client.
A minimal implementation could therefore be a lifecycle hook/service that owns session attachment paths and safely removes only OpenWork-managed data for that session after a confirmed session deletion.
A future extension could expose this behind a small SessionStorage abstraction so browser downloads, Office tooling, PDF derivations, and other tools can all resolve session-owned paths consistently, but that abstraction is not required for the initial feature.
Alignment with VISION/PRINCIPLES/PRODUCT
This reinforces OpenWork's local-first desktop model:
- user files remain on the user's machine/workspace;
- tools operate on real local files instead of repeatedly sending binary payloads to the model;
- conversations have predictable, inspectable resource ownership;
- deleting a conversation can also delete the local temporary resources that conversation owns;
- existing workspace files referenced by the user remain untouched because cleanup only applies to files copied into OpenWork-managed session storage.
It also makes the current attachment architecture easier to reason about for future tools such as richer spreadsheet/document/presentation editing.
Testability
Suggested tests:
- Create a session and drag/drop a PDF, DOCX, XLSX, and PPTX into the composer.
- Assert each original file is materialized below the current session's managed attachment directory.
- Restart OpenWork and reopen the session; assert the transcript references and local files still resolve.
- Archive/unarchive and rename the session; assert files remain unchanged.
- Delete a message containing an attachment after later session steps have referenced it; assert the file is not unexpectedly removed.
- Delete the session; assert its managed attachment directory is removed.
- For PDFs/Office attachments, assert any derived data owned exclusively by the session is also removed.
- Assert deletion cannot escape the OpenWork-managed attachment root (path traversal/symlink safety).
- Assert files elsewhere in the workspace, including files referenced rather than uploaded, are never deleted by this cleanup.
Ready to build it yourself?
Yes — I am willing to help iterate on the design, test it, and contribute implementation if the maintainers agree with the direction.
Additional context
The current layout is already very close to the requested model, so this can potentially be implemented incrementally rather than as a storage redesign.
An example conceptual layout could remain as simple as:
.opencode/openwork/inbox/chat-attachments/
<session-id>/
<attachment-id>-report.pdf
<attachment-id>-budget.xlsx
<attachment-id>-contract.docx
<attachment-id>-deck.pptx
The important part is explicit lifecycle ownership and cleanup, not the exact directory naming.
If useful later, session-owned derived files and generated outputs could follow the same ownership model, but I would keep that out of the MVP unless it naturally fits the existing attachment/PDF implementation.
Summary
Make chat attachments explicitly session-owned local resources with a lifecycle tied to the conversation.
OpenWork already gets very close to this: attachments are copied into the workspace under a per-session path such as:
The proposal is to formalize that behavior so that files dropped into a chat remain locally available to that session for its entire lifetime, and are cleaned up when the chat/session is deleted.
The main file types I would like to treat as first-class drag-and-drop attachments are:
.pdf.docx.xlsx.pptxProblem / goal
A desktop agent should be able to treat files attached to a conversation as persistent local working context rather than ephemeral model uploads.
Desired lifecycle:
This would provide a simple invariant:
Today the attachment materialization path is already session-scoped (
chat-attachments/<sessionId>/...), but session deletion appears to call the OpenCode session deletion API independently. I could not find an explicit lifecycle cleanup tying deletion of the session to deletion of the corresponding attachment directory and derived attachment data.Primary user(s)
OpenCode primitive alignment
This should stay a thin OpenWork lifecycle layer around existing primitives rather than introduce a parallel document store.
Relevant existing behavior/code:
apps/app/src/react-app/domains/session/sync/attachment-file-part.tsalready builds paths underchat-attachments/<sessionId>/...and materializes them below.opencode/openwork/inbox/.client.session.delete(...)through the existing OpenCode client.A minimal implementation could therefore be a lifecycle hook/service that owns session attachment paths and safely removes only OpenWork-managed data for that session after a confirmed session deletion.
A future extension could expose this behind a small
SessionStorageabstraction so browser downloads, Office tooling, PDF derivations, and other tools can all resolve session-owned paths consistently, but that abstraction is not required for the initial feature.Alignment with VISION/PRINCIPLES/PRODUCT
This reinforces OpenWork's local-first desktop model:
It also makes the current attachment architecture easier to reason about for future tools such as richer spreadsheet/document/presentation editing.
Testability
Suggested tests:
Ready to build it yourself?
Yes — I am willing to help iterate on the design, test it, and contribute implementation if the maintainers agree with the direction.
Additional context
The current layout is already very close to the requested model, so this can potentially be implemented incrementally rather than as a storage redesign.
An example conceptual layout could remain as simple as:
The important part is explicit lifecycle ownership and cleanup, not the exact directory naming.
If useful later, session-owned derived files and generated outputs could follow the same ownership model, but I would keep that out of the MVP unless it naturally fits the existing attachment/PDF implementation.