Blob store

Status: Supported
Milestone: 2b — alongside MQTT and live-test prep
Spec: Blob storage §5
Package: internal/blob

Goal

Content-addressed storage for large attachments, referenced from events via blob_ref. Primary use case: iOS Shortcuts share-sheet photo capture — upload image bytes, store content-addressed, set blob_ref on the journal event (not inline in payload).

Interfaces

type BlobStore interface {
    Put(ctx context.Context, data io.Reader) (ref string, err error)
    Get(ctx context.Context, ref string) (io.ReadCloser, error)
    Range(ctx context.Context, ref string, start, end int64) (io.ReadCloser, error)
    Enumerate(ctx context.Context) (<-chan string, error)
}

Implementation notes

  • v0 backend: filesystem with hash-prefix layout (/data/blobs/ab/cd/abcd...)
  • ref format: sha256-<hex>
  • Implement BlobStore in internal/blob and wire [blobs] config in cmd/trove/main.go
  • Add HTTP blob upload to http-ingest module: PUT /blobs returning { "blob_ref": "sha256-..." } (dedicated endpoint, not multipart on ingest)
  • Update share-sheet Shortcut docs to upload photo then POST event with blob_ref
  • blob_ref is accepted by journal and HTTP ingest; blob bytes are stored via PUT /blobs on http-ingest and referenced from ingest events
  • get_event MCP tool: optionally include blob metadata or serve URL once blobs exist (follow-up acceptance criterion)

Acceptance criteria

  • [x] Put/Get round-trip on filesystem backend
  • [x] Put returns stable ref for same content (dedup)
  • [x] Range supports partial reads
  • [x] Enumerate lists all refs
  • [x] PUT /blobs on http-ingest returns stable blob_ref
  • [x] Event with blob_ref references retrievable bytes
  • [x] Share-sheet Shortcut recipe documents photo upload path

Dependencies

  • Blocks: photo/attachment capture via iOS Shortcuts
  • Blocked by: none

Open questions