The Problem

Shepherd addresses a fundamental problem in agent workflows: execution traces are ephemeral and opaque. When agents run, their decisions, intermediate states, and outcomes disappear. For meta-agents that need to supervise, debug, or train other agents, this lack of reversibility and inspection creates a blind spot. The repo explicitly positions itself as a "runtime substrate that turns an agent's execution into a reversible, Git-like trace" — but the codebase's internal structure reveals significant maintainability debt that could impede exactly the kind of meta-shepherding it claims to enable.

What This Does

Shepherd is not a single framework but a portfolio of 8 projects. The core shepherd package (1183 files, 1041 code files) provides the runtime substrate for reversible execution traces, copy-on-write forking, and KV-cache reuse. vcs-core (452 files) handles version control substrate. commons-vcs (32 files) is a lower-level VCS utility library. shepherd2 (46 files) appears to be a condensed or next-generation subset. examples (67 files) and integration-tests (12 files) round out the structure.

The core runtime records agent runs as durable, inspectable execution traces with retained workspace outputs. A task is a plain Python function with no body — the signature and docstring become the contract the agent fulfills at runtime, including explicit permission grants like repo: sp.GitRepo. The framework records everything as effects, with a KV-cache that achieves ~95% reuse on replay, and fork operations that are ~5x faster than docker commit.

However, the code health findings reveal that this capability comes at a cost. The analysis found 270 issues across 36 high, 233 medium, and 1 low severity findings. The most consequential structural problems are: 4 import cycles involving shepherd/packages/runtime/src/shepherd_runtime/nucleus/delivery.py, shepherd/packages/runtime/src/shepherd_runtime/step/inline.py, and shepherd/packages/runtime/src/shepherd_runtime/nucleus/workspace.py; 40 files with deep nesting (max indentation depth 6); 649 duplicated 6-line blocks across 131 files; and an oversized delivery.py at 765 lines. Additionally, 3 files open files without context managers, and 8 files have broad exception handling that could swallow errors indiscriminately.

How It Is Wired

Execution starts from several entry points. The execute function in shepherd/packages/authoring/src/shepherd_authoring/workflows/design_refinement/run.py:36 reaches 170 functions and is called from 4 places. The main function in docs/_src/shepherd/tutorials/first_app/app.py:58 reaches 252 functions called from 3 places. run in shepherd/eval/bases/rich-cli/base/src/rich_cli/__main__.py:934 reaches 259 functions. run_sync in shepherd/packages/core/src/shepherd_core/run.py:61 reaches 260 functions and is the most broadly called entry point.

The internal call graph shows 6000 resolved call edges. The most connected symbols: Lit called from 123 places, bind from 97, from_path from 84. The hub modules with the highest blast radius: shepherd/__init__.py (56 modules depend on it, instability 0), vcs-core/packages/core/tests/support/cli.py (13 dependents), and shepherd/packages/runtime/src/shepherd_runtime/_scope/substrate.py (12 dependents, instability 0). Four modules participate in import cycles, meaning changes to any one ripple through the others without clear boundaries.

Traced paths from entry points to process exits are shortest-over-edges: execute -> launch_confined [filesystem via (tmp_path / "index.html").write_text], main -> git_repo [subprocess via subprocess.run, filesystem via (tmp_path / ".gitkeep").write_text], run -> _redacted_text_payload [crypto via hashlib.sha256(value.encode('utf-8')).hexdigest]. The code touches files (270 functions), runs external commands (67 functions), performs crypto operations (31 functions), makes outbound network calls (3 functions), and calls models for inference (2 functions).

Key files by responsibility: shepherd/packages/contexts/src/shepherd_contexts/kvstore/store.py (22 functions, 1 class, called from 46 files, performs crypto operations); shepherd/packages/core/src/shepherd_core/effects/effects.py (24 functions, 42 classes, called from 24 files); shepherd/packages/core/src/shepherd_core/scope/stream.py (58 functions, 3 classes, called from 18 files); commons-vcs/src/commons_vcs/backends/git.py (50 functions, 7 classes, called from 15 files, reads/writes files, runs external commands); shepherd/packages/core/src/shepherd_core/effects/views.py (51 functions, 18 classes, called from 13 files).

How To Use It

Setup: Install via pip install shepherd-ai for the published package. For local development, the README instructs: python -m venv .venv && . .venv/bin/activate && pip install -r requirements-dev.txt. Python 3.11+ is required; OS-level grant enforcement runs on macOS (Seatbelt) and Linux (Landlock, in a privileged container); Windows is unsupported (use WSL).

Configuration: The pyproject.toml at the repo root and commons-vcs/pyproject.toml manage dependencies. No lockfile is present — builds are non-reproducible without manual pinning. The .devcontainer/Dockerfile uses mcr.microsoft.com/devcontainers/python:1-3.11-bookworm (mutable base, no digest pinning). Environment variables and Claude CLI credentials are needed for cloud runs; the offline quickstart runs keyless.

Running it: For the tutorial quickstart, main in docs/_src/shepherd/tutorials/first_app/app.py:58 is the entry point. For CLI-based runs, run_sync in shepherd/packages/core/src/shepherd_core/run.py:61 is the primary path. The serve command in shepherd/extras/trace-viewer/src/shepherd_trace_viewer/server.py:78 starts the trace viewer. Without an ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN, the offline quickstart runs anywhere keyless.

Real-World Use

A meta-agent supervising a task agent can fork the workspace at any point in the trace, inspect the reversible effects, replay from any checkpoint, or revert bad decisions — all while maintaining ~95% KV-cache reuse so replay is nearly as cheap as re-execution. For example, if a code-generation agent produces a buggy module, the supervisor can fork the workspace to the point before the buggy edit, replay with a corrected prompt, and accept the new version without affecting the main branch. The Git-like trace means every change is a commit-like object with a hash, enabling true fork/revert/merge workflows on agent output. The commons-vcs/src/commons_vcs/backends/git.py provides the underlying Git operations (digestto_segment, segmentto_digest, roleto_segment, etc.) that make the trace durable and inspectable.

Code Health & Issues

The measured analysis found 270 total issues across 7 distinct kinds:

  • [HIGH/clarity] Hub module x3: shepherd/__init__.py, vcs-core/packages/core/tests/support/cli.py, shepherd/packages/runtime/src/shepherd_runtime/_scope/substrate.py — 56+ modules depend on the hub; churn here has high-blast-radius impact.
  • [HIGH/cognitive_load] Deep nesting x40: shepherd/packages/runtime/src/shepherd_runtime/_lifecycle/_phase_context.py, _phase_base.py, _emitter.py — max indentation depth 6 makes control flow hard to follow.
  • [HIGH/soundness] Import cycle member x4: shepherd/packages/runtime/src/shepherd_runtime/nucleus/delivery.py, step/inline.py, nucleus/workspace.py — mutually reachable modules create fragile dependencies.
  • [MEDIUM/cognitive_load] Oversized file: shepherd/packages/runtime/src/shepherd_runtime/nucleus/delivery.py — 765 code lines hard to hold in one head; changes ripple widely.
  • [HIGH/clarity] Duplicated code blocks: 649 repeated 6-line blocks across 131 files in context/runtime and context directories — extract shared helpers.
  • [MEDIUM/resource_safety] File opened without context manager x3: shepherd/packages/runtime/src/shepherd_runtime/_persistence_manager.py, shepherd/packages/runtime/src/shepherd_runtime/device/container/vm_extraction.py, commons-vcs/src/commons_vcs/backends/git.pyopen(...) not wrapped in with; handle may leak on error.
  • [MEDIUM/resilience] Broad exception handling x8: shepherd/packages/runtime/src/shepherd_runtime/_task_discovery.py, _cache_key.py, combinators/speculation.py — bare/Exception-wide except swallows errors indiscriminately.

SDLC observations from the file structure: no lockfile declared (commons-vcs/pyproject.toml has unpinned dependencies), 20 manifests with no Dependabot or Renovate configured, GitHub Actions not pinned to commit SHAs (astral-sh/setup-uv@v6, pypa/gh-action-pypi-publish@release/v1), container base image untagged (mcr.microsoft.com/devcontainers/python:1-3.11-bookworm), no dependency vulnerability scan in CI, checkout retains token (lane-c-linux-probe.yml), and 3 workflows declare no job timeout.

The Bottom Line

Shepherd is a capable technical substrate for reversible agent execution, with genuine innovation in copy-on-write forking and KV-cache reuse. However, the codebase carries significant structural debt: import cycles, oversized files, deep nesting, and duplicated logic that collectively raise the cost of modifying the very reversibility features the framework depends on. The hygiene gaps (no lockfile, untagged Docker base, unpinned GitHub Actions) are fixable but indicate an alpha project still catching up to its own ambitions. Teams that need to build on top of Shepherd should budget refactoring time — particularly around the hub modules and import cycles — or risk brittle dependencies as the platform evolves.