[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.
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:
The answer is stored in files and runtime history rather than relying on the model to remember everything.
| Approach | Remembers phase | Blocks invalid transitions | Supports repair loops | Survives context refresh | Agent-editable |
|---|---|---|---|---|---|
| Prompt-only workflow | Partial | No | Informal | No | Yes |
| TODO list | Partial | No | Informal | Yes | Yes |
| CI pipeline | Yes | Yes | Limited | Yes | Usually no |
| General workflow engine | Yes | Yes | Yes | Yes | Rarely |
| StateM | Yes | Yes | Yes | Yes | Yes |
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.
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
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
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
StateM separates the shared workflow definition from per-run execution state:
| Layer | Contents | Commit to git? |
|---|---|---|
| Static runbook | Nodes, edges, prompts, hooks, gates | Yes |
| Runtime state | Current node, history, results, timestamps | No |
| Dynamic checks | Task-specific current-entry verification | No |
| Durable project notes | Plans, decisions, progress, artifacts | Usually yes |
A transition is a transaction:
before_transfer checks.condition.out_hook and the edge hook.in_hook.If a blocking check fails, the agent remains in the current state with the failure recorded for repair.
| Field | Purpose |
|---|---|
name | Human-readable graph name |
initial | Node entered when a new run starts |
nodes | Named state definitions |
edges | Directed transitions between states |
| Field | When it runs | Typical use |
|---|---|---|
prompt / pre_request | While the node is active | State-local instructions |
in_hook | After entering | Load context or initialize evidence |
before_transfer | Before leaving | Block on required verification |
dynamic_before_transfer | Before leaving | Run task-specific current-entry checks |
out_hook | Before the transition commits | Persist progress or handoff notes |
| Field | Purpose |
|---|---|
from / to | Source and target nodes |
condition | Transition-specific blocking gate |
hook | Prepare-transfer work after exit gates pass |
max_attempts | Optional 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.
| Type | Behavior |
|---|---|
message | Display non-blocking guidance |
manual | Ask for explicit confirmation |
checklist | Confirm a set of completion conditions |
command | Run a shell command and use its exit code |
predicate | Inspect files declaratively |
llm_review | Delegate 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.
| Command | Purpose |
|---|---|
statem start SPEC | Create or resume a run |
statem cur | Show the current node and its prompt |
statem state | Show the full graph |
statem ls NODE | Inspect one node |
statem next | Show outgoing transitions |
statem goto TARGET | Attempt a checked transition |
statem save | Persist state and run the current out_hook |
statem history | Inspect prior transitions and results |
statem prompt | Generate a durable post-clear resume prompt |
statem compact-prompt | Generate a safe compaction prompt |
statem validate SPEC | Validate graph structure and references |
statem validate SPEC --strict | Also 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.
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.
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;Runbooks belong in version control. Runtime state does not. Add .statem/ to .gitignore when using the default local state directory.
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.
statem start.codex-stop-autoloop.hooks.json into .codex/hooks.json or ~/.codex/hooks.json.claude-stop-autoloop.settings.json into a project or user settings file.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.
| Host / environment | Entry point |
|---|---|
| Codex | plugins/statem/skills/statem/SKILL.md |
| Claude Code | integrations/claude/statem/ |
| Harbor / Terminal-Bench | Executable git_webserver_deploy family guide |
| Till-finish Stop hook | examples/hooks/README.md |
StateM's core remains host-agnostic: any agent that can run shell commands can query and advance a runbook.
| Example | What it demonstrates |
|---|---|
coding-agent.yaml | Plan, execute, review, context refresh, and handoff |
git_webserver_deploy family · reproduction guide | Executable single-family graph, task-visible routing, fixed end-to-end gate, and Harbor adapters |
| DeepSeek server-readiness policy extract · guide | Auditable, 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.
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:
| Configuration | Result | Operating condition |
|---|---|---|
| GPT-5.5 xhigh + StateM | 92.1% | 89 tasks, 445 trials; 88/89 five-trial coverage |
| GPT-5.6 Sol xhigh + frozen StateM profile | 95.28% raw | 424/445 public-submission trials; 89/89 coverage |
| DeepSeek-V4-Flash + adapted StateM profile | 88.09% | 392/445 under standard timeouts |
| DeepSeek-V4-Flash + adapted StateM profile | 88.76% descriptive | 395/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.
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.
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.
examples/coding-agent.yaml and remove any states your workflow does not need.design.md when you need the full runtime, transition, hook, and recovery semantics.before_transfer checks at consequential boundaries.@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}
}
We thank Zekai Li and Mengxuan Wu for discussions and feedback on this work.
StateM is released under the Apache License 2.0.
Python
99.8%
[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.
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:
The answer is stored in files and runtime history rather than relying on the model to remember everything.
| Approach | Remembers phase | Blocks invalid transitions | Supports repair loops | Survives context refresh | Agent-editable |
|---|---|---|---|---|---|
| Prompt-only workflow | Partial | No | Informal | No | Yes |
| TODO list | Partial | No | Informal | Yes | Yes |
| CI pipeline | Yes | Yes | Limited | Yes | Usually no |
| General workflow engine | Yes | Yes | Yes | Yes | Rarely |
| StateM | Yes | Yes | Yes | Yes | Yes |
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.
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
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
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
StateM separates the shared workflow definition from per-run execution state:
| Layer | Contents | Commit to git? |
|---|---|---|
| Static runbook | Nodes, edges, prompts, hooks, gates | Yes |
| Runtime state | Current node, history, results, timestamps | No |
| Dynamic checks | Task-specific current-entry verification | No |
| Durable project notes | Plans, decisions, progress, artifacts | Usually yes |
A transition is a transaction:
before_transfer checks.condition.out_hook and the edge hook.in_hook.If a blocking check fails, the agent remains in the current state with the failure recorded for repair.
| Field | Purpose |
|---|---|
name | Human-readable graph name |
initial | Node entered when a new run starts |
nodes | Named state definitions |
edges | Directed transitions between states |
| Field | When it runs | Typical use |
|---|---|---|
prompt / pre_request | While the node is active | State-local instructions |
in_hook | After entering | Load context or initialize evidence |
before_transfer | Before leaving | Block on required verification |
dynamic_before_transfer | Before leaving | Run task-specific current-entry checks |
out_hook | Before the transition commits | Persist progress or handoff notes |
| Field | Purpose |
|---|---|
from / to | Source and target nodes |
condition | Transition-specific blocking gate |
hook | Prepare-transfer work after exit gates pass |
max_attempts | Optional 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.
| Type | Behavior |
|---|---|
message | Display non-blocking guidance |
manual | Ask for explicit confirmation |
checklist | Confirm a set of completion conditions |
command | Run a shell command and use its exit code |
predicate | Inspect files declaratively |
llm_review | Delegate 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.
| Command | Purpose |
|---|---|
statem start SPEC | Create or resume a run |
statem cur | Show the current node and its prompt |
statem state | Show the full graph |
statem ls NODE | Inspect one node |
statem next | Show outgoing transitions |
statem goto TARGET | Attempt a checked transition |
statem save | Persist state and run the current out_hook |
statem history | Inspect prior transitions and results |
statem prompt | Generate a durable post-clear resume prompt |
statem compact-prompt | Generate a safe compaction prompt |
statem validate SPEC | Validate graph structure and references |
statem validate SPEC --strict | Also 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.
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.
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;Runbooks belong in version control. Runtime state does not. Add .statem/ to .gitignore when using the default local state directory.
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.
statem start.codex-stop-autoloop.hooks.json into .codex/hooks.json or ~/.codex/hooks.json.claude-stop-autoloop.settings.json into a project or user settings file.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.
| Host / environment | Entry point |
|---|---|
| Codex | plugins/statem/skills/statem/SKILL.md |
| Claude Code | integrations/claude/statem/ |
| Harbor / Terminal-Bench | Executable git_webserver_deploy family guide |
| Till-finish Stop hook | examples/hooks/README.md |
StateM's core remains host-agnostic: any agent that can run shell commands can query and advance a runbook.
| Example | What it demonstrates |
|---|---|
coding-agent.yaml | Plan, execute, review, context refresh, and handoff |
git_webserver_deploy family · reproduction guide | Executable single-family graph, task-visible routing, fixed end-to-end gate, and Harbor adapters |
| DeepSeek server-readiness policy extract · guide | Auditable, 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.
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:
| Configuration | Result | Operating condition |
|---|---|---|
| GPT-5.5 xhigh + StateM | 92.1% | 89 tasks, 445 trials; 88/89 five-trial coverage |
| GPT-5.6 Sol xhigh + frozen StateM profile | 95.28% raw | 424/445 public-submission trials; 89/89 coverage |
| DeepSeek-V4-Flash + adapted StateM profile | 88.09% | 392/445 under standard timeouts |
| DeepSeek-V4-Flash + adapted StateM profile | 88.76% descriptive | 395/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.
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.
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.
examples/coding-agent.yaml and remove any states your workflow does not need.design.md when you need the full runtime, transition, hook, and recovery semantics.before_transfer checks at consequential boundaries.@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}
}
We thank Zekai Li and Mengxuan Wu for discussions and feedback on this work.
StateM is released under the Apache License 2.0.
Python
99.8%