henryqin1997/statem

CLI runbook for agent long run.

1,012

stars

12

commits

Python

primary language

Sep 2, 2026

updated

README

StateM

A command-line state machine for reliable, long-running AI agents.

Project Page Paper Hugging Face Papers X / Twitter Version Python License

News

[2026-08-18]🤗 StateM ranked #1 on Hugging Face Daily Papers.

[2026-08-18]🔥 We released the DeepSeek-V4-Flash StateM runbook and reproducibility release, reaching 88.8% descriptive accuracy on Terminal-Bench 2.1 (395/445 trials; 88.76% unrounded). Everyone can try!

StateM turns an agent workflow into an inspectable graph of states, transitions, and executable checks. It keeps planning, execution, verification, repair, and handoff from collapsing into one long prompt.

Overview

Long agent runs often fail for ordinary reasons: the original goal fades from attention, progress lives only in chat history, verification is postponed, or a new session cannot reconstruct what happened. StateM moves that procedural state out of the model context and into a lightweight, versioned runbook.

prepare -> execute -> verify -> handoff
              ^          |
              +-- repair-+

At every state, the agent can ask:

  • What should I do now?
  • Which transitions are legal?
  • What evidence is required before I move?
  • What happened earlier in this run?

The answer is stored in files and runtime history rather than relying on the model to remember everything.

Why StateM?

ApproachRemembers phaseBlocks invalid transitionsSupports repair loopsSurvives context refreshAgent-editable
Prompt-only workflowPartialNoInformalNoYes
TODO listPartialNoInformalYesYes
CI pipelineYesYesLimitedYesUsually no
General workflow engineYesYesYesYesRarely
StateMYesYesYesYesYes

StateM is deliberately smaller than a workflow engine. It is a state-aware runbook that an agent can read, author, inspect, and repair from the command line.

Highlights

  • Explicit phase boundaries — model planning, implementation, review, recovery, and handoff as real states.
  • Executable transition gates — use checklists, commands, predicates, manual approval, and LLM review before leaving a state.
  • Dynamic checks — let an agent register task-specific checks for the current state entry without mutating the shared runbook.
  • Durable runtime history — persist the current node, transitions, hook results, evidence, timestamps, and spec identity.
  • Context lifecycle support — generate safe resume and compaction prompts for long cyclic runs.
  • Zero runtime dependencies — the core package requires only Python 3.11 or newer.

Installation

Clone the repository and install it in editable mode:

git clone https://github.com/henryqin1997/statem.git
cd statem
python3 -m pip install -e .

Check the CLI:

statem --help

Quick start

Validate and start the included coding-agent runbook:

statem validate examples/coding-agent.yaml
statem start examples/coding-agent.yaml --run-id demo
statem cur --run-id demo
statem next --run-id demo

Move only when the current state's checks pass:

statem goto plan --run-id demo
statem history --run-id demo

Runtime data defaults to .statem/. For durable machine-local state that survives disposable checkouts, place it outside the repository:

export STATEM_STATE_DIR="$HOME/.local/state/statem/my-project"
statem start examples/coding-agent.yaml --run-id demo

A minimal runbook

name: implementation-loop
initial: plan

nodes:
  plan:
    prompt: |
      Read the task and write a concrete implementation plan.
    before_transfer:
      type: checklist
      items:
        - Scope and constraints are recorded
        - Verification steps are defined

  execute:
    prompt: |
      Implement the plan and keep the change scoped.
    before_transfer:
      - type: command
        run: "python3 -m pytest -q"
      - type: checklist
        items:
          - Relevant tests pass
          - Unrelated files were not changed

  handoff:
    prompt: |
      Summarize the change, verification, and remaining risks.

edges:
  - from: plan
    to: execute
    condition: The plan is ready.
  - from: execute
    to: plan
    condition: Verification found a fixable gap.
  - from: execute
    to: handoff
    condition: The implementation and verification are complete.

Save it as runbook.yaml, then run:

statem validate runbook.yaml
statem start runbook.yaml --run-id my-run
statem cur --run-id my-run

How it works

StateM separates the shared workflow definition from per-run execution state:

LayerContentsCommit to git?
Static runbookNodes, edges, prompts, hooks, gatesYes
Runtime stateCurrent node, history, results, timestampsNo
Dynamic checksTask-specific current-entry verificationNo
Durable project notesPlans, decisions, progress, artifactsUsually yes

A transition is a transaction:

  1. Resolve the requested outgoing edge.
  2. Run the current node's before_transfer checks.
  3. Load and run current-entry dynamic checks.
  4. Evaluate the edge's condition.
  5. Run the current node's out_hook and the edge hook.
  6. Record the transition, create a new target entry, and run the target node's in_hook.

If a blocking check fails, the agent remains in the current state with the failure recorded for repair.

Runbook reference

Top-level fields

FieldPurpose
nameHuman-readable graph name
initialNode entered when a new run starts
nodesNamed state definitions
edgesDirected transitions between states

Node fields

FieldWhen it runsTypical use
prompt / pre_requestWhile the node is activeState-local instructions
in_hookAfter enteringLoad context or initialize evidence
before_transferBefore leavingBlock on required verification
dynamic_before_transferBefore leavingRun task-specific current-entry checks
out_hookBefore the transition commitsPersist progress or handoff notes

Edge fields

FieldPurpose
from / toSource and target nodes
conditionTransition-specific blocking gate
hookPrepare-transfer work after exit gates pass
max_attemptsOptional positive retry ceiling for this edge and source-node entry

Leaving out max_attempts preserves the default unbounded retry behavior. When configured, each real goto consumes one attempt; blocked checks count, and a fresh source-node entry receives a fresh budget.

Check and hook types

TypeBehavior
messageDisplay non-blocking guidance
manualAsk for explicit confirmation
checklistConfirm a set of completion conditions
commandRun a shell command and use its exit code
predicateInspect files declaratively
llm_reviewDelegate a structured review to an external command/model

Checks can be configured with fields such as blocking, on_failure, timeout, and cwd. Prefer checks that exercise the same interface the task promises to its eventual consumer.

CLI at a glance

CommandPurpose
statem start SPECCreate or resume a run
statem curShow the current node and its prompt
statem stateShow the full graph
statem ls NODEInspect one node
statem nextShow outgoing transitions
statem goto TARGETAttempt a checked transition
statem savePersist state and run the current out_hook
statem historyInspect prior transitions and results
statem promptGenerate a durable post-clear resume prompt
statem compact-promptGenerate a safe compaction prompt
statem validate SPECValidate graph structure and references
statem validate SPEC --strictAlso reject unknown or misplaced runbook keywords
statem dynamic ...Manage current-entry dynamic checks

Most commands accept --run-id, --state-dir, and --json for explicit run selection, isolated state, and machine-readable output.

Dynamic checks

Static gates cover invariants known when the runbook is authored. Dynamic checks cover verification discovered during the concrete task—for example, a regression test for the exact bug just fixed.

statem dynamic path --run-id demo
statem dynamic write checks.json --run-id demo --agent-id implementer
statem dynamic list --run-id demo --json

Dynamic checks are scoped to the current node entry. StateM records who registered them and runs them before the transition is allowed to commit.

Context and recovery

Long runs should keep durable facts in project files and use the model context for the current decision. StateM supports that split with:

  • statem history for the durable transition record;
  • statem prompt for restoring attention after a cleared session;
  • statem compact-prompt for safe compaction inside cyclic runbooks;
  • explicit recovery or session-refresh nodes when another loop should continue;
  • spec hashes and run identifiers to detect or deliberately rebind edited runbooks.

Runbooks belong in version control. Runtime state does not. Add .statem/ to .gitignore when using the default local state directory.

Till-finish mode (optional)

StateM works without a host hook. To keep an agent moving after it would otherwise end its turn, register the optional Stop hook as a till-finish mode. When an active run is still on a non-terminal node with outgoing transitions, the hook returns a continuation prompt that tells the agent to inspect StateM and continue from the durable state.

  1. Start the run normally with statem start.
  2. For Codex, merge codex-stop-autoloop.hooks.json into .codex/hooks.json or ~/.codex/hooks.json.
  3. For Claude Code, merge claude-stop-autoloop.settings.json into a project or user settings file.
  4. If the hook runs outside this repository, replace its command with the absolute path to integrations/hooks/statem_stop_hook.py. Set STATEM_STATE_DIR too when the run does not use the default .statem/ directory.

The hook does not advance StateM by itself, bypass transition checks, run /clear, or run /compact. It allows the host to stop when no active run exists, the current state is terminal, or the graph has no outgoing transition. See the complete setup and behavior reference.

Integrations

Host / environmentEntry point
Codexplugins/statem/skills/statem/SKILL.md
Claude Codeintegrations/claude/statem/
Harbor / Terminal-BenchExecutable git_webserver_deploy family guide
Till-finish Stop hookexamples/hooks/README.md

StateM's core remains host-agnostic: any agent that can run shell commands can query and advance a runbook.

Examples

ExampleWhat it demonstrates
coding-agent.yamlPlan, execute, review, context refresh, and handoff
git_webserver_deploy family · reproduction guideExecutable single-family graph, task-visible routing, fixed end-to-end gate, and Harbor adapters
DeepSeek server-readiness policy extract · guideAuditable, non-executable policy boundary and receipt schema

For advanced guidance on evidence receipts, consumer-facing checks, adaptive verifier plans, freshness, recovery, and benchmark integrity, read the verification guide.

Evaluation snapshot

The accompanying paper evaluates StateM as an execution harness on Terminal-Bench 2.1. These are system-level results, not claims about a new base model:

ConfigurationResultOperating condition
GPT-5.5 xhigh + StateM92.1%89 tasks, 445 trials; 88/89 five-trial coverage
GPT-5.6 Sol xhigh + frozen StateM profile95.28% raw424/445 public-submission trials; 89/89 coverage
DeepSeek-V4-Flash + adapted StateM profile88.09%392/445 under standard timeouts
DeepSeek-V4-Flash + adapted StateM profile88.76% descriptive395/445, replacing one task with disclosed extended-timeout trials

The 95.28% value is the raw pre-adjudication public-submission score. The DeepSeek descriptive aggregate is reported separately from the standard-timeout result. See the paper for experimental protocol, references, costs, and limitations.

DeepSeek policy-v9 artifacts

The policy-v9 artifact release provides:

The result artifact covers 88 tasks and excludes gpt2-codegolf: it records 392/440 raw passes (89.09%). The table above uses the paper's standard 89-task denominator, 392/445 (88.09%). These large artifacts are hosted as release assets and are not downloaded when cloning or installing StateM.

Project layout

statem/                  Core state machine and CLI
examples/                Runbooks and hook examples
integrations/            Host adapters
plugins/statem/          Codex skill packaging
tests/                   Unit and integration tests
design.md                Detailed runtime and schema design
docs/verification-guide.md
                        Advanced verification patterns

README media is served from the separate henryqin1997.github.io repository, so cloning or installing StateM does not download the demo video.

Where to go next

  1. Start with examples/coding-agent.yaml and remove any states your workflow does not need.
  2. Read design.md when you need the full runtime, transition, hook, and recovery semantics.
  3. Add deterministic before_transfer checks at consequential boundaries.
  4. Use dynamic checks only when the concrete task reveals a verification need the shared runbook could not know in advance.
  5. Keep large outputs and durable decisions in files; keep the active model context focused on the current state.

Citation

@misc{qin2026statemreaching953raw,
  title         = {StateM: Reaching 95.3\% Raw Accuracy, or a \$15 Frontier Run,
                   on Terminal-Bench 2.1 via Harness Scaling},
  author        = {Ziheng Qin and Yaxin Lu and Zhangyang Atlas Wang and Kai Wang},
  year          = {2026},
  eprint        = {2608.15089},
  archivePrefix = {arXiv},
  primaryClass  = {cs.AI},
  url           = {https://arxiv.org/abs/2608.15089}
}

Acknowledge

We thank Zekai Li and Mengxuan Wu for discussions and feedback on this work.

License

StateM is released under the Apache License 2.0.

Contributors

kaiwang960112

5 commits

henryqin1997

2 commits

Yaxin-Lu

1 commits

henryqin1997/statem

CLI runbook for agent long run.

1,012

stars

12

commits

Python

primary language

Sep 2, 2026

updated

README

StateM

A command-line state machine for reliable, long-running AI agents.

Project Page Paper Hugging Face Papers X / Twitter Version Python License

News

[2026-08-18]🤗 StateM ranked #1 on Hugging Face Daily Papers.

[2026-08-18]🔥 We released the DeepSeek-V4-Flash StateM runbook and reproducibility release, reaching 88.8% descriptive accuracy on Terminal-Bench 2.1 (395/445 trials; 88.76% unrounded). Everyone can try!

StateM turns an agent workflow into an inspectable graph of states, transitions, and executable checks. It keeps planning, execution, verification, repair, and handoff from collapsing into one long prompt.

Overview

Long agent runs often fail for ordinary reasons: the original goal fades from attention, progress lives only in chat history, verification is postponed, or a new session cannot reconstruct what happened. StateM moves that procedural state out of the model context and into a lightweight, versioned runbook.

prepare -> execute -> verify -> handoff
              ^          |
              +-- repair-+

At every state, the agent can ask:

  • What should I do now?
  • Which transitions are legal?
  • What evidence is required before I move?
  • What happened earlier in this run?

The answer is stored in files and runtime history rather than relying on the model to remember everything.

Why StateM?

ApproachRemembers phaseBlocks invalid transitionsSupports repair loopsSurvives context refreshAgent-editable
Prompt-only workflowPartialNoInformalNoYes
TODO listPartialNoInformalYesYes
CI pipelineYesYesLimitedYesUsually no
General workflow engineYesYesYesYesRarely
StateMYesYesYesYesYes

StateM is deliberately smaller than a workflow engine. It is a state-aware runbook that an agent can read, author, inspect, and repair from the command line.

Highlights

  • Explicit phase boundaries — model planning, implementation, review, recovery, and handoff as real states.
  • Executable transition gates — use checklists, commands, predicates, manual approval, and LLM review before leaving a state.
  • Dynamic checks — let an agent register task-specific checks for the current state entry without mutating the shared runbook.
  • Durable runtime history — persist the current node, transitions, hook results, evidence, timestamps, and spec identity.
  • Context lifecycle support — generate safe resume and compaction prompts for long cyclic runs.
  • Zero runtime dependencies — the core package requires only Python 3.11 or newer.

Installation

Clone the repository and install it in editable mode:

git clone https://github.com/henryqin1997/statem.git
cd statem
python3 -m pip install -e .

Check the CLI:

statem --help

Quick start

Validate and start the included coding-agent runbook:

statem validate examples/coding-agent.yaml
statem start examples/coding-agent.yaml --run-id demo
statem cur --run-id demo
statem next --run-id demo

Move only when the current state's checks pass:

statem goto plan --run-id demo
statem history --run-id demo

Runtime data defaults to .statem/. For durable machine-local state that survives disposable checkouts, place it outside the repository:

export STATEM_STATE_DIR="$HOME/.local/state/statem/my-project"
statem start examples/coding-agent.yaml --run-id demo

A minimal runbook

name: implementation-loop
initial: plan

nodes:
  plan:
    prompt: |
      Read the task and write a concrete implementation plan.
    before_transfer:
      type: checklist
      items:
        - Scope and constraints are recorded
        - Verification steps are defined

  execute:
    prompt: |
      Implement the plan and keep the change scoped.
    before_transfer:
      - type: command
        run: "python3 -m pytest -q"
      - type: checklist
        items:
          - Relevant tests pass
          - Unrelated files were not changed

  handoff:
    prompt: |
      Summarize the change, verification, and remaining risks.

edges:
  - from: plan
    to: execute
    condition: The plan is ready.
  - from: execute
    to: plan
    condition: Verification found a fixable gap.
  - from: execute
    to: handoff
    condition: The implementation and verification are complete.

Save it as runbook.yaml, then run:

statem validate runbook.yaml
statem start runbook.yaml --run-id my-run
statem cur --run-id my-run

How it works

StateM separates the shared workflow definition from per-run execution state:

LayerContentsCommit to git?
Static runbookNodes, edges, prompts, hooks, gatesYes
Runtime stateCurrent node, history, results, timestampsNo
Dynamic checksTask-specific current-entry verificationNo
Durable project notesPlans, decisions, progress, artifactsUsually yes

A transition is a transaction:

  1. Resolve the requested outgoing edge.
  2. Run the current node's before_transfer checks.
  3. Load and run current-entry dynamic checks.
  4. Evaluate the edge's condition.
  5. Run the current node's out_hook and the edge hook.
  6. Record the transition, create a new target entry, and run the target node's in_hook.

If a blocking check fails, the agent remains in the current state with the failure recorded for repair.

Runbook reference

Top-level fields

FieldPurpose
nameHuman-readable graph name
initialNode entered when a new run starts
nodesNamed state definitions
edgesDirected transitions between states

Node fields

FieldWhen it runsTypical use
prompt / pre_requestWhile the node is activeState-local instructions
in_hookAfter enteringLoad context or initialize evidence
before_transferBefore leavingBlock on required verification
dynamic_before_transferBefore leavingRun task-specific current-entry checks
out_hookBefore the transition commitsPersist progress or handoff notes

Edge fields

FieldPurpose
from / toSource and target nodes
conditionTransition-specific blocking gate
hookPrepare-transfer work after exit gates pass
max_attemptsOptional positive retry ceiling for this edge and source-node entry

Leaving out max_attempts preserves the default unbounded retry behavior. When configured, each real goto consumes one attempt; blocked checks count, and a fresh source-node entry receives a fresh budget.

Check and hook types

TypeBehavior
messageDisplay non-blocking guidance
manualAsk for explicit confirmation
checklistConfirm a set of completion conditions
commandRun a shell command and use its exit code
predicateInspect files declaratively
llm_reviewDelegate a structured review to an external command/model

Checks can be configured with fields such as blocking, on_failure, timeout, and cwd. Prefer checks that exercise the same interface the task promises to its eventual consumer.

CLI at a glance

CommandPurpose
statem start SPECCreate or resume a run
statem curShow the current node and its prompt
statem stateShow the full graph
statem ls NODEInspect one node
statem nextShow outgoing transitions
statem goto TARGETAttempt a checked transition
statem savePersist state and run the current out_hook
statem historyInspect prior transitions and results
statem promptGenerate a durable post-clear resume prompt
statem compact-promptGenerate a safe compaction prompt
statem validate SPECValidate graph structure and references
statem validate SPEC --strictAlso reject unknown or misplaced runbook keywords
statem dynamic ...Manage current-entry dynamic checks

Most commands accept --run-id, --state-dir, and --json for explicit run selection, isolated state, and machine-readable output.

Dynamic checks

Static gates cover invariants known when the runbook is authored. Dynamic checks cover verification discovered during the concrete task—for example, a regression test for the exact bug just fixed.

statem dynamic path --run-id demo
statem dynamic write checks.json --run-id demo --agent-id implementer
statem dynamic list --run-id demo --json

Dynamic checks are scoped to the current node entry. StateM records who registered them and runs them before the transition is allowed to commit.

Context and recovery

Long runs should keep durable facts in project files and use the model context for the current decision. StateM supports that split with:

  • statem history for the durable transition record;
  • statem prompt for restoring attention after a cleared session;
  • statem compact-prompt for safe compaction inside cyclic runbooks;
  • explicit recovery or session-refresh nodes when another loop should continue;
  • spec hashes and run identifiers to detect or deliberately rebind edited runbooks.

Runbooks belong in version control. Runtime state does not. Add .statem/ to .gitignore when using the default local state directory.

Till-finish mode (optional)

StateM works without a host hook. To keep an agent moving after it would otherwise end its turn, register the optional Stop hook as a till-finish mode. When an active run is still on a non-terminal node with outgoing transitions, the hook returns a continuation prompt that tells the agent to inspect StateM and continue from the durable state.

  1. Start the run normally with statem start.
  2. For Codex, merge codex-stop-autoloop.hooks.json into .codex/hooks.json or ~/.codex/hooks.json.
  3. For Claude Code, merge claude-stop-autoloop.settings.json into a project or user settings file.
  4. If the hook runs outside this repository, replace its command with the absolute path to integrations/hooks/statem_stop_hook.py. Set STATEM_STATE_DIR too when the run does not use the default .statem/ directory.

The hook does not advance StateM by itself, bypass transition checks, run /clear, or run /compact. It allows the host to stop when no active run exists, the current state is terminal, or the graph has no outgoing transition. See the complete setup and behavior reference.

Integrations

Host / environmentEntry point
Codexplugins/statem/skills/statem/SKILL.md
Claude Codeintegrations/claude/statem/
Harbor / Terminal-BenchExecutable git_webserver_deploy family guide
Till-finish Stop hookexamples/hooks/README.md

StateM's core remains host-agnostic: any agent that can run shell commands can query and advance a runbook.

Examples

ExampleWhat it demonstrates
coding-agent.yamlPlan, execute, review, context refresh, and handoff
git_webserver_deploy family · reproduction guideExecutable single-family graph, task-visible routing, fixed end-to-end gate, and Harbor adapters
DeepSeek server-readiness policy extract · guideAuditable, non-executable policy boundary and receipt schema

For advanced guidance on evidence receipts, consumer-facing checks, adaptive verifier plans, freshness, recovery, and benchmark integrity, read the verification guide.

Evaluation snapshot

The accompanying paper evaluates StateM as an execution harness on Terminal-Bench 2.1. These are system-level results, not claims about a new base model:

ConfigurationResultOperating condition
GPT-5.5 xhigh + StateM92.1%89 tasks, 445 trials; 88/89 five-trial coverage
GPT-5.6 Sol xhigh + frozen StateM profile95.28% raw424/445 public-submission trials; 89/89 coverage
DeepSeek-V4-Flash + adapted StateM profile88.09%392/445 under standard timeouts
DeepSeek-V4-Flash + adapted StateM profile88.76% descriptive395/445, replacing one task with disclosed extended-timeout trials

The 95.28% value is the raw pre-adjudication public-submission score. The DeepSeek descriptive aggregate is reported separately from the standard-timeout result. See the paper for experimental protocol, references, costs, and limitations.

DeepSeek policy-v9 artifacts

The policy-v9 artifact release provides:

The result artifact covers 88 tasks and excludes gpt2-codegolf: it records 392/440 raw passes (89.09%). The table above uses the paper's standard 89-task denominator, 392/445 (88.09%). These large artifacts are hosted as release assets and are not downloaded when cloning or installing StateM.

Project layout

statem/                  Core state machine and CLI
examples/                Runbooks and hook examples
integrations/            Host adapters
plugins/statem/          Codex skill packaging
tests/                   Unit and integration tests
design.md                Detailed runtime and schema design
docs/verification-guide.md
                        Advanced verification patterns

README media is served from the separate henryqin1997.github.io repository, so cloning or installing StateM does not download the demo video.

Where to go next

  1. Start with examples/coding-agent.yaml and remove any states your workflow does not need.
  2. Read design.md when you need the full runtime, transition, hook, and recovery semantics.
  3. Add deterministic before_transfer checks at consequential boundaries.
  4. Use dynamic checks only when the concrete task reveals a verification need the shared runbook could not know in advance.
  5. Keep large outputs and durable decisions in files; keep the active model context focused on the current state.

Citation

@misc{qin2026statemreaching953raw,
  title         = {StateM: Reaching 95.3\% Raw Accuracy, or a \$15 Frontier Run,
                   on Terminal-Bench 2.1 via Harness Scaling},
  author        = {Ziheng Qin and Yaxin Lu and Zhangyang Atlas Wang and Kai Wang},
  year          = {2026},
  eprint        = {2608.15089},
  archivePrefix = {arXiv},
  primaryClass  = {cs.AI},
  url           = {https://arxiv.org/abs/2608.15089}
}

Acknowledge

We thank Zekai Li and Mengxuan Wu for discussions and feedback on this work.

License

StateM is released under the Apache License 2.0.

Contributors

kaiwang960112

5 commits

henryqin1997

2 commits

Yaxin-Lu

1 commits

Languages

Python

99.8%