I started by running /init so Claude reads the repo and rewrites CLAUDE.md with real project affordances: how to run one test with xcodebuild, where Vice models live, what Swift 6.1 concurrency rules we enforce, and the bundle/CloudKit facts. I cut redundancy, kept only the sharp bits, and verified with CI. This establishes a trustworthy "ops manual" Claude sees first, not tribal memory.
Why: if the source of truth is precise, agents stop hallucinating paths/flags.
Next pass: I mapped the whole Claude Code surface (settings, slash commands, MCP hooks, status line, nested CLAUDE.mds). Then I added:
.claude/settings.json— status line, model prefs, environment, and hook wiring.- Custom commands as the primary UX: small, composable, documented.
- Hooks for pre/post edit guardrails (formatting, concurrency checks).
- Nested
CLAUDE.mdper target/package so context is hyper-local and bloat-free.
Examples
/build-device # Build+install to a plugged-in device
/test-single ViceStatsTests # Run just this class (or test) fast
/pr-ready # Lint, format, unit tests, widget tests
/swift6-check # Strict concurrency audit
Opinion: commands are the product. Don't bury them in a Makefile if Claude is the driver; keep them where the agent looks first.
I created /claude-optimize to re-scan the project and suggest upgrades when Claude ships new features, and /update-docs to rewrite all CLAUDE.md files with current paths, commands, and "last updated" stamps. I set a light process: run optimize weekly, update docs at sprint end, and before a release. This keeps the doc surface tight without thinking about it.
Goal: unified tool calls Claude can drive. I integrated XcodeBuildMCP and removed raw xcodebuild from slash commands. • Context detection (.claude/scripts/detect-context.sh) sets env defaults based on CWD: • In Packages/ViceKit → use Swift package test tools. • In app target dirs → pick the main scheme/workspace. • For widgets → choose the widget scheme. • Auto-select a booted simulator or the newest iPhone. • Dynamic tools: I wanted "dynamic" discovery; Claude Code doesn't support sampling-based tool discovery yet, so I emulate "dynamic" via env + routing (pragmatic, works today). • Commands now call MCP tools exclusively: build, test, run, clean, device/sim ops.
// pseudo mcp server config shell-out { "XcodeBuildMCP": { "command": "bash", "args": ["-c", "source .claude/scripts/detect-context.sh && npx xcodebuildmcp"] } }
Net effect: one interface, better errors, fewer flags.
I wrote a master prompt (setup-prompt.md) that recreates the entire system in a new project in one Claude session: • Phase 0: verify prerequisites (Xcode, Node/npm for MCP, Git). • Phase 1: deep analysis (workspace vs project, schemes, packages, tests, Swift version). • Phase 2: scaffold Claude structure (.claude/, nested docs, commands, hooks). • Phase 3: wire XcodeBuildMCP with context detection. • Phase 4–8: create commands, optional hooks/settings, test + verify, and add troubleshooting.
No assumptions about Make/Rake; the prompt builds what it needs, asks for optional imports if present, and ships with a clear success checklist.
Final pass: removed non-Claude IDE talk, added a real troubleshooting appendix, and clarified that MCP is already available in Claude Code (no extra config files needed there). Hooks and settings are optional but recommended; the context script is mandatory (it's where the magic lives).