← Series Hub
Builder's Guide
Companion to Two Suits · 20 min read · 11 stops · 3 modes each · Graphic novel →

The architecture, as a map.

Eleven stations on the line. At every stop, three ways to do it: run the skill, prompt your own AI, or do it by hand. Hover any underlined term for a plain-English definition.

Fork the stack on GitHub

First time? You probably want Start Here — a Friendly Walkthrough instead. It's the same thing but warmer, with no jargon, written for someone opening a terminal for the first time. This page is the technical companion for builders.

How to use this guide

Pick the mode that fits your moment.

Every stop on the map below offers three paths to the same finish line. Whichever you pick, you'll end with the same working piece of the stack. Pick by how much time and brain you want to spend right now.

Mode 1 · Auto
Run the skill
Invoke one slash command (like /exoskeleton-install). The skill walks the whole stop for you. You watch what happens and learn by reading along. Fastest path. Recommended for first-time runs.
Mode 2 · Self-prompt
Have your AI do it
Copy a ready-made prompt block, paste into your own Claude (or ChatGPT, Cursor, anything). Adjust the bracketed parts for your stack. Your AI does the work; you adjust as it goes.
Mode 3 · Manual
Do it yourself
Type every command, write every file. Slowest path; most instructive. Best when you want to truly own the muscle of how each piece works.
Step 0 · before any "Mode 1" works. The /exoskeleton-* slash commands ship in the bundle — install it into your AI's skills folder first, then everything below becomes invokable.
git clone https://github.com/c-merkel/exoskeleton.git .claude/skills/exoskeleton
claude
> /exoskeleton-install
Codex CLI users: clone to .codex/skills/exoskeleton and run codex instead. Once /exoskeleton-install is running, the orchestrator dispatches the right sub-skill for every station below — let it drive and use this page as the reference for what's happening under the hood. Full skill-bundle reference at the bottom →
Pressed for time? Skim only the takeaway and the schematic at each stop — that's the 30-second version of every chapter. Or, if you only build three things: Memory (04) · Guards (06) · Layers (07). Those three give you most of the leverage.
Platform support. macOS and Linux work out of the box — the guards are bash + python3. On Windows, run Claude Code inside WSL2 (the documented path for Claude Code on Windows anyway). Native PowerShell or cmd is not supported and there's no plan to add it — the asymmetry these guards depend on lives in the POSIX shell, not Windows shells.
Stop 01 · Setup
≈ 15 min

The Workshop.

Your local development environment must mirror what production will look like. Build the workshop first — everything else depends on it.

Three rules: same container shape as production; a live preview answering its own URL; one command brings the whole stack up.

Before you start · install Docker for your OS
  • macOS — install Docker Desktop for Mac (pick the right chip: Apple Silicon or Intel — check with uname -m). Launch it; wait until the whale icon in the menu bar stops animating.
  • Linux — Docker Engine via the official one-liner: curl -fsSL https://get.docker.com | sudo sh. Then add yourself to the docker group so you don't need sudo every time: sudo usermod -aG docker $USER, then log out and back in (or run newgrp docker).
  • Windows — install WSL2 first (open PowerShell as Administratorwsl --install → reboot → finish the Ubuntu first-run setup), then install Docker Desktop for Windows with the WSL2 backend enabled. Every command in this guide runs inside the WSL2 Ubuntu shell — not the Windows CMD or PowerShell you used for the WSL2 install.
Verify before continuing: docker info returns details (not "Cannot connect to the Docker daemon").
▸ Mode 1 · Run the skill

Invoke /exoskeleton-local. The skill asks for your stack, then:

  1. Generates docker-compose.yml mirroring your production shape — same base image, same DB engine, same web server.
  2. Mounts your source as a volume so file changes are live without rebuild.
  3. Writes a start.sh that verifies prereqs and brings the stack up.
  4. Runs ./start.sh for you and confirms the stack is live.

When it finishes you'll see:

# ./start.sh output
 Docker running
 Stack up
Web: http://localhost:8080
▸ Mode 2 · Prompt your own AI
I want a Docker-based local dev environment that mirrors production:
  Web framework: [DJANGO / RAILS / NEXT.JS / etc.]
  Database: MARIADB (default — or postgres / sqlite)
  Live preview port: 8080

Write me docker-compose.yml + start.sh.
Mount my source as a volume for live reload.
Make start.sh executable. Run it. Verify with curl.
▸ Mode 3 · Do it yourself

docker-compose.yml

services:
  web:
    image: [your-base-image]
    volumes:
      - .:/app
    ports:
      - "8080:8080"
    depends_on: [db]
  db:
    image: mariadb:11
    environment:
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MARIADB_DATABASE: ${DB_NAME}
    volumes: [dbdata:/var/lib/mysql]
volumes:
  dbdata:

start.sh

#!/usr/bin/env bash
set -euo pipefail
docker compose up -d
echo "Web: http://localhost:8080"

Then chmod +x start.sh && ./start.sh.

Verify
  • curl -s http://localhost:8080 returns HTTP 200.
  • Editing a file triggers live reload without rebuild.

Your production-shape stack is now running on your laptop. Same containers your servers will run.

Stop 02 · Setup
≈ 30 min

The Manual.

CLAUDE.md is the first message the AI sees on every session. Not documentation for humans. Optimize it for the AI's eyes.

Three things go in: hard rules, the tool selection protocol, and named frameworks. Facts that change live in the knowledge graph, not here.

▸ Mode 1 · Run the skill

Invoke /exoskeleton-manual. It asks seven questions and writes:

  • CLAUDE.md with your project name, layers, stack, and hard rules.
  • Three sub-agent definitions in .claude/agents/.
  • Three slash commands in .claude/commands/.

Target length for CLAUDE.md: under 500 lines. Load-bearing rules only.

▸ Mode 2 · Prompt your own AI
Write me a CLAUDE.md operating manual.

Project: [NAME — one-line description]
Layers: [LIST — e.g. "DB, API, admin, mobile, public"]
Database: MARIADB (default — or postgres / sqlite)
Stack: [LANGUAGE + FRAMEWORK]

Sections needed: Pre-Change Protocol, Tool Selection
Protocol, Four Guards, Sub-agent tiers, Commit rules.
Target: under 500 lines. Load-bearing only.
▸ Mode 3 · Do it yourself

Create CLAUDE.md at your project root. Use the template at .claude/skills/exoskeleton/templates/CLAUDE.md.template as a starting point. Keep it under 500 lines.

Verify
  • Open a fresh Claude Code session. Ask: "summarize the discipline you're following."
  • The AI names your frameworks back to you — without you mentioning them.

The AI just walked into your repo already knowing what you care about.

Stop 03 · Setup
≈ 25 min

The Tools.

Give the AI better senses through MCP servers. Default tools (full-file read, grep, raw shell) are wrong on a real codebase.

Five MCP servers do most of the work:

  • Code intelligenceSerena. Symbol-level retrieval via LSP. Cuts read-token spend ~10×.
  • Live data — a database MCP matching your stack. AI queries the real schema instead of guessing.
  • Browser automation — Playwright MCP. AI clicks through your live preview like a user.
  • Doc retrieval — fetches sections of long docs, not the whole file.
  • Knowledge graph — Stop 04.
▸ Mode 1 · Run the skill

The /exoskeleton-local skill printed the MCP install list. Run each install command. The skill verifies each before moving on.

Then it updates CLAUDE.md with the Tool Selection Protocol (five questions, in order — code, doc, wiring, large output, conceptual).

▸ Mode 2 · Prompt your own AI
Install these MCP servers in my Claude Code:
  1. Serena (code intel) - github.com/oraios/serena
  2. jCodeMunch (repo-scale code intel, blast radius, dep graphs)
  3. jDocMunch (section-level doc retrieval)
  4. MemPalace (knowledge graph + memory drawers)
  5. MariaDB live-DB MCP (default — or postgres / sqlite)
  6. Playwright MCP for browser automation

For each: find the install command, run it, verify with a
small test query.

Then add a Tool Selection Protocol to CLAUDE.md. Five
questions, in order: code → doc → cross-cutting wiring →
large output → conceptual. Forbid Read on indexed code.
▸ Mode 3 · Do it yourself

Use claude mcp add <name> ... per each tool's README. Test each. Update CLAUDE.md.

Verify
  • Ask the AI: "find every place we call user.permissions." It uses code intel, not grep.
  • Ask: "what columns are on the users table?" It queries the live DB.

Your AI now has eyes on the real schema. Hallucinated columns — gone.

Stop 04 · Setup
≈ 45 min · highest leverage of any stop

The Memory.

The AI without memory walks in cold every session. The AI with memory walks in already knowing what you fixed last Tuesday.

— SessionStart hook fires before the first user turn —
NEW SESSION opens HOOK FIRES ~12 lines of bash QUERY KG by branch + diff INTO CONTEXT first user turn

Three entity types to start: Decision (why we chose this), KnownBug (we fixed this before), Rule (this is what we learned). A hook queries the knowledge graph on every new session and dumps relevant entities into the AI's context.

▸ Mode 1 · Run the skill

Memory is bundled with /exoskeleton-guards (Stop 06). It installs the knowledge graph MCP, writes the SessionStart hook, the post-commit miner, and seeds three entity types.

Asks you for 5 recent bugs to seed as KnownBug entries.

▸ Mode 2 · Prompt your own AI
Build me a knowledge graph for this project.

Three entity types: Decision, KnownBug, Rule.

Need:
  1. A Python MCP server backed by SQLite. Tools:
     kg_query, kg_add, kg_list.
  2. A SessionStart hook (~12 lines of bash). Queries the
     KG by current branch + recent diff. Dumps matches as
     a system-reminder.
  3. A post-commit hook that re-indexes the KG.

Then seed 5 KnownBug entries (I'll list).
▸ Mode 3 · Do it yourself

Pick a KG store (Python + SQLite is simplest). Write a small MCP server. Write the SessionStart hook in .claude/hooks/session-start.sh. Seed entities manually.

Verify
  • Open a fresh session on a branch related to a seeded KnownBug.
  • The AI's first message references the entity — before you ask anything.

The first time the AI walks in and says "you fixed this on Tuesday, here's why" — the AI just became a colleague.

Stop 05 · Core
≈ 1 hour

The Hierarchy.

One operator. One Architect that plans. Specialists that execute. The Architect never writes code. The operator signs every decision.

— Operator → Architect → Specialists —
OPERATOR ARCHITECT CODER WEB MOBILE DB DESIGN Each specialist sees only its surface · smaller context · sharper output
▸ Mode 1 · Run the skill

The Hierarchy is wired by /exoskeleton-manual (Stop 02). It writes three sub-agent definitions and one slash command.

The agents: architect (largest model, plans only), executor (medium model, implements), researcher (read-only).

The slash command: /plan dispatches the Architect, waits for your sign-off, then dispatches the Executor.

▸ Mode 2 · Prompt your own AI
Create three Claude Code sub-agent definitions:
  1. architect.md - largest-tier. Plans only. Never writes code.
     Produces a plan: Mission / Layers / Order / Acceptance /
     Verification / Commit msg. Waits for operator sign-off.
  2. executor.md - medium-tier. Implements plan literally.
     Full git autonomy.
  3. researcher.md - medium-tier. Read-only. SELECT-only DB.

And one slash command:
  4. /plan <description> - dispatches Architect → operator
     sign-off → Executor with approved plan.
▸ Mode 3 · Do it yourself

Copy templates from .claude/skills/exoskeleton/templates/agents/ and templates/commands/plan.md.

Verify
  • Invoke /plan add a soft-delete field to the customer entity.
  • The Architect produces a plan. Waits for you to say "go" before code moves.

You just stopped the AI from making the most expensive mistake in software: starting work it didn't yet understand.

Stop 06 · Guards
≈ 2 hours · build these first if you build only one stop

The Four Guards.

Non-AI. Bash and Python. Regex + state files. An AI can argue any position eloquently. A regex cannot be persuaded. That asymmetry is what makes the whole stack shippable.

— Guard decision flow —
AI PROPOSES DROP TABLE... GUARD READS state file + regex REFUSED PASS The guard does not read prose.

The four guards: Pre-Change Protocol (warns on edits to load-bearing files without prior KG query), Schema-Verify (refuses destructive DB ops on un-inspected tables), Parity Check (pre-commit gate; refuses if layers disagree), KG Refresh (post-commit; rebuilds the system map).

▸ Mode 1 · Run the skill

Invoke /exoskeleton-guards. The skill copies four hook templates, replaces placeholders with your project specifics, makes them executable, activates the git hooks, and smoke-tests each guard.

Default mode for new installs: WARN. Upgrade to BLOCK once you trust them.

▸ Mode 2 · Prompt your own AI
Install four non-AI guards for my project. Bash + Python only.

  1. .claude/hooks/pre-change-protocol.sh — PreToolUse hook
     on Edit/Write. Warns when load-bearing files are about
     to be edited without a prior KG query this session.

  2. .claude/hooks/schema-verify.sh — PreToolUse on the
     live-DB MCP. Parses SQL for destructive verbs
     (INSERT/UPDATE/DELETE/ALTER/DROP/TRUNCATE/RENAME).
     Refuses if target table wasn't inspected this session.

  3. .githooks/pre-commit — parity check on every staged
     file. Refuses if any two layers disagree.

  4. .githooks/post-commit — background-runs the KG miner.

Wire them. Activate: git config core.hooksPath .githooks
Default mode: WARN.
▸ Mode 3 · Do it yourself

Copy templates from .claude/skills/exoskeleton/templates/hooks/. chmod +x everything. Activate git hooks. Test each guard.

Verify
  • Try destructive SQL without inspecting the table. Schema-Verify refuses.
  • Commit a one-layer-only change. Parity Check refuses.

The AI just hit a wall it cannot argue past. That asymmetry is yours now.

Stop 07 · Contract
≈ 90 min · per entity

The Layers.

Most platforms have 3–7 layers. Each has a different audience and writer. If any two stop agreeing about a field, somebody gets called by the wrong number on a wedding day.

— 5 layers · 1 pre-commit gate —
PUBLIC SITE where they find her ADMIN where she works API where they cross the wire DATABASE where the truth lives MOBILE where her life lives PRE-COMMIT GATE · ANY TWO DISAGREE → REFUSE
▸ Mode 1 · Run the skill

Invoke /exoskeleton-guards if you haven't. It ships a parity-check.sh.template.

For your first entity (recommend: customer or user): the skill asks which fields are on each layer, then writes the fields_in_* functions for you. Tests by staging a one-line change.

▸ Mode 2 · Prompt your own AI
Customize parity-check.sh.template for the [ENTITY] entity.

For each of my five layers, find which fields exist:
  - Database: query my schema
  - API: parse my serializer / API definition
  - Admin: parse my admin form
  - Mobile: parse my Codable / model
  - Public: parse my public template

Generate fields_in_*() functions. Smoke-test by staging a
one-line edit. If two layers disagree, the gate refuses.
▸ Mode 3 · Do it yourself

Copy parity-check.sh.template to parity-check.sh. For each entity, implement five fields_in_* functions. Each returns a sorted list of field names per layer.

Verify
  • Add a new field in DB only. Try to commit. The gate refuses and names the missing layers.

Your model now physically cannot ship a half-finished feature.

Stop 08 · Contract
≈ 1 day · skippable if no mobile

The Sync.

Most apps die the day the user is offline. Build for the venue with bad WiFi, not the happy path. Skippable if you have no mobile app.

Every record carries a small metadata bundle (identifier, version counter, hash, soft-delete flag, per-field timestamps). The phone holds a local mirror. Offline edits queue. They drain on reconnect. The server-side merge is authoritative for money and state. (Academic name: CRDT-adjacent.)

▸ Mode 1 · Run the skill

Sync is too stack-specific for full automation. /exoskeleton-deploy instead walks you through the design choices, recommends a sync engine for your stack (Replicache, PowerSync, or roll-your-own), and writes a sync-contract.md the AI honors going forward.

▸ Mode 2 · Prompt your own AI
Build offline-first sync for my mobile app.
Stack: [LANGUAGE], DB: MariaDB (default)

Help me:
  1. Choose a sync engine (Replicache, PowerSync, custom).
  2. Define per-record metadata: identifier, version, hash,
     soft-delete, per-field timestamps.
  3. Set merge precedence: server wins for money + state;
     phone wins for free-text.
  4. Wire the mobile local mirror.
  5. Write a sync-contract.md.
▸ Mode 3 · Do it yourself

Pick an engine. Read its docs. Define your metadata schema. Write the merge logic. Document the contract.

Verify
  • Airplane mode on. Make three edits. Re-enable WiFi. Edits drain silently. No spinner, no popup.

Your user just survived a WiFi outage without knowing there was one.

Stop 09 · Ship
≈ 2 hours · per integration

The Integrations.

Every external system has a bad day. Plan for that day. Every integration fails closed.

For each external system you depend on (payments, email, calendar, storage, webhooks), wrap the call so that if the system errors, your code returns "we'll retry later" — not "success." Also: rate-limit primitives on public POST endpoints, and an SSRF guard on every server-side URL fetch.

▸ Mode 1 · Run the skill

/exoskeleton-deploy handles integrations as a sub-step. For each external system, the skill walks the contract, sets up the fail-closed wrapper, and documents it in integration-map.md.

▸ Mode 2 · Prompt your own AI
For every external integration (payments, email, calendar,
storage, webhooks):

  1. Wrap with fail-closed logic. If external errors,
     return "we'll retry later" — not "success."
  2. Rate-limit every public POST endpoint.
  3. SSRF guard: refuse fetches to internal IPs and cloud
     metadata.
  4. Document in integration-map.md.

For each, show me a phantom-success failure mode my current
code might have, and the fix.
▸ Mode 3 · Do it yourself

For each integration: write a wrapper. Test the failure path. Add rate-limit + SSRF guard. Document the contract.

Verify
  • Disable network for your payment processor. Try to charge. Platform queues + tells the truth. No phantom-success.

Your platform now tells the truth under stress.

Stop 10 · Ship
≈ 4 hours · once

The Deploy.

Same container topology in production as on the desk. "Works on my machine" stops being a possible failure when the machines are identical.

Production runs on a VPS with the same docker-compose.yml as local. A reverse-proxy called Caddy auto-issues TLS for your domain. The deploy script takes a database backup before touching anything; if the post-deploy health check fails, the previous version is restored automatically.

▸ Mode 1 · Run the skill

Invoke /exoskeleton-deploy. The skill never runs automatically — you have to type it. It:

  1. Verifies your local stack is green first.
  2. Asks for SSH host, user, key path, domain.
  3. Generates bin/vps/deploy.sh (backup → pull → up → health-check → rollback-on-fail).
  4. Generates bin/vps/rollback.sh, the Caddyfile, the env example.
  5. Walks you through the first supervised deploy.

Secrets never get committed. .env with real values lives on the server, not in the repo.

▸ Mode 2 · Prompt your own AI
Set up production deployment.
VPS: [HOST/IP], user [SSH_USER], domain [DOMAIN].

Generate:
  1. bin/vps/deploy.sh - backup → pull → up → health-check
     → rollback-on-fail. Takes a DB backup first.
  2. bin/vps/rollback.sh - restore latest backup, revert
     to HEAD~1, restart.
  3. etc/Caddyfile.template - Caddy reverse-proxy with
     auto-TLS for my domain.
  4. etc/.env.example - every env var production needs,
     with comments. Never commit real secrets.

Walk me through the first supervised deploy. Stop before
any destructive command and confirm.
▸ Mode 3 · Do it yourself

Get a VPS. Install Docker. Copy your docker-compose.yml + a Caddy service. Write deploy.sh and rollback.sh by hand. Test on a sacrificial server first.

Verify
  • Deploy runs in < 2 min. Backup before touching anything. Health check passes. Public URL returns 200.
  • Break the deploy intentionally. Rollback fires automatically. Production stays up.

Your stack is running on a server with the same containers as your laptop. Production exists.

Stop 11 · Security
≈ 4 hours · ongoing

The Red Team.

Real customer data deserves real security maturity. Defense in depth. Multiple unrelated guards on every sensitive surface, so no single failure is catastrophic.

Two threats to defend against

Daily threat: the random internet scanner that finds your platform by accident and walks the public surface looking for anything default, exposed, or sleepy.
Tail-risk threat: the targeted attacker who actually wants the customer data in your database.

The architecture defeats the first comfortably and slows the second enough that anything they touch leaves a trail.

The nine guards of defense in depth

1. Money + state machines recomputed from canonical sources on the server. Never trusted from the screen.
2. Public POST endpoints rate-limited with fail-closed primitives.
3. Server-side URL fetches guarded against internal IPs and cloud metadata (SSRF guard).
4. Passwords hashed with a modern memory-hard key-derivation function. Auto-upgraded on next login.
5. 2FA codes replay-resistant. Used codes cannot be reused.
6. User-supplied HTML (email templates, page-builder blocks) sanitized at save time, not at render. Saved content is already safe.
7. Uploaded files content-type checked against actual bytes, not extension.
8. CSP headers enforced on every response. Violations reported.
9. TLS auto-issued by Caddy and renewed transparently. Nothing speaks plaintext to the outside world.

▸ Mode 1 · Run the skill

As its closing step, /exoskeleton-deploy walks the nine-guard checklist for your stack. For each item it asks: is this in place, where, what's the file path? Items already covered get noted in SECURITY.md. Items missing get a stub TODO with a recommended primitive (e.g. "rate-limit: use express-rate-limit / Flask-Limiter / Rack::Attack — pick one"). Stack-agnostic by design — the skill recommends the right primitive for your language, never invents one.

For ongoing red-team: dispatch a sub-agent with an adversarial review prompt against every diff. Findings get fixed forward or require a typed override recorded in SECURITY.md.

▸ Mode 2 · Prompt your own AI
Red-team my codebase against the nine-guard checklist:

  1. Money + state recomputed server-side
  2. Public POST endpoints rate-limited
  3. SSRF guard on server-side URL fetches
  4. Modern password hashing + auto-upgrade
  5. 2FA replay protection
  6. HTML sanitized at save
  7. Uploaded files content-type checked by bytes
  8. CSP enforced + reported
  9. TLS auto-issued

For each: find one specific place I might be exposed.
Tell me the fix without naming the exact attack shape
(I don't want a writeup that becomes a checklist for
attackers). Write findings into a SECURITY.md.
▸ Mode 3 · Do it yourself

Walk the nine-item list yourself. For each: confirm the guard exists, write where it is in SECURITY.md, and add a test that demonstrates it works. Schedule a quarterly review.

Verify
  • You can answer "where is this guard implemented?" for each of the nine items, by file path.
  • A basic security scanner (e.g., nuclei) against your public endpoints comes back clean for default + exposed checks.

A feature is not finished when it works. It is finished when it fails safely.

— The shortcut · install the whole stack —

Exoskeleton — the skill bundle.

The article is called Two Suits because that's the story. The thing doing the work is called exoskeleton. The bundle ships everything you read about above as a set of Claude Code skills invoked with one command.

/exoskeleton-install — orchestrator (runs the rest in order)
/exoskeleton-local — Workshop (01) + Tools (03)
/exoskeleton-manual — Manual (02) + Hierarchy (05)
/exoskeleton-guards — Memory (04) + Guards (06) + Layers (07)
/exoskeleton-deploy — Integrations (09) + Deploy (10) + Red Team (11)

# Install the bundle — Claude Code
$ cd your-project
$ git clone https://github.com/c-merkel/exoskeleton.git .claude/skills/exoskeleton
$ claude
> /exoskeleton-install
# Or — Codex CLI (OpenAI)
$ cd your-project
$ git clone https://github.com/c-merkel/exoskeleton.git .codex/skills/exoskeleton
$ codex
> /exoskeleton-install

Repository: github.com/c-merkel/exoskeleton — public, free, no auth required to clone. Stack-agnostic — you provide the seven specifics in the prompts.

From here, the orchestrator takes over. It asks four calibration questions, then dispatches the right sub-skill for every station above — Workshop, Manual, Tools, Memory, Hierarchy, Guards, Layers, Sync, Integrations, Deploy, Red-Team — in order. You watch and confirm; it does the work.

Habits the AI cannot see do not exist.

Write them down once. Watch them stick.