v0.2.1
Shepherd 0.2.1 — Claude CLI lane diagnostics, interrupted-run recovery, and hardening.
This release packages PRs #24–#29. Highlights:
Fixed — the Claude CLI agent lane (#23)
The claude CLI (headless) lane is the supported public agent provider, and this release makes
its failures diagnosable and its preflight honest (PRs #27, #28):
- Actionable failures. A nonzero
claudeexit now surfaces the CLI's own reason plus a
remedy — not a blind 300-char tail-slice. Not-logged-in, org-policyaccess_denied(HTTP 403),
and rootfulroot_permissionare classified, with the safe envelope scalars kept in the trace.
Abudget_secondsalarm kill (rc=-14) maps to a trace-preservingBudgetExhausted, with a
hung-body hint when the CLI produced no output at all (e.g. a staleclaudeversion). - Fail-fast preflight. A jailed run with no usable credential (or an expired seeded
subscription login) is refused before launch (auth_missing/auth_expired,
launch_attempted: false) instead of spending a confined launch that fails not-logged-in.
Wrappers that authenticate out-of-band can opt back in withSHEPHERD_ALLOW_KEYLESS_CLAUDE=1. - Honest doctor.
shepherd doctor claudehard-fails an expired subscription token instead of
reporting a merely readable credential blob as ready, and names which credential source failed
(config file unreadable, keychain denied/timed out, nothing found). New
shepherd doctor claude --probeperforms a real auth round-trip under the provider's
scrubbed-config conditions. - Recommended for subscription users:
export CLAUDE_CODE_OAUTH_TOKEN=$(claude setup-token)—
a long-lived token survives the sandbox; a short-lived signed-in session cannot be refreshed
from inside it.
Added — interrupted-run recovery (#26)
- Ctrl-C and SIGTERM now discard cleanly instead of leaving orphaned operations.
- A dead prior run's orphaned operations auto-recover at run start.
- New
shepherd run repaircommand, and an honestOrphanedOperationsErrorthat names it. - Session-lock reclaim is process-identity authoritative (PID-reuse safe), not time-based.
Internal — engine refactor and hygiene (#24, #25, #29)
- vcs-core controller extractions + strict-mypy cleanup (behavior-neutral), with the strict gate
now in CI. - Public-surface contract baseline synced (#25).
- Repo-wide
ruff formatalignment (#29).
Evidence
- Lane C jail-enforcement sentinel executed GREEN at the tagged revision on macOS Seatbelt:
all 10 required ids passed, all 7 jailed legs skip-free. (Linux Landlock remains
container-gated, unchanged from 0.2.0.) - Real-token happy path verified end-to-end on macOS:
doctor claude→--probe(live auth
round-trip) → jailed retained run with fail-closed ground. - Failure paths (not-logged-in, org-403, rootful, alarm-kill) reproduced in a login-free Linux
cleanroom and pinned by envelope-fixture tests that run in CI without credentials.
Thanks to the reporter and commenter on #23 for exact envelopes, the Linux datapoint, and the
stale-CLI rc=-14 triage note.
🤖 Generated with Claude Code