agentleFS
Space-DinosaursSpace-Dinosaurs/DinoStack/bin/AGENTS.md

DinoStack / bin

AGENTS.md14 starsChanged 12 days agoApache-2.0View on GitHub

CLI entry points (Python, Bash, and Node) that the dinostack methodology exposes as PATH-wired commands - the table below is a curated subset, not a full enumeration (see ls bin/ds-* for the live count). Each binary ships with a header docstring (Purpose / Public API / Upstream deps / Downstream consumers / Failure modes / Performance) that is the authoritative description of that command. Read the binary itself for full detail; this file is the module-group map, not a duplicate…

  • Deletes or force-pushes

The file

We split this AGENTS.md into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every ds-* name below has a permanent agentic-* compat symlink (e.g.

    line 12
  2. Very specific:

    Every binary is fail-open: unexpected input, missing files, and permission errors are swallowed and surfaced via non-zero exit codes or …

    line 72

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

bin/

CLI entry points (Python, Bash, and Node) that the dinostack methodology exposes as PATH-wired commands - the table below is a curated subset, not a full enumeration (see ls bin/ds-* for the live count). Each binary ships with a header docstring (Purpose / Public API / Upstream deps / Downstream consumers / Failure modes / Performance) that is the authoritative description of that command. Read the binary itself for full detail; this file is the module-group map, not a duplicate of those manifests.

Every ds-* name below has a permanent agentic-* compat symlink (e.g. bin/agentic-cost -> bin/ds-cost) - both invoke the same file and behave identically. ds-* is the primary name; the agentic-* form is never sunset (external cron jobs and shell aliases reference it).

Entry points

CommandLangOne-line role
ds-base-syncBashFast-forward the local base branch to origin/<base-branch> after a merge, with a normalized exit-code contract (synced/diverged/skipped-dirty/usage-error/inconclusive); prints a non-blocking DS-54 hooks-snapshot-staleness advisory note after every invocation.
ds-branch-prunePythonSquash-aware local branch prune (DS-153): deletes a local branch only when a four-layer, first-match-wins subsumption predicate (ancestry, squash-patch equivalence, tip-subsumption, content-on-main) proves its tip content is on the resolved base branch; absence of proof is always SKIP_UNPROVEN, never a force-delete. Resolves its own base via bin/_lib.py's shared resolve_base_branch when --base is omitted, and deletes nothing (no ledger entry, exit 0) when that resolution fails. --dry-run reports without deleting; every deletion is recorded to an append-only ledger BEFORE the destructive git branch -D. Layers L1/L2 structurally cannot prove a squash-merged or rebased branch - those surface as SKIP_UNPROVEN and need archive-then-delete, not a longer PR list. The merged-PR window that feeds L2/L3 is fetched by cursor-paginated GraphQL and its completeness is PROVEN rather than assumed - node count must equal the pullRequests connection's own totalCount, and every other outcome (count mismatch, absent totalCount, mid-pagination failure, GraphQL errors, a gh call or whole-fetch timeout, or exhausting the page bound) prints a NOTE naming the reason and downgrades pr_state to not_checked, never the affirmative NONE. This replaced a gh pr list --limit 500 ceiling that this repository's merged-PR count had already outgrown, so the truncation NOTE fired on every run; absence of a candidate has never been, and still is not, proof that a branch is unmerged.
ds-calibratePythonRender Skeptic calibration rollups (findings density, meta-Skeptic divergence rate) from .agentic/events.jsonl; with $AGENTIC_DIR unset, run from a linked worktree, also reads the primary checkout's hook spawn rows (DS-246).
ds-change-deltaPythonOne-shot before/after telemetry delta tool (DS-241): resolves a --cut (git SHA, committer date, or ISO date) into a UTC instant, computes two equal-length windows either side of it, and re-derives sessions/spawns/hook-denies/tokens/wall-time (merged across every --repo) plus per-repo commits-per-merged-PR from the same live stores ds-cost/ds-evaluate/ds-hook-fire-report/ds-branch-prune already read. A 5-case status precedence (ABSENT/NOT_YET_ELAPSED/INSUFFICIENT_COVERAGE/ZERO_SESSIONS/OK) reports null rather than a misleading numeric zero when a store can't support a trustworthy comparison; tokens/wall-time additionally carry a zero-filled/zero-filled-before/zero-filled-after data-quality flag. DS-246 adds agent_model (per agent x model runs and dollars, exact-id and family-priced reported separately) and per_ticket (Skeptic reviews counted from every Skeptic run with skeptic_reviews_with_findings as findings coverage, findings, QA fail-backs, PRs, loops, end-to-end wall, escaped-defect signals), both computed only from telemetry_v: 2 hook spawn rows and gated by their coverage extent; the per-ticket, PR-attribution and pricing helpers live in bin/_eval.py, shared with ds-eval. The eval block runs _eval.evaluate(use_gh=False, include_sessions=True) per window: its window figures, then cost-state dollars per session pooled and per entrypoint (empty sessions excluded and counted; fewer than 10 sessions on a side is PARTIAL), mix_shifted (an entrypoint's session share moved more than 10 points), model/version/base-commit confounders, and prefix_test at K = 5, 25, 100, pooled and per entrypoint. A failure inside it is an ABSENT eval block, never a non-zero exit; it calls neither gh nor ds-feedback, and costs tens of seconds on a repo with hundreds of sessions; --no-eval skips it. The report's session counts are over different populations and each is labelled (metrics.sessions.basis, eval.meta.session_counts): session-log rows, transcript sessions overlapping the window, sessions assigned by first timestamp, and the non-empty ones among them; usd_per_reconciled_session leaves empty sessions out. Read-only: never writes a telemetry file, never mutates git/gh state.
ds-cleanup-worktreesPythonSingle-repo worktree removal (classify -> lock/dirty -> merge-evidence -> disposition, bin/tests/worktree_model.py), PLUS an in-process --multi-repo/--report surface: discovers a set of repos (explicit --repo xN, positional root scan, --init-config to scaffold, or a ~/.agentic/cleanup-worktrees.json fallback), sweeps each with its own independently-resolved base branch, --max-repos N to bound discovery cost, and can rank them read-only ("which project is worst") via a cheap 2-git-call FAST tier or a full-cost DEEP tier. DS-196 adds a LENIENT-only origin_reachable evidence source (resolves worktree removal, never branch deletion, for a squash-merged/never-PR'd branch that is nonetheless pushed and past a resolved PR state) plus a --activity-window-hours (default 3.0) file-activity liveness gate (SKIP_RECENT_ACTIVITY); also launched automatically on Claude Code by hooks/session-start-wrap.sh (detached, --min-age-hours 24, at most once per 6 h per repo, log ~/.agentic/worktree-reap/<repo>-<sha1(root)[:8]>.log) - suppressible via AE_WORKTREE_REAP_DISABLE=1. DS-245 moves the lock gate ahead of self and makes --min-age-hours explicit-supply only; every unattended caller (the SessionStart sweep, /ds-wrap Step 5, --archive-unproven) supplies it. Every removal (including via ds-retire-carrier) first saves the worktree's gitignored non-build files to ~/.agentic/worktree-archive/<repo>/<name>.ignored.tgz and skips the removal if that fails; --archive-unproven writes prerequisite bundles (only commits off the origin base branches) there too, covers detached HEADs, and appends MANIFEST.tsv. Loads ds-branch-prune by path to fill content_subsumption (its subsumption_layer plus a git cherry rule, only when the PR query answered MERGED/CLOSED/NONE) and a detached entry's head_reachable (ref containment only); runs ds-retire-carrier's gate-7 pin check before any REMOVE or archive; a live-process-cwd gate after self (SKIP_LIVE_CWD, matched by device and inode so a case-variant path still matches, fails closed when the scan cannot run) is reused by ds-retire-carrier gate 1.
ds-costPythonToken / wall-time / dollar rollups per agent, session, task, and developer team from .agentic/events.jsonl and session logs; hook spawn rows are folded and priced by the shared bin/_telemetry.py (DS-246), which also merges the primary checkout's hook spawn rows when run from a linked worktree. The session/task/project/team/operator tables size each column to its widest value (bin/_lib.py's format_columns).
ds-disablePythonAppend the opt-out marker to AGENTS.md; optionally update the global config.
ds-doctorPythonInspect and repair global install health (symlinks, bin wrappers, a non-blocking WARN when ~/.local/bin is not on PATH, hook paths in settings.json, DS-54 hooks-snapshot staleness), foreign-plugin PreToolUse Agent/Task hook detection (DS-198), and a non-blocking WARN when the installed Claude Code CLI is inside the worktree nested-memory reload window 2.1.259 to <2.1.287 (CLAUDE_RELOAD_FIRST_SUSPECT/CLAUDE_RELOAD_FIRST_CLEAN).
ds-emitBashAppend one structured JSON event to .agentic/events.jsonl at orchestration boundaries.
ds-evalPythonRead-only evaluation of one or more repos over one window (bin/_eval.py's evaluate()): per-agent priced cost and value signals, Skeptic yield per round, ticket-keyed work items (tiers 1-4 with tier agreement) with PR outcome and rework, per-hook deny quality with operator fire_labels, cost reconciled exactly to the harness cost-state across every ~/.claude* store, and ranked proposals (D1a-D3, each with a route) plus telemetry gaps. [steps] counts fires and outcomes per step id (bin/_steps.py) from sources that record their own step only. Every metric is {status: OK|ABSENT|PARTIAL, value, coverage, missing}; missing input is ABSENT with a reason, never 0. --store replaces the default store set (_transcripts.resolve_stores), and an unreadable or missing store is listed ABSENT in meta.stores. --no-gh makes no gh call. The text report's [work_items] lists the --top N (default 10) keyed items by priced cost (key, tier, priced usd, summed spawn wall, Skeptic rounds, PR outcome) plus a summary line (work_items.summary); by_iteration prints iteration_tagged_share and findings_carrying_share separately; cost.reconciled.empty_sessions and cost.no_cost_state.empty_sessions (no usage record and no cost-state spend; _eval.is_empty_session, the definition ds-change-delta shares) are left out of cost.window_total.coverage. PR outcome never asserts "not merged": an item the in-window ticket-id match misses is checked against its own PR numbers in the window's merge set (own_prs_merged_in_window), then one undated git log --first-parent --grep on the base ref for its PR numbers and ticket id (merged_outside_window, counting (#N) and Merge pull request #N from subjects and never a Revert " one; ticket_mention_commits). It prints one of n/a (no merged-PR history), merged #N (with , K follow-up and , reverted when they apply), merged #N (before window), merged #N (after window), no PR merge found (ticket id mentioned in K base commit(s)), no merge found in window (wider base history unreadable), or no merge found when that first-parent history has neither. Each outcome then gains , H changes-requested when gh shows H >= 1 CHANGES_REQUESTED reviews on the item's PRs from any author, automated /ds-review-pr reviews included (changes_requested), or , changes-requested n/a (changes_requested null) when gh was disabled, failed, or did not list one of the item's PRs, never 0. keepalive (per repo, from transcripts only) reports pings fired/passed/dropped/deleted/wrapped, ping tokens and priced dollars per outcome, operator returns after more than 20 min idle (gap since the previous non-ping main-chain request) in 20-60/60-120/120-240/over-240 min buckets split by whether any ping that made a request fell in the gap, with count, cold count and average cache read/creation, and an estimated_net_usd (avoided creation minus all ping spend) that is an estimate, never a measured saving, and ABSENT when the avoided side cannot be estimated. Returns are reported in windows without pings too, so a pre-keepalive window is the baseline; they need turnOrigin (Claude Code 2.1.280+, else ABSENT "no turnOrigin in transcripts") and never count a session file's first human turn. A bucket under 10 returns is PARTIAL; with no ping in the window the ping figures are ABSENT. Window-edge skew: the estimate's avoided side counts in-window returns whose ping may have fired before --since, while its cost side counts only in-window pings, so short windows are skewed and comparisons need windows of similar length. Value change: agents.conductor no longer includes keepalive ping usage (cost and mix still do). For ds-change-delta on the keepalive, cut at the first real ping fire, not the merge date.
ds-evaluatePythonSignal collector for /ds-evaluate: runs bin/_eval.py's evaluate() over --telemetry-repo (repeatable; default the cwd's git toplevel) for a --since/--until window (default 30 days), adds the --repo DinoStack checkout's budget gates, resident floor and vision pillars, and ends with the ranked refinement proposals (rule, evidence, rank_usd or unpriced, route) and then the telemetry gaps (no route, no rank). Reads no session-log file.
ds-feedbackPythonManage the home-dir feedback store (~/.agentic/feedback.jsonl) - append/list/mark operator and agent friction items. A draft may carry an optional fire_label {hook, fire_key, fire_ts, verdict} (operator verdict on one hook deny); such an item is born triaged, so /ds-feedback-triage never lists it, and ds-eval reads it for a hook's labelled false-positive rate.
ds-helpPythonPrint the static slash-command reference to stdout. Zero file I/O; never fails.
ds-hook-fire-reportPythonPer-hook fire-count status for hooks/enforce-*.py, joining posture (ACTION_ONLY vs EVERY_VERDICT, via scripts/lib/enforcer_facts.py) against .agentic/.enforcement-fires.jsonl. Also merges any stranded .claude/worktrees/*/.agentic/.enforcement-fires.jsonl copies (deduped by exact line text) into the same analysis at query time - see meta.stranded_worktree_logs_merged/meta.stranded_worktree_records_merged. --repo may be a consumer repo with no hooks/ dir: hook sources then come from the tool's own checkout while fire logs still come from --repo (meta.hooks_dir names which). Each row also carries fire_count_window_no_session_id (table column no-sid): the part of the window count whose rows have no session_id (a hook test fixture, or a row written before rows carried one), which is not a measured live-session figure, and two flags for a hook none of whose window rows has one: window_predates_session_ids (every such row is at or before meta.first_session_id_ts, so the missing id says nothing) and window_all_unjoinable (table status ACTIVE*: ids were being logged, the rows still cannot be attributed to a session, cause unknown - never zero-fire evidence). meta.legend explains all three. Operator-run; ds-change-delta and _eval.py duplicate its timestamp parsing and fires-log reading rather than importing it.
ds-identityPythonManage per-developer identity files used by the Stop hook for session telemetry attribution.
ds-laneBash + Python stdlib helperLaunch harness-matched headless lanes: Claude streaming -p supports live send; Codex bounded exec --json requires post-exit exact-session resume, and close never terminates it. Commands: start/send/close/reap/resume/list/wait/tail/watch/open/open-all/stop/resume-hint/count/path/doctor. Native identities and agreeing explicit bindings select the harness; missing/conflicting identity or policy refuses without fallback. Saved executable, config, cwd, and live permission context control resume; Claude preserves mode/background ceiling, Codex preserves supported sandbox fields with unattended approvals denied. State is the primary checkout's self-ignoring .agentic/lanes/, printed by path, even from a linked worktree; runtime cwd stays the caller's original cwd. Capacity is shared (DS_LANE_MAX, default 5). Assistant-only task markers produce done/blocked unless a fatal current-run event overrides them: alive/up while live, dead/down after exit. reap closes marked Claude input and records exited Codex outcomes, never killing a live Codex turn. A live Claude lane closes its own input once its turn's result follows LANE-DONE (a detached per-lane sentinel); start/resume/list/count/send/wait reap first; send refuses a done lane; wait blocks until a named lane is done, blocked or dead (exit 2 at its ceiling). Send, close, stop and the sentinel serialize on a python-held per-lane flock. PID birth time plus exact executable and backend command shape protect ownership. Legacy records with claude_bin stay Claude; resume requires explicit original config and captured init mode/cwd. Optional watch views never take focus and print tab:/fix: outcomes: inside tmux a detached tmux window by default; a macOS Terminal tab only with DS_LANE_VIEWER=terminal (outside tmux, open still uses Terminal); DS_LANE_NO_TAB=1 disables them. Read-only doctor [--json] separates selected runtime/policy readiness, tab readiness, and PATH launch offer; authentication, quota and macOS consent remain unverified. Canonical procedure: content/references/runbook-conductor.md.
ds-learning-shardPythonManage the home-dir per-session learning shard store (~/.agentic/learnings-shards/<repo-key>/<session-key>.jsonl) - append one in-flight learning (capped at 5 per session, soft-fail), rollup the not-yet-folded raw entries idempotently, list for diagnostics. Performs no classification. --repo accepts any path inside the repo - a linked worktree and its primary checkout resolve to one <repo-key>, via git rev-parse --git-common-dir.
ds-learnings-retrieval-ratePythonRead-only, on-demand measurement of the per-role firing rate of the prior-learnings retrieval step, from Claude Code's own subagent transcripts (<store>/*/*/subagents/agent-*.jsonl plus each .meta.json sidecar's agentType) in every config-dir store bin/_transcripts.py finds (~/.claude*/projects plus the active config dir), not only the active one; repeatable --store DIR replaces that set, and output names every store with its transcript count (an unreadable store, or a --store path that is missing or not a directory, is reported ABSENT with a reason; a store with an unreadable directory inside it is partial, its count a floor (>= N) or ABSENT - an unreadable directory is never counted as 0). Reports wired roles against unwired controls with both pooled lines; wiring is derived from whether content/agents/<role>.md carries a <!-- shared:learnings-retrieval --> span, so it self-updates. Exit 0 on every path, errors via envelope. Read-side only - DS-159 owns write-side per-entry outcome.
ds-memoryPythonQuery .agentic/events.jsonl, MEMORY.md, and .agentic/context.md; return compact Markdown summaries.
ds-memory-capturePythonTwo-tier memory capture: detect reports standard vs two-tier from shard state, flush turns .agentic/memory-capture-inbox.md lines into shards through the project's own ingest (exit 2, nothing touched, in standard mode), new-shards lists shards absent from a ref for the Phase 11e / Part G ride-along, repair re-sequences after a merge collision. See content/references/memory-shard-convention.md §Two-tier capture.
ds-migratePythonApply additive project scaffolding migrations (check / apply / diff subcommands).
ds-parse-subagent-usagePythonParse a Claude Code subagent transcript JSONL and emit {tokens, model, wall_seconds} for spawn_complete events.
ds-qa-evidence-publishBash/ds-implement-ticket Phase 8.5 (flags only, never inherited env), called from content/references/qa-evidence-publish.md: commits the PASS screenshots given as JSON arguments to the orphan qa-evidence branch under <ticket-slug>/<branch-slug>/, pushes with three attempts, retires its worktree with ds-retire-carrier, deletes the consumed files, and prints one {url, criterion_id, description, result} record per screenshot on stdout (nothing when the push failed). Soft-fail: exit 0 once flags parse, 2 usage.
ds-retire-carrierPythonCompletion-time retirement of one worktree carrier: removes the checkout (never the branch) only when it is unlocked, clean, free of protected ignored content, contains no other registered worktree and pins no commit that would lose its last ref; otherwise appends a hold (owner, reason, revisit event) to .agentic/worktree-cleanup-skips.jsonl. --hold/--release for explicit holds, --pin keeps unpinned commits on a carrier-pin/* branch, --list-holds folds the ledger, --dry-run writes and fetches nothing. Never forces, unlocks, prunes, pushes or deletes a branch.
ds-skill-load-ratePythonRead-only, on-demand measurement (DS-227) of how often the dinostack skill actually loads per session, from Claude Code's own TOP-LEVEL session transcripts (<store>/<project-dir>/*.jsonl in every config-dir store bin/_transcripts.py finds, not only the active one; repeatable --store DIR replaces that set, and output names every store with its session count, an unreadable store or a missing or non-directory --store path as ABSENT with a reason, and a store with an unreadable in-scope project dir as partial with a floor count (>= N) or ABSENT - an unreadable directory is never counted as 0; deliberately not the */subagents/agent-*.jsonl glob ds-learnings-retrieval-rate reads). Headline figure is the unprompted (model-initiated Skill tool_use) load rate against operator-typed /dinostack, plus a nudge-fired-but-no-load count. Scoped by default to the current repo's project directories as _transcripts.project_dirs() maps them (the repo and its worktrees; --repo-path/--project-dir/--all-projects to override or widen); reports ABSENT, never 0, when no transcripts are in scope. A diagnostic, not standing telemetry - see its own module docstring's retirement condition.
ds-statusPythonRead-only dump of the activation resolver state with provenance and plain-English explainer.
ds-ticket-ciBash/ds-implement-ticket Phase 10 CI wait (--pr N --gh-repo G): bounded gh pr checks --json name,state,bucket polling that passes only when every required check of the base branch (ruleset contexts, enforced branch-protection contexts, and each repeatable --required NAME) is registered and passing, nothing is pending or failed, and two consecutive polls see the same count. Exit 0 passed, 1 failed (names the fail/cancel checks), 2 timeout (names required checks not passing), 3 usage, 4 required set unknown without --required (rules failing other than 403/404, or neither source readable) or checks unreadable on 5 consecutive polls. App-scoped required checks match by name only. Never merges, pushes, or marks the PR ready (Phase 10b does that after its thread rule). Every exit appends one step_outcome row to the primary checkout's .agentic/events.jsonl (scripts/lib/step-outcome.sh; enum in its header).
ds-ticket-commitBash/ds-implement-ticket Phase 8 as one command (flags only, never inherited env): feature commit from named files with DCO/Developer: trailers, the chore(telemetry) session-log commit, the push, then ds-retire-carrier on the engineer's worktree after a verified push (exit 3 prints HELD, never fails the phase) or an explicit BLOCKED: unpushed commit hold when the push is not verified (exit 1); files passed while the commit checkout is off the PR branch, an unmatched pathspec, or a commit failing with changes staged exit 3 with nothing pushed or retired; files unchanged from HEAD on the PR branch are skipped. Every exit appends one step_outcome row to the primary checkout (enum in its header).
ds-ticket-finishBashPost-PR steps of /ds-implement-ticket (flags only): ledger (Phase 9 ticket-rework ledger write), knowledge (Phase 11e knowledge commit), merge (Phase 12 qa.md snapshot cleanup, conditional auto-merge, unconditional ds-base-sync, then retirement of the ticket's .agentic/worktrees/<branch> and qa-<branch> carriers and re-evaluation of this session's automatic holds; never --release/--force, exit 0 regardless of holds). ledger and merge append one step_outcome row per exit to the primary checkout (enums in its header); ledger also records elevated_route.
ds-ticket-grantPythonWrite a one-shot, TTL-bounded exception to hooks/enforce-ticket-batching.py's deny on agent-initiated tracker-ticket creation (grant --repo <path> --session-id <id> --reason <str>); the hook itself reads, validates, and atomically consumes it on the next denied creation.
ds-ticket-setupBash + Python stdlib helperThe /ds-implement-ticket Setup call: prints one JSON line {repo_dir, base_branch, tracker, ticket_id, loop_key, mode, resume, rework} (the loop-key derivation and Phase 1 rework read, moved verbatim from the command; tracker is ds-tracker resolve --json; resume classifies the loop-state candidates without touching them), then, when mode is batch, open_goal or resume, that mode's procedure reference body, so the procedure arrives in tool output rather than behind a pointer the conductor rarely Reads. --stdin takes the operator's input on stdin (the command passes it in a quoted heredoc, so no shell expands it); --ticket - runs it for one batch ticket read from stdin, and --rework-only --ticket - prints only {ticket_id, rework} for a ticket Phase 0 resolved, so it never re-keys the loop. Read-only. Sourcing it defines the shell functions its tests execute.
ds-trackerPythonManage the project-local, gitignored .agentic/tracker.yml tracker-config overlay (init / show / set / resolve / path), merged field-by-field over the AGENTS.md tracker resolution chain.
ds-updatePythonNon-interactive updater: fetch origin, rebuild adapters (forcing the loop even when old_head==new_head if the local DS-54 hooks-snapshot has diverged from the live checkout), reset version-check cache, run ds-doctor --fix.
ds-wrap-acquire-lockNodePoll-wait (background) for the /ds-wrap directory lock, exiting when acquired, on a 20-minute timeout, or (--no-wait) immediately busy; publishes a role-tagged (--role=agent|daemon|commit) lock descriptor and structurally never removes a lock.
ds-wrap-release-lockNodeRelease the /ds-wrap directory lock (.agentic/wrap/lock) safely where rm -rf is permission-denied; owner-scoped - refuses removal when the descriptor names a live foreign-process PID, and refuses to touch anything at the lock path that isn't a lock directory it created.

Upstream dependencies

  • Python 3 stdlib only - no third-party installs required for any Python binary.
  • ds-wrap-acquire-lock and ds-wrap-release-lock require Node; both load hooks/lib/wrap-marker.js via __dirname-relative path (not cwd).
  • ds-emit shells out to python3 and date for safe JSON assembly.
  • ds-cost soft-depends on pyyaml for ~/.agentic/pricing.yml; absent = token-only output.
  • ds-update shells out to git and bash <adapter>/install.sh.
  • ds-parse-subagent-usage reads <config_dir>/projects/ transcript files, where config_dir is resolved via bin/_lib.py's resolve_claude_config_dir(): AGENTIC_CONFIG_DIR > CLAUDE_CONFIG_DIR > CODEX_HOME > PI_CODING_AGENT_DIR (first non-empty wins), falling back to ~/.claude only when none is set - not a hardcoded ~/.claude/projects/ path.

Downstream consumers

content/commands/ slash-command specs; adapter install scripts (.claude/install.sh, .codex/install.sh, etc.) that symlink these onto PATH; hooks/stop-context.js for ds-identity helpers; Activation preflight Step 6 for ds-migrate; content/commands/ds-wrap.md Part D.5 (also run by ds-implement-ticket.md Phase 11b), content/commands/ds-evaluate.md, content/commands/ds-feedback-triage.md and bin/_eval.py for ds-feedback.

Failure-mode discipline

Every binary is fail-open: unexpected input, missing files, and permission errors are swallowed and surfaced via non-zero exit codes or stderr lines, never uncaught exceptions. Exit-code conventions are per-command in each binary's Public API block. Conductors must not treat a non-zero exit as a session-fatal error.

Why polling belongs in a binary, not conductor prose

An LLM cannot reliably run a long foreground poll loop (foreground sleep is blocked in the harness). /ds-wrap's lock-wait was once prose the conductor hand-ran ("poll every 5s for 20min") and reliably gave up after one or two checks. Fix pattern: move the poll loop into a small binary invoked as a background spawn (run_in_background: true) so the conductor stays available and gets notified with an exit code on completion - a background spawn on this harness does deliver a synchronous exit code on completion. This is why ds-wrap-acquire-lock exists as a binary rather than as conductor prose.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.