A comprehensive setup for professional solo development with Claude Code, emphasizing workflow discipline, session persistence, and automated quality gates.
- Philosophy: Global-First Configuration
- File Structure
- Session State Architecture
- The Master Workflow
- Review Triage System
- Workflow Profiles
- Rules System
- Skills Inventory
- Superpowers Plugin
- Commands Inventory
- MCP Server Integration
- Repository Registry
- CompanyOS: Shared Configuration
- Blog and Learning Capture
- Git Workflow Rules
- Multi-Instance Safety (Worktrees)
- Coding Standards
- Database Migration Discipline
- Secrets Management
- Testing Patterns
- Critical Gotchas
- Quick Start for New Setup
- Key Insights
Core Insight: As a solo developer on one machine, preferences should be consistent everywhere. Project-level configuration creates maintenance burden and inconsistency.
| Configuration Type | Location | When to Use |
|---|---|---|
| Permissions, MCP servers | ~/.claude/settings.json |
Always global |
| Coding rules | ~/.claude/rules/ |
Cross-project standards |
| Skills/commands | ~/.claude/skills/ |
Reusable workflows |
| Shared config (two-person) | ~/Code/companyos/ |
CompanyOS skills/rules (symlinked) |
| Project-specific only | project/.claude/ |
Truly unique patterns |
Why this matters:
- One place to update rules = less drift
- Claude Code inherits global config automatically
- Project settings can accidentally override global permissions (causing unexpected prompts)
The Discipline Philosophy: There is no "quick fix mode." Every ticket gets the full workflow. Simple fixes are when discipline matters most — process ensures consistency, documentation, and audit trails.
CRITICAL: Never create project-level .claude/settings.json. When one exists — even with just hooks — Claude Code may not properly inherit path-based permissions from global settings, causing unexpected permission prompts.
~/.claude/
├── settings.json # Permissions, env vars, plugin config
├── CLAUDE.md # Global instructions for Claude
├── rules/ # Coding standards (auto-loaded, 17 files)
│ ├── code-quality.md
│ ├── evidence-first.md
│ ├── commit-recipe.md
│ ├── review-triage.md
│ ├── co-*.md # Symlinked from CompanyOS
│ └── ...
├── skills/ # Auto-invoked based on context (19 file-based skills)
│ ├── linear/
│ ├── testing/
│ ├── co-*/ # Symlinked from CompanyOS
│ ├── ceos-*/ # Symlinked from CEOS
│ └── ...
├── commands/ # User-level slash commands (25 commands)
│ ├── commit.md # Universal commit workflow
│ ├── start.md # Universal ticket start workflow
│ ├── checkpoint.md
│ ├── note.md
│ └── ...
├── comms/
│ └── drafts/ # Email drafts (draft-review-approve loop)
├── blog/
│ └── notes/ # Daily insight capture
│ └── YYYY-MM-DD.md
├── hooks/ # File protection hooks
├── scripts/ # Utility scripts
└── PATTERNS.md # Gotcha graduation journal
~/.claude-personal/
├── CLAUDE.md # Personal context (separate from shared)
├── .claude.json # MCP server configuration
├── voice/ # Writing voice profiles
│ ├── voice-profile.md # Brad's writing rules (hyphens, no AI slop, etc.)
│ └── samples.md # Calibration samples
└── projects/ # Project-specific persistent memory
└── -Users-bfeld-Code-magic0/
└── memory/
└── MEMORY.md # Auto-memory (symlinked across worktrees)
~/Code/companyos/ # Shared two-person config repo
├── skills/co-*/ # 9 skills (symlinked into ~/.claude/skills/)
├── rules/co-*.md # Shared rules (symlinked into ~/.claude/rules/)
├── .claude/commands/ # CompanyOS-specific commands
├── scripts/
│ ├── git-hooks/ # Version-controlled hooks (auto-push, auto-pull)
│ ├── auto-update.sh # Launchd auto-sync (--autostash, failure alerting)
│ ├── co-sync # Manual sync command
│ └── com.intensitymagic.companyos-update.plist
└── setup.sh # Idempotent installer
project/.claude/
├── commands/ # Project-specific slash commands (18 for magic-platform)
│ ├── staging.md
│ ├── production.md
│ └── ...
└── agents/ # Custom agent definitions
The workflow system uses persistent session files that survive context compaction — solving the "amnesia" problem in long Claude sessions.
project/.claude-session/
├── TICKET-XXX.json # Workflow state checkpoint
├── TICKET-XXX-plan.md # Implementation plan (survives compaction)
├── chain-state.json # Chain mode orchestration state
└── checkpoint.md # Full session state (via /checkpoint)
{
"schemaVersion": 1,
"ticket": "PROJ-123",
"ticketUUID": "uuid-here",
"branch": "feature/PROJ-123-add-user-auth",
"project": "my-project",
"targetDir": "/absolute/path/to/project",
"chainInvokingDir": null,
"stashCreated": false,
"stashOriginalBranch": null,
"workflow": {
"currentStep": 15,
"status": "awaiting_user_test",
"blockedActions": ["git commit", "git push"],
"nextAction": "User tests manually, then runs /commit"
},
"sessionRules": ["integration only", "no new dependencies"],
"ticketContext": {
"description": "Full ticket description...",
"comments": [],
"isReopened": false,
"feedbackToAddress": [],
"previousImplementation": null
},
"plan": {
"file": ".claude-session/PROJ-123-plan.md",
"postedToLinear": true
},
"progress": {
"filesModified": ["src/auth.ts", "src/middleware.ts"],
"testsStatus": { "typeCheck": "pass", "lint": "pass" },
"completedTasks": 12,
"totalTasks": 15
}
}- Survives context compaction — Plan and state persist when Claude's context fills
- Prevents accidental commits —
blockedActionsenforces workflow discipline - Enables multi-session work — Resume in different terminal, same state
- Session rules enforcement — Constraints from
/startapply throughout - Reopened ticket handling — Tracks previous implementation and feedback to address
- Chain mode coordination — Tracks multi-ticket progress across context windows
Before ANY git commit, the system checks for session files with status: "awaiting_user_test". If found, commit is BLOCKED:
Cannot commit - session state shows awaiting user test.
Run /commit when ready to review and push.
This prevents bypassing the review workflow.
Use before context is about to compact:
/checkpointSaves: Current ticket and branch, implementation plan, progress, session rules, review status.
Output: .claude-session/checkpoint.md with full state snapshot.
Every ticket follows this exact loop — no exceptions:
/start TICKET-XXX
| Fetch ticket, analyze, create branch, post plan to Linear
| Sets status: "awaiting_user_test" (blocks git commit)
v
Implement locally + manual testing
v
/commit
| Auto-triage review level -> run reviews -> push -> update Linear
v
/staging (when ready to deploy batch — magic-platform only)
| Batch merge feature branches -> deploy -> reset worktrees
v
/production (after staging verification — magic-platform only)
| Health audit -> create PR -> manual merge -> verify -> update Linear
v
LIVE
Note: For direct-to-main repos (CompanyOS, CEOS, Adventures in Claude), /commit IS the deploy — no staging/production steps needed.
The entry point for all ticket work. Creates session state and posts plan to Linear.
| Mode | Usage | Behavior |
|---|---|---|
| Single ticket | /start AUTM-123 |
Full 15-step workflow with plan approval |
| Explicit chain | /start chain AUTM-123 AUTM-124 AUTM-125 |
Sequential autonomous processing of listed tickets |
| Epic chain | /start epic PLA-50 |
Fetch epic children, process eligible tickets sequentially |
Chain mode processes multiple tickets autonomously:
- Plans are auto-approved (no user gate per ticket)
- User testing is skipped (no manual test wait)
/commitruns automatically after each implementation- Chain state persists in
chain-state.jsonfor resume across context windows - Cross-project chains supported (e.g., mix of AUTM and PLA tickets)
- Failure on one ticket doesn't halt the chain — moves to next
| Step | Phase | What Happens |
|---|---|---|
| 0 | Resume check | If session exists, resume from last checkpoint |
| 1 | Project detection | Identify project type from working directory |
| 2 | Pre-flight | Validate git clean, check pattern journal health |
| 3 | Ticket validation | Verify ticket ID format matches expected pattern |
| 4 | Fetch ticket | Get from Linear: title, description, status, priority |
| 5 | Fetch context | Get all comments (oldest first) |
| 6 | Reopened detection | Check for previous work, extract feedback to address |
| 7 | Team-repo validation | Auto-switch repos if ticket belongs elsewhere |
| 7.1 | Load profile | Read Workflow Profile from project CLAUDE.md |
| 7.5 | Session rules | Parse constraints from message ("no new files", "integration only") |
| 8 | Create plan | Plan subagent explores codebase, creates implementation plan |
| 9 | User approval | Present plan, wait for confirmation (skipped in chain mode) |
| 10 | Create branch | feature/TICKET-XXX-description (or stay on main for direct-to-main repos) |
| 11 | Update Linear | Status -> "In Progress", post plan as comment (threaded) |
| 12 | Confirm ready | Show branch, plan location, next steps |
| 13 | Implement | Execute plan tasks with TaskCreate/TaskUpdate tracking |
| 14 | Run quality gates | Profile-driven: type-check, lint, tests |
| 15 | Handoff | Set status: "awaiting_user_test", show test instructions |
/start detects the ticket's team prefix and auto-switches to the correct repository:
| Prefix | Target Repository |
|---|---|
| AUTM, MED, MYH, NEW, PLA, INT | Magic Platform (current worktree) |
| TARS | MagicEA (~/Code/magicea) |
| FRE | Freshell (~/Code/freshell) |
| COS | CompanyOS (~/Code/companyos) |
| CEO | CEOS (~/Code/ceos) |
| AIC | Adventures in Claude (~/Code/adventuresinclaude) |
Reviews code, commits, pushes, and updates Linear. Adapts to each project's Workflow Profile.
| Phase | What Happens |
|---|---|
| 0. Load profile | Detect project, read Workflow Profile from CLAUDE.md |
| 0.5. Session check | Read .claude-session/*.json, verify branch matches |
| 1. Pre-flight | Must be on correct branch, must have changes |
| 2. Quality gates | Run profile.quality_gates commands sequentially |
| 3. Review triage | Auto-detect review level based on changes |
| 4. Review dispatch | NONE: skip / LIGHT: code-reviewer / FULL: parallel agents |
| 4.5. Auto-label | Detect labels from file paths and branch name |
| 5. Commit | Stage, generate message, include ticket reference |
| 6. Push | Push with upstream tracking (or direct to main) |
| 7. Update Linear | Set status per profile, apply labels, post comment (threaded) |
| 8. Summary | Profile-driven output with next steps |
Batch merge feature branches to preview, deploy, and update Linear. Magic Platform only.
| Step | What Happens |
|---|---|
| 1. Validate | Show branches to merge, worktree status |
| 2. Merge | Loop through feature branches, merge to preview |
| 3. Format | pnpm run format, commit formatting changes |
| 4. Push | Push to origin/preview |
| 5. Monitor CI | Poll gh run list every 15s (token-efficient) |
| 5b. Auto-fix | Common failures: format, lint, type errors |
| 6. Update Linear | Extract tickets, parallel update -> "Staging" |
| 7. Cleanup | Delete remote branches, reset worktrees |
Deploy staging to production after approval gates. Magic Platform only.
| Step | What Happens |
|---|---|
| 1. Pre-flight | Must be on preview branch in main worktree |
| 1.5. Marker check | Block if any tickets not "Approved" |
| 2. Health audit | Run environment-health-auditor agent |
| 3-4. Verify + confirm | pnpm run verify:preview, interactive checklist |
| 5. Create PR | preview -> main with ticket list |
| 6-7. CI + merge | Monitor CI, provide URL for manual merge (safety gate) |
| 8. Verify production | pnpm run verify:production (waits 90s for Vercel) |
| 9-11. Finalize | Update Linear -> "Done", changelog reminder |
The system automatically selects review depth based on changes, saving tokens on small changes while maintaining rigor on complex ones.
| Signal | Review Level | What Runs |
|---|---|---|
| < 3 files, app-only, no sensitive paths, no behavior changes | NONE | Skip reviews entirely |
| 3-9 files, or behavior changes (server actions, hooks, deps) | LIGHT | Quick code-reviewer (single agent) |
| 10+ files, or 200+ lines | FULL | Parallel multi-agent review |
Touches packages/* or sensitive paths |
FULL | Always (shared code / security) |
| Epic child ticket | FULL+ | spec-reviewer + code-reviewer |
| Docs/tests/config/styling only | NONE | Exempt regardless of file count |
Even a 1-file change triggers at least LIGHT review when it modifies:
- Server actions (
actions.ts) - API routes (
route.ts,api/) - React hooks (
hooks/,use*.ts) - Production dependencies (
package.json) - Database queries/services (
services/,queries/)
**/auth/** **/middleware/** **/rls/**
**/payment/** **/billing/** **/stripe/**
**/webhook/** **/cron/** **/admin/**
supabase/migrations/*
Up to 5 agents run in parallel based on file types:
| Agent | Triggers On | Focus |
|---|---|---|
| code-reviewer | Always at FULL | Code quality, patterns, bugs |
| ui-consistency-reviewer | .tsx files |
Design system, accessibility |
| silent-failure-hunter | API routes, services | Error handling, unhandled promises |
| security-auditor | Auth, migrations | RLS, SQL injection, CSRF |
| test-quality-reviewer | Test files | Assertions, edge cases, reliability |
Each repository defines a Workflow Profile in its CLAUDE.md that drives /start and /commit behavior. This replaces hardcoded per-project logic with declarative configuration.
| Field | Description | Example Values |
|---|---|---|
workflow.base_branch |
Base for feature branches | preview, main |
workflow.direct_to_main |
Skip feature branches | true / false |
workflow.investigation |
Explore agent depth | full / light |
workflow.plan_approval |
Require user approval of plans | required / auto |
workflow.user_testing |
Manual testing gate | required / optional / skip |
workflow.quality_gates |
Commands to run before commit | ["pnpm run type-check"] |
workflow.review.triage |
Enable review triage | true / false |
workflow.review.max_level |
Cap review depth | NONE / LIGHT / FULL |
workflow.ship.method |
How to ship code | direct_push / pr |
workflow.ship.linear_status |
Status to set on commit | "In Progress" / "Done" |
workflow.ship.deploy_hint |
What to do after commit | "/staging", "git push" |
| Profile Field | Magic Platform | MagicEA | Freshell | CompanyOS | CEOS | WP |
|---|---|---|---|---|---|---|
base_branch |
preview | main | main | main | main | main |
direct_to_main |
false | false | false | true | true | true |
quality_gates |
type-check, lint | type-check | npm test | (none) | (none) | (none) |
review.max_level |
FULL | LIGHT | LIGHT | NONE | NONE | NONE |
ship.method |
pr (deferred) | pr | pr | direct_push | direct_push | direct_push |
ship.linear_status |
In Progress | In Progress | In Progress | Done | Done | Done |
ship.deploy_hint |
/staging | /deploy-ea | Maintainer merge | Auto-push | git push | deploy.sh |
Rules in ~/.claude/rules/*.md are automatically loaded into every Claude session. Each rule file is focused and actionable.
| Rule File | Key Points |
|---|---|
| evidence-first.md | Never assert about code without reading it first. Tools first, conclusions second |
| scope-intent.md | Match response scope to request. Review mode = report only. Don't over-engineer process |
| output-formatting.md | Include required formatting on first attempt. Always output full URLs and file paths |
| protected-workflows.md | Never bypass skill commands (/commit, /staging, etc.) with manual git |
| parallel-patterns.md | When to parallelize with Task agents. Subagents need full inline context |
| skill-authoring.md | Description = WHEN to invoke, not WHAT it does. Command delegation rule |
| Rule File | Key Points |
|---|---|
| code-quality.md | TypeScript strict, avoid any, ?.trim() || "fallback" for DB text, pre-existing monorepo errors |
| testing-vitest.md | Mock at factory level, Vitest 4 signatures, waitFor assertions only, vi.mock() path matching |
| bash-patterns.md | Reserved variables (status, path), multi-line in loops, grep exit codes with set -e |
| Rule File | Key Points |
|---|---|
| commit-recipe.md | Shared commit structure for all projects, quality gates, pre-commit hook discipline |
| review-triage.md | NONE/LIGHT/FULL triage logic, behavior change overrides, agent selection |
| mcp-server-config.md | Prefer PAT/API key auth over OAuth, user-scope config in ~/.claude-personal/.claude.json |
| mcp-linear.md | Labels replace (not append), id vs issueId, state not status |
| learning-capture.md | Auto-capture insight blocks, suggested discovery capture, gotcha graduation |
| Rule File | Key Points |
|---|---|
| co-company-context.md | Company info, people, products, communication conventions |
| co-skill-patterns.md | Quality checklist and template for CompanyOS skills |
| co-protected-workflows.md | Never send emails without draft-review-approve loop |
These live in project/.claude/rules/ and are loaded only in that project:
| Rule File | Key Points |
|---|---|
| ui-patterns.md | Semantic color tokens (never hardcoded), @platform/ui first, app visual identity |
| ci-pipeline.md | CI polling (never gh run watch), production merge sync pattern |
| database-migrations.md | Git is source of truth, CLI-first, idempotent SQL, RLS DROP+CREATE |
| production-safety.md | ALTER ROLE SET replaces (not appends). Read pg_roles.rolconfig before modifying |
| env-local-protection.md | Vercel CLI overwrites .env.local. Use .env.development.local for local Supabase |
| nextjs-monorepo.md | Stale .next cache causes false type-check failures. Clean validator.ts files |
| vercel-operations.md | Shell escaping in Ignored Build Step. Use heredoc to avoid \!= |
| jsonb-naming.md | Database JSONB = snake_case, TypeScript = camelCase, conversion layer |
| mcp-resend.md | Domain-scoped API keys. Wrong key = silent send failure |
Skills in ~/.claude/skills/ are auto-invoked based on context. They encode domain expertise and enforce discipline.
| Skill | Trigger Context | Purpose |
|---|---|---|
| testing | Writing/debugging tests | Vitest, Playwright, mocking patterns |
| supabase | Database operations | Queries, migrations, RLS debugging |
| vercel | Deployment issues | Build failures, environment management |
| linear | Ticket management | Issue operations, workflow updates |
| context7 | Library docs | Up-to-date API documentation lookup |
| notion | Documentation | Notion pages, databases |
| sentry | Error monitoring | Investigate errors, view trends |
| oauth | Auth integrations | Social provider setup |
| performance | Slow pages | Bundle optimization, Core Web Vitals, React render optimization |
| mobile | Mobile UI work | Responsive patterns, touch targets |
| Skill | Trigger Context | Purpose |
|---|---|---|
| form-patterns | Form development | Dirty state, validation, unsaved changes |
| ceos-lma | EOS assessment | Leadership and management accountability framework |
| Skill | Trigger Context | Purpose |
|---|---|---|
| co-ops | Company operations | Decisions, contacts, conventions |
| co-comms | Business communications | Draft-review-approve loop, tone guidelines, voice profile |
| co-content | Marketing content | Blog posts, announcements, social copy |
| co-feedback | User feedback | Triage, analyze patterns, respond |
| co-calendar | Scheduling | Meeting prep, time awareness |
| co-secrets | API keys, credentials | GCP Secret Manager operations |
| co-search | Cross-tool search | Find info across Linear, Gmail, Notion, Help Scout, Sentry, Drive |
| co-launch | Product launches | Launch planning and coordination |
| co-support | Customer support | Help Scout integration, support workflow |
The co-comms skill uses a voice profile at ~/.claude-personal/voice/voice-profile.md to match Brad's writing style:
- Hyphens with spaces for asides ( - ), never em dashes
- Short sentences, 1-3 sentence paragraphs
- No hedging, no corporate language, no AI slop words
- No greeting line, no sign-off
- Per-recipient calibration via Gmail history (when MCP available)
The superpowers plugin (superpowers@superpowers-marketplace) provides a core development methodology that auto-updates via the plugin marketplace. It adds skills for debugging, verification, brainstorming, plan writing/execution, code review, TDD, and subagent-driven development.
| Skill | When Invoked | Purpose |
|---|---|---|
| systematic-debugging | Bug reports, errors, test failures | 4-phase root cause analysis before any fix |
| verification-before-completion | Before claiming work is done | Require fresh evidence (tests, builds) |
| writing-plans | Complex multi-step implementation | Create plans with 2-5 minute atomic tasks |
| executing-plans | Have a plan to execute | Task-by-task with review checkpoints |
| brainstorming | Before any creative/feature work | Explore intent, requirements, design before code |
| test-driven-development | Before writing implementation | Write failing tests first, then implement |
| requesting-code-review | After completing features | Structured code review request |
| receiving-code-review | After getting review feedback | Technical rigor, not performative agreement |
| dispatching-parallel-agents | 2+ independent tasks | Parallel subagent orchestration |
| subagent-driven-development | Plans with independent tasks | Execute plan tasks via parallel agents |
| using-git-worktrees | Need isolation for feature work | Smart worktree creation and management |
| finishing-a-development-branch | Implementation complete | Merge, PR, or cleanup decision guide |
| writing-skills | Creating/editing skills | Skill authoring with verification |
| using-superpowers | Start of conversation | Establishes skill discovery patterns |
Plugin skills auto-update independently of the repository. When superpowers publishes a new debugging technique or verification pattern, all sessions get it automatically without commits or manual updates.
Commands are explicit slash commands invoked by the user. /start and /commit are user-level (work across all 7 repositories).
Available in all projects:
| Command | Purpose |
|---|---|
/start |
Begin work on a Linear ticket (with chain and epic modes) |
/commit |
Review, commit, push, update Linear (profile-driven) |
/deploy-ea |
Deploy MagicEA to DigitalOcean |
/freshell |
Freshell-specific operations |
| Command | Purpose |
|---|---|
/checkpoint |
Save full session state before context compaction |
/rules |
Add session rules that persist across compaction |
/verify-branch |
Verify correct git branch for current work |
/git-clean |
Clean up git state |
| Command | Purpose |
|---|---|
/note |
Capture a learning or interesting technique |
/learn |
Graduate a pattern to permanent rules/skills |
/til |
Extract an atomic learning for GitHub TIL repo |
/blogaic-draft |
Generate blog post draft from captured daily notes |
/blogaic-post |
Publish a blog post to Adventures in Claude |
/blog-feld |
Blog operations for feld.com |
| Command | Purpose |
|---|---|
/screenshot |
View and analyze most recent Desktop screenshot |
/view |
Visually inspect a file (image, PDF, HTML) |
/diagnose |
Investigate system resource issues (memory, CPU) |
/global-status |
Universal project health check |
/validate |
Type-check + lint + build verification |
/secrets-scan |
Security scan for secrets in code |
/linear-image |
View images attached to Linear tickets |
| Command | Purpose |
|---|---|
/test |
Generate tests or run test coverage campaign |
/localhost |
Open local dev server |
/done-color |
Change terminal background when Claude finishes |
/pr |
Create a pull request |
/start-epic |
Legacy epic starter (now integrated into /start epic) |
Specific to the Magic Platform monorepo (project/.claude/commands/):
| Command | Purpose |
|---|---|
/staging |
Batch merge to preview, deploy |
/production |
Deploy to production with safety gates |
/validate |
Type-check + lint + build (project-scoped) |
/verify |
Verify deployment health |
/review |
Code review current changes |
/review-codebase |
Broader codebase review |
/health |
Infrastructure health check |
/sweep |
Cross-codebase cleanup operations |
/cleanup |
Clean up after staging/production |
/whats-next |
Suggest next ticket to work on |
/ui |
UI component operations |
/backup |
Backup secrets to Google Drive |
/blog-new |
Create new blog post |
/blog-edit |
Edit existing blog post |
/blog-publish |
Prepare blog post for publication |
/blog-idea |
Brainstorm blog post ideas |
/migration-baseline |
Database migration baseline |
/start-epic |
Epic workflow (project-level version) |
| Command | Purpose |
|---|---|
/co-create-skill |
Generate a new CompanyOS skill from description |
Each MCP server is configured individually with direct connections. Tool Search (ENABLE_TOOL_SEARCH=true) enables lazy loading — tools are discovered on-demand rather than loaded upfront, saving ~5k tokens per server in context.
OAuth tokens stored in macOS Keychain use version-specific keys. When Claude Code updates, previous tokens are orphaned. PAT/API key auth survives updates — only Vercel still requires OAuth.
| Server | Transport | Auth Method | Survives Updates? | Purpose |
|---|---|---|---|---|
| linear | HTTP | Bearer PAT (lin_api_) |
Yes | Issue tracking, ticket management |
| supabase | HTTP | Bearer PAT (sbp_) |
Yes | Database queries, project management |
| stripe | HTTP | Bearer restricted key (rk_) |
Yes | Billing, subscriptions |
| context7 | HTTP | API key header | Yes | Up-to-date library documentation |
| betterstack | HTTP | Bearer API key | Yes | Uptime monitoring, incidents |
| vercel | HTTP | OAuth (Keychain) | No | Deployment management |
| sentry | Stdio | Env var (SENTRY_ACCESS_TOKEN) |
Yes | Error monitoring |
| notion | Stdio | Env var (NOTION_TOKEN) |
Yes | Documentation, databases |
| firecrawl | Stdio | Env var (FIRECRAWL_API_KEY) |
Yes | JS-rendered web scraping |
| helpscout | Stdio | Env vars (app ID + secret) | Yes | Customer support inbox |
| google-workspace | Stdio | Google OAuth client creds | Yes | Gmail, Calendar, Drive, Docs, Sheets |
| claude-in-chrome | Built-in | Extension | Yes | Browser automation (read pages, fill forms, navigate) |
Instead of loading all tool schemas from all servers upfront (thousands of tokens), tools are deferred:
// 1. Search for tools by keyword
ToolSearch({ query: "linear issues" })
// Returns: mcp__linear__list_issues, mcp__linear__get_issue, ...
// 2. Call the tool directly (now loaded)
mcp__linear__get_issue({ id: "PROJ-123" })CRITICAL: User-scope MCP config lives in ~/.claude-personal/.claude.json, NOT ~/.claude.json. Never manually edit JSON. Always use CLI:
# HTTP servers with Bearer token (preferred — survives updates)
claude mcp add --transport http --scope user linear https://mcp.linear.app/mcp \
--header "Authorization: Bearer lin_api_XXXX"
claude mcp add --transport http --scope user supabase https://mcp.supabase.com/mcp \
--header "Authorization: Bearer sbp_XXXX"
# HTTP servers with API key header
claude mcp add --transport http --scope user context7 https://mcp.context7.com/mcp \
--header "CONTEXT7_API_KEY: $KEY"
# Stdio servers with environment variables
claude mcp add --transport stdio --scope user -e SENTRY_ACCESS_TOKEN=sntryu_XXXX sentry \
-- npx -y @sentry/mcp-server@latest
# Verify
claude mcp list| Service | Approach | Why |
|---|---|---|
| GitHub | CLI (gh ...) |
Full feature access, auth configured |
| Supabase mutations | CLI + migrations | Git-based audit trail |
| Vercel CLI | Direct (npx vercel ...) |
More reliable for env operations |
Seven repositories, all accessible via /start TICKET-XXX with auto-switching:
| Repository | Location | Linear Prefix | Base Branch | Ship Method | Deploy |
|---|---|---|---|---|---|
| Magic Platform | ~/Code/magic0-7 |
AUTM, MED, MYH, NEW, PLA, INT | preview |
PR (via /staging) | /staging + /production |
| MagicEA | ~/Code/magicea |
TARS | main |
PR | /deploy-ea |
| Freshell | ~/Code/freshell |
FRE | main |
PR (upstream) | Maintainer merge |
| CompanyOS | ~/Code/companyos |
COS | main |
Direct push | Auto-push hook |
| CEOS | ~/Code/ceos |
CEO | main |
Direct push | git push |
| Adventures in Claude | ~/Code/adventuresinclaude |
AIC | main |
Direct push | Vercel auto-deploy |
| WordPress Sites | ~/Code/wp |
WP | main |
Direct push | deploy.sh |
| Model | Repos | Commit Status | Why |
|---|---|---|---|
| Pipeline (3-tier) | Magic Platform | In Progress | /staging -> /production advance status |
| Feature branch + PR | MagicEA, Freshell | In Progress | PR/deploy advances status |
| Direct-to-main | CompanyOS, CEOS, AIC, WP | Done | Commit IS the deploy |
CompanyOS is a shared git repository for two-person company configuration — skills, rules, decisions, and operational knowledge.
~/Code/companyos/
├── skills/co-*/ # 9 shared skills (symlinked into ~/.claude/skills/)
├── rules/co-*.md # Shared rules (symlinked into ~/.claude/rules/)
├── .claude/commands/ # CompanyOS-specific commands
├── co-skill-rules.json # Trigger definitions for co-* skills
├── mcp-registry.json # MCP servers to auto-configure
├── scripts/
│ ├── git-hooks/ # Version-controlled hooks
│ │ ├── pre-commit # Auto-pull --autostash before commit
│ │ ├── post-commit # Auto-push after commit
│ │ └── post-merge # Auto-run setup.sh after pull
│ ├── auto-update.sh # Launchd-driven sync (--autostash, failure alerting)
│ ├── co-sync # Manual sync command
│ └── com.intensitymagic.companyos-update.plist
└── setup.sh # Idempotent installer
Changes propagate automatically between users:
User A commits in CompanyOS
| pre-commit hook: git pull --ff-only --autostash (handles dirty working tree)
v
Commit happens
| post-commit hook: git push origin main
v
User B's launchd (every 30 min)
| auto-update.sh: git pull --ff-only --autostash
| On failure: increment counter, alert every 3rd consecutive failure (macOS notification)
v
| post-merge hook: setup.sh runs
v
User B has new skills/rules symlinked
The auto-sync script tracks consecutive failures and alerts when stale:
- File-based counter at
~/.companyos-update-failures - Resets to 0 on successful pull
- macOS notification every 3rd consecutive failure
- Prevents silent staleness (previously went 6 days unnoticed)
Run once to configure everything, safe to re-run anytime:
- Symlinks
skills/co-*/into~/.claude/skills/ - Symlinks
rules/co-*.mdinto~/.claude/rules/ - Merges
co-skill-rules.jsoninto~/.claude/skills/skill-rules.json - Configures MCP servers from
mcp-registry.json(check-before-add) - Sets up Google Workspace MCP (if not configured)
- Configures
git core.hooksPathto use version-controlled hooks
A subsystem for capturing insights during development and turning them into blog content.
Every Insight block generated during work is automatically appended to daily notes:
File: ~/.claude/blog/notes/YYYY-MM-DD.md
## [HH:MM] category - Worktree: magicN
**Context:** Branch name or what you were working on
**Note:** The insight content as a cohesive paragraph
**Related:** Files, tickets, or conceptsCategories: gotcha, deep-dive, magic-trick, day-in-life, insight
Entries categorized as gotcha are automatically added to ~/.claude/PATTERNS.md — a permanent journal of surprising behaviors and edge cases.
During development, Claude suggests capturing discoveries for blog content when it encounters high-value triggers (surprising behavior, clever solutions, long debugging sessions, architectural decisions). Max 3 suggestions per hour, respects user flow.
| Command | Purpose |
|---|---|
/note |
Manually capture a learning |
/learn |
Graduate a pattern to permanent rules/skills |
/til |
Extract atomic learning for GitHub TIL repo |
/blogaic-draft |
Aggregate daily notes into blog post draft |
/blogaic-post |
Publish post to Adventures in Claude blog |
Daily work -> Insight blocks (auto-captured) -> /blogaic-draft (aggregation) -> Blog post
-> Gotchas graduate to PATTERNS.md
-> /learn graduates to rules/skills
Never commit directly to main (production) or preview (staging). Pre-commit hooks block this automatically.
Exception: Direct-to-main repos (CompanyOS, CEOS, Adventures in Claude, WP) commit directly to main per their Workflow Profile.
feature/TICKET-XXX-description— New featuresfix/description— Bug fixesrefactor/description— Code restructuring
<type>: <description>
[Optional body explaining WHY]
Refs TICKET-XXX
Types: feat:, fix:, refactor:, docs:, chore:, test:
Note: Co-author attribution is added automatically by settings.json attribution.commit. Do not add it manually.
NEVER bypass with --no-verify except for two documented exceptions:
- Merge commits in
/stagingor merge fix commits onpreviewduring/production - Pre-existing type errors in unrelated packages — errors in apps you didn't modify and don't depend on. Document skipped errors in the commit message.
Never use gh run watch — outputs 13K+ lines and overflows context.
Self-contained polling:
SHA=$(git rev-parse HEAD)
for i in {1..60}; do
result=$(gh run list --workflow "CI/CD Pipeline" -L5 \
--json databaseId,headSha,status,conclusion \
-q ".[] | select(.headSha==\"$SHA\") | \"\(.databaseId),\(.status),\(.conclusion)\"" | head -1)
[[ -z "$result" ]] && { sleep 10; continue; }
IFS=',' read -r run_id run_status conclusion <<< "$result"
echo "Run $run_id: $run_status ${conclusion:+($conclusion)}"
[[ "$run_status" == "completed" ]] && break
sleep 15
doneAfter every production squash merge (preview -> main), sync preview with main's ancestry:
git checkout preview
git fetch origin main
git merge -s ours origin/main -m "chore: sync preview with main after production release"
git push origin previewKey distinction:
| Command | What it does | When to use |
|---|---|---|
git merge -s ours |
Keeps our tree exactly, records ancestry | Post-production sync |
git merge -X ours |
Resolves conflicts favoring ours | NEVER for post-production sync |
For running multiple Claude Code sessions simultaneously:
- Each session = different worktree
- Each worktree = different branch (never same branch in two places)
- Commit before switching between sessions
- Never modify main/preview in any worktree
Formula: PORT = 3000 + (worktree * 10) + app_slot
| App | Slot | magic0 | magic1 | magic2 | ... | magic7 |
|---|---|---|---|---|---|---|
| AuthorMagic | 0 | 3000 | 3010 | 3020 | ... | 3070 |
| MedicareMagic | 1 | 3001 | 3011 | 3021 | ... | 3071 |
| IntensityMagic | 2 | 3002 | 3012 | 3022 | ... | 3072 |
| MyHealthMagic | 3 | 3003 | 3013 | 3023 | ... | 3073 |
| Book Sites | 4 | 3004 | 3014 | 3024 | ... | 3074 |
| NewsletterMagic | 5 | 3005 | 3015 | 3025 | ... | 3075 |
All worktrees (magic1-7) symlink env files to magic0:
magic1/apps/*/web/.env.local -> magic0/apps/*/web/.env.local
magic1/apps/*/web/.env.development.local -> magic0/apps/*/web/.env.development.local
A sync script (scripts/sync-claude-config.sh) manages Claude config symlinks across worktrees with safety guards:
- Blocks magic0 as sync target (it's the source)
- Automated daily backups via launchd ->
~/.claude-backups/ - Manifest validation (
--check) catches partial recovery
// Explicit types for function signatures
function processUser(user: User): ProcessedUser { ... }
// Type guards for unknown
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value;
}
// Handle null/undefined explicitly
const name = user?.profile?.name ?? 'Unknown';?? only handles null/undefined, not empty strings:
const title = dbRecord.title ?? "Untitled"; // "" stays ""
const title = dbRecord.title?.trim() || "Untitled"; // handles all three// Parameterized queries ONLY
await db.query('SELECT * FROM users WHERE id = $1', [userId]);
// Input validation at boundaries with Zod
const userInput = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
}).parse(req.body);try {
await riskyOperation();
} catch (error) {
logger.error('Operation failed', {
operation: 'riskyOperation',
userId: user.id,
error: error instanceof Error ? error.message : String(error),
});
throw new UserFacingError('Unable to complete operation');
}Never hardcode Tailwind colors. Always use semantic tokens:
// BAD: Hardcoded
<div className="bg-white text-gray-900 border-gray-200">
// GOOD: Semantic
<div className="bg-card text-foreground border-border">Visual differences between apps come from CSS variable values in each app's globals.css, not different class names.
Git is the source of truth for migrations. Every migration must:
- Be a file in
supabase/migrations/ - Be committed to git BEFORE any remote database has it
- Be applied to environments via CI/CD (not MCP or manual SQL)
supabase migration new add_user_preferences # Create file
# Edit the SQL
supabase db reset # Test locally
git add supabase/migrations/ && git commit # Commit-- Tables and indexes: IF NOT EXISTS
CREATE TABLE IF NOT EXISTS my_table (...);
-- RLS Policies: DROP + CREATE (no IF NOT EXISTS support)
DROP POLICY IF EXISTS "policy_name" ON my_table;
CREATE POLICY "policy_name" ON my_table FOR SELECT USING (...);ALTER ROLE SET REPLACES the entire parameter value, it does NOT append. This caused a production outage when pgrst.db_schemas was overwritten.
-- SAFE: Read first, then modify
DO $$
DECLARE current_schemas TEXT;
BEGIN
SELECT option_value INTO current_schemas
FROM pg_options_to_table(
(SELECT rolconfig FROM pg_roles WHERE rolname = 'authenticator')
) WHERE option_name = 'pgrst.db_schemas';
IF current_schemas NOT LIKE '%newschema%' THEN
EXECUTE format('ALTER ROLE authenticator SET pgrst.db_schemas TO %L',
current_schemas || ', newschema');
END IF;
END $$;
NOTIFY pgrst, 'reload config';Secrets are stored in GCP Secret Manager (project: authormagic-480416). No persistent plaintext vault on disk — sync scripts auto-regenerate from GCP SM on demand.
| Script | Purpose |
|---|---|
scripts/secrets-regenerate-vault.sh |
Download all secrets from GCP SM |
scripts/secrets-sync-env.sh [app] [env] |
Generate .env.local for an app |
scripts/secrets-sync-vercel.sh [app] [env] |
Push env vars to Vercel |
scripts/secrets-validate.sh |
Validate vault completeness |
Each sending domain has its own Resend API key. Using the wrong key causes silent send failure:
| From Domain | Vault Path |
|---|---|
authormagic.com |
authormagic.resend.api_key |
intensitymagic.com |
intensitymagic.resend.api_key |
mynewslettermagic.com |
newslettermagic.resend.api_key |
# 1. Add to GCP Secret Manager
printf '%s' 'value' | gcloud secrets create name --project=authormagic-480416 --data-file=-
# 2. Regenerate local .env.local
./scripts/secrets-sync-env.sh app/web local
# 3. Push to Vercel (no vercel link needed!)
vercel env add VAR_NAME preview --force
vercel env add VAR_NAME production --forceCRITICAL: Never run vercel link just to add env vars. Projects are already linked via .vercel/. vercel link overwrites .env.local.
Options come BEFORE the test function:
// Vitest 4
it("slow test", { timeout: 15000 }, () => { ... });// BAD: Low-level SDK mock — factory initialization still runs
vi.mock("@supabase/supabase-js", () => ({ createClient: vi.fn() }));
// GOOD: Mock the factory your code actually calls
vi.mock("@/lib/supabase/factory", () => ({
SupabaseClients: { admin: () => mockClient },
}));Never put async operations inside waitFor callbacks. They fire on EVERY retry:
// GOOD: actions outside, assertions inside
await user.click(button);
await waitFor(() => {
expect(button).toBeDisabled();
});vi.mock()path must match import path — mismatched paths are silently ignoredvi.clearAllMocks()doesn't drain once-value queues — usemockReset()to prevent cross-test leaksNODE_ENVis"test"in Vitest — not"development"- Vitest doesn't resolve package.json exports — add vitest.config aliases for
@platform/ui/* - Class constructor mocks — arrow functions lack
[[Construct]], useclass MockClass { ... }pattern
Symptom: Type-check fails on apps you didn't modify:
.next/types/validator.ts: Cannot find module '../../src/app/page.js'
Fix:
find apps -name "validator.ts" -path "*/.next/*" -deleteNEVER use rm -rf on an APFS hardlinked directory. Both directory entries share child inodes — rm -rf destroys data at BOTH paths.
Both vercel link and vercel env pull completely overwrite .env.local. Protection: Store local-only vars in .env.development.local.
Tailwind's cn() silently drops invalid class names (hex codes, rgb values).
Use step-by-step queries instead of nested .select() with !inner.
See Database Migration Discipline — caused a production outage.
| Avoid | Use Instead | Why |
|---|---|---|
status |
run_status |
zsh read-only |
pipestatus |
pipe_result |
zsh reserved |
path |
file_path |
PATH conflict on macOS |
Only affects Vercel (the last OAuth server). All other MCP servers now use PAT/API key auth that survives updates.
mkdir -p ~/.claude/{rules,skills,commands,blog/notes}
mkdir -p ~/.claude-personal/voice
touch ~/.claude/CLAUDE.md
mkdir -p project/.claude/{commands,session}# HTTP servers with Bearer token
claude mcp add --transport http --scope user linear https://mcp.linear.app/mcp \
--header "Authorization: Bearer lin_api_XXXX"
claude mcp add --transport http --scope user supabase https://mcp.supabase.com/mcp \
--header "Authorization: Bearer sbp_XXXX"
claude mcp add --transport http --scope user stripe https://mcp.stripe.com/ \
--header "Authorization: Bearer rk_test_XXXX"
# HTTP servers with API key header
claude mcp add --transport http --scope user context7 https://mcp.context7.com/mcp \
--header "CONTEXT7_API_KEY: $KEY"
claude mcp add --transport http --scope user betterstack https://mcp.betterstack.com \
--header "Authorization: Bearer $KEY"
# Stdio servers with environment variables
claude mcp add --transport stdio --scope user -e SENTRY_ACCESS_TOKEN=sntryu_XXXX sentry \
-- npx -y @sentry/mcp-server@latest
claude mcp add --transport stdio --scope user -e NOTION_TOKEN=ntn_XXXX notion \
-- npx -y @notionhq/notion-mcp-server
# OAuth (only if no PAT option exists)
claude mcp add --transport http --scope user vercel https://mcp.vercel.com
# Verify
claude mcp listAdd to ~/.claude/settings.json env section:
{ "env": { "ENABLE_TOOL_SEARCH": "true" } }// In ~/.claude/settings.json
{ "plugins": ["superpowers@superpowers-marketplace"] }Essential files for ~/.claude/rules/:
evidence-first.md— Read before assertingcode-quality.md— TypeScript strict, error handlingcommit-recipe.md— Shared commit structurereview-triage.md— Auto-detect review depthscope-intent.md— Match response to requestprotected-workflows.md— Don't bypass skill commands
# Global Claude Code Configuration
## Developer Context
Solo developer, one machine, multiple concurrent workspaces via worktrees.
## Workflow Discipline
Every ticket gets the full workflow:
1. /start TICKET-XXX
2. Implement
3. /commit
No exceptions. No "quick fixes."
## Session State
Check .claude-session/ for current ticket state.
Respect blockedActions when status is "awaiting_user_test".
## Key Rules
See ~/.claude/rules/ for standards.
Evidence-first: read before asserting.
Root cause: trace before fixing.claude mcp list # All servers connected
ls ~/.claude/rules/ # Rules loaded
ls ~/.claude/skills/ # Skills available-
Session state solves context amnesia — The
.claude-session/directory creates "process memory" that survives context compaction. -
Review triage saves tokens without sacrificing quality — Automatic NONE/LIGHT/FULL selection handles most commits without agent overhead while maintaining rigor on complex changes.
-
Tool Search transforms MCP economics — Lazy loading tools on-demand saves ~5k tokens per server, making 12 MCP servers practical without overwhelming context.
-
PAT/API key auth over OAuth — Migrating from OAuth to PAT/API key for MCP servers eliminates the reauth-on-update problem. Only Vercel still requires OAuth.
-
Evidence-first prevents confident wrong answers — Requiring source reading before assertions catches the "sounds right but isn't" failure mode.
-
Workflow Profiles make commands project-agnostic —
/startand/commitwork across 7 repositories by reading declarative config instead of hardcoded logic. -
Chain mode enables batch ticket processing —
/start chainand/start epicprocess multiple tickets autonomously with auto-approval and auto-commit. -
Global-first reduces cognitive load — One place for standards means less drift and easier maintenance across 7 repositories.
-
Worktrees enable true parallelism — Multiple Claude sessions can work simultaneously without conflicts.
-
The description trap wastes skill potential — If a skill description summarizes workflow, Claude may skip the detailed body.
-
CompanyOS makes config collaborative — Git hooks + launchd auto-sync means shared skills/rules propagate without manual steps. Failure alerting prevents silent staleness.
-
Superpowers plugin auto-updates methodology — Core development patterns (debugging, verification, TDD) improve automatically without manual updates.
-
Voice profile calibration — Per-recipient tone matching via Gmail history produces natural-sounding communications, not generic AI output.
-
ALTER ROLE SET is a replace operation — This production outage taught the universal rule: always read current state before modifying shared configuration.
-
Self-describing data prevents drift — When the data itself describes how it should be processed, adding new items never requires script changes.
Configuration patterns from a two-person company setup optimized for workflow discipline, session persistence, knowledge capture, and automated quality gates with Claude Code. Last updated: 2026-02-16.