CLAUDE.md is a symlink to this file.
shepherd is the CoW Protocol composition root over the nexum WASM Component Model runtime and the videre intent and venue layer.
nexum-runtime supplies the venue-agnostic host: the Component Model runtime, the module supervisor, and the capability tables.
videre supplies the intent and venue platform on top of it.
This repository adds the CoW-specific parts: the shepherd engine binary, the CoW venue adapter, the ComposableCoW keeper machinery, and the production keeper modules.
Every module is a wasm32-wasip2 component, and the host grants each one only the capabilities its manifest declares.
crates/shepherd-enginebuilds theshepherdbinary: the nexum runtime and the videre host wired as the CoW composition root.crates/cow-venueholds the CoW venue slices, and it is orderbook-only. The defaultbodyslice carries the venue-neutral order intent body types and their borsh codec; theclient,assembly, andadapterfeatures layer the typed client, the chain-edge order assembly, and the wasm32-wasip2 venue adapter component on top.crates/composable-cowholds the ComposableCoW keeper machinery: the conditional-order body, the structured pollVerdict, and theruncomposition over the venue client.modules/ccow-monitorandmodules/ethflow-watcherare the production keeper modules.tools/orderbook-mockis the orderbook REST mock that the forked-mainnet engine test drives, andtools/baseline-latencyis the Python latency baseline tooling.wit/holds no WIT package of this repository's own.wit/deps/vendors the cross-repo WIT packages, andwit/deps.tomlnames their sources.docs/deployment.mdis the operator guide, with the Docker guide and the Prometheus scrape config underdocs/deployment/.docs/operations/soak-runbook.mdis the soak runbook.extensions.tomlis the client-capability registry that the module world synthesis reads. It names the WIT import each[capabilities]declaration becomes, so it must stay next toCargo.toml.- The
engine*.tomlfiles are engine configs.engine.example.tomlis the annotated template, andengine.docker.tomlis the config thatdocker-compose.ymlmounts into the image. A realengine.tomlcarries paid RPC keys and is git-ignored; the committed files read each RPC URL from an environment variable.
This repository was carved out of the runtime monorepo, so the siblings are now external dependencies.
Each crate manifest pins nexum-* to a git rev of nxm-rs/nexum-runtime and videre-* to a git rev of nxm-rs/videre.
The vendored wit/deps/ copies match the WIT at those two crate revs.
wit/deps.toml names the same two revs with the digests of their archive tarballs, and the wit-sync CI job fails when the vendored tree drifts from it.
To move to a newer sibling rev, change every occurrence of the old rev in the crate manifests together.
Set the wit/deps.toml urls, prefixes and digests to that rev in the same change, and run wit-deps update to refresh the vendored copies.
A partial bump splits the graph and breaks the WIT resolve.
Cargo.toml also patches cowprotocol to a git rev of nullislabs/cow-rs until an upstream release carries the hash-only constructor.
The workspace is edition 2024 on a pinned Rust 1.96 toolchain.
The flake devshell, the CI setup action, and the Dockerfile all pin 1.96; bump them in lockstep.
Enter the devshell with nix develop, or let direnv allow do it.
Every external dependency is hoisted into the [workspace.dependencies] table, and the core crates inherit with dep.workspace = true.
Guest modules under modules/ do not inherit that table: they declare their own external dependencies, because a real module author has no access to it.
Use the justfile recipes:
just build # build-modules + build-engine
just test # cargo nextest run, then cargo test --doc
just fmt # cargo fmt --all
just lint # cargo clippy --workspace --all-targets --all-features -- -D warnings
just ci # the full CI series locally
Run tests with cargo nextest run and doctests with cargo test --doc, because nextest does not run doctests.
Run just ci before you push: it mirrors .github/workflows/ci.yml one-to-one.
cargo fmt --all --check and the clippy -D warnings gate are the pre-commit gate, and both are blocking CI jobs.
CI also runs cargo doc --workspace --no-deps under -D warnings and the blocking scripts/check-cow-orderbook-only.sh gate, which holds crates/cow-venue to orderbook-only.
just docker-build builds the image, and .github/workflows/docker.yml publishes it to ghcr.io.
The .claude/hooks/ scripts support this loop.
rustfmt-on-edit.sh formats each edited .rs file with rustfmt.
nextest-on-stop.sh runs nextest for the crates with uncommitted .rs changes at the end of a turn.
Each hook exits without an error when its tool is absent, so nothing runs outside the dev shell.
Do not use em-dashes (U+2014) anywhere.
Use ASCII hyphens, a colon, or split the sentence.
.claude/hooks/content-lint.sh blocks an edit that adds one to a .rs or .md file.
Write commit messages as Conventional Commits with an imperative subject.
Disclose AI assistance with an honest AI Assistance: <tool> used for <what> line in the commit message and the PR body.
Never add the Co-Authored-By: Claude Code or Generated with Claude Code boilerplate.
In a PR or issue body, keep one logical line per paragraph.
Write all documentation in ASD-STE100 Simplified Technical English. Use short sentences, the active voice, and one idea per sentence. In markdown files, put each sentence on its own line and do not wrap within a sentence; GitHub reflows the file when it displays it. This keeps a diff to one changed line per changed sentence. In PR and issue bodies, keep one line per paragraph, because GitHub renders a single newline in a comment as a line break.