Goal / problem
The /faber slash command at ~/.claude/commands/faber.md was created by hand and hardcodes the control-plane repo path (~/git/fabrica/...) in ~6 places. It is not reproducible from this repo and not covered by RESTORE.md — which breaks both team goals: reusable-by-anyone (a new adopter can't regenerate it) and full-backup (it can't be reconstructed if lost). Today there is no scripts/install.sh at all.
Build an idempotent scripts/install.sh that generates ~/.claude/commands/faber.md with the control-plane repo path derived from the repo's own location (not hardcoded ~/git/fabrica), then prints next steps. This formalizes the hand-made command and makes the install reproducible.
Acceptance criteria
- New
scripts/install.sh — #!/usr/bin/env bash, set -euo pipefail, shellcheck-clean, executable.
- Path derived, never hardcoded. Resolve the repo root from the script's own location (e.g.
cd "$(dirname "$0")/.." && pwd, resolving symlinks) and substitute that absolute path everywhere the /faber command references the control plane. No ~/git/fabrica literal in the generated output.
- Generates
~/.claude/commands/faber.md containing the current /faber behavior (read role files → operate on the current repo → issue/round/reviewer/merge-gate loop → never write code, never merge). Source the body from a template in this repo (e.g. templates/faber-command.md with a path placeholder) so the command text lives in version control and isn't duplicated inside the script. Creating that template is part of this issue.
- Idempotent. Re-running produces the same result and overwrites cleanly; create
~/.claude/commands/ if missing. If an existing faber.md differs, back it up (e.g. faber.md.bak) before overwriting rather than clobbering silently.
- Prints next steps on success: where the command was written, that the repo path was derived to
<resolved path>, and the follow-on setup (scripts/setup-target-repo.sh in a target repo; confirm CI + optional CLAUDE.md). Match the output style of scripts/setup-target-repo.sh.
RESTORE.md — replace any "recreate the /faber command by hand" step with "run scripts/install.sh".
README.md — add scripts/install.sh (and the new template) to the Layout block with a one-line description.
Likely files
scripts/install.sh (new)
templates/faber-command.md (new — the parameterized command body)
RESTORE.md (install step)
README.md (Layout)
Test expectations
- CI green:
install.sh shellcheck-clean, structure check intact.
- Verify (in PR description) a real run generated
~/.claude/commands/faber.md with the derived path and that a second run is idempotent.
- CI does not write to
~/.claude — static check only.
Out of scope
- Installing routines, Codex, or any connector setup (this is just the
/faber command + its derived path).
- Changing the behavior/wording of the Faber role beyond parameterizing the path.
- A full multi-component installer — one concern: reproducibly generate the
/faber command.
Goal / problem
The
/faberslash command at~/.claude/commands/faber.mdwas created by hand and hardcodes the control-plane repo path (~/git/fabrica/...) in ~6 places. It is not reproducible from this repo and not covered byRESTORE.md— which breaks both team goals: reusable-by-anyone (a new adopter can't regenerate it) and full-backup (it can't be reconstructed if lost). Today there is noscripts/install.shat all.Build an idempotent
scripts/install.shthat generates~/.claude/commands/faber.mdwith the control-plane repo path derived from the repo's own location (not hardcoded~/git/fabrica), then prints next steps. This formalizes the hand-made command and makes the install reproducible.Acceptance criteria
scripts/install.sh—#!/usr/bin/env bash,set -euo pipefail, shellcheck-clean, executable.cd "$(dirname "$0")/.." && pwd, resolving symlinks) and substitute that absolute path everywhere the/fabercommand references the control plane. No~/git/fabricaliteral in the generated output.~/.claude/commands/faber.mdcontaining the current/faberbehavior (read role files → operate on the current repo → issue/round/reviewer/merge-gate loop → never write code, never merge). Source the body from a template in this repo (e.g.templates/faber-command.mdwith a path placeholder) so the command text lives in version control and isn't duplicated inside the script. Creating that template is part of this issue.~/.claude/commands/if missing. If an existingfaber.mddiffers, back it up (e.g.faber.md.bak) before overwriting rather than clobbering silently.<resolved path>, and the follow-on setup (scripts/setup-target-repo.shin a target repo; confirm CI + optionalCLAUDE.md). Match the output style ofscripts/setup-target-repo.sh.RESTORE.md— replace any "recreate the/fabercommand by hand" step with "runscripts/install.sh".README.md— addscripts/install.sh(and the new template) to the Layout block with a one-line description.Likely files
scripts/install.sh(new)templates/faber-command.md(new — the parameterized command body)RESTORE.md(install step)README.md(Layout)Test expectations
install.shshellcheck-clean, structure check intact.~/.claude/commands/faber.mdwith the derived path and that a second run is idempotent.~/.claude— static check only.Out of scope
/fabercommand + its derived path)./fabercommand.