Skip to content

Instantly share code, notes, and snippets.

@bradfeld
Last active July 2, 2026 19:07
Show Gist options
  • Select an option

  • Save bradfeld/1deb0c385d12289947ff83f145b7e4d2 to your computer and use it in GitHub Desktop.

Select an option

Save bradfeld/1deb0c385d12289947ff83f145b7e4d2 to your computer and use it in GitHub Desktop.
Feld Claude Code Configuration Guide - patterns for professional solo development

Feld Claude Code Configuration Guide - patterns for professional solo development

Feld Claude Code Configuration Guide

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.


Table of Contents

  1. Core Philosophy
  2. Directory Structure
  3. Session State Architecture
  4. Master Workflow
  5. Review Triage and Agents
  6. Workflow Profiles
  7. Rules System
  8. On-Demand Reference Docs
  9. Hooks System
  10. Model Strategy
  11. Skills Inventory
  12. Plugin Ecosystem
  13. Commands Inventory
  14. MCP Server Integration
  15. Repository Registry
  16. CompanyOS: Multi-Repo Architecture
  17. CEOS: EOS Framework
  18. Automated Jobs
  19. Multi-Instance Safety (Worktrees)
  20. Backup and Version Control
  21. Blog and Learning Capture
  22. Cursor Integration
  23. Git Workflow Rules
  24. Coding Standards
  25. Pre-commit Pipeline
  26. Quality Automation
  27. Database Migration Discipline
  28. Secrets Management
  29. Testing Patterns
  30. Critical Gotchas
  31. Quick Start for New Setup
  32. Key Insights

Core Philosophy

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-verify with 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), and plan_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

Directory Structure

~/.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.

The 2026-04-15 Consolidation

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 checkout would delete config files (PLA-609, PLA-762)
  • APFS hardlink destruction when rm -rf ran on directory hardlinks (PLA-448)
  • Worktree symlink ELOOPs
  • Project-level settings.json breaking 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 State Architecture

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.


Master Workflow

All tickets follow an identical loop:

  1. /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), classify risk_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)
  2. 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
  3. /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
  4. /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
  5. /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.


Review Triage and Agents

Triage Levels

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.

Triage Signals

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 with prompt-reviewer (no compiler for prompts)
  • Infrastructure config (vercel.json, next.config.ts, turbo.json, .github/workflows/*.yml) → at least LIGHT

⚠️ Triage is MECHANICAL, not interpretive (PLA-1015 incident). If the filename matches → route accordingly. The review agent interprets; the triage routes.

Review Agents

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.


Workflow Profiles

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.

Risk-Tiered Gates (2026-06)

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; /staging and /production remain user-triggered. Legacy required scalars 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 (a required profile, or no Workflow Profile at all) it fails safe to ask. The irreversible step — applying a migration or deploying — stays gated separately by block-live-mutations.sh. Magic Platform's AGENTS.md declares this override explicitly.

Rules System

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 definition
  • verify-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 examples
  • verify-bash32-compat.sh (Rule 7, 2026-06-20) — blocks bash 4+ constructs / macOS-bash-3.2-unparseable syntax in staged hooks/*.sh and scripts/*.sh, because Claude Code's hook environment resolves to /bin/bash 3.2.57 more often than not

On-Demand Reference Docs

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.


Hooks System

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 safetyworktree-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.

Hook Scripts

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 Configuration

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.


Model Strategy

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.

Opus 4.7+ Migration Notes

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_tokens and compaction triggers
  • Sampling params removedtemperature, top_p, top_k 400-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

Skills Inventory

~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

Domain Skills (20)

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.

Superpowers Skills (14) — plugin-provided, auto-updating

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.

CompanyOS and CEOS skill details

See CompanyOS and CEOS sections.


Plugin Ecosystem

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

Marketplaces Registered

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.


Commands Inventory

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.)

Tier 1 — Primary Workflow

/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).

Tier 2 — Development Utilities

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).


MCP Server Integration

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.

Configured Servers (18)

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.

Gateway Routing (2026-06-03)

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 to mcp__.*save_comment form.

/mcp-migrate <service> wraps the migration checklist end-to-end (matcher conversion, skill trigger descriptions, hook-verification matrix).


Repository Registry

/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: Multi-Repo Architecture

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.

Three-Level PR Hierarchy

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.

Skill Activation and Telemetry

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.

Safety

  • 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.md calibrates writing style
  • Protected email workflow: co-comms skill enforces draft-review-approve. Never call send_gmail_message directly.

Key Commands

/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.


CEOS: EOS Framework

~/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.


Automated Jobs

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

Three Execution Models (no overlap)

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.

Local macOS launchd Jobs (10)

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.


Multi-Instance Safety (Worktrees)

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.

Port Allocation

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).

Configuration Sharing

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.

Concurrent-Session Safety (INT-625 / INT-649, late June 2026)

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.sh blocks foreign-session git mutations inside a worktree — the rule is one session per worktree (INT-625).
  • worktree-owner-lock.sh records the owning session so the guard can tell "mine" from "foreign."
  • config-edit-lock.sh handles 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 /commit staging 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.


Backup and Version Control

~/.claude/ contains irreplaceable content (commands, rules, hooks, skills, agents, blog notes, email drafts, memory) not stored in any project git repo. Two protection layers:

Layer 1: Git Repository

~/.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.

Layer 2: Tarball Backups

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).


Blog and Learning Capture

Learning capture uses a batch-at-pause-points model — capture happens at natural workflow breakpoints, not per-insight-block.

Capture Triggers

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.

Downstream Consumers

  1. /publish draft aic — aggregates daily notes into Adventures in Claude drafts (was /blog draft aic, now the unified command)
  2. /publish draft feld — brad feld blog posts
  3. /daily-review — automated triage of the prior day's notes into Linear tickets (2026-06-23)
  4. /flywheel sweep — graduates repeated patterns to permanent rules/skills (absorbed the old /learn review on 2026-05-29; also runs weekly via launchd, propose-only when unattended)
  5. Simmer is mandatory — every /publish draft auto-runs the simmer plugin (3 iterations; judges pinned to Sonnet since PLA-1896)
  6. /publish zk-read chapters cross-post to X + LinkedIn via a shared Typefully draft (ZK-17, 2026-06-25)

Phin Argofy (Claude's Identity)

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.


Cursor Integration

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 update
  • cursorcommit thorough — includes optional test run
  • cursorcommit 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.

.agents/skills/ Directory

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.


Git Workflow Rules

  • Never commit directly to main or preview (pre-commit hooks block). Exception: direct_to_main: true repos.
  • Branch naming: feature/TICKET-XXX-description, fix/, refactor/
  • Never bypass pre-commit with --no-verify except four documented exceptions:
    1. Merge commits during /staging or /production
    2. Pre-existing type errors in unrelated packages (document in commit message)
    3. Evidence gate: all convergence models unavailable
    4. Subagent-driven-development per-task commits blocked by convergence hook
  • Force push: Always --force-with-lease, never --force
  • git add -A is mandatory before every commit — subagents that stage scoped files miss plan files and post-review fixes (MYH-180 incident)
  • Attribution: Automatic via settings.json attribution setting
  • CI monitoring: Self-contained polling, never gh run watch (13K+ line output)
  • Production release: Sync preview with main using git merge -s ours

Coding Standards

Anti-Slop Enforcement

AI agents reliably emit certain patterns from stale training data. Three enforcement layers catch these before they land:

  1. Custom ESLint pluginno-bare-logger-context (packages/config/plugins/no-bare-logger-context.mjs, PLA-1278) rejects logger context strings that don't match the canonical Module:Function format. 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).

  2. no-restricted-syntax bans in packages/config/eslint.config.mjs — blocks the patterns Claude reliably produces from training data:

    • error as Error casts → use toError(error) from @platform/types
    • process.env.FOO! non-null assertions → use env() / envOptional() from @platform/config
    • Promise.all → use Promise.allSettled with settledVal / settledQuery / logSettledRejections
    • Raw <input type="date">, <input type="email">, etc. → use specialized @platform/ui components
  3. .deprecated-terms grep 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.

TypeScript Strict Mode

  • Explicit types for function signatures, type guards for unknown
  • ?.trim() || "fallback" for database text (empty strings pass through ??)
  • prop?: T | undefined for exactOptionalPropertyTypes
  • 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.ts use typed env from @/env (T3-env, build-time validated, NEXT_PUBLIC_* inlined); apps without one fall back to env() / envOptional() from @platform/config. Never raw process.env.X! (ESLint enforced). The per-app pattern subsumes the old process.env.NEXT_PUBLIC_X ?? "" client-component exception
  • Export surface: only export the public API. Internal helpers = plain function

Promise Handling

  • Promise.all is banned via ESLint — use Promise.allSettled with settledVal(), settledQuery(), logSettledRejections() from @platform/infra/settled. Decision matrix and full pattern: docs/standards/ERROR_HANDLING.md § "Partial failures".

Security

  • Parameterized queries only
  • Input validation with Zod at boundaries
  • Always .trim() env vars used in equality comparisons

UI

  • 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" />}, not icon={Users} — component refs aren't serializable at the Server→Client boundary and Next.js throws a hidden production crash
  • Dialog footers always use DialogFooterActions from @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 import ColumnDef<T> directly; ESLint blocks raw <table> outside emails/print templates
  • Tailwind v4 @source directive required when consuming shared package components

React

  • startTransition breaks native picker inputs — platform Input component skips it for picker types
  • Check existing abstractions before building new ones

Logger

  • Context strings use 'Module:Function' format (e.g., 'Auth:Callback')
  • For Supabase errors, use logSupabaseError() from @platform/logger — preserves .code/.details/.hint

Pre-commit Pipeline

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.

Other Husky Hooks

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)

Quality Automation

Beyond per-commit enforcement, ~60 scheduled and on-demand scripts plus 34 GitHub Actions workflows keep the platform healthy.

GitHub Actions Workflows (34 total)

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 every create*() reference in docs/ops/ADDING_NEW_APP.md still resolves to an exported symbol in packages/. Catches stale onboarding docs before a new app is added.
  • drift-detection.yml — detects when preview and production have diverged beyond the expected merge lag
  • health-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

Scripts Directory (scripts/ — 40+ files)

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

Custom ESLint Plugins (packages/config/plugins/)

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.

Codemods (scripts/codemods/)

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.


Database Migration Discipline

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.

Idempotent Patterns

  • Tables/indexes: IF NOT EXISTS
  • RLS policies: DROP + CREATE (no native IF NOT EXISTS)
  • Every CREATE POLICY must include explicit TO clause (defaults to PUBLIC otherwise)
  • Every migration modifying existing tables: SET LOCAL statement_timeout = '30s'

Schema Creation

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;

Critical

  • RLS without policies = silent deny-all — always create policies in the same migration that enables RLS
  • USING(true) without TO clause grants access to ALL roles
  • Table GRANT checked BEFORE RLS — missing GRANT SELECT causes "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 CONCURRENTLY in migrations — pipeline failure

See the database-migrations skill for the full 7-layer column-drop verification checklist.


Secrets Management

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' not echo for env values. Code must also .trim() env vars defensively.

Testing Patterns

Vitest 4 Signature (CRITICAL)

Options come BEFORE the test function:

it("slow test", { timeout: 15000 }, () => { ... });

Test Isolation (PLA-1249 / 1585 / 1593 / 1594)

7 rules, 4 incidents — leakage between parallel vitest workers is the #1 source of flake.

  • Every setup.ts calls resetTestState() from @platform/test/reset in afterEach
  • Use vi.stubGlobal() not global.X = … (direct writes leak across parallel workers; PLA-1249)
  • Module-scope vi.stubGlobal / vi.spyOn / vi.stubEnv calls in test files must be re-registered in beforeEach because resetTestState() restores them between tests
  • setup.ts files setting env defaults across an entire file must use direct process.env.X = "…" assignments, not vi.stubEnvvi.unstubAllEnvs() only undoes vi.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 an afterAll snapshot restore, preventing leakage into the next file in the same vitest worker (PLA-1593)
  • Exception — vi.hoisted() callbacks: setTestEnv can't be called inside a hoisted body because the helper's import is in TDZ at hoist-time. Write process.env.X = "…" directly inside vi.hoisted and pair with a top-level afterAll(() => { 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 Use the Real-Token Harness (AUTM-1828, June 2026)

RLS tests in tests/db/ authenticate with real signed tokens (createEphemeralUser()admin.generateLinkverifyOtp), 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).

Key Rules

  • 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 exactly
  • vi.clearAllMocks() doesn't drain once-value queues — use mockReset()
  • Class constructor mocks need actual classes, not arrow functions
  • jsdom v27: class-based ResizeObserver mock required
  • Recharts v3.6: formatter params now undefined-able

Critical Gotchas

Tactical "what breaks, why, and how to avoid" — for strategic insights see Key Insights.

  1. Stale .next cache (Next.js monorepos): Type-check fails on unmodified apps. Fix: find apps -name "validator.ts" -path "*/.next/*" -delete

  2. APFS directory hardlinks: Never use rm -rf on hardlinked directories — destroys data at both paths (PLA-448)

  3. Vercel CLI overwrites .env.local: Both vercel link and vercel env pull completely overwrite. Store local-only vars in .env.development.local

  4. cn() silent failures: Tailwind's cn() silently drops invalid class names (hex codes, rgb values). DB color config must store Tailwind class names.

  5. Nested Supabase joins with RLS: Fail silently. Use step-by-step queries instead of nested .select() with !inner

  6. ALTER ROLE SET replaces, doesn't append: Caused a production outage when pgrst.db_schemas was overwritten. Always read current value via pg_options_to_table(), append, then write.

  7. Reserved Bash variables: Avoid status, pipestatus, path

  8. 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.

  9. Linear MCP unified tools: save_issue replaces old create_issue/update_issue. save_comment replaces create_comment. Parameter state not status. Labels replace, not append. Always use project IDs, not names (ambiguous across teams).

  10. Next.js 16 + Turbopack: Apps with outputFileTracingIncludes, outputFileTracingRoot, or serverExternalPackages must build with --webpack. All apps must set NODE_ENV=production in build scripts.

  11. SSE error invisibility: onRequestError does NOT fire for errors inside SSE async pipeline closures. Add explicit Sentry.captureException alongside logger.error.

  12. Auth metadata source mismatch: user_metadata.full_name populated only by Google OAuth. Email/password uses camelCase. Always read from shared.users via getUserIdentity().

  13. .schema() chain may silently route to wrong schema: supabase.schema('appname') returns a PostgrestClient, not a full SupabaseClient. Use adminForSchema().

  14. pnpm override gotchas: Use first_patched_version from Dependabot, not the vulnerable range boundary. Can't fix bundled deps (e.g., Next.js pins webpack).

  15. git checkout --theirs drops new files: After conflict resolution, verify new files exist.

  16. Never bypass pnpm run scripts with raw CLI tools: pnpm run format has NODE_OPTIONS=--max-old-space-size=8192; raw npx prettier OOMs.

  17. Subagents don't inherit current branch (recurring): Always prefix dispatch prompts with git checkout <branch>. Verify with git log --oneline <branch> after. Subagent "DONE" reports aren't trustworthy for git state.

  18. Subagents invoke slash commands unless forbidden: Paste the HARD CONSTRAINTS block (in subagent-stalls.md) verbatim into every dispatch that modifies code. Forbid /commit, --no-verify, pushing, and Linear posts.

  19. 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.

  20. Opus 4.7+ sampling param rejection (carries forward to 4.8): temperature, top_p, top_k 400-error. Platform AI client auto-strips, but direct API callers must update. Thinking budgets also removed — use thinking: {type: "adaptive"}.

  21. $<digit> substitutes silently in command/skill bodies: Claude Code replaces $0, $1, … in commands/*.md and skills/*/SKILL.md at 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.

  22. MCP tool identity is service + suffix, not prefix: Gateway migrations rename every tool (mcp__linear__save_commentmcp__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.

  23. 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 and supabase gen types --local. A test:db "table not found in schema cache" means the migration isn't on preview yet — NOT that local Docker is down. Hook nudge-two-target-supabase.sh warns when a test raw-probes the local port.

  24. 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.sh keeps it read-only.

  25. Two sessions in one worktree silently collide: a foreign session's git checkout/commit hijacks the shared tree. Run one session per worktree; worktree-git-guard.sh blocks foreign-session git mutations (INT-625). See Multi-Instance Safety § Concurrent-Session Safety.


Quick Start for New Setup

  1. Create structuremkdir -p ~/.claude/{rules,skills,commands,docs,hooks,agents,blog/notes,voice,plans,comms/drafts}, then git init + push to private GitHub repo for backup.

  2. Configure settings.json — permissions, ENABLE_TOOL_SEARCH=true, env.CLAUDE_CODE_EFFORT_LEVEL=xhigh (the env var, not the effortLevel key — only the env var beats the model's startup default), alwaysThinkingEnabled: true, attribution, hooks.

  3. Install core plugins — superpowers (dev methodology), episodic-memory (cross-session recall), simmer, documentation-audit, vercel-plugin, LSPs. See Plugin Ecosystem.

  4. Add MCP servers to ~/.claude/.claude.json — prefer PAT/API key auth. See MCP Server Integration.

  5. Write core rules and docs — see Rules System and On-Demand Reference Docs for what belongs in each layer.

  6. Add review agents and a global CLAUDE.md with developer context and repository registry. See Review Triage and Agents and Workflow Profiles.

  7. Set up daily backup — launchd job running tar + git push on ~/.claude/.

  8. Verifyclaude mcp list, inspect rules/skills/hooks/agents, run /global-status.


Key Insights

Strategic observations — "what would someone get wrong without knowing this?" For tactical gotchas see Critical Gotchas.

Architecture

  1. 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-linear and mcp-supabase now activate only when those MCP tools are called.

  2. 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.

  3. /simplify runs 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.

  4. Workflow Profiles are what make /commit project-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.

  5. co-* and ceos-* 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.

  6. The 2026-04-15 consolidation eliminated an entire bug class. The old model (project-level .claude/ with worktree symlinks) produced recurring incidents from git checkout, APFS hardlinks, and permission inheritance. Moving everything to ~/.claude/ with daily backup removed the root cause instead of patching symptoms.

Workflow

  1. 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.

  2. .claude/commands/*.md and .claude/rules/*.md are NOT exempt from review. They get at least LIGHT with prompt-reviewer. Non-obvious because they look like documentation. Prompt instruction files have no compiler — ordering bugs and dead references are only caught by review.

  3. 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.

  4. 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.

  5. 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.

  6. 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 test command 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).

  7. Anti-slop enforcement is its own category. AI agents reliably emit certain patterns from stale training data: error as Error casts, process.env.X! non-null assertions, @clerk/* imports after migration, generic logger contexts. Three enforcement layers catch these: custom ESLint plugins (when no-restricted-syntax can't regex-match), no-restricted-syntax bans (for structural patterns), and .deprecated-terms grep (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.

Configuration

  1. Project-level settings.json breaks 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.

  2. 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).

  3. CompanyOS's GitHub Actions propose-skills.yml creates 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.

  4. 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.

  5. 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?"

  6. 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+.

  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-verify with one of the four canonical exceptions stated to the user (PLA-942 incident).

  8. 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) and plan_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.

  9. A report batched with the action it reports on is a fabrication. A git commit and 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 /commit run 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.

  10. 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.

  11. 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/commit hijacks 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.

@philsimon

Copy link
Copy Markdown

This list is very impressive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment