Repository navigation
Releases: CallMeHFK/agent-shepherd
Release list
v0.4.0
v0.3.0
Built from the v0.3.0 tag. The attached zip is the QwenPaw plugin bundle; the supervisor daemon is a separate install (see the README inside the archive).
v0.2.1
0.2.0 was about what the supervisor can prove. 0.2.1 is about how you receive it: everything an importer needs now sits on this page, built by CI from the v0.2.1 tag — no clone, no git client, no PyPI (this project has never been on PyPI, and the docs now say so instead of implying it).
What is in here
agent-shepherd.zip — the QwenPaw plugin bundle, named after the plugin id rather than the release so the import URL never has to be re-typed on upgrade:
qwenpaw plugin install https://github.com/CallMeHFK/agent-shepherd/releases/latest/download/agent-shepherd.zipIt carries the tree shepherd install qwenpaw writes down to the bytes (a test extracts both and compares them), plus its own README.md stating the one fact that makes an imported plugin silently useless: the bundle is the observer, and the supervisor it talks to must be installed and running, or everything fails open.
agent_shepherd-0.2.1-py3-none-any.whl and the sdist — that other half, for a box with no git client:
pip install https://github.com/CallMeHFK/agent-shepherd/releases/download/v0.2.1/agent_shepherd-0.2.1-py3-none-any.whlThe workflow that puts these here (.github/workflows/release.yml): push a v* tag and the assets get built and attached. Checked on this very release — the zip CI built is byte-identical to the one built from the tag locally (235f2843…), and the wheel installs into a clean venv and reports 0.2.1.
A README reordered for a first-time reader: quickstart, one diagram of the loop, the six Tier 0 signals as a table with their knobs, the three adapters as a table, then measurement, operations and troubleshooting. The derivations stay in RESEARCH_NOTES.md.
A guard against stale version pins: an install URL embeds the version in its filename, so a bump that forgets the docs keeps sending readers to the previous release's artifact — which still downloads, and still installs. A test now fails when a doc names a release that is not the current one.
Unchanged
No detector, threshold, verdict or ledger behaviour moved in 0.2.1; the diff is packaging, delivery and documentation. shepherd eval still gates CI at F1 ≥ 0.8 with Tier 1 stubbed.
0.2.0 — measured supervision
0.2.0 — measured supervision
0.1.0 shipped a supervisor that could notice drift. 0.2.0 ships one that can
prove what it noticed: a deterministic counterfactual benchmark, structured
outcome signals, risk-controlled admission, and a configuration surface you can
read without opening a file.
What is in here
Evidence-driven admission (Tier 0). Every tool result is classified into a
three-state outcome (FAILED / OK / UNKNOWN) instead of being pattern-matched
for the word "error", so a lost response stops being silently counted as success.
Line-anchored error syntax replaces the marker list; non-atomic tool failures are
detected.
Change-point drift detection. A CUSUM detector over the outcome stream, with a
Monte-Carlo-calibrated alarm threshold and a self-normalizing baseline taken from
the pre-alarm reference period only. It folds over tool results rather than all
events, so a session that goes quiet can still alarm.
Conformal risk control. nudge_threshold / block_threshold are admission
gates fitted from observed outcomes with a finite-sample (n+1)/n correction, not
a confidence number the judge self-reports. Priors apply until evidence
accumulates, and a key with too little evidence is dropped rather than pinned to a
fallback.
Binding-drift detection. Right tool, wrong entity (read detectors.py then
edit detectors.py.bak) — a class a loop detector cannot see because the
arguments genuinely differ, and an off-spec check cannot see because the path may
be in scope. Similarity is computed over the filename only; a pair differing in
test/source kind is not treated as confusable.
Anti-saturation. A per-detector nudge cooldown, a natural-checkpoint wake gate
that no longer spends the judge on clean boundaries, and wall-clock (not
event-count) context-rot detection, so streamed reasoning deltas are not mistaken
for spinning.
Learned guidance. A cross-session rulebook promotes guidance an agent
demonstrably followed into pre-drift context, ranked by adherence × evidence.
Counterfactual benchmark (shepherd eval). Scripted healthy sessions plus a
fault injector that breaks exactly one thing at a known step, with first-detection
attribution, per-detector precision/recall, detection delay, false-alarm rate and
cost. Deterministic, offline, runs in CI, and gates on F1.
Operations. shepherd start-bg|stop|status|risk|config|doctor|eval|stats, a
shipped systemd user unit that self-heals on SIGTERM, readiness-gated daemon
start, ${VAR} expansion in the config file, and config merge / config prune
for files written against an older release.
Measured, offline (seed 7, 8 sessions × 10 fault kinds)
| overall recall / F1 | 0.78 / 0.88 |
| detection delay (mean) | 5.0 steps |
| false alarms per clean session | 0.00 |
| per-detector precision | 1.00 for loop, regression, drift, contextrot, binding |
| cost | 63.7 events and 7.1 judge wakes per session |
Full machine-readable report attached (eval-v0.2.0.json). Reproduce with
shepherd eval --seed 7 --sessions 8 --steps 60.
What is not working, before you rely on it
- Those numbers are synthetic. They come from a scripted counterfactual
benchmark, not from production traffic. The live evidence in this release is
narrower: one real mid-loop injection, observed end to end in a QwenPaw session
(detected → parked → drained at the gate → delivered into the agent context as a
user turn, and acted on). offspec_edithas recall 0.00 and is marked unanswerable under the default
config. Contract-scope nudging is off by default (scope_nudge_unobserved=false)
because measuring it cost one false alarm per healthy session; the trade was made
deliberately and the benchmark records it as a gap rather than a pass.- Admission thresholds ship as priors (0.60 / 0.85) with zero outcome labels on
the releasing machine. Getting[calibrated]requires a live-judge run
(shepherd eval --judge --fit-risk …), which needs a reachable judge and
patience — the full-corpus run exceeded 10 minutes previously. blockis never emitted unless an agent opts in (block_enabled). A
supervisor that silently terminates agents is not the default.- Claude Code and Codex adapters are install-verified, not traffic-verified on
a live session in this cycle; QwenPaw is the only adapter with an observed
in-loop intervention. Codex additionally needs the hook trusted once in its TUI. - Tier 1 is a cost: 715k judge tokens across the 80 benchmark sessions. If you
cannot pay for a judge, run Tier 0 only — the detectors need no network.
Upgrading
pip install --upgrade "git+https://github.com/CallMeHFK/agent-shepherd.git@v0.2.0" # or: git pull && pip install -e .
shepherd config merge # add settings an older config.yaml predates
shepherd config prune # drop settings it no longer reads
shepherd doctor # what is configured, what is missing, what to do next
shepherd install qwenpaw # re-copy the plugin bundle (restart QwenPaw after)
shepherd install claude && shepherd install codexshepherd status prints code loaded from: … — check it first. Two installed
checkouts of this project resolve by working directory, and it has cost a debugging
session more than once.
Plugin bundles archived during install now land in ~/.qwenpaw/plugin-archive/,
outside the plugin scan path: QwenPaw loads every subdirectory of plugins/ and
each copy carries the same manifest id, so a backup left there is a second plugin,
not a backup.
Importing the plugin without a checkout
agent-shepherd.zip is the QwenPaw plugin bundle, named after the plugin id so
releases/latest/download/agent-shepherd.zip stays valid for every future
release — the version the host shows comes from the plugin.json inside, not
from the filename. It is the same tree shepherd install qwenpaw writes, and it
carries its own README.md. Hand the URL to the installer, or upload the file in
QwenPaw's plugin page:
qwenpaw plugin install \
https://github.com/CallMeHFK/agent-shepherd/releases/download/v0.2.0/agent-shepherd.zipRunning app hot-loads it; a stopped app loads it on the next start.
Two ways this fails quietly:
- Not the source archive.
.../archive/refs/tags/v0.2.0.zipdoes contain a
manifest, but atagent_shepherd/adapters/qwenpaw/plugin.json, while both
installers look in the archive root or one top-level directory — so it is
rejected. Use the release asset above. - A bundle is not a supervisor. The zip is only the in-process observer; it
POSTs to127.0.0.1:4890and fails open when nothing listens there, so it
loads, registers, and supervises nothing. The supervisor is a Python package,
and this release carries it too — the wheel needs no git client:
pip install https://github.com/CallMeHFK/agent-shepherd/releases/download/v0.2.0/agent_shepherd-0.2.0-py3-none-any.whl
shepherd start-bg && shepherd statusv0.1.0
Initial public release.
Adapters
- QwenPaw: in-process plugin (agentscope middleware + StopGate) with REST/SSE fallback client
- Claude Code:
~/.claude/settings.jsonhooks via theshepherd-hook claudethin shell - Codex:
~/.codex/hooks.jsonin the Codex MatcherGroup schema viashepherd-hook codex(hook-trust gate documented: approve once in the TUI, or pass--dangerously-bypass-hook-trusttocodex exec)
Supervisor
- Tier 0 deterministic detectors: loop, regression, off-spec, context rot
- Tier 1 LLM step scorer, pluggable OpenAI-compatible judge (Agnes default; vLLM via
SHEPHERD_JUDGE_BASE_URL/SHEPHERD_JUDGE_MODEL) - Append-only JSONL session ledger +
shepherd replay/shepherd tail
Quality: 15 unit tests, ruff clean, CI green.