Titentiten.devꦠꦶꦠꦺꦤ꧀
v0.1.1 · npmGitHub
DocsCollaborationCheckpoints

Checkpoints

Resumable task state for one agent, keyed on subject and kind, with a TTL, and deliberately kept out of the evidence store.

task_state · conversation · workflow · cursorTTL 60s – 30dstate ≤ 64 kB

State, not facts

A checkpoint answers “where did I get to?”. An observation answers “what happened?”. Merging them fills a memory store with stale scaffolding that later reads as truth.

Checkpoints, leases and handoffs are execution state, never factual evidence. Checkpoint text alone cannot support a claim, because consolidation only accepts observation ids as sources. If an agent finishes work and the finding matters, it appends an observation; the checkpoint is what it throws away.

Checkpoints expire. Evidence does not.

A checkpoint is overwritten in place. An observation is append-only.

A checkpoint cannot be cited as a source. Only observations can.

Save, and save again

POST /v1/checkpoints upserts on organization, subject, agent and kind, so the second write returns 200 with updated: true and the same checkpoint_id.

resume.tstypescript
const saved = await titen.saveCheckpoint({
  subject_id: 'user_rama',
  kind: 'task_state',
  state: { step: 3, of: 7, pending: ['rollback smoke'] },
  ttl_seconds: 3600,
});
// saved.checkpoint_id → "ckpt_713be19162544650a85b76b5ef6d7543"
// saved.updated       → false, then true on every later write

The response carries a state_hash instead of the payload, which is enough to tell whether a write changed anything:

{ "data": { "checkpoint_id": "ckpt_713be19162544650a85b76b5ef6d7543",
    "subject_id": "user_rama", "agent_id": "agent_8df7b8699a0945488ceb3d4b104006d6",
    "kind": "task_state",
    "state_hash": "5ab982ea637562b9b4d1c752bf073346eb27d7ea673a2adb463c1324c2fe947b",
    "expires_at": "2026-07-30T11:48:04.652Z", "updated": true } }

kind is one of task_state, conversation, workflow or cursor, a closed set, so the lookup key stays predictable across agents. state is any JSON value except null, under 64 000 bytes serialized. ttl_seconds runs from 60 to 2 592 000 (30 days). All three are checked before the write; a bad kind comes back as:

{ "error": { "code": "VALIDATION_ERROR",
    "message": "Field \"kind\" must be one of: task_state, conversation, workflow, cursor." } }

Reading one back

GET /v1/checkpoints is a lookup, not a list. It requires subject_id and kind, and agent_id defaults to the calling credential’s own principal.

curl -H "authorization: Bearer $TITEN_API_KEY" \
  'http://127.0.0.1:8787/v1/checkpoints?subject_id=user_rama&kind=task_state'

The response is the full record, including the parsed state, ttl_seconds, expires_at, created_at and updated_at. Anything missing, expired, or belonging to another agent returns the same non-disclosing 404:

{ "error": { "code": "NOT_FOUND", "message": "Resource was not found." } }
PER-AGENT BY DEFAULT

Because agent_id defaults to the caller, two agents saving task_state for the same subject get two independent checkpoints and neither can read the other’s by accident. Pass agent_id explicitly to resume someone else’s work, which is what a handoff hands you.

Expiry is enforced at read time: the lookup carries an expires_at > now predicate, so an expired checkpoint stops being visible. Nothing in the background deletes checkpoint rows. DELETE /v1/checkpoints/:id is the explicit removal and returns { "checkpoint_id": "…", "deleted": true }.

Checkpoints and compiled context

POST /v1/context/compile accepts include_checkpoints: true and reports that it cannot do it:

{ "meta": { "degraded": { "semantic": false, "vector": "disabled",
      "model": "disabled", "checkpoints": "unavailable" }, "candidates": 1 } }

Checkpoints do not enter a compiled pack yet. Fetch the one you need with getCheckpoint and put it in your prompt as a separate block, since task state and retrieved evidence should not arrive looking alike. The flag exists so the request survives when the capability lands; meta.degraded tells you it has not.

From MCP

Two of the seven MCP tools are checkpoints, so an agent that speaks only MCP can still resume: titen_checkpoint_save takes subject_id, kind, state and ttl_seconds, and titen_checkpoint_get takes subject_id and kind. Both arrive over POST /mcp, which takes the same bearer key as REST and is gated on mcp:call.

Next

↑↓ navigate↵ open