Tasks, sessions, and agent lifecycle

Repository work often spans commands, turns, or agent processes. Knowl records bounded event state and explicit checkpoints so work can resume without retaining raw conversations.

Manual work loops

For one bounded command, task run performs the initial focused lookup and records success or a failure checkpoint with the child exit code:

knowl task run "Run tests" --query "test verification" -- npm test

For resumable work, start once, checkpoint meaningful progress or blockers, and finish after verification:

knowl task start "Implement search UI" --query "search retrieval"

knowl task checkpoint <task-id> "Search tests are in place" \
  --goal "Ship the search UI" \
  --completed "Added empty and error-state tests" \
  --next-action "Implement the result list" \
  --artifact "src/search-ui.ts" \
  --verification-status "tests-passing"

knowl task finish <task-id> "Search UI implemented and verified"

Use these manual tools only when verified lifecycle hooks are unavailable. Hook-owned sessions must be left to their host lifecycle; a manual task finish or knowl_session_finish must not close them.

Session retention, recovery, and promotion

Lifecycle events are temporary scratch records and expire after 48 hours. Active session rows receive a nominal seven-day expiresAt, but the current implementation does not automatically purge those rows. A session idle for more than two hours can be marked recovered; recovery does not finalize the session or promote candidates.

At a normal terminal event, deterministic promotion selects at most eight durable candidates. Decision candidates outrank generic outcomes. A repeatedly successful command becomes a skill atom candidate after three runs, but that promoted atom is still descriptive knowledge, not an executable .knowl/skills package. Failed terminal events create a handoff for the next matching host session.

Hooks run as separate, short-lived knowl agent-hook processes. They normalize host events and never start, stop, or supervise the long-lived stdio knowl serve process. Lifecycle capture itself stores no raw prompts, transcripts, stdout, stderr, or environment variables. When transcript indexing is explicitly enabled, the separate transcript index reads supported host transcript files already present on the machine; it does not create them.

Leaving work for later

Two different shapes, deliberately not merged:

knowl_handoff knowl_park / knowl_resume
How many One per project Many at once
Who holds it The project The user, as a short key
Delivery Pushed to the next session here Pulled on demand, by key
Spent on use Yes, one-shot No, resume repeatedly
Reach Next session in this repository Any session, any directory, any time later

"I am stopping for the night, whoever picks this up should know where I left it" is a handoff. "Park this branch of work, I will come back to it in a fortnight" is a resume point. A parked baton reads as planned work rather than as a crash, because a session told it "ended before a clean finish" goes looking for damage that does not exist.

Both are passes, not durable notes. Anything worth keeping goes to knowl_store.

Searchable session transcripts (optional, off by default)

Atoms are distilled and therefore lossy: whatever the writer did not judge salient is gone. The raw Claude Code .jsonl transcripts are the complete record underneath. Indexing them turns a memory miss into a slower lookup instead of amnesia.

Off by default, and off means nothing exists — no database file, no registered tools, no tokens spent in the guidance card.

// .knowl/config.json
"search": {
  "transcripts": {
    "enabled": false,   // nothing is created, no MCP tools are registered
    "share": false      // let linked workspace repos read this index
  }
}
knowl config                                  # toggle it interactively
knowl reindex --transcripts --budget 5        # build the index, resumable

What it indexes and what it costs, measured on this repository's own archive: prose is 2.7% of 80.9 MB across 75 transcripts. Only user messages and assistant prose are indexed; tool_use and tool_result blocks are skipped entirely. Rows are pointers — (session, line, role) — and message bodies stay in the .jsonl, so the whole index is under 3 MB.

Ranking fuses BM25 with whole-corpus semantic search over int8 vectors, so a message that shares no word with your query can still win. Semantic ranking follows search.vector.enabled; with vectors off, transcript search is keyword-only and every result says so.

Three tools appear only when the feature is enabled, which is why they are absent from the canonical tool table below:

  • knowl_session_list — browse past sessions: best-known name, opening ask, status, and what each one promoted into memory.
  • knowl_transcript_search — search prose across sessions; returns transcript://<repo>/<session>#L<line> locators.
  • knowl_transcript_read — open one locator with the surrounding turns.

Disabling the feature deletes .knowl/transcripts.db. An index nothing will refresh is not something to leave on the disk of the person who just turned it off.

Workspace peers may opt in with share: true, which lets linked repositories open the index read-only. Sharing is re-checked on every read, so revoking it revokes previously issued locators too.

Both Claude Code and Codex archives are discovered. They are found by different mechanisms because they are laid out differently: Claude Code names a directory after the project (~/.claude/projects/<encoded-root>/), while Codex partitions by date (~/.codex/sessions/YYYY/MM/DD/) and records the project inside each file as session_meta.payload.cwd. Every Codex candidate is therefore opened, with a bounded header read.

knowl transcripts — turning sessions into candidates

Searching a transcript answers a question. This turns one into memory. Extraction runs the configured model over indexed sessions and stages what it finds; nothing reaches the knowledge store until you approve it.

knowl transcripts extract --limit 10        # prints the estimate, then stops
knowl transcripts extract --limit 10 --yes  # actually runs
knowl transcripts candidates                # review what was staged
knowl transcripts approve <id>...           # promote, or --all
knowl transcripts discard <id>...           # reject, or --all

Extraction spends your model quota, so it tells you first. extract prints the session count, the character estimate and the provider it would call, and does nothing without --yes. The default is 10 sessions, not the archive. It requires ai.provider and ai.model; without them, distil a session yourself with knowl_transcript_read and store the result through knowl_ingest_atoms, which needs no AI configuration.

Nothing is promoted automatically, and that is the point. A first run over a real archive produces on the order of a thousand atoms. An unreviewed corpus that size would be answering every future query while nobody had yet decided any of it was true, so approval is a separate, explicit act — one candidate at a time, each passing the same secret validation, confidence range and dedup checks that every other write does.

Runs are resumable and never pay twice. An extracted session is watermarked, including one that yielded nothing — short sessions yield nothing most often and would otherwise dominate the bill. A session whose extraction failed is deliberately left unwatermarked, because a provider error is not a verdict about that session. Long sessions are truncated from the start, keeping the tail, where a session's conclusions are.

Promoted atoms carry provenance: inferred and source: transcript:<harness>:<session>. A model distilled them from a conversation nobody re-read at approval time; calling that observed would rank it above knowledge somebody actually verified.

Candidates live in .knowl/transcripts.db, not the knowledge store, so speculative rows never reach a query and disabling transcript search discards them with the index. They are regenerable from the transcripts, which is what makes that safe.

Host and subagent behavior

Host MCP Automatic lifecycle Subagent lifecycle Current session behavior or limit
Codex Yes Yes Yes Main turns share one memory session
Claude Code Yes Yes Yes Main turns share one memory session; prompt guidance is also installed
Cursor Yes Yes No Finalizes per turn; supplied additional_context may not surface to the model
Gemini CLI Yes No No MCP plus the manual work loop
Claude Desktop Yes No No MCP plus the manual work loop

Claude Code and Codex subagents share their parent's memory session, but each subagent has its own binding, reminder counter, change watermark, and lifecycle identity. Their retrieved memory is capped at half of the normal 3,000-character context allowance, plus a compact workflow card. Cursor does not expose a corresponding subagent event.

Each accepted successful non-Knowl tool event advances a per-agent drift counter. After 12 consecutive events, a mid-turn card reminds the agent to re-query. A Knowl call or an emitted change card resets the counter. Change cards report new knowledge commits since that agent's watermark; matched writes made through that agent's own MCP call are suppressed so the caller is not notified about its own change.