shepherd-cli 6.7.7

Small installed-plugin diagnostics for the Shepherd workflow
shepherd-cli-6.7.7 is not a library.

shepherd-cli

shepherd init --root PROJECT creates the focused .shepherd/runs/ workspace. shepherd lane --root PROJECT --run RUN --name LANE adds a no-clobber lane plan, ledger, and evidence directory. These commands do not select topology or create a registry. Existing edited records are preserved and initialization refuses to replace them; resume reads those records instead of calling lane again. The scaffold separates the filesystem lane ID from the full branch ref, absolute worktree/common directory, owner, base, integration target, accepted plan revision, allowed paths, tested candidate, and evidence custody. Blank fields are not verified facts.

shepherd lane-check --root ACTUAL_ROOT --worktree ABS_WORKTREE --common-dir ABS_COMMON_DIR --branch refs/heads/lane/NAME.INDEX --base-ref refs/heads/v6.7.7 --base-sha FULL_SHA [--head FULL_SHA] [--require-clean] compares native Git against an explicit recorded identity. It requires the inspected root itself to be the expected Git worktree root, compares canonical absolute worktree/common-directory paths and the full branch, checks that the qualified base ref still resolves to the expected SHA and is an ancestor of HEAD, and binds the branch's non-prunable registration to this canonical path while detecting a branch checked out in multiple worktrees. --head additionally pins the candidate. Use qualified base refs even if a branch and tag have the same name. A relocated worktree requires a freshly verified mapping.

Successfully parsed invocations emit JSON, schema shepherd.lane-check.v1, with ok, worktree, common_dir, branch, head, base_ref, base_sha, dirty, untracked, findings, and ownership: "not_assessed". Unavailable observations are null. Exit 0 means the requested Git checks passed, exit 1 means a mismatch or inspection failure. Exit 2 means invalid CLI usage: Clap writes human-readable stderr and does not emit a JSON report. Dirty work includes every initialized recursive submodule, even when an ancestor's submodule configuration sets ignore=all; untracked identifies superproject untracked entries, while submodule untracked files also make dirty true. Nested status.showUntrackedFiles=no is overridden. The command compares each indexed regular file's filtered content hash and each indexed symlink target with its index blob, in the root and every initialized submodule. Same-size edits with restored mtimes are detected even under core.trustctime=false or core.checkStat=minimal. Native status also checks staged, mode, and untracked changes. Git-ignored files remain excluded. Work is preserved; --require-clean makes dirty work a failing condition. Index assume-unchanged or skip-worktree entries can hide tracked edits. The command declines inspection when these flags occur in the root or an initialized recursive submodule, including unchanged flagged files; cleanliness is unknown rather than certified. It does not clear flags, repair an index or discard files. Sparse checkouts using those flags need another verified custody route before a clean-worktree claim. An uninitialized or deinitialized gitlink at any depth also makes cleanliness unknown, even when its directory is empty or absent. Native Git skips such directories during recursive inspection, so the command exits 1 with ok:false and null dirty/untracked both with and without --require-clean. It neither initializes submodules nor fetches their contents. Git's executable-bit check is forced on for command-scoped inspection, including initialized submodules, so core.fileMode=false cannot hide a tracked 0644-to-0755 change. Repository and submodule configuration and file modes are left intact. Missing tracked files, unexpected file types, and unsupported symlink targets leave cleanliness unknown instead of certifying a clean tree. Hashing uses Git without -w; it does not write new objects or refresh indexes. Git 2.52.0's recursive submodule wrapper cannot inspect an initialized submodule from a newline-ending root; this input also fails closed with unknown cleanliness. Newline-ending roots without submodules remain supported by the native probes. Inherited Git environment variables are removed case-insensitively, including Windows caller spellings such as Git_Dir. Legacy graft overlays are disabled; real trailing path whitespace is preserved. The command requires Git's --no-lazy-fetch option: unsupported Git fails before inspection instead of silently fetching. Cloud setup checks this capability directly rather than assuming it from a version string. Missing promisor objects fail without populating the object store; inherited stdin and credential prompts are disabled. Git 2.52.0 is tested here; native Windows remains unverified. Non-UTF-8 Git paths or porcelain filenames are unsupported: inspection exits 1 with ok:false and unavailable fields null, including unknown cleanliness, rather than accepting a lossy path or clean tree. The CLI requests observations without intentionally changing files, index, refs or working trees. Use it only with operator-trusted Git, repository configuration, attributes and configured helpers, including those in initialized submodules. Native Git inspection is not an execution sandbox: external clean/process filters may run during status or content hashing and can write files, disclose data or block. The optional-lock, fsmonitor, no-fetch and prompt controls do not prevent all configured subprocess execution. If this trust boundary is unsuitable, use an operator-approved alternative before inspecting the repository. Do not silently disable filters and certify cleanliness; their normalization may be needed for a correct comparison. Git output is capped at 1 MiB per inspection; this is not a process deadline or atomic snapshot. This does not establish owner identity, process liveness, permission, or integration acceptance. Root still reconciles surviving writers and evidence.

shepherd doctor --host HOST --plugin-root ABS_PATH inspects an installed Claude, Codex, or Pi Shepherd carrier. It reports the helper and plugin versions, required resources, the selected host hook, and optional jq availability. It does not authorize tools or prove host trust and event delivery.

shepherd handoff --host HOST --plugin-root ABS_PATH --context JSON_PATH renders the installed templates/handoff.md from a flat JSON object. The current template uses task, objective, artifact_root, status, changed_paths_or_commit, verification, review, evidence_location, remaining_work, and next_action; branch, base, candidate, rollback, and date are optional. Missing referenced fields fail before output. Optional fields set to JSON null are treated as absent by the current template; they do not assert a supplied Git tuple, review history or activation receipt. Default output is stdout. --output PATH creates one complete file atomically and refuses to replace different existing bytes; an identical retry leaves the file untouched. Rendering does not verify the truth of the supplied result.

The CLI has no run registry, daemon, broker, or extracted runtime dependency.

Install from the Shepherd checkout with cargo install --path crates/cli --locked. Use the installed shepherd --version to confirm the helper version before running doctor against the actual plugin installation path.

CI uses scripts/ci-candidate.py for its offline-tested event/ref policy. Allowed relations are lane to patch or legacy/namespaced dev, matching dev to patch, and patch to main/master. Version coordinates and dev iteration use digits 0 through 9 inclusive; lane incarnation numbers have no one-digit bound. Dispatch payloads require ref, sha, target, and target_sha: qualified refs and exact commits. Shorthand and raw-SHA-only dispatch are rejected. Repository dispatch acquires policy from default-branch code; manual workflow dispatch acquires it from github.workflow_sha, the immutable code revision of the authorized selected workflow. The payload-selected candidate cannot choose its policy revision, and dispatch preflight runs before the candidate gate. PR/push policy and workflow code can come from the candidate, just like ordinary repository tests. These checks assume the host's runner and permission controls; they are not an independent security attestation against malicious candidate code. For private repositories the workflow supplies its read-only token only to the pre-gate policy step; native fetch uses a transient, origin-server-scoped HTTP header, without persisting credentials or placing them in command arguments. PR validation binds current base, head, candidate merge commit and tree. Dispatch accepts only a proven target-ancestor pair, so its candidate head tree is the exact fast-forward integration tree. Candidate history is fetched to a bounded depth of 256; an unproven ancestor is rejected, including incomplete history. Diverged candidates use an exact PR merge candidate instead. Dispatch concurrency keys include the candidate ref/SHA and target ref/SHA, rather than the selected workflow-policy ref.

Preflight records use candidate_sha, candidate_merge_sha and candidate_tree, with acceptance: "not_assessed"; they do not claim that tests have already run. The workflow no longer gives a candidate-writable post-gate helper a fresh token or lets it issue acceptance. GitHub reports the actual job conclusion separately. A green self-check cannot replace independent review or root's fresh head/base/ target reconciliation before integration. Moved targets or changed candidates invalidate the applicable evidence; do not reuse stale green checks. Metadata-only edits use a distinct check name and do not grant candidate acceptance. Offline fixtures do not establish hosted branch-protection or ruleset settings.