agents: pluggable checkpoint store — wire cursor AgentCheckpointStore + claude session-map equivalent #958
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#958
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator I want session-resume to be observable, debuggable, and provider-symmetric (cursor + claude-code), so a stuck or stale session shows up clearly in the dashboard and can be force-cleared without restarting the service.
Context
Today:
cursor:agent-<uuid>(seecursor-sdk-adapter.ts).@cursor/sdkexposes a richer surface —AgentCheckpointStore,AgentRunStore,RunEventStore— that we don't plug into. These would let us persist intermediate checkpoints and replay run events from disk, not just the latest session id.Goals:
CheckpointStoreinterface used by both adapters.Acceptance criteria
Shared interface
CheckpointStoreinapps/server/src/infrastructure/agent/:getSession(key): Promise<string | null>(already exists; lift into the interface)setSession(key, sessionId): Promise<void>(exists)dropSession(key): Promise<void>(exists)listSessions({ agent? , provider? }): Promise<{ key, sessionId, provider, createdAt, lastUsedAt }[]>— newgetCheckpoint(sessionId): Promise<Checkpoint | null>— new (cursor-only data; claude returns null)appendRunEvent(sessionId, event): Promise<void>— new (cursor-only persisted run-event log)SQLite schema
agent_sessiontable (or extend the existing session map):(key TEXT PK, session_id TEXT NOT NULL, provider TEXT NOT NULL, created_at INTEGER, last_used_at INTEGER).agent_checkpointtable for cursor:(session_id TEXT PK, checkpoint_blob BLOB, updated_at INTEGER).agent_run_eventtable for cursor:(session_id TEXT, seq INTEGER, payload TEXT, ts INTEGER, PRIMARY KEY (session_id, seq)).Cursor adapter
CheckpointStoreadapter intoAgent.create({ stores: { checkpointStore, runStore } })(verify the cursor SDK's actual option names against current published types). OnappendRunEvent, persist to the new table.Agent.resume(...), the checkpoint store satisfies cursor's reads from disk instead of (or in addition to) the cloud.Claude adapter
getCheckpoint/ no-ops forappendRunEvent.Admin surface
GET /agents/sessions?agent=<name>&provider=<...>— list sessions.DELETE /agents/sessions/:key— drop a session (operator escape hatch when a stuck resume keeps failing).Tests
Out of scope
References
node_modules/.bun/@cursor+sdk@1.0.12/node_modules/@cursor/sdk/dist/cjs/public-api.d.ts(AgentCheckpointStore,AgentRunStore,RunEventStore)getSession/setSession/dropSession(search the server tree)🦵 @charles kicked the queue — re-running address-review on @code-lead.