From dev-on-leash
Use to set up dev-on-leash in a target project — bootstrap this project, add the harness, install the dev-on-leash discipline. Interviews the user, renders CLAUDE.md / AGENTS.md / .claude/settings.json from templates, and copies the project-agnostic harness layer in.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dev-on-leash:bootstrap-dev-leashThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill runs **inside a target project** (not inside the dev-on-leash plugin repo). It is the entry point a user invokes after installing the `dev-on-leash` plugin. It produces the **project-specific layer** (`CLAUDE.md`, `AGENTS.md`, `.claude/settings.json`) by interview, then triggers the copy of the **project-agnostic layer** (harness scripts, plan skeleton, task/plan templates).
This skill runs inside a target project (not inside the dev-on-leash plugin repo). It is the entry point a user invokes after installing the dev-on-leash plugin. It produces the project-specific layer (CLAUDE.md, AGENTS.md, .claude/settings.json) by interview, then triggers the copy of the project-agnostic layer (harness scripts, plan skeleton, task/plan templates).
The user wants to install the dev-on-leash development discipline into their project — phrasings like "set up dev-on-leash", "bootstrap this project", "add the harness". Run once per project. Do NOT use it to edit an already-bootstrapped project's discipline files — those are hand-maintained after the first render.
Read these before doing anything. They bound the entire skill.
The fixed process prose is non-negotiable. The templates contain fixed prose — branch discipline, TDD (Red → Green → Refactor), the integration-suite gate, the planning trigger, the harness-tooling description. The interview only fills {{placeholder}} values and selects which optional blocks to keep. It MUST NOT let the user weaken, soften, reword, or remove TDD, branch discipline, or any fixed section. If the user asks to "skip TDD" or "allow direct commits to main", refuse: explain that those rules are the point of dev-on-leash and are not configurable. The interview customizes; it never edits the discipline.
Never overwrite an existing CLAUDE.md or AGENTS.md without an explicit confirmed diff. If either file already exists in the target project, do NOT write over it. Show the user a diff between the existing file and the proposed rendered output, explain what would change, and get an explicit "yes, overwrite" before writing. The same applies to .claude/settings.json — if it exists, show the diff and confirm. If the user declines, write the rendered file alongside with a .dev-on-leash-proposed suffix and tell them to merge manually.
The templates ship inside the plugin. Reference them via the CLAUDE_PLUGIN_ROOT environment variable, which Claude Code sets to the plugin's absolute install path:
${CLAUDE_PLUGIN_ROOT}/templates/CLAUDE.md.tmpl${CLAUDE_PLUGIN_ROOT}/templates/AGENTS.md.tmpl${CLAUDE_PLUGIN_ROOT}/templates/settings.json.tmplNever hardcode an absolute install path — it breaks across machines. If CLAUDE_PLUGIN_ROOT is unset, stop and tell the user the skill must be run as part of the installed dev-on-leash plugin.
Collect every project-specific value. Use the AskUserQuestion tool for questions with discrete choices; use plain free-text questions otherwise. Ask in small batches; do not dump everything at once.
Collect:
| # | Item | Mechanism | Feeds |
|---|---|---|---|
| 1 | Project name | free-text | {{PROJECT_NAME}} |
| 2 | Language / stack | free-text | {{STACK_SUMMARY}}, {{STACK_DESCRIPTION}} |
| 3 | Mono-repo or single package | AskUserQuestion (mono-repo / single package) | {{PACKAGE_LAYOUT}} |
| 4 | Test command(s) | free-text | {{TEST_COMMANDS}}, {{TEST_RUNNER_COMMANDS}} |
| 5 | Lint command(s) | free-text | {{LINT_COMMANDS}} |
| 6 | Typecheck command(s) | free-text | {{TYPECHECK_COMMANDS}} |
| 7 | Build command(s) | free-text | {{BUILD_COMMANDS}} |
| 8 | Branch flow | AskUserQuestion (PR-based / direct-to-main) | informational — see note below |
| 9 | Domain-rules concern? (multi-tenancy, per-user scoping, etc.) | AskUserQuestion (yes / no) | keep or drop OPTIONAL:DOMAIN_RULES |
| 10 | Design-system / UI concern? | AskUserQuestion (yes / no) | keep or drop OPTIONAL:UI_RULES |
| 11 | Coverage targets | free-text | {{COVERAGE_TARGETS}} |
| 12 | Parallel-work worktree layout? | AskUserQuestion (yes / no) | keep or drop the .worktrees/ gitignore patch (Step 3c) |
Notes on specific items:
{{COMMON_COMMANDS}} in CLAUDE.md.tmpl): assemble from the test/lint/typecheck/build answers — no separate question needed.main; it only describes the team's PR habit. If the user picks direct-to-main, confirm they understand the harness still expects feature branches for any source/test/config change.{{DOMAIN_RULES}}. If no, drop the optional block entirely.{{UI_RULES}}. If no, drop the optional block entirely..worktrees/ to
.gitignore. This standardizes the proactive parallel-work layout used by
the leash-start-work skill. If no, make no .worktrees/ change — the skill
still works but will warn the directory is not ignored. This is opt-in and
never weakens branch discipline; it only makes N mandatory branches livable
at once.Read each .tmpl, substitute placeholders, handle optional blocks, write the result into the target project.
CLAUDE.md.tmpl → CLAUDE.md: {{PROJECT_NAME}}, {{STACK_SUMMARY}}, {{COMMON_COMMANDS}}.AGENTS.md.tmpl → AGENTS.md: {{PROJECT_NAME}} (appears multiple times), {{STACK_DESCRIPTION}}, {{TEST_COMMANDS}}, {{COVERAGE_TARGETS}}, {{PACKAGE_LAYOUT}}, and {{DOMAIN_RULES}} / {{UI_RULES}} (only if their optional block is kept).settings.json.tmpl → .claude/settings.json: {{TEST_RUNNER_COMMANDS}}, {{LINT_COMMANDS}}, {{TYPECHECK_COMMANDS}}, {{BUILD_COMMANDS}}.Substitute every {{...}} occurrence — after rendering, no {{ may remain in any output file. If an interview answer left a placeholder with no value, ask the user rather than emitting an empty token.
{{TEST_RUNNER_COMMANDS}}, {{LINT_COMMANDS}}, {{TYPECHECK_COMMANDS}}, {{BUILD_COMMANDS}} each sit on their own line inside a JSON "allow" array. Render each as one or more comma-separated, quoted JSON strings in Bash(<command>*) permission form — e.g. a pytest answer becomes "Bash(pytest*)", "Bash(python -m pytest*)". The final rendered file MUST be valid JSON: no trailing comma before ], no empty slots. If the user has no command for a category, remove that placeholder line entirely (and its trailing comma) rather than leaving an empty string.
The optional blocks are delimited in AGENTS.md.tmpl by HTML-comment markers:
<!-- OPTIONAL:DOMAIN_RULES -->
...
<!-- /OPTIONAL:DOMAIN_RULES -->
<!-- OPTIONAL:UI_RULES -->
...
<!-- /OPTIONAL:UI_RULES -->
CLAUDE.md.tmpl and settings.json.tmpl have no optional blocks.
For each of CLAUDE.md, AGENTS.md, .claude/settings.json:
<name>.dev-on-leash-proposed and report it.Create the .claude/ directory if it does not exist.
scripts/harness/cycle_done.py closes a cycle only when every command in .harness/gates exits 0. Build that file from the interview's verification answers (Step 2, items 4–7):
.harness/ in the target project if it does not exist..harness/gates with one shell command per line — the project's test, lint, typecheck, and build commands. Skip any category the project does not have. Lines starting with # are comments.Example:
# Commands run by cycle_done.py to close a cycle. All must exit 0.
python -m pytest
ruff check .
If the project has no verification commands at all, still write .harness/gates with just the comment header — cycle_done then closes on checkbox state alone, and the user has an obvious place to add gates later.
.gitignoreThe harness writes runtime files to .harness/ that must NEVER be
committed:
.harness/exceptions.log — audit log for cycle_done --force..harness/sessions/<pid>.json — per-session lockfiles written by the
session-leash SessionStart hook. They record live PIDs and
worktree paths.Read the target project's .gitignore (create it if absent). Ensure
both of these lines are present; add whichever is missing, leaving the
file otherwise byte-identical:
.harness/exceptions.log
.harness/sessions/
If you must add lines, group them under a # dev-on-leash comment
heading that you also add when missing — so the patched lines are
discoverable later. Do NOT duplicate a line that is already present
(an exact match anywhere in the file counts as present).
If the user opted in to the worktree layout (interview item 12), also ensure
.worktrees/ is present, under the same # dev-on-leash heading:
.worktrees/
This is the proactive parallel-work directory created by leash-start-work;
ignoring it keeps worktree checkouts out of commits. Idempotent — an exact
match anywhere in the file counts as present; never duplicate. If the user
declined item 12, make no .worktrees/ change.
Invoke the plugin's init script to drop the agnostic layer into the target project. The script requires the target repo path as its first argument — omitting it causes the script to exit 1 with an error. Since the skill runs from the target project root, pass . as the target path. Use the script matching the OS:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/init.sh" .pwsh "${CLAUDE_PLUGIN_ROOT}/scripts/init.ps1" .This copies scripts/harness/, docs/task-schema.md, docs/plan-template.md, and an empty docs/plans/ directory into the target project. Run it from the target project root. If the init script is not yet present in the installed plugin version, report that the agnostic layer could not be copied and tell the user to update the plugin — do not hand-copy files.
The init script copies an opt-in pre-commit hook to
.harness/hooks/pre-commit. It runs scripts/harness/recheck_plan.py on any
staged plan file and blocks the commit if a ticked task fails to re-verify —
the local half of the enforcement model.
Ask the user (one AskUserQuestion, yes/no) whether to activate it now:
git config core.hooksPath .harness/hooks in the target repo.
Tell the user the bypass is git commit --no-verify, and that
core.hooksPath redirects all git hooks to .harness/hooks/.git config command.For CI enforcement, point the user at ${CLAUDE_PLUGIN_ROOT}/templates/ci-snippet.md
— a copy-pasteable step that re-verifies ticked tasks on every push.
Tell the user concisely:
CLAUDE.md, AGENTS.md, .claude/settings.json), and which (if any) were written as .dev-on-leash-proposed pending manual merge.scripts/harness/, docs/task-schema.md, docs/plan-template.md, and an empty docs/plans/ directory..harness/gates was written from the verification commands — editing it tunes what cycle_done checks before closing a cycle.git config core.hooksPath), and
that the CI snippet in templates/ci-snippet.md enforces the same check on push..worktrees/ parallel-work layout was standardized (interview
item 12) — if so, .worktrees/ was added to .gitignore.docs/plans/ (by hand from docs/plan-template.md, or with superpowers:writing-plans if those skills are installed), then execute it task-by-task with the execute-plan-task skill. Augment each task you want machine-verified with a task-meta block — see docs/task-schema.md.npx claudepluginhub diogeneshfg/dev-on-leash --plugin dev-on-leashGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.