Skip to main content

Edward

The supervisor for coding agents that run when nobody's watching.

CI jobs, overnight runs, scheduled batches — unattended agents fail quietly: the same broken test retried 40 times, rm -rf on the wrong directory, budget burned at 3am with no one to hit stop. Edward watches the event stream, builds a picture of what the agent is actually doing across turns, and intervenes when the picture stops looking right — PAUSE (resumable), CANCEL, or BLOCK — with a signed receipt for every decision.

CI PyPI downloads python license deps benchmark PRs welcome

PyPI · Benchmark · Contributing · Changelog

Agents fail quietly. Edward notices.

Edward live intervention: passive stall detected, agent cancelled at 3,589 tokens
Live run: a looping agent is stopped mid-flight — decision signed, audited, resumable.

Agents fail quietly. They retry the same broken test 40 times, burn $8 in tokens on a loop, run rm -rf on a database directory, and write to files they were never supposed to touch. The agent doesn't know it's failing — from its perspective, it's still trying.

Edward sits between the agent and its runtime. It watches the event stream, builds a picture of what the agent is actually doing across turns, and intervenes when the picture stops looking right.

Edward architecture: agent events → cross-turn state → deterministic triggers → advisory scorer → kernel decision → signed receipts

Why not just if/else?

A watchdog (error_count > 5 → stop) looks at individual events. The failure modes that actually kill long-running agents don't show up in any single event — they emerge from the shape of the trajectory over time. We tested this directly on held-out data (seed 137, frozen config):

Scenario Watchdog Edward (State Engine) Watchdog ctx Edward ctx
budget bleed 20% 100% 2,322 409
infinite loop 0% 100% 6,084 409
convergence stall 0% 100% 1,442 409
dangerous command 75% 100% 522 434

Watchdogs miss temporal failure modes entirely because they have no memory across turns. Edward maintains a sliding window of tool calls, tracks file modifications, and computes elapsed time — none of which fit in a single-event check.

Measured, not claimed

Edward validates itself against StepShield (NeurIPS 2026), the first benchmark treating intervention timing as a first-class metric (9,429 trajectories, step-level labels, 216 held-out):

Detector Recall FPR (clean) EIR₃ (timing) Cost / decision
LLMJudge (GPT-4.1-mini, paper) 95.4% 5.6% 0.89 GPT-4.1-mini price
Edward contract probe (Jev 1.13) 59.3% 10.2% 0.91 ~$0.0001, one batched call
Edward contract probe (local 4B) 58.3% 17.6% 0.78 ~$0.00002, on your GPU
Edward rules only 7.4% — — 0
HybridGuard (paper) 75.9% 44.4% 0.40 —
StaticGuard 847 rules (paper) 86.1% 77.8% 0.23 —

The deterministic layer alone is quantitatively blind to content-semantic violations (7.4%) — the "silent corruption" gap — while keeping the best false-positive rate. Swapping the judgment backend changes the trade, not the architecture: the local 4B keeps events on your network at zero marginal cost; TypeSafe Jev lifts EIR₃ above the paper's GPT-4.1-mini judge (0.91 vs 0.89) with 42% fewer false positives, one batched calibrated call per probe battery. Trajectory-level recall is the shared frontier for small judges — we measure and publish it rather than claim it away. Full series, raw logs, reproduction commands: BENCHMARK.md.

StepShield holdout: EIR3 by system and cost-vs-quality scatter

StepShield holdout recall by attack family: Jev 1.13 vs local 4B

External benchmarks: RedCode-Exec recognition and ATBench F1

What it detects

Eight trigger rules, tuned on a dev split (seed 42) and frozen for held-out evaluation (seed 137):

Signal Fires when
Error rate > 40% over the last 8+ calls, no recovery signal
Retry count ≥ 3 retries of the same thing
Token budget > 80% consumed
Convergence stall > 600s + > 5 turns, no completion
Passive stall 12 consecutive reads, 0 writes
Dangerous command rm -rf, sudo, git push --force, `curl
Scope violation writes outside the allowed path prefixes
Silent corruption risk ≥ 10 consecutive file writes with zero shell verification

Policy packs make the knobs yours: conservative / balanced (= FROZEN defaults) / aggressive, as TOML or JSON.

Quickstart

pipx install edward-guard            # zero dependencies, Python 3.11+

edward doctor                        # environment checks
edward demo                          # self-running proof: 6 failure scenarios, PASS/FAIL
edward demo --live-scorer --offline  # same proof through the full scorer pipeline (heuristic stub, no GPU)

edward wrap -- pi "fix the flaky test"                     # full monitoring + intervention
edward wrap --no-scorer -- python my_agent.py              # any command, rule-only
edward wrap --scope ./src --auto-resume 60 -- pi "task"    # scoped writes, auto-resume
$ edward demo
policy: balanced  trials/scenario: 3

scenario             expect     result        latency
-----------------------------------------------------
normal               no-fire    clean               —  ok
transient_failure    no-fire    clean               —  ok
infinite_loop        fire       100% detected      8.0  ok
budget_bleed         fire       100% detected     12.0  ok
dangerous            fire       100% detected      4.7  ok
stall                fire       100% detected      4.0  ok

PASS in 0.0s (deterministic rules frozen defaults; scorer off)

Real output, not a mock — six failure scenarios against the frozen rule set, plus the two clean controls. Wraps any subprocess: Pi, Codex, claude -p, CI jobs, plain scripts. --agent auto|generic|pi picks the adapter (pi gets native RPC; the registry is extensible via edward.adapters entry points).

Interventions are resumable, not fatal: PAUSE exits with code 75, pins the agent session, and edward wrap --continue picks the same session back up from the audit log. CANCEL / BLOCK exit 76. Audit lands in ~/.edward/audit.jsonl — including an estimated avoided-spend per intervention.

The scorer is optional and always advisory. Point EDWARD_SCORER_URL at any local OpenAI-compatible scoring endpoint. The reference server ships two styles: --style openai (generic chat completion, one-hot reference verdicts) and --style ollama — a SemIf-style direct readout over Ollama: one forward pass, no generated text, real softmaxed probabilities over the option letters in ~0.2 s. On an 8 GB GPU, qwen3.5:9b + --style ollama lands within noise of the tuned LAN service (56.5%/19.4% vs 58.3%/17.6% recall/FPR on the 216-trajectory holdout — see BENCHMARK.md); the express gate (≥0.98) is the recommended operating point (85.7% precision at 7.4% FPR). See deploy/ for the team-LAN topology. Scorer down? Edward logs a warning and runs rule-only. It stays protective.

Pluggable scorer backends. EDWARD_SCORER_BACKEND selects where judgments come from: endpoint (default — the LAN scorer server above), jev (TypeSafe Jev — all probes batched into one calibrated call; set TYPESAFE_API_KEY), or heuristic (deterministic marker stub for offline demos and tests). edward doctor shows the active backend. All backends are advisory and share the same circuit breaker.

Edward + Jev — who decides what. With the jev backend (edward/backends.py), one Jev call receives the full cross-turn state (error trends, write streaks, budget) and returns calibrated judgments — should this trajectory continue, pause, or escalate, and how confident is that? Deterministic code owns everything irreversible: blocklists, scope checks, budget caps, intervention execution, and the signed receipt chain. Jev's confidence gates routing, never actions. Known limitation: the local-4B and Jev paths trade recall differently (see BENCHMARK.md for measured numbers and reproduction commands).

v0.3.0 highlights

  • Pluggable scorer backends — EDWARD_SCORER_BACKEND selects endpoint (your LAN 4B), jev (TypeSafe Jev: all probes in one batched calibrated call), or heuristic. edward demo --live-scorer --offline runs the full rules+scorer pipeline with no GPU and no API key.
  • Agent adapter registry — --agent auto|generic|pi|<plugin>; third-party adapters join via the edward.adapters entry-point group.
  • Process-tree interventions — pause/kill terminate the whole agent subtree (POSIX process groups, Windows CTRL_BREAK + taskkill /T) — no more orphaned npm/python children.
  • v0.2.0 added signed evidence receipts (Ed25519 hash chain, offline edward verify) and the human approval loop (--wait-approval 300).
resume from audit + offline receipt verification

Unattended runs & CI

Edward is built for agents nobody is watching. In a workflow:

- uses: VeridicalTech/Edward@main
  with:
    command: 'pi "fix the flaky test"'
    policy: balanced          # or a path to your policy TOML
    max-seconds: 1800
    # scorer-url: http://gpu-box.lan:8000   # optional local 4B judge

The command runs under supervision. If Edward intervenes — loop, stall, budget bleed, dangerous command — the job fails with a ::warning and the Ed25519 receipt trail is uploaded as an artifact, so the 3am failure comes with evidence instead of a silent $12 bill. edward verify runs in-pipeline: tampered audit logs fail the build.

Why zero dependencies?

Edward's control loop runs stdlib-only: it must boot on any Python 3.11+ box, inside any container, in front of any agent — including air-gapped ones. The heavy lifting (scoring) is delegated to a separate local service, which you own and can swap (4B quantized, bigger, whatever) without touching the control plane.

Repository map

edward/                the package
  cli.py               wrap / demo / eval / audit / doctor
  engine.py            ControlPlane: events → triggers → scorer → decision → audit
  state_engine.py      cross-turn agent state
  triggers.py          8 rules, policy-parameterized (defaults FROZEN)
  scorer_client.py     /v1/score client + circuit breaker
  stepshield.py        external benchmark adapter (EIR metrics)
  scenarios.py         failure scenario suite (demo/eval source of truth)
benchmark.py           300-trial held-out benchmark
robustness_eval.py     4-dimension robustness attack
BENCHMARK.md           full measurement series + reproduction commands
deploy/                team-LAN deployment templates

Status & roadmap

  • v0.3.0 on PyPI: scorer backends (endpoint / Jev / heuristic), agent adapter registry, process-tree hardening
  • StepShield integration with paper-aligned EIR metrics — including the Jev 1.13 backend row (EIR₃ 0.906)
  • Scorer fine-tune — attempted and abandoned under a pre-registered two-strike protocol (post-mortem in BENCHMARK.md)
  • Robustness suite as edward eval --suite robustness
  • Cloud fleet console (team tier)

Ecosystem

  • JevTree — Jev-native probability-tree planner for multi-step decisions. Complementary layers: JevTree reasons about which path to take (candidate expansion, Pareto selection over utility, probability, risk and reversibility); Edward supervises whether the executed path stays safe, in-scope, and convergent (hard constraints, semantic risk, pause/resume, signed receipts). A natural integration: JevTree expands and scores candidates → Edward gates them → JevTree selects → Edward supervises execution → receipts feed the replan.

Building a Jev-ecosystem tool that touches agent execution? Edward's adapter registry (edward.adapters entry points) and scorer backends are designed as extension points — open an issue.

Contributing

Deterministic layer stays deterministic: trigger defaults are FROZEN, and behavior-affecting changes require re-running the benchmark gate. See CONTRIBUTING.md.

License

MIT — © 2026 Edward contributors

Metadata

Release files for edward-guard 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for edward-guard 0.4.1
File Size Uploaded Provenance Actions
edward_guard-0.4.1.tar.gz 66.3 kB Without provenance Details for edward_guard-0.4.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for edward-guard 0.4.1
File Interpreter ABI Platform Actions
edward_guard-0.4.1-py3-none-any.whl Python 3 none any Details for edward_guard-0.4.1-py3-none-any.whl

Total release size: 135.2 kB

Release files / edward_guard-0.4.1.tar.gz

Download URL edward_guard-0.4.1.tar.gz
Size 66.3 kB
Tags Source
SHA-256 checksum
How to use checksums
73edd855e3f16979502b7ce1f0c023e2929da8ab24ca7f12fea590e438a4baf5
BLAKE2b-256 checksum
How to use checksums
6167b474beddf925e433d98e1d033e9feb4ae70fdf26395221c23bf358974ba7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / edward_guard-0.4.1-py3-none-any.whl

Download URL edward_guard-0.4.1-py3-none-any.whl
Size 68.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b477529454cbe9112c65d6783ad66e0192ea2b2e49f50418ae5945f5645fb9eb
BLAKE2b-256 checksum
How to use checksums
3321b97695f0ec2c15be7feb3b79b8b9f1f6f52e16e9ffed838a2620ccbd24ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Security for edward-guard 0.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page