| name | init |
| description | Bootstrap harness user files by copying them from plugin templates into
the user project. Seeds files such as `CLAUDE.md`, `.claude/config.json`,
and `.claude/rules/*.md` on first install. The default mode is
idempotent — existing files are skipped and reported. `--force` makes a
`.bak` backup and overwrites; `--check-drift` is a dry-run diff only.
Usage: /harness:init [--force] [--check-drift]
|
| allowed-tools | ["Bash","Read"] |
init — Bootstrap user files
Copies seed files from the plugin templates directory
(${CLAUDE_PLUGIN_ROOT}/templates/) into the user project. config.json
is handled by the SessionStart ensure-config.sh hook, so this skill's
primary targets are CLAUDE.md and .claude/rules/*.md.
Flags
| Flag | Behavior |
|---|
| (none) | default: copy missing files only; skip + report existing files |
--force | back up existing files as <file>.bak, then overwrite |
--check-drift | dry-run; report diffs without copying |
--force and --check-drift are mutually exclusive — combining them is rejected.
Step 1 — Input validation and path resolution
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$PROJECT_DIR/.claude}"
TEMPLATES_DIR="$PLUGIN_ROOT/templates"
if [[ ! -d "$TEMPLATES_DIR" ]]; then
echo "templates dir not found: $TEMPLATES_DIR" >&2
exit 1
fi
FORCE=0
DRY=0
for arg in "$@"; do
case "$arg" in
--force) FORCE=1 ;;
--check-drift) DRY=1 ;;
*) echo "unknown flag: $arg" >&2; exit 1 ;;
esac
done
[[ "$FORCE" -eq 1 && "$DRY" -eq 1 ]] && { echo "--force and --check-drift cannot be combined" >&2; exit 1; }
Step 2 — Enumerate seed targets
templates/CLAUDE.md.tmpl -> CLAUDE.md (project root)
templates/rules/*.tmpl -> .claude/rules/* (subdir preserved, .tmpl stripped)
templates/config.json.tmpl -> skipped (owned by ensure-config.sh)
Step 3 — Per-file behavior
For each mapped (src, target) pair:
| Target state | default | --force | --check-drift |
|---|
| absent | cp -> created | cp -> created | "would create" |
| present + identical | skip -> unchanged | skip -> unchanged | "unchanged" |
| present + different | skip -> diverged + notice | backup + overwrite -> forced | diff shown |
diff_files() {
diff -u "$1" "$2" 2>/dev/null
}
source "$PLUGIN_ROOT/hooks/lib/baseline.sh"
apply_one() {
local src="$1" target="$2" key="$3"
if [[ -L "$target" ]]; then
echo " skipped $target (symlink — rejected; remove it and retry)"
return 0
fi
if [[ ! -e "$target" ]]; then
if (( DRY )); then
echo " + would create $target"
else
mkdir -p "$(dirname "$target")"
cp "$src" "$target"
baseline_record "$key" "$target"
echo " created $target"
fi
return 0
fi
if cmp -s "$src" "$target"; then
if (( DRY )); then
echo " = unchanged $target"
else
[[ -z "$(baseline_get "$key")" ]] && baseline_record "$key" "$target"
echo " = skipped $target (identical)"
fi
return 0
fi
if (( DRY )); then
echo " ~ diverged $target"
echo " (run 'diff -u $src $target' to inspect)"
return 0
fi
if (( FORCE )); then
if [[ -e "$target.bak" ]]; then
echo " skipped $target ($target.bak already exists — move/remove it and retry)"
return 0
fi
cp "$target" "$target.bak"
cp "$src" "$target"
baseline_record "$key" "$target"
echo " forced $target (backup: $target.bak)"
else
echo " skipped $target (user modification detected — preserved)"
fi
}
Step 4 — Driver loop (executed by the agent)
The agent emits the following driver verbatim:
CREATED=0; SKIPPED=0; FORCED=0
run_one() {
local out
out=$(apply_one "$1" "$2" "$3")
echo "$out"
case "$out" in
*"created"*) CREATED=$((CREATED+1)) ;;
*"forced"*) FORCED=$((FORCED+1)) ;;
*) SKIPPED=$((SKIPPED+1)) ;;
esac
}
run_one "$TEMPLATES_DIR/CLAUDE.md.tmpl" \
"$PROJECT_DIR/CLAUDE.md" \
"CLAUDE.md"
for tmpl in "$TEMPLATES_DIR/rules/"*.tmpl; do
[[ -f "$tmpl" ]] || continue
base="$(basename "$tmpl" .tmpl)"
run_one "$tmpl" \
"$PROJECT_DIR/.claude/rules/$base" \
".claude/rules/$base"
done
Step 5 — Summary
echo ""
echo "--- harness:init complete ---"
echo "created: $CREATED, skipped: $SKIPPED, forced: $FORCED"
[[ "$FORCED" -gt 0 ]] && echo "Overwritten originals are preserved as .bak files."
Step 6 — Follow-up
- First-time install (
created > 0): recommend running /harness:doctor for a full environment diagnostic.
- If a drift notice surfaced at SessionStart, prefer
/harness:update (preserves user edits, auto-applies the rest).
Operational guarantees
- Idempotent: without
--force, user files are never overwritten.
- Automatic backup:
--force always writes <file>.bak first.
- Plugin templates location: falls back to
${CLAUDE_PROJECT_DIR}/.claude when CLAUDE_PLUGIN_ROOT is unset — also works in standalone (cc-ecosystem dev) mode.
Sample output
$ /harness:init
[harness:init] templates dir: /Users/x/.claude/plugins/harness@tkstardev/templates
created /Users/x/myproject/CLAUDE.md
created /Users/x/myproject/.claude/rules/code-style.md
created /Users/x/myproject/.claude/rules/file-conventions.md
created /Users/x/myproject/.claude/rules/review-finding-format.md
--- harness:init complete ---
created: 4, skipped: 0, forced: 0
Next: run /harness:doctor for a full environment diagnostic
$ /harness:init --check-drift
+ would create /Users/x/myproject/.claude/rules/review-finding-format.md
~ diverged /Users/x/myproject/CLAUDE.md
(run 'diff -u .../templates/CLAUDE.md.tmpl /Users/x/myproject/CLAUDE.md' to inspect)
= unchanged /Users/x/myproject/.claude/rules/code-style.md