In-Session Engine¶
The in-session engine is the v0.1 tier: it runs entirely inside one Claude Code session, using two hooks and a set of skills. No external process, no API key, no new infrastructure.
Two more hooks ship alongside the engine
The installer also wires the prompt enhancer — a
UserPromptSubmit hook independent of the run engine (it improves your
everyday prompts, off by default) — and the repo carries
persona-guard.sh, armed only while a
persona run is active. This page covers the
two hooks that implement the autonomous run.
The two hooks¶
flowchart TB
subgraph Turn["A Claude Code turn"]
TC["tool call"] --> PRE{{"PreToolUse hook<br/>guard-irreversible.sh"}}
PRE -- "safe" --> EXEC["run tool"]
PRE -- "git/destructive,<br/>no token" --> DENY["deny + log"]
EXEC --> ENDTURN["turn ends"]
end
ENDTURN --> STOP{{"Stop hook<br/>stop-continuity.sh"}}
STOP -- "work remains,<br/>no stop condition" --> CONT["block stop ·<br/>re-inject continue"]
STOP -- "plan done / kill / budget /<br/>@human node next under autonomy: ask" --> HALT([allow stop])
CONT --> Turn
Stop hook — continuity¶
When the agent finishes a turn, the Stop hook reads .leopold/state.json and
PLAN.md. If a run is active and the plan has open items and no stop condition is
met, it returns {"decision":"block","reason":"..."}. The reason is not a
bare "continue"; it is a compact instruction that tells the agent to read the
plan, take the next item, apply the decision protocol, log, and not ask. Each
continuation increments an iteration counter, which feeds the budget stop
condition.
One plan construct changes what that instruction says: a @human node. Under
the default posture (autonomy: full) nobody is coming to decide it, so the hook
still blocks the stop — but the re-injected instruction tells the agent to
synthesize the role that decision needs, take it, do the item, and record the call
in DECISIONS.md with a Reversal line. Under autonomy: ask the hook allows
the stop with awaiting_human and names the item instead. Either way it matches
what the driver does at the same node. See
Hooks → Node kinds.
Fail-open by design
A broken Stop hook must never trap a session in a loop, so any unexpected error makes it allow the stop. Continuity is best-effort; halting is safe.
PreToolUse hook — the git lock¶
The PreToolUse hook inspects every Bash command and edit while a run is active.
Irreversible or destructive operations are denied unless an explicit per-session
token is present.
| Operation | Default | Token to allow |
|---|---|---|
git commit |
denied | .leopold/ALLOW_GIT |
git push |
denied | .leopold/ALLOW_PUSH |
| force-push | denied | none (always denied) |
everything else (rm -rf, reset --hard, gh pr, publish, …) |
allowed | — (the run's own call) |
The skills¶
flowchart LR
B["/leopold-brief"] --> R["/leopold-run"]
R --> S["/leopold-status"]
R --> X["/leopold-stop"]
B -.writes.-> Art[(.leopold/ brief)]
R -.reads.-> Art
/leopold-brief— Phase 1. Debates the mission and writes the brief./leopold-run— Phase 2. Activates the run and does turn 1; the Stop hook carries it forward./leopold-status— read-only dashboard of the run./leopold-stop— clean shutdown at the next turn boundary.
These four are the engine's core loop. The full family — /leopold-workflow,
/leopold-learn, /leopold-triage, /leopold-enhance, /leopold-watch,
/leopold-up, /leopold-update, /leopold-doctor — is documented in the
Skills reference.
Known limit¶
The loop runs while the Claude Code session is open. State persists on disk, so a run is resumable, but the in-session engine is not a background daemon. For unattended runs, use the SDK driver.