# Claude Code harness setup: 3 skills, 30 minutes

> 15 transcripts scanned, 1 permission survivor, 5 misplaced allow rules found, 2 remote agents scheduled: what three harness skills found in 30 minutes.

**Canonical URL**: https://agentcookbooks.com/blog/claude-code-harness-setup-sprint/

**Published**: 2026-04-29

**Tags**: claude-code, hooks, skill-development

---

Before this session: zero project-scoped permissions, recurring approval prompts on git and npm commands, no session-start visibility into the open-work backlog, and five allow rules in user-global settings that belonged to a completely different project. One session with three skills fixed most of it — and each skill surfaced something that wasn't obvious going in. The skills: `/fewer-permission-prompts` scanned 15 transcripts and found one strict-survivor pattern from ~50 candidates, `/update-config` relocated the five misplaced allow rules and added a `SessionStart` hook that surfaces the open-work checklist as a `systemMessage` in the UI, and `/schedule` shipped two routines and rejected a third because remote agents can't see gitignored directories. Total elapsed: 30 minutes. The post documents the receipts and three non-obvious edges that don't live in any skill's documentation.

## `/fewer-permission-prompts`: 15 transcripts, ~50 patterns, 1 survivor

The skill scans session transcript JSONLs in `~/.claude/projects/<project>/`, extracts Bash command frequencies, and filters them against Claude Code's built-in auto-allow list. Commands that appear 3+ times and aren't already covered are candidates for your project `.claude/settings.json`.

**15 transcripts scanned. ~50 distinct command patterns extracted. 1 strict survivor.**

That survivor was `Bash(npm run build)` — 14 hits, not auto-allowed, safe to add. I added `Bash(npm run dev)` and `Bash(npm run preview)` proactively even though neither had hit the threshold — both are documented npm scripts, no side effects, and local dev work hadn't started yet but would.

The gap between expectation and reality: **Claude Code's built-in auto-allow list covers more than most people assume.** `git status`, `git diff`, `git log`, `cat`, most read-only filesystem operations — all auto-allowed already. The commands I was actually being prompted on (`gh api`, `git push`, `node scripts/*`) either carry mutation risk or are flagged by the skill as arbitrary-code-execution candidates. `Bash(gh api *)` would authorize all HTTP methods, not just GETs. No good narrow pattern fits.

The honest deliverable from this skill on an active project: you're probably already covered on what matters, and you'll add 1–3 lines.

**The edge case the skill missed:** the skill says to write to `.claude/settings.json` (committed to the repo). I wanted `.claude/settings.local.json` (gitignored — no reason to commit three npm commands). But `settings.local.json` wasn't in `.gitignore` yet. The skill doesn't check for this; I had to add the entry manually before writing the file.

## `/update-config`: 5 misplaced rules, 1 missing hook

Two problems going in:

1. **User-global `~/.claude/settings.json` had 5 allow rules for a different project** — gcloud deploy commands from an unrelated bot project that had been set globally instead of in that project's local settings. They applied to every project on the machine.

2. **The open-work list in `CLAUDE.local.md` wasn't visible at session start.** Eight active items; none surfaced automatically when opening a session.

The skill's core instruction — READ before WRITE, MERGE not REPLACE — earned its keep immediately. The existing `~/.claude/settings.json` had 10 deny rules and 2 hooks. Writing blind would have lost all of them.

**Fix 1 — stray rules:** appended the 5 allow rules to the bot project's `.claude/settings.local.json` (now 60 rules, all gcloud-related and scoped correctly). User-level allow: 5 → 0.

**Fix 2 — session-start hook:** created `.claude/hooks/session-start-checklist.mjs` — 18 lines. Reads `CLAUDE.local.md`, regex-extracts the `## Open work` section, emits `{"systemMessage": ...}` JSON. Registered as a `SessionStart` hook in `.claude/settings.json`.

**The `systemMessage` vs `additionalContext` distinction:** both can carry content from a SessionStart hook. `systemMessage` shows it to the human in the UI — the checklist appears as a visible message when you open a session. `additionalContext` injects it into the model's context silently. For a checklist you want to read yourself, `systemMessage` is right. The skill's documentation mentions both; which to use isn't obvious until you've seen them in practice.

One regex edge case during pipe-testing: the initial `\n## ` pattern matched ambiguously at end-of-file. Tightened to `(?=\n## |\n*$)`. Pipe-test to confirm valid JSON before registering — the skill's instructions include this step and it caught a real bug.

## `/schedule`: 2 routines created, 1 declined

Three routines requested:
1. +7 days: check custom domain status and Search Console setup readiness
2. +14 days: audit whether Haines and obra wiki entries still have TODO Receipts
3. Weekly recurring: run `/skill-evolve` against `receipts-drafts/`

Two created, one declined with explanation.

**Routine #1** (run once, +7 days): web-only checks on whether `agentcookbooks.com` has resolved and Search Console is ready to verify. No repo access needed.

**Routine #2** (run once, +14 days): repo read — scan wiki entries for TODO markers in Receipts sections.

**Routine #3 declined.** The remote agent runs against the GitHub checkout of the repo. `receipts-drafts/` is in `.gitignore`. The entire purpose of `/skill-evolve` on this project is to read that directory — real session notes captured locally as skills run. The remote agent would clone the repo, find no `receipts-drafts/` directory, and have nothing to do.

Nowhere in the `/schedule` skill documentation does it say this. The constraint is only discoverable by cross-referencing `.gitignore`.

**Remote agents = GitHub repo state.** Not your local working tree, not gitignored directories, not uncommitted files. Any routine that depends on local-only data needs to be redesigned before it can be scheduled — either commit the data or restructure the workflow so the remote agent can source what it needs from somewhere public.

Both create calls batched in one turn to avoid a second cache-miss round-trip.

## What each skill actually delivered

| Skill | Output | The non-obvious thing |
|---|---|---|
| `/fewer-permission-prompts` | 1 survivor from ~50 patterns | Claude Code's auto-allow list already covers most read-only commands |
| `/update-config` | 5 rules relocated, 1 hook added | `systemMessage` shows to human; `additionalContext` injects silently |
| `/schedule` | 2 routines shipped, 1 rejected | Remote agents can't see gitignored directories |

All three took about 30 minutes. The harness is cleaner in each case. The useful output in each case was the thing the skill found that wasn't obvious going in — not the mechanical output, but the edge case that the documentation doesn't mention.

Subscribe to RSS for the rest.