Setup agent-harness
Prepares a repository to use the agent-harness plugin without risking committed hook output or hand-edited JSON. It does two things, each preceded by a timestamped backup:
- Adds or refreshes a managed block in
.gitignorecovering the harness runtime root,*.log, and the backups this skill creates. The root is named for the plugin's own marketplace repository, so every repository ignores the same directory name. Existing managed blocks are rewritten in place so obsoletelogs/,.claude/data/, and repository-named roots do not persist. The update is idempotent. - Merges
$schema, an optionalstatusLine, an optionaloutputStyle, and theenabledPluginsentry into.claude/settings.local.json— the per-user, git-ignored settings file, so nothing is forced on the team.
The deterministic work lives in scripts/setup_harness.py (stdlib-only PEP 723).
This skill owns all user interaction and never lets the script decide policy on a
conflicting statusLine / outputStyle.
Workflow
1. Detect current state (read-only)
$ uv run "${CLAUDE_SKILL_DIR}/scripts/setup_harness.py" detect
This prints a JSON report: which managed .gitignore patterns are missing,
whether settings.local.json exists and already has $schema / statusLine /
outputStyle, whether the plugin is enabled, and environment readiness
(uv, python3, gh auth).
2. Summarize findings
If settings_error is non-null, settings.local.json is unreadable (invalid
JSON): the has_* / output_style / plugin_enabled fields are reported as
null. Surface the error, tell the user to fix or remove the file, and stop —
apply would refuse to overwrite it anyway. Do not prompt for settings changes.
Otherwise, tell the user, in plain language: the missing .gitignore patterns,
the current statusLine / outputStyle (if any), whether agent-harness@boss-skills
is enabled, and any environment warnings (these are advisory — they never block).
3. Collect decisions with AskUserQuestion
Ask only for what detect shows is undecided:
- statusLine — if unset, ask Set the harness status line / Skip. If already set, ask Keep existing / Overwrite (never overwrite silently).
- outputStyle — offer the available styles plus Skip:
bullet-points, genui, html-structured, markdown-focused, table-based, tts-summary, ultra-concise, yaml-structured. If one is already set, ask Keep / pick a new one / Skip. - enable plugin — if
plugin_enabledis false, offer to enableagent-harness@boss-skills.
The .gitignore update is always safe to apply, so include --gitignore
whenever a pattern is missing or the managed block needs refreshing.
4. Preview the diff with --dry-run
Always preview before writing. Run the same apply command you intend to run,
plus --dry-run: nothing is written, and each touched file's result carries a
diff field — a git-style unified diff of exactly what would change in
.gitignore and .claude/settings.local.json. Show those diffs to the user
(rendered in a diff-highlighted fenced code block) and confirm before applying.
# preview without writing — emits a unified `diff` per changed file
$ uv run "${CLAUDE_SKILL_DIR}/scripts/setup_harness.py" apply --gitignore --status-line set --output-style yaml-structured --enable-plugin --dry-run
When dry_run is true and changed is true, read gitignore.diff and
settings.diff from the JSON and present them. A changed: false result means
that file is already in the desired state (no diff).
5. Apply the chosen flags
Map the answers to flags and run apply (same command, drop --dry-run). Use
--status-line set only if the user chose to set/overwrite; pass
--output-style <name> only for a concrete choice (otherwise skip); include
--enable-plugin only if requested.
$ uv run "${CLAUDE_SKILL_DIR}/scripts/setup_harness.py" apply --gitignore --status-line set --output-style yaml-structured --enable-plugin
6. Report
Relay the apply summary: what changed in .gitignore and
settings.local.json, the backup file paths created (<file>.backup.<timestamp>),
and confirm the written settings.local.json re-parsed successfully.
Notes
--dry-runwrites nothing and returns a unifieddiffper changed file, so you can show the user exactly whatapplywould do before running it for real.- Nothing is written without a backup first;
.gitignorechanges are idempotent (re-running produces no diff and no new backup). - The target is
.claude/settings.local.jsononly — this skill never touches the team-shared.claude/settings.json. - If
settings.local.jsoncontains invalid JSON,applyaborts and leaves the file untouched rather than overwriting it — fix the file and re-run. - The status line resolves to the plugin's
${CLAUDE_PLUGIN_ROOT}/status_lines/status_line_v10.pyat runtime. - All command examples are deliberately prefixed with a dollar sign and space —
the skill parser executes exclamation-backtick patterns even inside fenced code
blocks (see
.claude/rules/skill-development.md).