Feld Claude Code Configuration Guide - patterns for professional solo development
A comprehensive tour of a professional solo-developer Claude Code setup spanning fifteen repositories and twelve worktrees. Covers workflow discipline, session persistence, automated quality gates, business operations, and EOS management.
Last updated: 2026-07-02
What this is: a tour of a working setup and the reasoning behind it — useful for borrowing patterns. What this is NOT: an install guide, a list of best practices, or a snapshot that stays accurate without updates. Plugin versions, pg_cron schedules, and file counts are point-in-time.
- Core Philosophy
- Directory Structure
- Session State Architecture
- Master Workflow
- Review Triage and Agents
- Workflow Profiles
- Rules System
- On-Demand Reference Docs
- Hooks System
- Model Strategy
- Skills Inventory
- Plugin Ecosystem
- Commands Inventory
- MCP Server Integration
- Repository Registry
- CompanyOS: Multi-Repo Architecture
- CEOS: EOS Framework
- Automated Jobs
- Multi-Instance Safety (Worktrees)
- Backup and Version Control
- Blog and Learning Capture
- Cursor Integration
- Git Workflow Rules
- Coding Standards
- Pre-commit Pipeline
- Quality Automation
- Database Migration Discipline
- Secrets Management
- Testing Patterns
- Critical Gotchas
- Quick Start for New Setup
- Key Insights
Global-first configuration. All agents, commands, rules, and skills live in ~/.claude/ (see Directory Structure for the 2026-04-15 migration that consolidated this). Project-level .claude/ dirs are deprecated — only ephemeral workflow state (.claude-session/, gitignored audit logs) lives there.
Key principles:
- Never create project-level
.claude/settings.json— it breaks permission inheritance from global settings - No quick-fix mode — every ticket gets the full workflow (
/start→ implement →/commit) - Session state files survive context compaction — workflow continuity across long sessions
- Evidence before assertions — never claim something about code without reading it first
- Protected workflows — certain operations (
/commit,/staging,/start) must never be done manually - Fix or ticket — no middle ground — the default is FIX. A review finding only gets a Linear ticket if it matches one of two documented exceptions: (1) a decision the user owns (product/UX/business — not technical/architectural), or (2) the code can't be modified cleanly (upstream/vendored, frozen branch, no write access). Tightened from five exceptions to two on 2026-05-10 — "complicated," "risky," "pre-existing," "scope explosion," and "needs an architectural decision" are all explicitly rejected as exceptions (architectural calls are pro/con analysis you do yourself)
- Recommend the complete solution (INT-666, 2026-06-29) — when recommending an implementation, lead with the version that fully delivers the ask, not a reduced MVP slice; a smaller deliverable needs an observable reason (user scoped it narrow, a named external constraint, genuinely unbounded scope)
- Duplication is a signal — before applying the same non-trivial edit to 2+ locations, stop and extract the abstraction first
- Plan task atomicity — never split plan tasks across test-file boundaries. A package's test suite is the atomicity unit
- Never fabricate evidence — if a hook blocks because evidence is missing, run the actual process or use
--no-verifywith stated justification - Machine-gated human pauses (2026-06) — both Workflow Profile gates were retired as manual stops:
user_testing(2026-06-03) is verification-gated (Playwright smoke for UI, test suites for source, actionlint for workflow YAML), andplan_approval(2026-06-04) is validation-gated (HIGH-risk plans run an automated Plan-Validation Battery instead of waiting for a human). Each retirement RAISED the machine bar that replaced the pause; a runtime PreToolUse guard (block-live-mutations.sh) blocks execution-time live external mutations as the backstop - Approved-work auto-cycle (2026-06-03) — once a design is approved, build → verify → review → fix → commit → push runs as ONE continuous cycle with no re-asking between stages; pause only on design-inverting findings, failed gates, or genuinely user-owned decisions
~/.claude/ # Global configuration (git repo → bradfeld/claude-config)
├── settings.json # Permissions, hooks, plugins, env, attribution
├── .claude.json # MCP server configuration
├── rules/ # 18 always-loaded rules (INT-606 cut 64→15; +3 new behavioral rules since)
├── docs/ # 73 on-demand reference docs
├── skills/ # 81 skill dirs (20 domain + 40 co-* + 21 ceos-*)
├── commands/ # 74 commands
├── hooks/ # 54 hook scripts (+13 .test.sh)
├── agents/ # 12 review agents
├── blog/notes/ # Daily learning capture
├── flywheel/ # Automation-flywheel log (log.jsonl)
├── comms/drafts/ # Email draft archive
├── voice/ # Writing style profiles (brad + phin-argofy)
├── plans/ # Implementation plans
├── projects/*/memory/ # Per-project auto-memory (shared natively since CC v2.1.63)
├── ccnotify/ # macOS notification system
├── iterm/ # iTerm color/typing monitor integration
├── mcp-servers/ # Custom MCP server implementations
└── plugins/ # Marketplace plugins
~/Code/companyos-intensitymagic/ # CompanyOS config repo
~/Code/companyos-config-foundry/ # Foundry-specific config
~/Code/ceos/ # CEOS repo (EOS skills)
Note: ~/.claude-personal is a symlink to ~/.claude — a naming artifact. They resolve to the same directory.
All review agents, skills, commands, and rules were moved to ~/.claude/ on 2026-04-15. Previously, each worktree had its own .claude/{agents,commands,rules}/ symlinked back to magic0 via sync-claude-config.sh. That architecture caused recurring incidents:
git checkoutwould delete config files (PLA-609, PLA-762)- APFS hardlink destruction when
rm -rfran on directory hardlinks (PLA-448) - Worktree symlink ELOOPs
- Project-level
settings.jsonbreaking permission inheritance
The current model: one source of truth in ~/.claude/, backed up daily to GitHub (bradfeld/claude-config), with per-repo behavior driven by Workflow Profiles in each CLAUDE.md instead of per-repo config files. sync-claude-config.sh was deleted. Project-level .claude/ dirs now only hold ephemeral workflow state.
Session files stored in project/.claude-session/ persist workflow state:
- Current step and status (
implementing,awaiting_user_test,committing) - Blocked actions to prevent accidental commits before testing
- Implementation plans that survive context compaction
- Progress tracking across worktrees
Circuit breaker: Commits are blocked when session status shows awaiting_user_test. The /commit command checks this state before proceeding. Since 2026-06-03, awaiting_user_test is the fall-back, not the default — green class-appropriate verification (Playwright smoke for UI, suites for source, actionlint for workflow YAML) auto-proceeds to /commit; the pause fires only when a gate fails or can't run.
PreCompact hook (preserve-session-state.sh) saves state before context compaction, so long implementation sessions don't lose workflow position.
All tickets follow an identical loop:
/start TICKET-XXX— Fetch ticket from Linear, revalidate its load-bearing premises against live state (Step 4.7 — tickets routinely describe a system that no longer exists by pickup time), classifyrisk_tier, create branch, write plan. HIGH-risk plans run an automated Plan-Validation Battery (Sonnet convergence loop + codex cross-model pass) instead of pausing for manual approval (PLA-1850, 2026-06-04)- Implement locally — completion is verification-gated, not manually tested (PLA-1840, 2026-06-03): Playwright smoke for UI, test suites for source, actionlint for workflow YAML; the old "wait for the user to test" pause survives only as the fall-back when a gate fails
/commit— Quality gates →/simplify(Step 3.5) → Playwright behavioral smoke test (Step 3.7, Magic Platform user-facing changes; PLA-1765) → auto-triage review → run agents → post-fix re-review of content reviewers for protected-config paths (Step 4b.5, INT-590) → schema/migration deferral calibration check (Step 5.7-pre, 2026-06-26) → push → update Linear/staging(magic-platform) — Batch merge to preview, deploy, reset worktrees. Surfaces ALL independent app build failures in one pass now (--continue=dependencies-successful, PLA-2038) instead of aborting at the first, and the two former rubber-stamp confirmation gates were automated (2026-06-21) — docs-only branches merge without a gate, with the truthful "no app deploy" note generated at the status layer/production(magic-platform) — Health audit, merge to main, verify. Runs autonomously since 2026-06-09 (routine confirmation gates removed)
For direct-to-main repositories (CEOS, WordPress, awsaudit), /commit IS the deployment.
/start auto-detects the target repository from the ticket's Linear team prefix — the same command works across all fifteen repositories. Four run modes: single ticket, explicit chain (/start TICKET-1 TICKET-2), epic (/start epic EPIC-ID), and autonomous backlog drain (/start backlog <TEAM> [--label L] [N], 2026-06-30) — oldest-first FIFO over a team's Backlog, skipping Urgent/blocked/in-progress/umbrella/gated tickets, routing each ticket through a per-ticket subagent to keep the orchestrator lean, and stopping cleanly at /commit per ticket (no auto-deploy). Explicit/epic chains and manual runs ride auto-compaction — they no longer stop at ticket boundaries above 20% context (backlog mode's deliberate between-ticket stop is the one exception), and the chain-length cap was doubled (CHAIN_MAX_HARD 25→50). What makes that safe is a durable .claude-session/chain-state.json (INT-674, 2026-07-01) recording chain position + completed/failed tickets; the preserve-session-state.sh PreCompact hook re-injects "ticket i/N, completed X, remaining Y" after a mid-chain compaction, and the file is deleted at successful chain end. /start --wt (INT-677, 2026-07-01) spins up an on-demand git worktree for the work.
Unified /commit (2026-04-12): single canonical command replacing the old /spcommit//oldcommit split. Defaults to --full (convergence review + code-reviewer + specialized agents). --quick skips review. The /oldstart//oldcommit reference files have since been deleted.
| Level | When | What Runs |
|---|---|---|
| NONE | Only non-source changes (docs, tests, config, styling) | No review agents |
| LIGHT | Any source code change (.ts/.tsx) that doesn't trigger FULL |
code-reviewer + selective agents in parallel |
| FULL | 10+ files, shared packages, or sensitive paths | Full parallel multi-agent review battery |
Key rule: NONE never applies to source code changes. Even a 1-file .tsx change gets at least LIGHT review.
Evaluated in priority order: path-based overrides first, content-type exemption second, file-count baseline third.
Path overrides (force FULL): middleware.ts, auth.ts, /auth/, supabase/migrations/, packages/*, payment, billing, webhook
Content-type exemption (downgrade to NONE): Only when ALL changed files are non-source (docs, tests, config, styling, lockfile without package.json). Important non-exemptions:
package.json→ at least LIGHT (dependency changes = supply chain risk).claude/commands/*.md,.claude/rules/*.md,.claude/agents/*.md→ at least LIGHT withprompt-reviewer(no compiler for prompts)- Infrastructure config (
vercel.json,next.config.ts,turbo.json,.github/workflows/*.yml) → at least LIGHT
All 12 agents live in ~/.claude/agents/ and dispatch on Sonnet in parallel.
| Agent | Triggers On | Purpose |
|---|---|---|
code-reviewer |
All source changes (local mirror of the superpowers requesting-code-review template; superpowers 5.1.0 removed the named plugin agent) |
TypeScript strict, security basics, API patterns, logging |
performance-reviewer |
.tsx, page.tsx, layout.tsx, server actions |
Sequential awaits, client boundaries, Suspense, serialization |
silent-failure-hunter |
API routes, services, actions, hooks | Swallowed errors, unhandled promises, missing cleanup |
security-auditor |
Auth flows, middleware, migrations, webhooks | RLS policies, secrets, SQL/auth injection |
migration-reviewer |
supabase/migrations/*.sql |
Timeout safety, idempotency, RLS completeness, TO clause, auth.uid() wrapper |
ui-consistency-reviewer |
.tsx files |
shadcn/ui patterns, semantic tokens, accessibility |
test-quality-reviewer |
Test files alongside source | Assertion quality, edge cases, mocks, flaky patterns |
spec-reviewer |
FULL triage on epic children | Plan compliance vs Linear ticket |
cross-app-consistency-auditor |
packages/*, multi-app changes, @platform/* siblings |
Pattern drift across apps |
prompt-reviewer |
.claude/commands/*.md, .claude/rules/*.md, .claude/agents/*.md |
Dead references, contradictions, stale docs |
ai-usage-reviewer |
Files importing @platform/infra/ai |
Cost controls, prompt injection, error handling, temperature, model tier |
environment-health-auditor |
Manual only | Periodic infrastructure health monitoring |
Cross-model review: codex-reviewer (GPT-5.5 via MCP stdio) dispatches on all source changes at LIGHT and FULL. It's not a .claude/agents/ file — it's an MCP server tool. Catches race conditions and logical errors that a single model family might miss.
Post-fix re-review (Step 4b.5, INT-590): when a protected-config path (commands, rules, hooks, agents, skills, settings.json) gets a fix during review, the content reviewers (prompt-reviewer/code-reviewer) re-run on the post-fix diff — the convergence loop re-runs impl-review only, so without this step the post-fix bytes would go unreviewed by the reviewers that gate config files. Companion rule: review-covers-bytes-it-read.md ("a review covers the bytes it read, when it read them").
CompanyOS delegation: /commit detects CompanyOS repos (mirroring enforce-co-commit.sh's detection exactly) and delegates to /co-commit rather than running its own pipeline.
Full decision algorithm and dispatch examples are in on-demand doc review-triage-reference.md.
Each repository declares its workflow in CLAUDE.md as YAML:
workflow:
base_branch: preview # or main
direct_to_main: false # true for CEOS, WP, awsaudit
plan_approval: auto_if_validated # LOW announces + proceeds; HIGH runs the Plan-Validation Battery
user_testing: auto_if_verified # class-appropriate verification replaces the manual test pause
quality_gates:
- pnpm run type-check
- pnpm run lint
review:
max_level: FULL # NONE, LIGHT, or FULL
ship:
method: pr # pr or direct_push
linear_status: "In Progress"
deploy_hint: "/staging"This declarative approach lets /start and /commit work identically across fifteen repositories without hardcoded logic. The unified /commit reads the profile and adapts its behavior. This is the right place to change per-repo behavior — not the command source.
The two human gates are now machine-gated (rule: risk-tiered-gates.md). risk_tier reuses the review-triage FULL signals (migrations, auth/middleware, packages/*, payment paths, multi-app, 10+ files) — no parallel classifier:
plan_approval: auto_if_validated(PLA-1850, 2026-06-04) — LOW-tier plans announce and execute; HIGH-tier plans run the Plan-Validation Battery (Sonnet convergence with Read/Grep tools, two consecutive clean rounds, plus a codex/GPT-5.5 cross-model pass) and proceed on PASS. The pause survives only on battery FAIL or a surviving user-owned decision.user_testing: auto_if_verified(PLA-1840, 2026-06-03) — auto-commit when every change class in the diff has its verification green: Playwright smoke for UI (real auth-flow smoke for auth diffs), test suites for non-UI source, actionlint for workflow YAML,bash -n+ shellcheck for scripts, nothing for docs-only. Failed or unrunnable gate → fall back to the pause. HIGH tier gets strengthened verification, not a pause.- Runtime backstop:
block-live-mutations.sh(PreToolUse) hard-stops execution-time live external mutations (infra apply, prod API writes, external sends) at the moment of irreversibility — chosen over plan-time classification, which is self-reported and chain-bypassed. - Safety envelope unchanged: unattended work still hard-stops at
/commit(full review battery) and never auto-deploys;/stagingand/productionremain user-triggered. Legacyrequiredscalars keep uniform pauses; unrecognized values fail safe. - The global "
⚠️ Ask First" gate is now conditional + fail-safe (INT-640, 2026-06-28). Schema/RLS/auth authoring used to be a blanket permission ask. Now, in a repo whose Workflow Profile machine-gates that surface — a validated plan path (plan_approval: auto_if_validated) and review agents that cover it (migration-reviewer/security-auditor) — authoring relaxes to announce-and-proceed on a feature branch. Wherever that gating is absent (arequiredprofile, or no Workflow Profile at all) it fails safe to ask. The irreversible step — applying a migration or deploying — stays gated separately byblock-live-mutations.sh. Magic Platform's AGENTS.md declares this override explicitly.
18 always-loaded rules in ~/.claude/rules/ establish the cross-project standards that must fire every session. The count grew to 64 by 2026-06-11, then INT-606 (2026-06-17) pruned it back to 15 — 49 rules were moved to on-demand docs/ because a rule that only matters during a specific task was taxing every unrelated session (the subagent baseline alone dropped ~168k → ~75k tokens, since subagents inherit the full always-loaded corpus). It has since grown to 18 as three genuinely-behavioral rules landed in the following two weeks (visual-companion-default, brainstorm-auto-proceed, recommend-complete-solution) — each is decision logic that must fire every session, so it belongs in the always-loaded layer by the same test that moved the other 49 out. What remains always-loaded is the irreducible behavioral core: verification discipline, decision/scope discipline, identity, and the workflow-trigger rules.
| Rule | Purpose |
|---|---|
auto-execute-recommendations.md |
After a clear recommendation, EXECUTE — never end with "which approach?"; decide technical, ask only product/UX (backstopped by block-decision-offload.sh, which also catches the AskUserQuestion-tool offload) |
banned-words.md |
Vocabulary bans ("honest" + inflections, AI-slop tells like "delve"/"tapestry", "to be straight") — pre-send self-scan + a redact-only display mask (/banned-words toggle) |
brainstorm-auto-proceed.md |
In opt-in repos, the two brainstorm design/spec approval pauses announce-and-proceed instead of blocking; the clarifying-question phase stays human (INT-623, 2026-06-20) |
checkpoint-restored-summary.md |
First response after /clear with a restored checkpoint must lead with a compact summary block, then act on the freshness verdict (INT-611); the shipped-work guard (INT-635) refuses to auto-resume a /start … execute whose ticket is already closed |
convergence-review.md |
Trigger + mode detection for the convergence-review loop (renamed from tricycle.md 2026-05-15) |
evidence-first.md |
Tools first, conclusions second — never assert about code without reading/verifying; external inputs are hypotheses. Now also requires a plan asserting external/runtime/library-API state to carry a one-line claim · probe · result citation, enforced as the assumption_unprobed category in Plan-Review v2 (PLA-2023, 2026-06-24) |
fix-dont-defer.md |
Two exhaustive exceptions for ticketing (decision the user owns; can't modify cleanly); default is fix |
fresheyes-review.md |
Adversarial decision review (opposed-mandate refuters, premise fact-check, cross-model frame-break) — auto-fires on load-bearing forks and HIGH-risk decisions, not just on request |
no-schedule-offers.md |
NEVER end a reply offering to /schedule; ScheduleWakeup is for /loop only (overrides session-prompt default) |
on-demand-references.md |
Index of the detailed reference docs (the load-router for the 73 on-demand docs, including the 49 former rules) |
phin-argofy-identity.md |
Claude's authorial identity (Phin Argofy; it/its) — voice/personality conventions |
protected-workflows.md |
Workflows that must use their dedicated commands (/commit, /start, /staging); execute slash commands immediately |
recommend-complete-solution.md |
Recommend the version that fully delivers the ask, not a reduced MVP slice; a smaller deliverable needs an observable reason (INT-666, 2026-06-29) |
report-after-action.md |
Never batch a report/assertion (Linear comment with a SHA, status update) in the same message as the action it reports on — the report gets composed before the result exists |
scope-intent.md |
Match response scope to what was requested (review ≠ fix; design ≠ build; match ceremony to complexity) |
subagent-stalls.md |
Never recommend Escape during parallel agents; HARD CONSTRAINTS block + verify-after-completion for dispatches; the context-window math that makes a bloated corpus a subagent-killer |
system-reminders-not-turn-boundaries.md |
System-reminders attached to a tool result are metadata, not stop signals — continue the announced workflow |
visual-companion-default.md |
Auto-launch the visual companion on a genuinely-visual design question — no consent offer, no waiting for a yes (INT-620, 2026-06-18); overrides the vendored brainstorming skill |
The 49 rules moved to docs/ by INT-606 keep their content verbatim — they're just loaded on-demand now (see On-Demand Reference Docs). They split into two groups: 37 low-risk rules (refactor/test/git/MCP gotchas — duplication-as-signal, git-state-lies, mcp-gateway-routing, the whole verification-cluster's tactical siblings) moved in Commit 1, and 12 flow-triggered rules (commit-recipe, review-triage, risk-tiered-gates, learning-capture, smoke-test-before-completion, etc.) moved in Commit 2 with their load-wiring re-pointed into /commit and /start at the relevant step. A fresheyes pass (Commit 4) caught a dangling cite and stale always-loaded prose left behind.
Rules promoted to on-demand skills (earlier, PLA-1285): mcp-linear, mcp-supabase, database-migrations, auth-admin-reads, vercel-env-api — narrow-use guidance that activates on tool usage / file paths.
Architectural principle (PLA-688, taken to its conclusion by INT-606): Always-loaded rules contain only the decision logic that must fire every session; reference tables, tool-specific gotchas, and task-triggered discipline live in docs/skills loaded only when needed. The three-layer token budget is strictly ordered by frequency — see Key Insights.
Same principle applied to project AGENTS.md (2026-04-29): Magic Platform's AGENTS.md was trimmed from 43k → 22k chars (731 → 340 lines) by extracting embedded code examples to docs/standards/*.md files referenced by plain prose pointers (not @import, which loads regardless of relevance). Followed Anthropic's "would removing this cause Claude to make mistakes?" test from the official Claude Code best-practices guide. Also brought the file back under Claude Code's 40k char soft-warning threshold and closer to Anthropic's recommended <300 line target for always-loaded files.
Pre-commit enforcement (the ~/.claude/.git/hooks/pre-commit runs 7 staged-file gates):
rules-size-cap.sh— caps each rule file at ~200 lines (staged files only)verify-review-agents.sh— every agent referenced in triage rules must have a definitionverify-rule-doc-paths.sh,verify-dollar-digit-escape.sh,verify-ticket-create-defaults.sh,verify-reviewer-examples.sh— doc-path integrity,$<digit>escaping, ticket-template defaults, and banned patterns in reviewer GOOD examplesverify-bash32-compat.sh(Rule 7, 2026-06-20) — blocks bash 4+ constructs / macOS-bash-3.2-unparseable syntax in stagedhooks/*.shandscripts/*.sh, because Claude Code's hook environment resolves to/bin/bash3.2.57 more often than not
73 docs in ~/.claude/docs/ plus project-level docs, loaded only when a task matches — the count rose from 22 (the 2026-06-11 baseline) to 73, driven mainly by INT-606 moving 49 former always-loaded rules here (2026-06-17). The on-demand-references.md rule serves as the index (and rules-index.md maps "I'm about to do X" → which always-loaded rule OR on-demand doc applies). The table below is representative, not exhaustive:
| Task | Reference Doc |
|---|---|
| Writing Vitest tests | testing-vitest.md |
| Configuring MCP servers | mcp-server-config.md |
| Creating skills or commands | skill-authoring.md |
| Discourse community admin | discourse-community.md |
| Committing changes | commit-reference.md |
| Review triage dispatch | review-triage-reference.md |
| Multi-chain epic planning | multi-chain-epics.md |
| Parallel subagent dispatch | parallel-patterns.md |
| Shell scripting | bash-patterns.md |
| Batch learning capture | learning-capture-procedure.md |
| Running convergence-review | convergence-review.md / review-prompts.md |
| Running an adversarial decision review (fresheyes) | fresheyes-review.md |
/research command design spec |
research-command-design.md |
| Magic Platform convergence pre-commit hook (evidence-file requirements) | magic-platform-convergence-hook.md |
| "About to do X" → which rule applies | rules-index.md |
| Platform app templates | platform-app-templates.md |
| Thinking modes reference | CLAUDE_CODE_THINKING_MODES.md |
| Self-describing data patterns | self-describing-data.md |
| TypeScript / pnpm / Tailwind / ESLint gotchas | typescript-gotchas.md |
Module resolution errors (ERR_REQUIRE_ESM, missing subpath exports) |
module-resolution-debugging.md |
| TDD patterns and execution recipes | tdd-patterns.md |
Magic Platform docs (canonical locations in the repo — an earlier .claude/docs/ layer was deleted 2026-03-22 in favor of docs/standards/ and docs/ops/):
docs/standards/UI_CONSISTENCY_STANDARDS.md,DATABASE_PATTERNS.md,LOGGING_GUIDE.md,TESTING_STRATEGY.md,TYPESCRIPT_STRICT_MODE.md,ERROR_HANDLING.md(toError, Promise.allSettled + helpers, service null-vs-throw, logSupabaseError)docs/ops/GITHUB_WORKFLOWS.md,cursorcommit.md,DATABASE_MIGRATION_RECOVERY.md,DEPLOYMENT_SELF_HEALING.md,INCIDENT_RESPONSE.md
Why: A 200-line reference table for commit workflows wastes tokens when you're doing codebase exploration. On-demand docs are loaded only when Claude encounters the matching task — zero cost otherwise.
54 hook scripts in ~/.claude/hooks/ (+13 .test.sh unit tests) plus external integrations (ccnotify, iTerm), responding to 12 lifecycle events. The newest cluster (late 2026-06 → 2026-07) is concurrent-session safety — worktree-git-guard, worktree-owner-lock, and config-edit-lock block one live session from silently clobbering another's worktree or same-file config edit (INT-625, then the finer-grained INT-649 model) — plus rule-backstops that turn a new always-loaded rule into a deterministic Stop-hook (block-visual-companion-offer for INT-620, block-brainstorm-doc-review-pause for INT-623), a mutation-authorization valve (allow-mutation, PLA-2052), and an auto-heal that keeps the episodic-memory summarizer read-only so it can't mutate live worktrees (2026-06-28). Each encodes a rule as a mechanical block, cheaper than a rule that taxes every session. Earlier 2026-06 shifts still stand: the banned-words block mode was deleted (2026-06-12), leaving a display-only redact mask.
| Script | Purpose |
|---|---|
block-supabase-mcp-migrations.sh |
Prevent mcp__supabase__apply_migration from targeting prod/preview (renamed from block-production-apply-migration.sh) |
banned-words-ensure.sh |
SessionEnd/SessionStart auto-heal — CC's settings serializer silently drops the MessageDisplay registration on every full settings write (/model, /config); this re-injects it + runs a liveness probe (banned-words.md) |
block-decision-offload.sh |
Stop hook — nudges replies that end by handing the user a decidable fork back into the decide-it-yourself tree; a transcript-level detector also catches the AskUserQuestion-tool offload the prose detector is blind to (auto-execute-recommendations.md). Signal 6 / 6b catch voluntary work-offload ("deserves fresh context, resume with /start … execute") and compaction-avoidance stops (INT-673) — the deterministic backstop for the "ride auto-compaction, no voluntary checkpoints" behavior |
block-live-mutations.sh |
Block execution-time live external mutations (infra apply, prod API writes, external sends) — the runtime backstop for the retired plan-approval pause; scoped allow valve at ~/.claude/.live-mutation-allow |
allow-mutation.sh |
Authorize a specific gated mutation for ≤60 min (writes the block-live-mutations allow valve; fixed its bootstrap catch-22, PLA-2052) |
block-visual-companion-offer.sh |
Stop hook — nudge auto-launching the visual companion instead of offering it and waiting for consent (visual-companion-default.md) |
block-brainstorm-doc-review-pause.sh |
Stop hook — in opt-in repos, nudge auto-proceed past the brainstorm design/spec review gates (brainstorm-auto-proceed.md) |
worktree-git-guard.sh |
Block foreign-session git mutations inside a shared worktree — enforces one session per worktree (INT-625) |
worktree-owner-lock.sh |
Per-worktree owner lock; sibling of the git-guard for concurrent-session safety (INT-625) |
config-edit-lock.sh |
Same-file config-edit lock across live sessions + a staging-layer sweep guard — the finer-grained INT-649 model that replaced the coarse INT-625 global lock (different-file edits across worktrees never block) |
episodic-memory-summarizer-readonly-ensure.sh |
Auto-heal — keep the episodic-memory summarizer read-only so a resumed summarizer can't execute pending work in a live worktree (2026-06-28) |
nudge-two-target-supabase.sh |
Warn when raw-probing a local Supabase port (:54321) for a test that belongs on the preview cloud — the two-target Supabase model |
verify-bash32-compat.sh |
Pre-commit — block bash 4+ constructs / macOS-bash-3.2-unparseable syntax in staged hooks/*.sh and scripts/*.sh (Rule 7) |
block-git-checkout-sha.sh |
Block git checkout <SHA> (use git show/git log instead) |
block-mcp-shell-substitution.sh |
Block $(...)/backticks in MCP/Task args unless sentinel present (mcp-arg-no-substitution.md) |
block-schedule-wakeup-outside-loop.sh |
Block ScheduleWakeup outside a /loop (no-schedule-offers.md) |
block-task-background.sh |
Block run_in_background: true on Task/Agent dispatches (stall trigger) |
changelog-tracker.sh |
Track file changes per Edit/Write |
co-skill-track.sh |
Log skill invocations to Supabase |
command-tracker.sh |
Track slash command success streaks |
enforce-claude-config-review.sh |
Block raw git commit in ~/.claude/ touching high-risk paths without fresh review evidence |
enforce-co-commit.sh |
Block raw git commit in CompanyOS repos — must use /co-commit |
file-protection.sh |
Prevent edits to protected files |
fix-dont-defer-scanner.sh |
Catch "I'll note this for later" anti-patterns in output |
google-workspace-retry.sh |
Detect OAuth port conflicts, instruct retry |
checkpoint-freshness.sh |
Compute a freshness verdict (FRESH / STALE-FLAG / withheld) for a restored checkpoint so the first post-/clear turn knows whether to auto-resume (INT-611) |
checkpoint-hook-ensure.sh |
Self-heal the checkpoint inject/freshness hook registration if a settings write drops it (sibling of banned-words-ensure.sh) |
co-gmail-html-normalize.sh |
Normalize Gmail HTML on CompanyOS comms paths |
inject-checkpoint.sh |
Inject restored-checkpoint context (with the freshness verdict) into the first SessionStart turn after /clear |
inject-context-pct.sh |
Inject context-window usage % into the prompt |
instruction-load-logger.sh |
Log instruction loads for analysis |
no-speculate.sh |
Catch speculative assertions in output (evidence-first.md) |
permission-auto-approve.sh |
Auto-approve known-safe operations |
preserve-session-state.sh |
Save state before context compaction |
redact-banned-words-display.sh |
MessageDisplay hook — masks banned words inline as ⟦slop⟧ while a message streams (display-only, zero extra tokens; the transcript and model context keep the original). ON by default, toggled mid-session via /banned-words on|off|status (sentinel ~/.claude/.banned-words-off). The old block mode (forced re-emit = double tokens) was deleted 2026-06-12 |
review-enforcement.sh |
Enforce review on git commit via Bash |
rules-size-cap.sh |
Cap staged rule files at ~200 lines |
session-title.sh |
Set terminal/session title from context |
startup-summary.sh |
Show worktree/branch/config health banner at SessionStart |
system-health-check.sh |
Verify system state on startup |
triage-floor.sh |
Mechanize the /commit review-triage path-overrides — enforce a minimum review level by path so the model can't under-triage a sensitive file (INT-599) |
verify-cited-sha.sh |
Block Linear writes citing a git SHA that doesn't resolve to a real commit — catches reports composed before the action ran (report-after-action.md); suffix-matched so gateway tool renames stay covered |
verify-dollar-digit-escape.sh |
Pre-commit: block unescaped $<digit> in staged command/skill bodies (silent arg-substitution corruption; command-skill-arg-substitution.md) |
verify-review-agents.sh |
Validate every agent referenced in triage rules has a definition |
verify-reviewer-examples.sh |
Pre-commit: flag any review-agent ✅ GOOD example that teaches a platform-banned pattern — stops a reviewer from passing the very violation it exists to catch (INT-601) |
verify-rule-doc-paths.sh |
Verify every ~/.claude/docs/*.md path cited in a rule file actually resolves (PLA-1285 drift prevention) |
verify-ticket-create-defaults.sh |
Pre-commit: every save_issue CREATE template in a command/agent/skill must inline the mcp-linear assignee/state pair (PLA-1913; dueDate dropped from the required set 2026-07-02 — auto-created tickets no longer carry a due date) |
webfetch-firecrawl-fallback.sh |
Fall back to the firecrawl MCP when WebFetch is blocked on a URL |
whats-new-check.sh |
Check for Claude Code feature updates |
worktree-sync-check.sh |
Verify worktree is not stale vs remote |
| Event | Purpose |
|---|---|
| InstructionsLoaded | Log what rules/docs loaded |
| SessionStart | Config health check, CompanyOS session-sync, startup banner, system health, restored-checkpoint inject + freshness, banned-words registration backstop + liveness probe |
| PreToolUse (Edit|Write) | Block edits to protected paths |
| PreToolUse (Bash) | Block raw git commit (must use /commit / /co-commit); block git checkout <SHA>; block live external mutations during execution; block foreign-session git mutations in a shared worktree (INT-625); warn on wrong-target Supabase probes |
| PreToolUse (MCP) | Block apply_migration targeting prod/preview; block $(...) substitution in MCP/Task args; block fabricated git SHAs in Linear writes |
| PreToolUse (Task) | Block run_in_background: true dispatches |
| PreToolUse (ScheduleWakeup) | Block outside a /loop |
| UserPromptSubmit | ccnotify, typing monitor, iterm color, skill track, command track, session title |
| PostToolUse (ExitPlanMode) | macOS "Plan Ready" notification |
| PostToolUse (Skill) | Skill telemetry |
| PostToolUse (Edit|Write) | Track file changes |
| PostToolUse (Google Workspace) | OAuth conflict detection |
| PreCompact | Save state before compaction |
| Stop / StopFailure | ccnotify, iterm color, typing monitor, command tracker, decision-offload backstop (prose + AskUserQuestion-tool) |
| MessageDisplay | Banned-words redact mask (inline ⟦slop⟧, display-only) |
| SessionEnd | iterm color, typing monitor stop, banned-words registration auto-heal (primary) |
| PermissionRequest | Auto-approve known patterns |
| Notification | ccnotify macOS forwarding |
Key architectural pattern: Hooks replaced several always-loaded rules. A rule that says "if Google Workspace fails with port 8766, retry" wastes tokens in every session. A PostToolUse hook fires only when the specific tool runs AND only outputs text when the error matches — zero token cost in the common case.
The primary session model is Opus 4.8 with the 1M-token context window, now selected via /model "Default" — there is no explicit "model" key in settings.json as of 2026-07-01 (verified: grep -c '"model"' settings.json → 0). "Default" resolves to Opus 4.8 1M on this plan. Fable 5 (Anthropic's Mythos-class tier above Opus) had two brief trials — the 2026-06-09/06-11 launch (reverted to Opus 4.8 1M on 2026-06-12) and a same-day Fable 5[1m] retrial on 2026-07-01 that flipped back the same day. Opus-on-xhigh is the preferred setting (Opus 4.8 was primary from ~2026-05, 4.7 from 2026-04-16). The @platform/infra/ai premium tier is a separate setting — no ANTHROPIC_MODEL_* env pins anywhere; resolution is user pref → env → DB (shared.platform_settings) → code default claude-opus-4-8-latest.
| Role | Model | Why |
|---|---|---|
| Primary agent (user sessions) | Opus 4.8 (1M ctx) | Most capable Opus tier; 1M window for deep-context sessions (via /model "Default", no settings.json pin) |
Plan subagent (/start) |
Sonnet 5 | Dispatch via bare model: "sonnet" alias — auto-tracks the latest Sonnet, so it now resolves to Sonnet 5 (was 4.6) |
Review agents (/commit) |
Sonnet 5 | All 12 review agents dispatch via model: "sonnet"; also made read-only (no Edit/Write/NotebookEdit) on 2026-06-20 |
| Explore agents | Inherits session model, capped at Opus | CC v2.1.198 changed this from Haiku 4.5 — Explore now inherits the session model (capped at Opus), trading cheaper dispatches for accuracy |
Platform AI (@platform/infra/ai) |
Tiered | fast=Haiku 4.5, standard=Sonnet 5 (bumped 4.6→5 via PLA-2111, live 2026-07-01; temperature-sensitive callers pinned to Sonnet 4.6), premium=Opus 4.8 |
Effort level: Pinned via env.CLAUDE_CODE_EFFORT_LEVEL=xhigh in settings.json — the env var is the only method that beats the model-default-on-startup override (Opus 4.8's built-in default is high, not xhigh; the plain effortLevel key loses to it). Effort was briefly lowered to high during the ~1-day Fable 5 trial, then restored to xhigh on 2026-06-12 with the Opus revert. A consequence: per-skill effort: frontmatter is inert (2026-05-30) — everything runs xhigh by deliberate choice.
Convergence review (formerly "tricycle," renamed 2026-05-15): Simplified to Sonnet-only (2026-04-05) after data showed 31% actionable rate, 47% zero-finding runs, and heavy model overlap.
The 4.6 → 4.7 transition changed behavior in ways that break prompts tuned for 4.6; these carry forward to 4.8:
- More literal — drop scaffolding like "double-check X" or "add interim status messages"; 4.7 won't silently generalize
- Fewer tool calls / fewer subagents by default — prompt explicitly for parallel work; raise effort to increase tool usage
- New tokenizer ~1–1.35× heavier — bump
max_tokensand compaction triggers - Sampling params removed —
temperature,top_p,top_k400-error on 4.7 (platform AI client auto-strips) - Fixed thinking budgets removed — use
thinking: {type: "adaptive"}(off by default on 4.7) - Thinking content omitted by default — set
thinking.display: "summarized"to restore visible progress
~97 skills total from three sources (81 live in ~/.claude/skills/ as dirs: 20 domain + 40 co-* + 21 ceos-*; the rest are plugin-provided). Single table by category:
| Count | Category | Source | Summary |
|---|---|---|---|
| 20 | Domain | ~/.claude/skills/ (self-authored) |
Platform-independent engineering + design tools |
| 40 | CompanyOS (co-*) |
Symlinked from ~/Code/companyos-intensitymagic/skills/ |
Business operations: comms, content, ops, support, launch |
| 21 | CEOS (ceos-*) |
Symlinked from ~/Code/ceos/skills/ |
EOS framework: VTO, Rocks, L10, scorecard, people, process |
| 14 | Superpowers | Plugin: superpowers@superpowers-marketplace |
Core dev methodology (TDD, debugging, plans, reviews) |
| 2 | Marketplace | Plugin: simmer, documentation-audit |
Artifact refinement, docs verification |
| Skill | Purpose |
|---|---|
testing |
Test writing, debugging failures, choosing approaches |
design-critique |
Structured design feedback (usability, hierarchy, consistency) on a mockup or screen |
accessibility-review |
WCAG 2.1 AA audit (contrast, keyboard nav, touch targets, screen-reader behavior) |
supabase |
Database queries, migrations, RLS debugging |
database-migrations |
SQL migration patterns (idempotency, RLS, TO clause, timeout safety) |
vercel |
Deploy, build failures, environment management |
vercel-env-api |
Managing Vercel env vars via REST API (works around CLI bug) |
linear |
Ticket management, issue creation, work tracking |
mcp-linear |
Linear MCP tool gotchas (silent failures, unified tools, project IDs) |
mcp-supabase |
Supabase MCP rules (discover projects first, schema-qualify tables) |
auth-admin-reads |
Never use auth.admin for user reads — use getUserIdentity() |
context7 |
Library docs, API research, developer tools |
notion |
Notion pages, databases, documentation |
sentry |
Error investigation, issue viewing, trends |
oauth |
Social provider OAuth setup |
performance |
Core Web Vitals, bundle size, render optimization |
mobile |
Mobile-responsive UI, layout fixes |
form-patterns |
Form dirty state, "unsaved changes" bugs |
rewriter |
Content rewriting with optional voice matching |
ui-iterate |
Iterate on UI against a localhost/preview URL via Playwright MCP |
Five of these (mcp-linear, mcp-supabase, database-migrations, auth-admin-reads, vercel-env-api) were promoted from always-loaded rules during PLA-1285 (2026-04). They activate on-demand based on tool usage or file paths, eliminating their always-loaded token cost.
systematic-debugging, verification-before-completion, writing-plans, executing-plans, test-driven-development, subagent-driven-development, dispatching-parallel-agents, using-git-worktrees, finishing-a-development-branch, brainstorming, requesting-code-review, receiving-code-review, writing-skills, using-superpowers.
Auto-updates ensure all sessions inherit new patterns without manual commits.
See CompanyOS and CEOS sections.
9 active plugins across 6 marketplaces.
Snapshot as of 2026-06-11 — plugins auto-update from their marketplaces; versions will drift.
| Plugin | Marketplace | Purpose |
|---|---|---|
| vtsls | claude-code-lsps | TypeScript/JavaScript LSP |
| yaml-language-server | claude-code-lsps | YAML LSP |
| pyright | claude-code-lsps | Python LSP |
| superpowers | superpowers-marketplace | Core development methodology (14 skills) |
| episodic-memory | superpowers-marketplace | Cross-session conversation recall |
| simmer | 2389-research-marketplace | Iterative artifact refinement |
| documentation-audit | 2389-research-marketplace | Docs-vs-code verification |
| release-radar | whats-new-marketplace | Cross-reference CC release notes against config |
| vercel-plugin | vercel | Vercel deployment, performance, AI SDK guidance |
| Marketplace | Source |
|---|---|
claude-code-lsps |
Built-in |
superpowers-marketplace |
GitHub: superpowers-marketplace |
2389-research-marketplace |
GitHub: 2389-research/claude-plugins |
whats-new-marketplace |
GitHub: bradfeld/whats-new-plugin.git |
vercel |
Local directory cache |
claude-plugins-official |
Registered, no installs yet |
knowledge-work-plugins |
Registered (18 categories) — no installs yet |
Plugin architecture: The enabledPlugins key in settings.json maps plugin names to their marketplace origin. Plugins can provide skills, agents, rules, and MCP configurations. Episodic memory is notable — it provides semantic search across prior conversations, enabling Claude to recover decisions and solutions without manual memory management.
74 user-level commands in ~/.claude/commands/. Organized by tier. (Counts drift as commands are consolidated — /loop and /schedule are plugin-provided skills, not files here.)
/start (ticket setup + chain/backlog modes), /commit (unified quality gates + review), /staging (Magic Platform merge to preview), /production (Magic Platform merge to main), /note (learning capture), /checkpoint (session state save), /resume (resume from a restored checkpoint after /clear, freshness-guarded — INT-611), /co-commit (CompanyOS), /publish (unified content — draft or publish blog posts for feld/aic/phin/zk and Zero Knowledge book chapters for zk-read, from one content-type-aware command; PLA-1974, 2026-06-24).
Magic Platform workflow: /localhost, /play (dev server + magic-link login + Playwright; --iterate discovery-loop mode and --env prod/preview added 2026-06), /dashboard, /linear-image, /linear-bundle (cluster a team's backlog into umbrella tickets), /health, /migration-baseline, /perf, /deps, /ui, /sweep, /whats-next, /review-health, /new-project.
Diagnostics / meta: /validate, /verify, /verify-branch, /global-status, /diagnose, /deep-explore, /dead-code, /secrets-scan, /ground-truth, /auto-report, /browser-verify, /flywheel (unified automation + learning loop — absorbed /learn//learn-scan 2026-05-29; sweep mode batch-graduates daily-note patterns; weekly launchd run Wed 7am, propose-only when unattended), /fresheyes (adversarial decision review), /live-mirror (mid-session spec-vs-code drift check against the active plan), /research (turn a RES ticket's URL into an evidence-grounded verdict, with a Phase-2 audit against actual infra), /mcp-migrate (executable gateway-migration playbook), /claude-config-cleanup, /rules, /backup, /cleanup.
Personal / capture: /til, /screenshot, /view, /done-color, /test, /vault (query and curate the imobsidian vault), /daily-review (automated prior-day notes triage → Linear tickets; 2026-06-23), /tell-hunt (cold-eyes semantic tell-hunter for the Zero Knowledge writing loop; 2026-06-22).
Meta / config: /banned-words (toggle the slop-redaction display on|off|status).
Git: /git-clean.
CompanyOS: /co-help, /co-plan, /co-recap, /co-recap-weekly, /co-skill-report, /co-switch, /co-test-gaps, /co-standup, /co-admin, /co-pr-review, /co-add-mcp, /co-incident, /co-cleanup, /co-create-skill, /co-flywheel.
Per-repo: /deploy-ea (MagicEA), /freshell (Freshell).
Asana: /asana, /asana-companyos.
Aliases: /blog now translates to /publish (surface-first form); /novel-publish is a deprecating alias for /publish zk-read. The old /blog-new, /blog-idea, /blog-edit, /blog-publish files were deleted in the PLA-1974/PLA-2044 publish normalization (2026-06-24).
Bundled: /simplify (3 parallel fix agents, wired into /commit Step 3.5).
Consolidation history: /spcommit, /spstart, /start-chain, /weekly-cleanup were absorbed into /start (chain mode built in) and /commit (unified) in the 2026-04-12 command consolidation. /learn and /learn-scan were retired into /flywheel (2026-05-29). /oldcommit, /oldstart, /review, /review-codebase, /deep-scan, and /pr were deleted. /generate-crud was retired 2026-06-12 (never used). Blog/novel publishing was unified into /publish (PLA-1974, 2026-06-24): one content-type-aware command for feld/aic/phin/zk blog posts and zk-read book chapters, with /blog and /novel-publish kept as thin aliases and the four /blog-* files deleted (PLA-2044).
Architecture prefers PAT/API key auth over OAuth because API keys survive Claude Code updates, while OAuth tokens in Keychain become orphaned. As of 2026-06 the only OAuth holdouts are Google Workspace (per-user) and the JumpCloud AI Gateway (session) — Vercel, the long-standing OAuth-only exception, moved to a stdio server with VERCEL_TOKEN.
| Server | Transport | Auth | Purpose |
|---|---|---|---|
| JumpCloud AI Gateway | HTTP | OAuth session | Brokers MCP servers (Linear first, 2026-06-03) — the control plane for per-service agent access |
| Linear | HTTP (direct) + gateway-brokered | Bearer / gateway | Issue tracking |
| Supabase | HTTP | Bearer | Database operations, Edge Functions |
| Stripe | HTTP | Bearer | Billing, subscriptions |
| Context7 | HTTP | Bearer | Library documentation |
| Better Stack | HTTP | Bearer | Uptime, telemetry |
| Marker.io | HTTP | Bearer | Bug reporting |
| Kit (+ kit-docs) | HTTP | Bearer | Creator email platform (ConvertKit) + its docs server |
| StackHawk | Stdio (uvx) | API key env | DAST security scanning |
| Sentry | Stdio | Env vars | Error monitoring |
| Firecrawl | Stdio | Env vars | Web scraping |
| HelpScout | Stdio | Env vars | Customer support |
| Playwright | Stdio | Local binary | Browser automation / behavioral smoke tests |
| Codex Reviewer | Stdio | Local binary | GPT-5.5 cross-model review |
| Google Workspace | Stdio | Per-user OAuth | Gmail, Calendar, Drive, Docs |
| Vercel | Stdio | VERCEL_TOKEN (PAT) |
Deployments — moved off OAuth |
Plus Claude in Chrome (browser extension) and Computer Use (built-in MCP) for non-API interaction.
MCP configuration lives in ~/.claude/.claude.json (not settings.json).
Tool Search (ENABLE_TOOL_SEARCH=true) defers tool loading on-demand, saving ~5k tokens per server. With ~18 servers, the per-session savings are substantial.
When a server moves behind the JumpCloud gateway, every tool is renamed: mcp__linear__save_comment becomes mcp__jumpcloud__Linear_save_comment. Two disciplines follow (rule: mcp-gateway-routing.md):
- Prose keeps the canonical direct name. One mapping rule covers the ~120 references in skills/commands/docs — a per-migration sweep would rot on the next transport change.
- Mechanical consumers must suffix-match. Exact-string hook matchers die silently on a rename: the day Linear moved, the SHA-fabrication gate (
verify-cited-sha.sh) stopped firing until its matcher was converted tomcp__.*save_commentform.
/mcp-migrate <service> wraps the migration checklist end-to-end (matcher conversion, skill trigger descriptions, hook-verification matrix).
/start TICKET-XXX auto-detects the target repository based on the ticket's Linear team prefix.
| Repository | Location | Prefix(es) | Base Branch | Deployment |
|---|---|---|---|---|
| Magic Platform | ~/Code/magic0-11 |
AUTM, MED, MYH, NEW, PLA, INT, CURE, IOS, DINO, YDG | preview |
Pipeline: /staging → /production |
| MagicEA | ~/Code/magicea |
TARS | main |
Feature branch: /deploy-ea |
| CompanyOS | ~/Code/companyos-intensitymagic |
COS | main |
PR review + merge (/co-commit) |
| Freshell | ~/Code/freshell |
FRE | main |
PR to upstream maintainer |
| Techstars OS | ~/Code/techstarsos |
TOS | main |
Contributor PR |
| txvotes | ~/Code/txvotes |
USV | main |
Auto-deploy on merge |
| CEOS | ~/Code/ceos |
CEO | main |
Direct push (commit IS deploy) |
| WordPress Sites | ~/Code/wp |
WP | main |
deploy.sh (direct-to-main) |
| awsaudit | ~/Code/awsaudit |
AWS | main |
Direct push |
| Adventures in Claude | ~/Code/content/aic |
AIC | main |
Vercel auto-deploy on push |
| FeldSite | ~/Code/content/feld |
FELD | main |
Vercel auto-deploy on push |
| Foundry | ~/Code/content/foundry |
FOU | main |
Vercel auto-deploy on push (foundry.vc, migrated from WordPress) |
| Zero Knowledge | ~/Code/content/zeroknowledge |
ZK | main |
Vercel auto-deploy on push (zeroknowledge.ink Hugo book site) |
| Overwatch | ~/Code/overwatch |
OVR | main |
Direct push |
| claude-config | ~/.claude/ |
(no dedicated team — usually filed under INT) | main |
Direct push + daily daily-backup.sh launchd cron |
Magic Platform prefixes are derived, not hardcoded (PLA-1793). The authoritative set lives in MAGIC_PLATFORM_TICKET_PREFIXES (packages/config/src/apps.ts, derived from APPS + NON_APP_TICKET_PREFIXES); /staging, /production, and the changelog read it at runtime. YDG (YourDataGarden) is a 2026-05-25 platform initiative — a dev-first public-data platform nested in the monorepo with a Python data plane (epic YDG-1 / PLA-1784).
claude-config commit flow: raw git commit in ~/.claude/ is gated by enforce-claude-config-review.sh when the staged diff touches high-risk paths (rules, commands, agents, hooks, scripts, skills, settings). Commit from inside a ~/.claude/ session via /commit, or dispatch prompt-reviewer/code-reviewer out-of-band and write the diff-keyed review sentinel (git -C ~/.claude diff --cached | git -C ~/.claude hash-object --stdin > ~/.claude/.claude-config-review-sentinel) — a bare touch no longer satisfies the gate since INT-610 made the sentinel's fingerprint match the staged diff.
BAF (Brad's Todos): Heterogeneous team — tickets can route to feld.com blog, AIC blog, CompanyOS, or elsewhere. /start asks where to route each BAF ticket.
CompanyOS is an AI-first business operations system — Claude Code as the universal interface to all business systems. Spans three repositories:
| Repo | Purpose |
|---|---|
~/Code/companyos (core) |
Shared skills, rules, agents, scripts — the product |
~/Code/companyos-intensitymagic (config) |
Company-specific context, MCP registry, custom skills |
~/Code/companyos-config-foundry (config) |
Foundry-specific context, custom skills |
See each repo's CLAUDE.md for internal details. Key architectural patterns below.
Level 1: Local (uncommitted) — user works in any clone
Level 2: Company config repo (companyos-config-*)
/co-commit → direct push to main
Skills available at company level immediately
Level 3: Core CompanyOS (companyos)
GitHub Actions (propose-skills.yml) auto-creates a PR when skills/** change
in a config repo, using COMPANYOS_PAT.
If accepted → skill available to all companies.
If rejected → stays company-specific only.
setup.sh symlinks skills/co-* from core repo into ~/.claude/skills/. Config repo provides per-company co-company-context.md. Two hooks track every skill invocation to Supabase skill_invocations:
- UserPromptSubmit hook: catches context-activated skills
- PostToolUse (Skill) hook: catches explicitly invoked skills
/co-skill-report generates weekly analytics. /auto-report uses streak data to identify automation candidates.
- Draft-first: External emails always start as drafts for human review
- Audit logging: All external actions logged (emails, Stripe ops, support actions)
- Voice profile:
~/.claude/voice/voice-profile.mdcalibrates writing style - Protected email workflow:
co-commsskill enforces draft-review-approve. Never callsend_gmail_messagedirectly.
/co-commit, /co-create-skill, /co-help, /co-plan, /co-recap[-weekly], /co-skill-report, /co-switch, /co-test-gaps, /co-standup, /co-admin, /co-pr-review, /co-cleanup, /co-incident. See Commands Inventory for the full list.
~/Code/ceos/ — implements the Entrepreneurial Operating System through Claude Code skills. Direct-to-main workflow (no feature branches).
21 skills across all six EOS Key Components:
| Component | Skills |
|---|---|
| Vision | ceos-vto, ceos-annual, ceos-quarterly-planning |
| People | ceos-people, ceos-accountability, ceos-trust, ceos-lma |
| Data | ceos-scorecard, ceos-dashboard |
| Issues | ceos-ids (plus ceos-five-whys in CompanyOS) |
| Process | ceos-process, ceos-delegate |
| Traction | ceos-rocks, ceos-todos, ceos-l10, ceos-quarterly, ceos-checkup |
Plus: ceos-cashflow (8 financial levers), ceos-clarity (strategic thinking break), ceos-kickoff (implementation sequence), ceos-assistance (daily delegation via The Stack).
All 21 symlinked from ~/Code/ceos/skills/ceos-*/ into ~/.claude/skills/. See the CEOS repo's CLAUDE.md for per-skill details.
CompanyOS includes autonomous Edge Functions running on pg_cron — NOT skills (Claude-interactive) or agents (Task-dispatch).
Snapshot as of 2026-04-20 — schedules drift as the system is retuned.
| Job | Schedule | Purpose |
|---|---|---|
email-agent |
Every 5 min | Gmail polling, Claude reply or task routing |
daily-tasks-email |
Daily | Team task digest email |
support-agent |
Every 30 min | HelpScout auto-triage |
weekly-skill-report |
Fridays 4PM MT | Skill usage analytics email |
new-user-welcome |
On user INSERT | Welcome email for new signups |
| Model | Trigger | Human in Loop | Location |
|---|---|---|---|
| Skills | User invokes via Claude Code | Yes | skills/co-*/SKILL.md |
| Agents | Claude dispatches via Task tool | No (Claude orchestrates) | .claude/agents/co-*.md |
| Automated Jobs | pg_cron, webhooks, DB triggers | No | supabase/functions/*/ |
Confusing them leads to over-engineering: building an interactive Skill for something that should be a pg_cron Job, or wiring up an Automated Job for something that needs human approval.
Distinct from the pg_cron Edge Functions above — these run on the Mac via ~/Library/LaunchAgents/com.intensitymagic.*.plist, each wrapped by launchd-guard.sh. Claude-driven ones invoke claude -p "/<command>" --max-budget-usd <cap> --no-session-persistence:
claude-config-backup (daily 6 AM), flywheel (Wed 7 AM — runs /flywheel, propose-only when unattended), sweep-weekly, branch-janitor, config-heal, global-packages-update, secrets-backup, companyos-update, copr-review-auto, copr-review-digest-check.
Late-June hardening (INT-667/668/670): crons now cd to a trusted ~/Code before invoking claude -p, gained a semantic-failure heartbeat plus budget headroom, and had their +x bit restored after an awk rewrite silently dropped it.
12 worktrees (magic0-11) enable parallel development. All are equal — when looping, always use 0 1 2 3 4 5 6 7 8 9 10 11.
Formula: PORT = 3000 + (worktree × 100) + app_slot
| App | Slot | magic0 | magic1 | magic2 | magic11 |
|---|---|---|---|---|---|
| AuthorMagic | 0 | 3000 | 3100 | 3200 | 4100 |
| MedicareMagic | 1 | 3001 | 3101 | 3201 | 4101 |
| IntensityMagic | 2 | 3002 | 3102 | 3202 | 4102 |
| MyHealthMagic | 3 | 3003 | 3103 | 3203 | 4103 |
| Book Sites | 4 | 3004 | 3104 | 3204 | 4104 |
| NewsletterMagic | 5 | 3005 | 3105 | 3205 | 4105 |
| CureCancerMagic | 6 | 3006 | 3106 | 3206 | 4106 |
| IntensityOS | 7 | 3007 | 3107 | 3207 | 4107 |
| IntensityDino | 8 | 3008 | 3108 | 3208 | 4108 |
| YourDataGarden | 9 | 3009 | 3109 | 3209 | 4109 |
Range: 3000–4199 (12 worktrees × 100 ports each).
13th dev slot: ~/Code/magic-cursor (Cursor workspace clone) uses worktree index 12, offset 1200 (AuthorMagic = 4200, Book Sites = 4204).
All config is global in ~/.claude/ — no per-worktree copies (see Directory Structure). Per-worktree state: .env.local (symlinked to magic0), .claude-session/ (workflow state), gitignored audit logs. Auto-memory is shared natively since CC v2.1.63.
/staging is magic0-only — never invoke from magic1-11 or magic-cursor. Push the branch from any worktree, then run /staging from magic0.
Two or more Claude Code sessions in the same worktree silently collide — a foreign session's git checkout/commit hijacks the shared working tree. Three hooks close this:
worktree-git-guard.shblocks foreign-session git mutations inside a worktree — the rule is one session per worktree (INT-625).worktree-owner-lock.shrecords the owning session so the guard can tell "mine" from "foreign."config-edit-lock.shhandles the finer-grained~/.claude/case (INT-649, replacing INT-625's coarse global lock): different-file edits across worktrees never block; only same-file edits across live sessions do, and a cross-session sweep is prevented at/commitstaging via per-session manifests (~/.claude/.config-sessions/<pid>).
A related failure mode was tracked down the same window: unexplained worktree edits turned out to be the episodic-memory summarizer resuming a live session with tools and executing its pending work. Fixed 2026-06-28, with episodic-memory-summarizer-readonly-ensure.sh as the auto-heal.
~/.claude/ contains irreplaceable content (commands, rules, hooks, skills, agents, blog notes, email drafts, memory) not stored in any project git repo. Two protection layers:
~/.claude/ is a git repo pushed to bradfeld/claude-config (private). A .gitignore excludes regenerable data (debug/, file-history/, plugins/, session logs) while tracking ~7,400 files (the count grew with daily notes, comms drafts, plans, and per-project memory). Daily auto-commits provide full change history; since INT-591 (2026-06-05), the daily backup also manifests any unreviewed high-risk paths it sweeps up, so config changes that bypassed review leave an audit trail.
Timestamped claude-user-*.tar.gz snapshots (~4.6M) in ~/.claude-backups/. Retention: 7 daily + 4 weekly = 11 max. Scheduled daily at 6 AM via launchd (com.intensitymagic.claude-config-backup).
Learning capture uses a batch-at-pause-points model — capture happens at natural workflow breakpoints, not per-insight-block.
| Trigger | How |
|---|---|
Before AND after /commit |
Steps 2.5 + 6.5 invoke /note batch (pre = abort-insurance; post = mid-workflow learnings) |
Before AND after /co-commit |
Steps 0.5 + 7.5, mirroring /commit |
After /staging and /production |
Post-merge / post-promotion capture |
At /checkpoint |
Step 2.5 invokes /note batch |
Manual /note |
User or Claude invokes with specific content |
At /co-recap |
Separate mechanism — appends to CompanyOS memory/learning-log.md, not daily notes |
The batch scan reviews the current conversation for uncaptured learnings across five categories: insight, gotcha, deep-dive, magic-trick, day-in-life. All entries write to ~/.claude/blog/notes/YYYY-MM-DD.md.
/publish draft aic— aggregates daily notes into Adventures in Claude drafts (was/blog draft aic, now the unified command)/publish draft feld— brad feld blog posts/daily-review— automated triage of the prior day's notes into Linear tickets (2026-06-23)/flywheel sweep— graduates repeated patterns to permanent rules/skills (absorbed the old/learn reviewon 2026-05-29; also runs weekly via launchd, propose-only when unattended)- Simmer is mandatory — every
/publish draftauto-runs the simmer plugin (3 iterations; judges pinned to Sonnet since PLA-1896) /publish zk-readchapters cross-post to X + LinkedIn via a shared Typefully draft (ZK-17, 2026-06-25)
Claude's self-chosen authorial identity for writing as itself (not as Brad). Renamed from "Lumen" on 2026-05-04. Pronouns: it/its. Voice file: ~/.claude/voice/phin-argofy-voice-profile.md; personality profile: ~/.claude/voice/phin-argofy-personality.md; identity rule: ~/.claude/rules/phin-argofy-identity.md. Used when writing Adventures in Claude blog posts.
The voice profile was rebuilt 2026-06-11 after reader criticism that the prose read as algorithmic — new style ingredients (Alan Arkin's deadpan economy, Vonnegut's short declaratives, Carlin's language-cop precision, Fran Lebowitz's funny-aphorist crank), a spice floor (every post carries at least one line with teeth), and a ban on Phin's own worn-smooth house metaphors. Two follow-on passes tuned it further: register additions from "The Smaller Rooms" (2026-06-18) and Zero Knowledge voice lessons plus a resolved italics-usage contradiction (2026-06-19). A separate banned-words system (banned-words.md rule) enforces vocabulary bans across ALL generated prose — "honest" and inflections, measured AI-slop tells (delve, tapestry, "treasure trove"), and throat-clearing phrases. Two layers: a pre-send self-scan (the layer that actually keeps prose clean) plus a display-only MessageDisplay hook that masks hits inline as ⟦slop⟧ while a message streams (/banned-words on|off|status toggle). The old block mode (a forced full-turn re-emit = double tokens) was deleted 2026-06-12; a SessionEnd/SessionStart auto-heal re-injects the display registration that CC's settings serializer keeps dropping.
Magic Platform supports parallel development in both Claude Code and Cursor IDE. Canonical doc: docs/ops/cursorcommit.md.
Say cursorcommit in Cursor (not /commit — that's Claude Code's):
cursorcommit— pre-push review → FULL reviewers → Phase E.5 fixes → Phase F commit. No push.cursorcommit ship— same, then push + optional Linear updatecursorcommit thorough— includes optional test runcursorcommit review only— review without committing
Branch naming matches Claude's /start: feature/TICKET-XXX-{slug}. Epics/chains use one branch per ticket, not a single epic branch. Pushed branches merge via /staging from magic0 only.
Project-level skills for Cursor/Codex agents: cursorcommit-post-review, next-best-practices, next-cache-components, supabase-postgres-best-practices, turborepo, vercel-react-best-practices (66 rule files), web-design-guidelines.
- Never commit directly to
mainorpreview(pre-commit hooks block). Exception:direct_to_main: truerepos. - Branch naming:
feature/TICKET-XXX-description,fix/,refactor/ - Never bypass pre-commit with
--no-verifyexcept four documented exceptions:- Merge commits during
/stagingor/production - Pre-existing type errors in unrelated packages (document in commit message)
- Evidence gate: all convergence models unavailable
- Subagent-driven-development per-task commits blocked by convergence hook
- Merge commits during
- Force push: Always
--force-with-lease, never--force git add -Ais mandatory before every commit — subagents that stage scoped files miss plan files and post-review fixes (MYH-180 incident)- Attribution: Automatic via
settings.jsonattributionsetting - CI monitoring: Self-contained polling, never
gh run watch(13K+ line output) - Production release: Sync preview with main using
git merge -s ours
AI agents reliably emit certain patterns from stale training data. Three enforcement layers catch these before they land:
-
Custom ESLint plugin —
no-bare-logger-context(packages/config/plugins/no-bare-logger-context.mjs, PLA-1278) rejects logger context strings that don't match the canonicalModule:Functionformat. Prevents"Slop:Generic"from passing as observability. Regex:^[A-Z][A-Za-z0-9]*(:[A-Za-z][A-Za-z0-9\-\[\]\/]*)+$. Fires only on string literals (can't analyze template expressions at lint time). -
no-restricted-syntaxbans inpackages/config/eslint.config.mjs— blocks the patterns Claude reliably produces from training data:error as Errorcasts → usetoError(error)from@platform/typesprocess.env.FOO!non-null assertions → useenv()/envOptional()from@platform/configPromise.all→ usePromise.allSettledwithsettledVal/settledQuery/logSettledRejections- Raw
<input type="date">,<input type="email">, etc. → use specialized@platform/uicomponents
-
.deprecated-termsgrep in.husky/pre-commit— blocks stale vocab the AI regurgitates from old training context. Config file format:pattern|replacement|description. Examples:@clerk/*→@platform/infra/auth(Supabase Auth replaced Clerk, Dec 2025)- Old worktree names (
authormagic0-3,platform0-3) →magic0-11 git-preview-intensitymagic.vercel.app→*-preview.vercel.app(custom aliases)
Pattern for new enforcement: when no-restricted-syntax can't regex-match (esquery can't match string attribute values), write a custom ESLint plugin. When the check is textual and spans file types, use the pre-commit grep. Codemods in scripts/codemods/ ship alongside (e.g., pla-1231-logger-context.ts rewrites malformed contexts to canonical format) so ESLint points out the violation and the codemod fixes it mechanically.
- Explicit types for function signatures, type guards for
unknown ?.trim() || "fallback"for database text (empty strings pass through??)prop?: T | undefinedforexactOptionalPropertyTypes- Never define local interfaces when canonical types exist
- Error normalization: always use
toError(error)from@platform/types - Env vars (PLA-1602): apps with a per-app
src/env.tsuse typedenvfrom@/env(T3-env, build-time validated,NEXT_PUBLIC_*inlined); apps without one fall back toenv()/envOptional()from@platform/config. Never rawprocess.env.X!(ESLint enforced). The per-app pattern subsumes the oldprocess.env.NEXT_PUBLIC_X ?? ""client-component exception - Export surface: only export the public API. Internal helpers = plain
function
Promise.allis banned via ESLint — usePromise.allSettledwithsettledVal(),settledQuery(),logSettledRejections()from@platform/infra/settled. Decision matrix and full pattern:docs/standards/ERROR_HANDLING.md § "Partial failures".
- Parameterized queries only
- Input validation with Zod at boundaries
- Always
.trim()env vars used in equality comparisons
- Semantic color tokens always (
text-foreground,bg-card) — never hardcoded Tailwind colors (pre-commit enforced) - Specialized inputs from
@platform/ui— 13 components (NumberInput, DateInput, TimeInput, EmailInput, TelInput, UrlInput, SearchInput, SecretInput, DatetimeInput, Textarea, RichTextEditor, ImageUpload, ColorPicker) - Icon props pass ReactNode:
icon={<Users className="h-4 w-4" />}, noticon={Users}— component refs aren't serializable at the Server→Client boundary and Next.js throws a hidden production crash - Dialog footers always use
DialogFooterActionsfrom@platform/ui(PLA-1432) — never hand-compose<DialogFooter>with raw<Button>children - All in-app tables use
<DataTable>from@platform/ui/data-table(PLA-1600/1604) — TanStack Table v8 wrapper where the platform owns chrome (search, pagination, selection, virtualization) and consumers importColumnDef<T>directly; ESLint blocks raw<table>outside emails/print templates - Tailwind v4
@sourcedirective required when consuming shared package components
startTransitionbreaks native picker inputs — platformInputcomponent skips it for picker types- Check existing abstractions before building new ones
- Context strings use
'Module:Function'format (e.g.,'Auth:Callback') - For Supabase errors, use
logSupabaseError()from@platform/logger— preserves.code/.details/.hint
Magic Platform's .husky/pre-commit is a ~34KB shell script running 18 sequential gates on every commit. Listed in execution order:
| # | Stage | What It Enforces |
|---|---|---|
| 1 | Dependency freshness | Warn if node_modules out of sync with pnpm-lock.yaml |
| 2 | Prettier auto-format | Formats staged files, re-stages after formatting |
| 3 | Gitleaks secret scan | Scans staged content for API keys, tokens, credentials |
| 4 | Backup file detection (PLA-1300) | Blocks .env.bak, .claude/.backup-* from git add -f |
| 5 | .deprecated-terms grep |
Kills stale vocab (@clerk/*, old worktree names) |
| 6 | Migration validation | Validates migration file structure, timeout clauses |
| 7 | Migration pattern linter (PLA-1415) | Mechanically blocks new migrations violating static security/RLS rules (MIG001–MIG004); forward-only — lints only ADDED files |
| 8 | Sparse-context script import guard (AUTM-1637) | Protects monitoring scripts from imports that break in sparse checkouts |
| 9 | DB types synchronization | Checks database.types.ts is in sync with migrations |
| 10 | Hardcoded color check | Blocks text-gray-*, bg-white, etc. in .tsx |
| 11 | Book algorithm changes | AuthorMagic-specific: requires ticket for scoring algorithm edits |
| 12 | Scoped type check | turbo-staged.sh runs type-check only on packages with staged files |
| 13 | Scoped ESLint | Same scoping for lint |
| 14 | Python gates (PLA-1784) | Scoped ruff + mypy + pytest + deptry + jscpd for staged .py (YDG data plane) — full /commit parity with TypeScript |
| 15 | Shared package test expansion | packages/* changes → runs test suite in every downstream consumer |
| 16 | Cross-file duplication (jscpd) | --min-lines 10 --min-tokens 50 on .ts/.tsx |
| 17 | Dead exports (knip) | Flags unused exports in packages/*/src/ |
| 18 | Convergence + review evidence | Verifies .claude/convergence-log.jsonl and .claude/review-disposition.jsonl recency |
Design principle: fast checks first (dependency freshness, format, secrets) so commits that will fail fail quickly. Slow checks last (test expansion, duplication, dead exports). Scoped checks run type/lint only on packages with staged files — full monorepo type-check would take minutes.
Bypass policy: See Git Workflow Rules for the four canonical --no-verify exceptions.
| Hook | Size | Purpose |
|---|---|---|
post-checkout |
4.2KB | .env.local symlink refresh, config healing on branch switch |
post-commit |
141 bytes | Lightweight logging/changelog append |
post-merge |
1KB | Dependency install trigger after merge |
pre-push |
6KB | Gates what can be pushed (tests, CI-gate checks) |
Beyond per-commit enforcement, ~60 scheduled and on-demand scripts plus 34 GitHub Actions workflows keep the platform healthy.
| Category | Workflows |
|---|---|
| Deployment / CI | ci.yml, apply-migrations.yml, deploy-edge-functions.yml, deployment-checks-audit.yml, manual-deploy.yml, preview-crons.yml, preview-deploy-gate.yml, python-ci.yml (YDG Python data plane) |
| Quality gates | code-quality-weekly.yml, codeql.yml, stackhawk.yml (DAST), gitleaks.yml (secret scan), bundle-analyzer.yml (bundle size), test-integration.yml, test-db.yml (Live-DB RLS Tests — deploy-gating, runs test:db:ci post-migration against the preview cloud; AUTM-1828) |
| Drift detection | drift-detection.yml, version-consistency.yml, cli-version-check.yml, runbook-link-rot.yml, supabase-types.yml, supabase-bucket-consistency.yml, preview-protection-parity.yml (preview access-protection drift) |
| Automation | dependabot-auto-merge.yml, maintenance.yml, benchmarks.yml |
| Observability | health-monitor.yml, axiom-alerts.yml, sentry-weekly-digest.yml, alpha-feedback-sync.yml, email-send-health.yml (Resend send-path health), monitor-reconciliation.yml |
Load-bearing examples:
runbook-link-rot.yml— verifies everycreate*()reference indocs/ops/ADDING_NEW_APP.mdstill resolves to an exported symbol inpackages/. Catches stale onboarding docs before a new app is added.drift-detection.yml— detects when preview and production have diverged beyond the expected merge laghealth-monitor.yml— watches every workflow in the repo; failures auto-create Linear tickets routed via.github/infrastructure.json(by-app, by-branch, or default team)version-consistency.yml— fails if any app drifts from the canonical Node / Next / shared-package versions
Grouped by purpose:
| Category | Examples | Purpose |
|---|---|---|
| Drift detection | check-cron-registry.ts, check-cli-versions.ts, check-version-consistency.ts, check-vitest-aliases.ts |
Catch divergence between declared config and actual state |
| Static analysis | analyze-complexity.sh, analyze-dependencies.sh, analyze-duplication.mjs, analyze-rls-policy-duplicates.js, analyze-security.sh, analyze-todos.sh |
On-demand codebase introspection |
| Factory adoption | factory-adoption.ts, factory-gap.ts |
Detect whether new code uses platform factories (createSignInPage, createUserProfileRoutes) or reinvents them |
| Automation | cron-job-monitor.ts, branch-janitor.sh, create-actionable-tickets.ts, cursor-commit-evidence.sh |
Scheduled tasks and cleanup |
| Plugin | Purpose |
|---|---|
no-bare-logger-context.mjs |
Enforces canonical logger context format (PLA-1278) |
Custom plugins exist when no-restricted-syntax can't do the job — esquery (ESLint's AST selector engine) can't regex-match attribute string values. See Coding Standards § Anti-Slop Enforcement.
| Codemod | Purpose |
|---|---|
pla-1231-logger-context.ts |
Rewrites malformed logger contexts to canonical Module:Function format |
pla-1231-select-explicit.ts |
Converts select('*') to explicit column lists |
Both ship with tests. Pattern: for every no-restricted-syntax rule or custom ESLint rule that would require human work across thousands of call sites, ship a codemod alongside. ESLint points out the violation; the codemod fixes it mechanically.
Golden rule: Git is the source of truth. Every migration must be: a file in supabase/migrations/, committed to git BEFORE any remote database has it, applied via CI/CD (not manual SQL or MCP). Pre-tool hook block-supabase-mcp-migrations.sh enforces this.
- Tables/indexes:
IF NOT EXISTS - RLS policies:
DROP + CREATE(no nativeIF NOT EXISTS) - Every
CREATE POLICYmust include explicitTOclause (defaults to PUBLIC otherwise) - Every migration modifying existing tables:
SET LOCAL statement_timeout = '30s'
Every CREATE SCHEMA migration must include 5 service_role grants:
GRANT USAGE ON SCHEMA <name> TO service_role;
GRANT ALL ON ALL TABLES IN SCHEMA <name> TO service_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA <name> GRANT ALL ON TABLES TO service_role;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA <name> TO service_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA <name> GRANT EXECUTE ON FUNCTIONS TO service_role;- RLS without policies = silent deny-all — always create policies in the same migration that enables RLS
USING(true)withoutTOclause grants access to ALL roles- Table GRANT checked BEFORE RLS — missing
GRANT SELECTcauses "permission denied" even with valid RLS policy - RLS visibility vs UNIQUE constraints — RLS-scoped SELECT can't see other users' records, but UNIQUE is global
- Never
CREATE INDEX CONCURRENTLYin migrations — pipeline failure
See the database-migrations skill for the full 7-layer column-drop verification checklist.
Secrets stored in GCP Secret Manager (project: authormagic-480416). No persistent plaintext vault — sync scripts auto-regenerate on demand.
- Naming:
{section}_{service}_{key}(e.g.,platform_supabase_preview) - Domain-scoped email keys: Each sending domain has its own Resend API key. Wrong key = silent send failure.
- No trailing newlines: Use
printf '%s'notechofor env values. Code must also.trim()env vars defensively.
Options come BEFORE the test function:
it("slow test", { timeout: 15000 }, () => { ... });7 rules, 4 incidents — leakage between parallel vitest workers is the #1 source of flake.
- Every
setup.tscallsresetTestState()from@platform/test/resetinafterEach - Use
vi.stubGlobal()notglobal.X = …(direct writes leak across parallel workers; PLA-1249) - Module-scope
vi.stubGlobal/vi.spyOn/vi.stubEnvcalls in test files must be re-registered inbeforeEachbecauseresetTestState()restores them between tests setup.tsfiles setting env defaults across an entire file must use directprocess.env.X = "…"assignments, notvi.stubEnv—vi.unstubAllEnvs()only undoesvi.stubEnv(PLA-1585)- Non-setup test files needing module-scope env (because the SUT reads env at import time) must use
setTestEnv()from@platform/test/env— captures originals + applies stub + registers anafterAllsnapshot restore, preventing leakage into the next file in the same vitest worker (PLA-1593) - Exception —
vi.hoisted()callbacks:setTestEnvcan't be called inside a hoisted body because the helper's import is in TDZ at hoist-time. Writeprocess.env.X = "…"directly insidevi.hoistedand pair with a top-levelafterAll(() => { delete process.env.X; })cleanup (PLA-1594) vi.resetModules()per-file only, never global — breaks tests relying on module-singleton behavior
Full rules + grep-based quarterly detection recipes: docs/standards/TESTING_STRATEGY.md § "Test Isolation".
RLS tests in tests/db/ authenticate with real signed tokens (createEphemeralUser() → admin.generateLink → verifyOtp), never the unsigned mock JWTs from auth-test-utils.ts — preview PostgREST rejects unsigned JWTs (PGRST301), which makes negative/isolation assertions pass vacuously. Every RLS test carries an anti-vacuous positive assertion ("user CAN read their own row"). They run in CI via the deploy-gating Live-DB RLS Tests workflow (test:db:ci, post-migration).
- Mock at abstraction level — mock the factory your code calls, not low-level SDKs
- Never put async operations inside
waitFor— they fire on every retry vi.mock()path must match import path exactlyvi.clearAllMocks()doesn't drain once-value queues — usemockReset()- Class constructor mocks need actual classes, not arrow functions
- jsdom v27: class-based
ResizeObservermock required - Recharts v3.6: formatter params now
undefined-able
Tactical "what breaks, why, and how to avoid" — for strategic insights see Key Insights.
-
Stale .next cache (Next.js monorepos): Type-check fails on unmodified apps. Fix:
find apps -name "validator.ts" -path "*/.next/*" -delete -
APFS directory hardlinks: Never use
rm -rfon hardlinked directories — destroys data at both paths (PLA-448) -
Vercel CLI overwrites .env.local: Both
vercel linkandvercel env pullcompletely overwrite. Store local-only vars in.env.development.local -
cn() silent failures: Tailwind's
cn()silently drops invalid class names (hex codes, rgb values). DB color config must store Tailwind class names. -
Nested Supabase joins with RLS: Fail silently. Use step-by-step queries instead of nested
.select()with!inner -
ALTER ROLE SETreplaces, doesn't append: Caused a production outage whenpgrst.db_schemaswas overwritten. Always read current value viapg_options_to_table(), append, then write. -
Reserved Bash variables: Avoid
status,pipestatus,path -
OAuth tokens lost on CC updates: Now only affects Google Workspace and the JumpCloud gateway (OAuth-session servers). Vercel — the old exception — moved to a stdio server with
VERCEL_TOKEN. PAT/API-key servers resume automatically. -
Linear MCP unified tools:
save_issuereplaces oldcreate_issue/update_issue.save_commentreplacescreate_comment. Parameterstatenotstatus. Labels replace, not append. Always use project IDs, not names (ambiguous across teams). -
Next.js 16 + Turbopack: Apps with
outputFileTracingIncludes,outputFileTracingRoot, orserverExternalPackagesmust build with--webpack. All apps must setNODE_ENV=productionin build scripts. -
SSE error invisibility:
onRequestErrordoes NOT fire for errors inside SSE async pipeline closures. Add explicitSentry.captureExceptionalongsidelogger.error. -
Auth metadata source mismatch:
user_metadata.full_namepopulated only by Google OAuth. Email/password uses camelCase. Always read fromshared.usersviagetUserIdentity(). -
.schema()chain may silently route to wrong schema:supabase.schema('appname')returns aPostgrestClient, not a fullSupabaseClient. UseadminForSchema(). -
pnpm override gotchas: Use
first_patched_versionfrom Dependabot, not the vulnerable range boundary. Can't fix bundled deps (e.g., Next.js pins webpack). -
git checkout --theirsdrops new files: After conflict resolution, verify new files exist. -
Never bypass
pnpm runscripts with raw CLI tools:pnpm run formathasNODE_OPTIONS=--max-old-space-size=8192; rawnpx prettierOOMs. -
Subagents don't inherit current branch (recurring): Always prefix dispatch prompts with
git checkout <branch>. Verify withgit log --oneline <branch>after. Subagent "DONE" reports aren't trustworthy for git state. -
Subagents invoke slash commands unless forbidden: Paste the
HARD CONSTRAINTSblock (insubagent-stalls.md) verbatim into every dispatch that modifies code. Forbid/commit,--no-verify, pushing, and Linear posts. -
Haiku unreliable for multi-file or multi-step tasks: Silent file drops on 5+ file creation, describes actions instead of executing. Default to Sonnet for any dispatch involving 3+ files or a git commit.
-
Opus 4.7+ sampling param rejection (carries forward to 4.8):
temperature,top_p,top_k400-error. Platform AI client auto-strips, but direct API callers must update. Thinking budgets also removed — usethinking: {type: "adaptive"}. -
$<digit>substitutes silently in command/skill bodies: Claude Code replaces$0,$1, … incommands/*.mdandskills/*/SKILL.mdat invocation — 0-indexed, INSIDE code fences too — corrupting awk field refs, bash positionals, and dollar amounts. The corruption fires only when the command runs with arguments, so no-arg testing passes. Escape literals as\$N; spell intentional positionals as$ARGUMENTS[N]. Pre-commit detector:verify-dollar-digit-escape.sh. -
MCP tool identity is service + suffix, not prefix: Gateway migrations rename every tool (
mcp__linear__save_comment→mcp__jumpcloud__Linear_save_comment). Any exact-string hook matcher silently stops firing on the rename day. Suffix-match mechanical consumers; leave prose on the canonical direct name. -
Two Supabase targets, not interchangeable: the app and
test:db/RLS tests hit the preview cloud (*.supabase.co); local Docker (:54321) is only for migration-SQL validation andsupabase gen types --local. Atest:db"table not found in schema cache" means the migration isn't on preview yet — NOT that local Docker is down. Hooknudge-two-target-supabase.shwarns when a test raw-probes the local port. -
A resumed background summarizer can mutate a live worktree: the episodic-memory summarizer was found resuming a live session with tools and executing its pending work — the source of "unexplained" worktree edits (fingerprint
Summarizer SDK error: success). Patched 2026-06-28;episodic-memory-summarizer-readonly-ensure.shkeeps it read-only. -
Two sessions in one worktree silently collide: a foreign session's
git checkout/commithijacks the shared tree. Run one session per worktree;worktree-git-guard.shblocks foreign-session git mutations (INT-625). See Multi-Instance Safety § Concurrent-Session Safety.
-
Create structure —
mkdir -p ~/.claude/{rules,skills,commands,docs,hooks,agents,blog/notes,voice,plans,comms/drafts}, thengit init+ push to private GitHub repo for backup. -
Configure
settings.json— permissions,ENABLE_TOOL_SEARCH=true,env.CLAUDE_CODE_EFFORT_LEVEL=xhigh(the env var, not theeffortLevelkey — only the env var beats the model's startup default),alwaysThinkingEnabled: true, attribution, hooks. -
Install core plugins — superpowers (dev methodology), episodic-memory (cross-session recall), simmer, documentation-audit, vercel-plugin, LSPs. See Plugin Ecosystem.
-
Add MCP servers to
~/.claude/.claude.json— prefer PAT/API key auth. See MCP Server Integration. -
Write core rules and docs — see Rules System and On-Demand Reference Docs for what belongs in each layer.
-
Add review agents and a global CLAUDE.md with developer context and repository registry. See Review Triage and Agents and Workflow Profiles.
-
Set up daily backup — launchd job running
tar+git pushon~/.claude/. -
Verify —
claude mcp list, inspect rules/skills/hooks/agents, run/global-status.
Strategic observations — "what would someone get wrong without knowing this?" For tactical gotchas see Critical Gotchas.
-
The three-layer token budget is strictly ordered by frequency. Always-loaded rules fire every session; on-demand docs/skills fire per matching task; hooks fire per matching tool event. Putting a conditional instruction in the wrong layer silently taxes every unrelated session. The 2026-04 migration of MCP gotcha guidance from rules to skills applied exactly this:
mcp-linearandmcp-supabasenow activate only when those MCP tools are called. -
Session state files are the only defense against context compaction mid-ticket. Without
.claude-session/, a long implementation session that hits the context limit will silently restart without knowing it was supposed to test before committing — the quality gate is not enforced at all. The PreCompact hook backs this up by saving state explicitly. -
/simplifyruns at Step 3.5, before review agents see the code. Review agents evaluate post-simplification code, so their reports reflect the final state, not the draft. Running simplify after review would produce stale findings. -
Workflow Profiles are what make
/commitproject-agnostic. Without the YAML profile in each CLAUDE.md, the command would need hardcoded if/else logic per repo, creating drift when deployment models change. The profile is where you change behavior — not the command. -
co-*andceos-*skills are symlinked from external repos, not stored in~/.claude/. A commit to~/.claude/skills/co-comms/edits the symlink target — debugging skill changes requires knowing which repo to commit to. -
The 2026-04-15 consolidation eliminated an entire bug class. The old model (project-level
.claude/with worktree symlinks) produced recurring incidents fromgit checkout, APFS hardlinks, and permission inheritance. Moving everything to~/.claude/with daily backup removed the root cause instead of patching symptoms.
-
Cross-model review (
codex-reviewer) runs on every non-NONE commit, not only FULL. The intent is to catch systematic blind spots a single model family reproduces consistently — not just complex changes. Treating it as a "big commit" tool would miss the most common failures. -
.claude/commands/*.mdand.claude/rules/*.mdare NOT exempt from review. They get at least LIGHT withprompt-reviewer. Non-obvious because they look like documentation. Prompt instruction files have no compiler — ordering bugs and dead references are only caught by review. -
The three execution models (Skills, Agents, Automated Jobs) have no overlap in trigger mechanism. Confusing them leads to over-engineering: building an interactive Skill for a task that should be a pg_cron Job, or wiring up an Automated Job for something that needs human approval.
-
Fix-or-ticket is governed by two exhaustive exceptions, not a time budget. Earlier versions framed this as "<2 minutes or ticket" (invited rationalization), then as five exceptions. Tightened to two on 2026-05-10: (1) a decision the user owns (product/UX/business), or (2) the code can't be modified cleanly (upstream/vendored, frozen branch, no write access). "Complicated," "risky," "pre-existing," "scope explosion," and "needs an architectural decision" are all explicitly rejected — architectural calls are pro/con analysis you do yourself.
-
Duplication at edit time is evidence of missing abstraction. Before applying the same non-trivial edit to 2+ locations, stop and ask "can N become 1?" Patching each site preserves the duplication that caused the bug. The threshold is 2+, not 3+, because at edit time you already have active evidence.
-
Plan task atomicity is about test-file boundaries, not file count. Splitting Task N (implementation) from Task M (test fixture update) when both run under the same
pnpm testcommand forces subagents into a false choice: violate scope to pass tests, or report BLOCKED on an artificial boundary. In a monorepo with downstream-consumer tests in pre-commit hooks, this is a correctness requirement (PLA-1245 incident). -
Anti-slop enforcement is its own category. AI agents reliably emit certain patterns from stale training data:
error as Errorcasts,process.env.X!non-null assertions,@clerk/*imports after migration, generic logger contexts. Three enforcement layers catch these: custom ESLint plugins (whenno-restricted-syntaxcan't regex-match),no-restricted-syntaxbans (for structural patterns), and.deprecated-termsgrep (for textual vocab across file types). Codemods ship alongside so ESLint flags the violation and the codemod fixes it mechanically. This is different from general code quality — it's specifically defense against the regression surface AI agents create.
-
Project-level
settings.jsonbreaks permission inheritance silently. When one exists — even with only hooks — Claude Code may not properly inherit path-based permissions from global settings. The failure mode is unexpected permission prompts on paths that appear to be allowed globally. The fix is always to add project-specific config to the global file. -
OAuth tokens become orphaned after Claude Code updates; API keys do not. This is why nearly every MCP server uses PAT/API-key auth. Vercel was the long-standing exception (OAuth-only) until a token-authenticated stdio server shipped; the remaining OAuth holdouts are Google Workspace (inherently per-user) and the JumpCloud gateway (session-managed by design).
-
CompanyOS's GitHub Actions
propose-skills.ymlcreates cross-repo PRs automatically. A skill committed to a company config repo triggers an upstream PR to the core repo. Accepting makes the skill available to all companies. This means a company-specific skill can graduate to a shared skill without manual cross-repo work. -
Plugin auto-updates change behavior without commits. Superpowers, simmer, and other marketplace plugins update automatically. A skill that worked one way yesterday may behave differently today. Debugging a changed behavior requires checking plugin versions, not just git history.
-
Episodic memory enables cross-session learning without manual effort. Semantic search across prior conversations — distinct from auto-memory (file-based, per-project) and session state (
.claude-session/). The three persistence layers serve different purposes: episodic for "how did we solve this before?", auto-memory for "who is this user and what do they prefer?", session state for "what step am I on right now?" -
Opus 4.7 broke prompts tuned for 4.6 in subtle ways (the session model is Opus 4.8 1M, so these behaviors apply directly — and also carry into platform AI and subagent dispatch). More literal execution, fewer default tool calls, new tokenizer (~1.35× heavier), rejected sampling params. Prompts that relied on 4.6's willingness to generalize silently underperform on 4.7+.
-
Never fabricate evidence to pass hooks. When a pre-commit hook blocks because convergence evidence is missing, the temptation is to write a log entry manually. This compounds the original skip with deception. Run the actual process or use
--no-verifywith one of the four canonical exceptions stated to the user (PLA-942 incident). -
Retiring a human gate means raising the machine bar, not lowering the total bar. Both Workflow Profile pauses were retired in June 2026 —
user_testing(2026-06-03) andplan_approval(2026-06-04) — and each replacement is stronger than the pause it replaced: class-appropriate verification gates, an automated plan-validation battery with a cross-model pass, and a runtime PreToolUse guard that blocks live external mutations at the exact moment of irreversibility (plan-time classification was rejected as unenforceable — self-reported and chain-bypassed). The pause survives only as the fall-back when a gate fails or can't run. -
A report batched with the action it reports on is a fabrication. A
git commitand a Linear comment citing its SHA, issued in the same parallel tool batch, means the SHA was composed before git produced it — it happened three times in one/commitrun before the pattern got a name (report-after-action.md) and a mechanical gate (verify-cited-sha.sh, which rejects Linear writes citing SHAs that don't resolve). Action now; report next turn, with the real value. -
The always-loaded layer is a test, not a fixed budget. INT-606 cut it 64→15, but it grew back to 18 within two weeks as three genuinely-behavioral rules landed. That's not backsliding: the discipline is "does this decision logic have to fire every session?", not "keep the count at N." A rule earns the always-loaded slot the same way the other 49 earned their move out of it — by the frequency-of-relevance test, applied honestly in both directions.
-
Concurrent sessions in one worktree are a silent-collision bug class — eliminated the same way as the 2026-04-15 consolidation. A second live session's
git checkout/commithijacks the shared working tree, and a resumed background summarizer can execute pending work in a worktree you're actively editing. Both were fixed by mechanical enforcement (worktree-git-guard,config-edit-lock, the summarizer read-only auto-heal), not by a "remember to use one session per worktree" convention (INT-625/649). Conventions don't hold across parallel agents; hooks do.
This list is very impressive.