cd /news/ai-agents/statem-stateful-control-for-long-hor… · home topics ai-agents article
[ARTICLE · art-107121] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

StateM: Stateful control for long-horizon agents

StateM, a stateful control system for long-horizon agents, ranked #1 on Hugging Face Daily Papers on 2026-08-18 and released a runbook and reproducibility package for DeepSeek-V4-Flash, achieving 88.8% descriptive accuracy (395/445 trials) on Terminal-Bench 2.1. The tool turns agent workflows into inspectable graphs of states, transitions, and executable checks, moving procedural state out of model context into a lightweight, versioned runbook with zero runtime dependencies beyond Python 3.11.

read10 min views1 publishedAug 22, 2026
StateM: Stateful control for long-horizon agents
Image: Michielbdejong (auto-discovered)

[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:

  • 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.

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.

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.

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:

  • Resolve the requested outgoing edge.
  • Run the current node's before_transfer

checks. - Load and run current-entry dynamic checks.

  • Evaluate the edge's condition

. - Run the current node's out_hook

and the edgehook

. - 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.

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;- 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.

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.

  • Start the run normally with statem start

. - For Codex, merge intocodex-stop-autoloop.hooks.json

.codex/hooks.json

or~/.codex/hooks.json

. - For Claude Code, merge into a project or user settings file.claude-stop-autoloop.settings.json

  • If the hook runs outside this repository, replace its command with the absolute path to integrations/hooks/statem_stop_hook.py

. SetSTATEM_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

integrations/claude/statem/

Executablegit_webserver_deploy

family guideexamples/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

·git_webserver_deploy

familyreproduction guideDeepSeek server-readiness policy extract·guideFor 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.

  • Start with and remove any states your workflow does not need.examples/coding-agent.yaml

  • Read when you need the full runtime, transition, hook, and recovery semantics.design.md

  • Add deterministic before_transfer

checks at consequential boundaries. - Use dynamic checks only when the concrete task reveals a verification need the shared runbook could not know in advance.

  • Keep large outputs and durable decisions in files; keep the active model context focused on the current state.
@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.

── more in #ai-agents 4 stories · sorted by recency
── more on @statem 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/statem-stateful-cont…] indexed:0 read:10min 2026-08-22 ·