Skip to main content
PathDocs

Attachments

In one sentence: ctx.attachments is a persistent binary attachment seam: it validates and atomically commits immutable image bytes, returning a serializable ImageAttachmentRef. attachment-local is its local filesystem implementation, and ui-attachment is the pure React attachment atom.

Unsent browser drafts do not live here; bytes only enter persistent storage when the user submits a prompt or a provider adapter submits structured model output.

1. What it is

The attachment capability solves one thing: persist image bytes so that session logs only keep a content-addressed reference + validated metadata, not browser paths, object URLs, provider URLs, or base64. Both core packages are product packages.

Packagectx keyRole
attachmentctx.attachmentsImmutable attachment references, image limits, storage service
attachment-local(registered on ctx.attachments)Content-addressed private storage under DSH_HOME
ui-attachmentnone (zero cordis)Pure React attachment atom: draft image rail, history gallery, large-image lightbox

2. Reference and write API (attachment)

ctx.attachments validates and atomically commits immutable image bytes, returning a serializable ImageAttachmentRef; consumers never persist browser paths, object URLs, provider URLs, or base64 into session events.

  • validateImage: runs the same admission policy but does not persist
  • saveImages (rc.7): ordered batch commit — validates every member before writing any; admission failures start no writes, storage failures return no partial references (already-published content-addressed objects may remain until a future retention policy collects them)
  • saveImage: commits every accepted image before each model-visible session event is published
  • readImage: validates the content-addressed object against recorded metadata; the caller can cancel, the implementation observes the cancellation and preserves it as a cancellation (not translated into a storage failure)

Unsent composer images remain temporary browser-owned drafts.

3. Local storage (attachment-local)

attachment-local is the private local implementation of attachment, mounted by default (base composition).

  • Objects live at <DSH_HOME>/attachments/v1/objects/<sha256-prefix>/<sha256>, addressed by an opaque sha256: id
  • Each process syncs home-directory ancestors step by step to the filesystem root, proving the home directory is durable only once, avoiding mistaking "a directory another process created but has not yet synced" for a safe boundary
  • Writes use a private staging directory, owner-only files, synced temporary files, atomic exclusive hard-link publication, and directory syncing on the publish path (POSIX; Windows relies on filesystem metadata journaling), ensuring the reported reference survives crashes
  • Both write admission and reads fully decode the raster before accepting format and dimensions
  • DSH_HOME follows the shared path policy: explicit config → $DSH_HOME~/.dsh. Session logs contain only references and validated metadata, never this host path
  • readImage forwards an optional cancellation into the filesystem read and preserves the cancellation rather than wrapping it as ATTACHMENT_READ_FAILED

4. Browser UI atom (ui-attachment)

A pure React attachment atom, zero cordis: all strings resolve through the owning plugin's own locale namespace and read no application state; ui-conversation is its current consumer.

  • AttachmentRail: draft image rail, a single row of 64px thumbnails that scrolls horizontally, hidden scrollbar, overflow paged with round-edge arrows (prefers-reduced-motion: reduce gives instant scrolling)
  • MessageImage / ImageGallery: a single history image (longest side capped at 240px), with an explicit retry on load failure; clicking opens ImageLightbox
  • ImageLightbox: document-level modal preview, closed by Escape / background click / close control, focus returned to the opener on unmount

Model visibility: none — it renders a pure React atom in the browser and never enters any model request.

5. Configuration

attachment-local has no explicit config options; the storage root is resolved from DSH_HOME. The mount line, as in the default composition:

- id: attachment-local
name: '@deepseek-ai/dsh-attachment-local'

6. Known limitations

  • The first version only accepts PNG, JPEG, WebP, and GIF
  • Retention and garbage collection are deferred (recovered/derived sessions may share immutable objects)
  • Generic files, audio, video, and persisting unsent drafts need their own lifecycle and provider contracts

7. Verification

# Check whether attachment-local is mounted
dsh web --dump-config | grep -iE "attachment"
# Look at the attachment object directory (owner-only, bucketed by sha256 prefix)
ls -la ~/.dsh/attachments/v1/objects/

Next steps

  • Storage: another kind of non-session persistent data (KV backends); attachments do not go through here
  • Session system: session logs only store sha256: references and validated metadata
  • Built-in tools: images enter provider requests as ImageBlock