Let AI write the code; you stay in charge of what ships.
· 简体中文 | English
Shepherd is an early-stage platform for supervising AI-driven development. The idea is simple: AI can write code now, but it won't judge whether it actually finished the requirement, and it won't be accountable for the result. So instead of building yet another "smarter agent," Shepherd is the layer around the agent — it breaks requirements down for AI executors to work on, then puts a human approval step at two points (design and verification), and keeps a record of the whole thing.
Status:
v0.0.1, experimental, and something we currently dogfood ourselves. The full loop works, but it's not production-ready and there's no public benchmark. Don't treat it as a finished tool.
A requirement roughly travels like this:
you file a requirement → AI drafts a design →(you approve)→ split into a task DAG → internal executors claim and work
│
you sign off ←(verification gate)← adjudication ← deliverable (diff / PR) ←────────────────────┘
The design gate and the verification gate are hard steps in the flow, not optional prompts. However fast the AI runs, nothing reaches your main branch until it clears a gate. That's basically the problem Shepherd is trying to solve: letting you put AI to work at scale because the output is reviewable and accountable.
This is the part of the project I find most interesting.
The AI tools in a company (Claude Code, Codex, and friends) usually run on internal dev machines or CI — boxes with no public inbound. The server, on the other hand, has a public address. So the server can't push work to an executor; it has to be the other way around: executors reach out and long-poll to claim work. Plenty of orchestration frameworks assume they can reach the agent, and that assumption falls apart on a real internal network.
- Single host: an in-process queue is enough, no external dependencies.
- Multiple hosts: set
SHEPHERD_FLEET_REDISto switch to Redis Streams consumer groups — exactly-once claim, ack on terminal state, and timeout-based reclaim when an executor dies.
The executor itself (agent-runtime) is plain Rust: concurrency is bounded by a semaphore, it drains in-flight tasks on shutdown, and each task runs in its own git worktree so they don't step on each other. GET /agent/work/stats shows per-capability backlog, in-flight, and oldest-stuck. Adding a new kind of executor means implementing one CliAgentBackend (a single execute(prompt, cwd, sink) method) and registering an enum variant.
(public) (internal, no inbound)
┌────────────┐ enqueue ┌──────────────┐ ←claim─ ┌──────────────────┐
│ Shepherd │─────────▶│ WorkQueue │ │ agent-runtime │
│ server │ │ in-mem/Redis │ ─spec→ │ spawn claude / │
│ (dispatch/ │◀─────────│ Streams grp │ │ codex / opencode│
│ gates) │ callback └──────────────┘ register/└──────────────────┘
└────────────┘ heartbeat per-task worktree isolation
# 1) A Postgres; migrations are applied automatically on startup
docker run -d --name shep-pg \
-e POSTGRES_USER=msuser -e POSTGRES_PASSWORD=mspass -e POSTGRES_DB=mstest \
-p 55432:5432 postgres:16-alpine
# 2) Start the server (the root sets default-members, so plain `cargo run` works)
DATABASE_URL=postgres://msuser:mspass@localhost:55432/mstest \
SHEPHERD_ADMIN_PASSWORD=s3cret \
cargo run # → http://localhost:8088# Log in for a token
curl -s localhost:8088/auth/login -H 'content-type: application/json' \
-d '{"username":"admin","password":"s3cret"}'The web console, and starting an executor on an internal machine:
cd web && npm install && npm run dev # Vite console
SHEPHERD_AGENT_FLEET=1 cargo run # server in fleet mode
SHEPHERD_BASE=http://<server>:8088 SHEPHERD_CAPS=CLAUDE_CODE cargo run -p agent-runtimePrefer one command? docker compose -f deploy/docker/docker-compose.yml up --build brings up the whole stack (server + agent-runtime + web + Postgres + Redis) — see the usage guide and deployment guide.
Each business module is its own crate, laid out hexagonally: domain / ports / application are pure logic with no IO by default, while the database and HTTP live in adapters behind feature flags. tests/architecture.rs scans the source and fails the build if a pure layer ever imports an IO crate like sqlx or axum — that keeps the layering from quietly eroding over time.
Working today: auth / RBAC / OIDC (Feishu, WeCom), projects, versioned requirements, the task DAG, the design approval gate, fleet dispatch and reclaim, MCP tools (POST /mcp), Skill orchestration, plus a test-management suite (cases / bugs / plans / API and scenario tests / Mock).
Not done yet: the verification gate is still heavier to use than I'd like; shepherd-cli is half-built; finer fleet metrics (e.g. claim-latency distribution) aren't there; and more executor backends (such as wiring OpenHands in as one) are on the list.
Full crate tree
crates/
kernel/ shared kernel (pagination / PermissionSet)
webauth/ shared auth primitives (AuthUser / SessionStore + axum extractors)
system-setting/ users · orgs · roles · auth (local + OIDC)
project/ requirement/ task/ orchestrator/ project · requirements (versioned) · task DAG · orchestration
design/ design stage (OpenSpec/BMAD, human approval gate)
delivery/ AI executor dispatch & delivery + fleet queue
agent-runtime/ pure-Rust executor (CLI spawn + event streaming + worktree isolation)
verification/ integrity verification + verification gate
mcp/ skill/ MCP tools + Skill orchestration
case/ bug/ test-plan/ api-test/ api-scenario/ test management
api-definition/ api-runner/ runner/ probe/ perf/ comment/ follow/ environment/ mock-runtime/ …
migrate/ versioned migrations (sqlx migrate! + uniqueness guard)
server/ composition root = the single binary (typed config + domain-grouped routes)
shepherd-cli/ CLI (still being built)
web/ React + antd frontend
Main environment variables
Server (consolidated into a typed ServerConfig):
| Variable | Default | Meaning |
|---|---|---|
DATABASE_URL |
local mstest | PG connection string |
SHEPHERD_BIND |
0.0.0.0:8088 |
main API listen address |
SHEPHERD_ADMIN_PASSWORD |
admin |
admin password upserted idempotently on boot |
SHEPHERD_AGENT_FLEET |
— | set to enable fleet mode |
SHEPHERD_FLEET_REDIS |
— | set to use a Redis distributed queue / registry |
SHEPHERD_FEISHU_* / SHEPHERD_WECOM_* |
— | OIDC third-party login |
Executor agent-runtime:
| Variable | Default | Meaning |
|---|---|---|
SHEPHERD_BASE |
http://127.0.0.1:9180 |
server address |
SHEPHERD_CAPS |
CLAUDE_CODE |
comma-separated capabilities (which tasks to claim) |
AGENT_CONCURRENCY |
1 |
max concurrent tasks |
CLAUDE_BIN / CODEX_CMD / OPENCODE_CMD |
claude / codex exec / opencode run |
each CLI invocation |
AGENT_MOCK |
— | set to use the mock backend (no real CLI) |
- Usage guide (中文) — concepts, quick start, the full configuration reference, the web console, fleet & executor setup, and the HTTP API.
- Deployment & ops (中文) — Docker Compose, Kubernetes via Helm (
deploy/helm/shepherd), multi-cloud Terraform (deploy/terraform/{aws,gcp,azure}), and CI/CD auto-deploy. - Architecture · Roadmap · fleet design notes
vs. agent harnesses — Claude Code, Codex, OpenCode, OpenHands, Aider. A harness wraps an LLM and runs the agentic loop (tools, context, turn by turn) to get one task done well. Shepherd is the layer above that: it doesn't run the loop — it decides what the tasks are, dispatches them, gates them on human approval, and verifies they were actually done. The harness is a swappable executor: agent-runtime literally shells out to claude / codex / opencode and streams their events back. So OpenCode isn't a competitor — it's one of the executors you hang on Shepherd's fleet (OPENCODE_CMD=opencode run).
vs. multi-agent frameworks — AutoGen, CrewAI. Most take the autonomy route: let agents loop until done, compete on benchmarks. Shepherd's focus is governance — approval and verification are steps you can't route around, not prompts you interrupt in a chat, and the deployment model is a central server plus internal executors that pull work outbound. Those frameworks are the agent; Shepherd is the supervisor above swappable agents.
One concrete boundary: Shepherd speaks MCP as a server (it exposes shepherd_* tools so an agent can drive the requirement→verify lifecycle), while coding agents like OpenCode speak MCP as a client. They compose in both directions rather than overlap.
cargo test --workspace # everything; non-integration runs in seconds
cargo test --workspace -- --ignored # real-database integration tests866 tests; the integration ones run against a real server + PG / Redis / MySQL. Besides the architecture guard there's a migration-uniqueness guard: a duplicate migration version number fails CI (sqlx silently drops duplicates — we hit that once and it cost us a missing-column 500).
More background in ARCHITECTURE.md, ROADMAP.md, and the fleet design notes.
Issues and PRs welcome. A few conventions:
- Follow the hexagonal layering: business logic in
domain/application, IO inadapters, and no IO crates in the pure layers (tests/architecture.rswill catch it). - Include tests;
cargo test --workspaceandcargo clippy --workspace(-D warnings) need to be green. - New migrations use a unique, increasing version number:
NNNN_description.sql. - Write commit messages that explain why, not just what changed.
GPL-2.0, see LICENSE.