Session lifecycle tracking, persistent context notes, transcript logging, and an explicit, unverified memory-promotion pipeline for AI agents in your agent harness.
Permissions and tool access are handled by your host AI agent harness. This MCP server provides session state tracking and the bridge between session context and long-term memory.
| Type | Phases | Description |
|---|---|---|
| ask | active | Read-only analysis and research |
| plan | active | Read-only, outputs actionable plan |
| build | active | Edit, run, verify. Use git for versioning |
| architect | planning → building → completed | Plan then Build with phase tracking |
Every session has a top-level status: active (default), completed, blocked,
or cancelled. The last three are terminal. phase remains the mode-workflow
field (e.g. architect planning/building/completed) and is separate from status.
- Close (
close_session) sets a terminal status plusclosed_at/close_reason. It is idempotent for an identical close and rejects a conflicting close. - Archive (
archive_session) is an independent, reversible flag (archived/archived_at/archive_reason). Archived sessions are hidden from default listings and reject writes. - Terminal/archived sessions are read-only:
append_context_note,append_transcript,set_mode,architect_advance_to_build, andupdate_session_metadataare rejected. Reads (get_session,get_context,get_transcript),resume_session(read-only with a warning), and promotion/export remain allowed. - Old state files are lazily normalized on read (missing
status⇒active, missingarchived⇒false). Legacy architect records withphase=completedand nostatusnormalize tostatus=completed, withclosed_atderived from the existingupdated_at/created_atand an explanatorynormalized: …close_reason. Nothing is eagerly rewritten on disk. - Every externally supplied session ID is validated against
^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$before any path is constructed from it; directory scans skip invalid names instead of aborting. - Every lifecycle/archive/metadata/stale mutation appends one auditable
systemevent totranscript.jsonl. History is never rewritten, and no hard delete is exposed anywhere. architect_completerequires an architect session inbuildingphase (idempotent for already-completed architects), rejects archived and terminalblocked/cancelledsessions, setsphase=completedandstatus=completed, appends onearchitect_completedevent, and never auto-promotes to memory.
create_session validates/normalizes these optional metadata fields exactly
(additional keys are preserved; update_session_metadata patches them later with
reserved-field validation):
| Field | Type | Default |
|---|---|---|
task_ids |
string[] | [] (references only — no Task Manager I/O) |
parent_session_id |
string | null | null |
owner |
string | null | null |
next_action |
string | null | null |
verification_status |
verified | partial | unverified |
unverified |
source_systems_checked |
string[] | [] |
tags |
string[] | [] |
npm startRegistered in your MCP client config as the agent-sessions MCP server.
list_modes- Show all session typescreate_session- Start a new session (validated metadata, see above)get_session- Get session statelist_sessions- List/filter sessions (newest updated first)resume_session- Resume the newest active non-archived session, or a specific one (closed/archived resume read-only)set_mode- Change session type (rejected when closed/archived)
close_session- Close with terminal statuscompleted|blocked|cancelled(idempotent/conflict-safe)archive_session- Archive/unarchive (reversible, idempotent)update_session_metadata- Patch metadata (reserved fields rejected; rejected when closed/archived)report_stale_sessions- Stale report: active, non-archived sessions, oldest-first byupdated_atcleanup_stale_sessions- Close stale sessions (blocked|cancelled) then archive them. Dry-run by default (writes nothing); applying requiresdry_run=false+confirm=true. Re-reads each candidate and skips it if status/archive/updated_atchanged or it is no longer past the cutoff. Never deletes anything.
architect_advance_to_build- Move from planning to building phase (rejected when closed/archived)architect_complete- Complete an architect session (closes it; never promotes)
append_transcript- Log a turn to the session transcript (rejected when closed/archived)get_transcript- Retrieve transcript entriesappend_context_note- Add note to rolling context summary (rejected when closed/archived)get_context- Read the full context document
promote_session_memory- Create a versioned (schema_version: 1), unverified promotion candidate in the queue. Deterministic content hash/candidate id; idempotent for identical content; changed content gets a hash-suffixed file (never an overwrite). Does not run the consumer.
These tools always use the canonical current base root (<OPENCODE_BASE_DIR>/.opencode)
— no caller-supplied filesystem override is accepted. Explicit baseDir remains
available only inside the consumer module, its CLI, and tests. Quarantine entries
store safe metadata only (IDs, hashes, memory count, queue path, rule IDs/counts/
indexes) — never candidate memory contents.
promotion_status- Read-only pipeline status (queue/inbox/quarantine/pages/ledger)promotion_process- Process queue candidates to inbox (clean) or quarantine. Dry-run unlesswrite=true. Never modifies queue/session files.promotion_lint- Lint inbox entries (schema, hash, secret/PII scan). Read-only.promotion_review- Approve (writes a trusted wiki page only after lint+scan+provenance pass) or reject. Requiresconfirm=trueand areviewer; dry-run unlesswrite=true.
No code path auto-trusts a candidate: queue → unverified inbox/quarantine → explicit human review → trusted page (ledgered).
All filters are additive. Defaults: lifecycle=all (active + closed),
include_archived=false, offset=0, limit=20, order by updated_at descending.
workspace_root- case-insensitive, normalized exact path matchmode/phase/status- single value or arraylifecycle-active|closed|allcreated_after/created_before/updated_after/updated_before- ISO dates (validated; inclusive>=/<=)metadata- subset match against session metadatatask_id- matchesmetadata.task_idsentries and legacymetadata.task_idparent_session_id- exact matchtags+tag_match-all(default) |anykeyword- case-insensitive substring overcontext.mdnotesoffset/limit/include_state- pagination and full-state embedding
Summaries include status, closed_at, archived, workspace_root, and the
linkage fields task_ids, parent_session_id, tags.
State lives under the canonical root <base>/.opencode/, where <base> is
OPENCODE_BASE_DIR (default: ~/.config/opencode):
.opencode/
sessions/<session-id>/
state.json # mode, phase, status, archive flags, plan steps, metadata
transcript.jsonl # Append-only turn + system-event log
context.md # Rolling distilled context
memory-promotions/<candidate-id>.json
# Unverified promotion candidates (schema_version 1)
wiki/
inbox/ # Processed, still-unverified candidates
quarantine/ # Failed validation/scan/provenance (safe metadata only, no contents)
pages/ # Trusted pages (explicit human approval only)
review-ledger.jsonl # Append-only review events
Restart note: the sessions root is resolved from OPENCODE_BASE_DIR when the
server process starts. After migrating state or changing the env var, restart the
agent-sessions server (restart your agent harness) so it picks up the new root.
create_session(mode="build", workspace_root="C:/path/to/project")
-> edit files, run tests (use git for versioning via /undo or git MCP tools)
-> append_context_note for important decisions
-> close_session(status="completed") when done
-> promote_session_memory to queue an unverified candidate (optional)
create_session(mode="architect", workspace_root="C:/path/to/project")
# Phase 1: Planning
-> analyze, produce plan
-> architect_advance_to_build(plan_steps=[...])
# Phase 2: Building
-> implement plan steps, commit via git
-> architect_complete() # sets phase=completed AND status=completed; no auto-promotion
resume_session() # resumes newest active non-archived session
resume_session(session_id="...") # closed/archived sessions resume read-only
promote_session_memory(session_id) # queue an UNVERIFIED candidate
promotion_process() # dry-run triage (inbox vs quarantine)
promotion_process(write=true) # write entries
promotion_lint() # re-validate inbox
promotion_review(candidate_id, action="approve",
confirm=true, reviewer="Matt Maas", write=true)
# trusted wiki page + ledger entry
report_stale_sessions(stale_after_days=14) # read-only report
cleanup_stale_sessions(stale_after_days=14) # dry-run: writes nothing
cleanup_stale_sessions(stale_after_days=14,
dry_run=false, confirm=true,
close_status="blocked") # close + archive, never delete
node --test agent-sessions-lifecycle.test.mjs promotion-consumer.test.mjs
node test-migrate-state-root.mjs
node test-logging-gate.mjs
node test-integration.mjs # tools/list smokeAll tests use temp roots (OPENCODE_BASE_DIR overrides) only; live session/queue/wiki
state is never touched.
File versioning is handled through git-based /undo /redo commands
and the git MCP server.