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
The memory ingestion watcher (#241) automatically captures every OpenCode session into the Graphiti knowledge graph. However, some sessions contain sensitive content (credentials, private discussions, experimental code) that should NOT be recorded in the shared memory system.
Users need a way to mark a session as "private" so the watcher skips it during ingestion.
Constraint
The OpenCode Session API has a fixed schema with no extensible metadata field. session.update() only accepts title and time.archived. There is no tags, metadata, or flags field available. This means we cannot store a "private" flag on the session object itself — we need a separate mechanism.
Goal
Add a UI toggle to mark sessions as private (excluded from memory ingestion)
The watcher respects the private list and skips those sessions
Private sessions should be visually distinct in the UI
Design
Storage: Watcher exclusion list
The watcher already maintains a state file for deduplication (~/.local/share/opencode-memory/state.json, from #241). Extend this to include a private list:
The watcher checks this list before ingesting any session. If the session ID is in private, it is skipped entirely.
Sync mechanism: Shared state file or watcher API
Two options (implementer should choose the simpler one):
Option A — Shared file: The UI server writes to the same state file the watcher reads. Both processes are on the same machine. The UI server gets a new extended API endpoint:
POST /api/ext/memory/private { sessionID: string, private: boolean }
GET /api/ext/memory/private → { sessions: string[] }
This endpoint reads/writes the watcher's state file directly.
Option B — Watcher HTTP API: The watcher exposes a small HTTP API (e.g., port 8766) for managing the private list. The UI server proxies to it.
Option A is simpler and recommended since both processes run on the same machine.
UI: Session header toggle + slash command
Session header: Add a lock/shield icon button next to the existing session action buttons (share, archive, etc.) in the session header. When toggled:
Icon changes to indicate private state (e.g., filled lock)
A subtle visual indicator appears (e.g., badge or border color)
Slash command: /private toggles private mode for the current session.
Sidebar indicator: Private sessions show a small lock icon in the session list.
New session flow: Consider adding a "Start private session" option alongside the existing "New Session" button, or a keyboard shortcut.
Visual Design
Private sessions should have a subtle but clear visual indicator
Suggested: small lock icon in the session sidebar entry
Suggested: "Private" badge or lock icon in the session header
Should NOT be distracting — most sessions will be non-private
Files to create/modify
UI (app-prefixable/)
app-prefixable/src/context/memory.tsx — new context provider for memory/private state (fetches private list, provides toggle function)
Session type has no metadata field: app-prefixable/src/sdk/gen/types.gen.ts line 807
Future Improvement
If/when the upstream OpenCode API adds a metadata or tags field to the Session type, the private flag should migrate to live on the session object itself. This would eliminate the need for the separate state file and make the feature work without the watcher being installed. File an upstream feature request at https://github.com/anomalyco/opencode if this epic proves the concept.
Acceptance Criteria
Users can toggle a session as private via UI button or /private slash command
Private sessions show a visual indicator in the sidebar and session header
The watcher skips private sessions during ingestion
Toggling private on a session that was already ingested does NOT retroactively remove it from the knowledge graph (document this limitation)
Private state persists across browser refreshes and watcher restarts
"Start private session" option available at session creation (optional, nice-to-have)
Context
The memory ingestion watcher (#241) automatically captures every OpenCode session into the Graphiti knowledge graph. However, some sessions contain sensitive content (credentials, private discussions, experimental code) that should NOT be recorded in the shared memory system.
Users need a way to mark a session as "private" so the watcher skips it during ingestion.
Constraint
The OpenCode Session API has a fixed schema with no extensible metadata field.
session.update()only acceptstitleandtime.archived. There is notags,metadata, orflagsfield available. This means we cannot store a "private" flag on the session object itself — we need a separate mechanism.Goal
Design
Storage: Watcher exclusion list
The watcher already maintains a state file for deduplication (
~/.local/share/opencode-memory/state.json, from #241). Extend this to include aprivatelist:{ "ingested": { "ses_abc123": { "lastMessageTime": 1713000000 } }, "private": ["ses_abc123", "ses_def456"] }The watcher checks this list before ingesting any session. If the session ID is in
private, it is skipped entirely.Sync mechanism: Shared state file or watcher API
Two options (implementer should choose the simpler one):
Option A — Shared file: The UI server writes to the same state file the watcher reads. Both processes are on the same machine. The UI server gets a new extended API endpoint:
This endpoint reads/writes the watcher's state file directly.
Option B — Watcher HTTP API: The watcher exposes a small HTTP API (e.g., port 8766) for managing the private list. The UI server proxies to it.
Option A is simpler and recommended since both processes run on the same machine.
UI: Session header toggle + slash command
Session header: Add a lock/shield icon button next to the existing session action buttons (share, archive, etc.) in the session header. When toggled:
Slash command:
/privatetoggles private mode for the current session.Sidebar indicator: Private sessions show a small lock icon in the session list.
New session flow: Consider adding a "Start private session" option alongside the existing "New Session" button, or a keyboard shortcut.
Visual Design
Files to create/modify
UI (app-prefixable/)
app-prefixable/src/context/memory.tsx— new context provider for memory/private state (fetches private list, provides toggle function)app-prefixable/src/pages/session.tsx— add/privateslash command, add header toggle buttonapp-prefixable/src/components/session-header.tsx— add private indicatorapp-prefixable/src/components/session-sidebar.tsx— add lock icon for private sessionsapp-prefixable/src/pages/layout.tsx— add "Start private session" option (optional)Server (shared/)
shared/extended-api.ts— addPOST /api/ext/memory/privateandGET /api/ext/memory/privateendpointsWatcher (memory/)
memory/watcher/state.ts— extend state model withprivatelistmemory/watcher/index.ts— check private list before ingestionReference
app-prefixable/src/components/session-header.tsxapp-prefixable/src/components/session-sidebar.tsxandapp-prefixable/src/pages/layout.tsx(lines 2350-2560)shared/extended-api.ts(see existingDELETE /api/ext/mcp/:namefor the pattern)app-prefixable/src/pages/session.tsx(search forregisterCommand)memory/watcher/state.ts(from Build background session ingestion watcher #241)app-prefixable/src/sdk/gen/types.gen.tsline 807Future Improvement
If/when the upstream OpenCode API adds a
metadataortagsfield to the Session type, the private flag should migrate to live on the session object itself. This would eliminate the need for the separate state file and make the feature work without the watcher being installed. File an upstream feature request at https://github.com/anomalyco/opencode if this epic proves the concept.Acceptance Criteria
/privateslash command