Skip to main content
Version: MVP

Persistent agent runtime

5 min readFor operatorsUpdated 2026-05-22

What you'll do

Launch and manage the v0.9.0 persistent agent runtime. This guide covers the lifecycle CLI, the operator-session requirement, the provider-backed prompt loop, and the records Craik leaves behind.

One-shot runs and persistent agents are separate surfaces.

Use craik run execute for bounded one-shot task runs. Use craik agent launch plus craik agent prompt when you want a longer-lived session that keeps provider, model, project, operator, policy, receipt, handoff, and recovery links together.

Before you launch

Persistent agent lifecycle commands require an active operator session. The CLI checks the same session store used by the operator surface:

craik auth login
craik whoami

If no session is available, lifecycle commands fail before reading or writing agent state.

Launch a session

craik agent launch \
--session-id agent_docs \
--project-id project_docs \
--provider-id provider_openai \
--model-id gpt-5.2 \
--auth-profile-id openai:work

The command persists a craik.agent_session_state record and returns JSON. The session is bound to the active operator subject and issuer, the project id, provider id, optional model id, optional auth profile, and optional policy envelope.

Send a prompt

craik agent prompt agent_docs "Implement the next bounded provider task."

prompt creates a task under the session project, executes it through the session provider, and returns the same run, provider receipt, handoff, and output shape used by provider-backed one-shot runs. The session moves back to idle when the run finishes and stores the active task id, run id, receipt ids, environment receipt ids, handoff ids, and recovery metadata.

Use /exit, exit, /quit, or quit as the prompt text to stop the session without starting a provider run:

craik agent prompt agent_docs /exit

For deterministic fixture-backed validation, the command grants the fixture action by default. Use --no-allow-fixture-action to exercise the blocked approval path. That path records a denied sandbox environment receipt and leaves the run blocked. Use --max-iterations to test interruption, and --provider-token-budget to test token-budget interruption.

Inspect and list sessions

craik agent status agent_docs
craik agent list

status returns one persisted session. When a future background launch stores a pid, status checks whether that pid still exists. Missing processes are marked failed with an operator-visible supervision note, which gives recovery code a precise state to act on.

Background sessions with an endpoint URL but no pid are also treated as stale endpoint state. Craik records redacted recovery metadata before returning the updated session.

Recover a session

craik agent recover agent_docs --reason auth_expired
craik agent recover agent_docs --reason provider_unavailable
craik agent recover agent_docs --reason sandbox_failed
craik agent recover agent_docs --action reconnect
craik agent recover agent_docs --action resume

Recovery reasons move the session into an explicit recoverable state: auth_expired, provider_unavailable, sandbox_failed, or failed for stale pid and endpoint state. Recovery metadata stores the reason, detected timestamp, recommended action, provider/model/project links, and redacted operator detail. reconnect moves the session back to running; resume moves it to idle while preserving prior task, run, receipt, handoff, and recovery references.

Run the launch demo

craik demo persistent-agent --repo-path .

The demo is deterministic and uses fixture provider transport. It launches persistent sessions, runs a prompt, records provider receipts, writes handoffs, inspects final session state, and prints the exact operator commands that mirror the flow. It deletes demo session artifacts on exit by default; pass --keep-artifacts only when you need to inspect those records afterward. By default it covers OpenAI, Anthropic, Gemini, and a local Ollama-style route:

craik demo persistent-agent \
--repo-path . \
--provider-id provider_openai \
--provider-id provider_anthropic

The demo refuses non-fixture provider transport unless --allow-live is supplied. Use that override only when you intentionally want the demo to consume live provider quota.

Provider transport model

Craik does not depend on the official OpenAI, Anthropic, or Gemini SDKs for persistent-agent execution. Provider adapters build published REST payloads and send them through Craik's transport layer. The tradeoff is a smaller runtime dependency surface and uniform receipt handling, while provider API changes must be tracked in Craik's adapters and tests.

Stop and restart

craik agent stop agent_docs --reason "operator stop"
craik agent restart agent_docs --reason "operator restart"

Stop is only valid for active sessions. Restart is only valid for stopped or failed sessions. Invalid transitions fail with a CLI input error and do not mutate stored state.

What is persisted

Agent sessions store identifiers and references, not credential material:

Operator

Subject and issuer from the active session.

Provider

Provider id, model id, and optional auth profile id.

Lifecycle

Mode, status, timestamps, pid, endpoint URL, and supervision notes.

Links

Project, task, run, policy envelope, receipt, environment receipt, handoff, and recovery ids.

Events

Prompt, run completion, interruption, and exit events.

Each prompt also persists redacted craik.agent_session_event records. Events carry stable ids for the session, task, run, handoff, receipts, provider, model, policy envelope, and recovery metadata. The raw prompt is not stored in the event; Craik stores a short prompt hash for correlation without adding operator text to logs.

Prompt execution also records environment receipts for provider and sandbox boundaries. These receipts carry agent_session_id and are linked back into the session receipt_ids, which lets operator views audit side-effect denials without storing raw commands or credentials.

Validation

uv run --extra dev pytest tests/test_cli_agents.py tests/test_agent_sessions.py

Expected output: launch, prompt, status, recover, stop, restart, operator-session gates, invalid transitions, prompt events, receipt and handoff links, interruption recovery metadata, explicit exit behavior, stale pid/endpoint detection, auth/provider/sandbox recovery, and redaction tests pass.

What's next