arc42 Architecture Documentation — clarc

clarc v1.0.0 · Workflow OS for AI coding assistants Generated: 2026-03-12 · Render diagrams: PlantUML online or VS Code PlantUML extension


Table of Contents

  1. Introduction & Goals
  2. Constraints
  3. System Scope & Context
  4. Solution Strategy
  5. Building Block View
  6. Runtime View
  7. Deployment View
  8. Cross-cutting Concepts
  9. Architecture Decisions
  10. Quality Requirements
  11. Risks & Technical Debt
  12. Glossary

1. Introduction & Goals

What is clarc?

clarc turns Claude Code (and compatible AI coding assistants) from a reactive chat tool into a structured engineering system. It provides:

  • Agents — 62 specialized subagents that delegate planning, review, testing, and debugging
  • Skills — 248 domain knowledge libraries loaded on demand
  • Commands — 172 slash commands for repeatable engineering workflows
  • Hooks — 37 background automations (format, lint, secret scan, budget guard, response dashboard, state persistence)
  • Rules — 20 language rule sets always active in every session
  • Learning flywheel — session patterns promoted into permanent skills over time

Core Requirements

#RequirementPriority
R1Developer can install clarc in < 5 minutes with a single npx commandCritical
R2All components symlink into ~/.claude/ without overwriting user's own filesCritical
R3Works across 4 editors: Claude Code, Cursor, OpenCode, CodexHigh
R4Session state survives context compaction without data lossHigh
R5Learned instincts persist across sessions and improve agent quality over timeHigh
R6Every component validated by CI before reaching usersMedium

Quality Goals

QualityTargetMeasure
CorrectnessZero broken cross-referencesCI validator (validate-wiring.js)
ReliabilityHooks non-blocking; session state always preservedAsync hooks, PreCompact snapshot
SecurityNo secrets in source; no secrets written to diskpre-write-secret-scan.js
LearnabilityNew developer onboarded in < 10 minutes/quickstart command
EvolvabilitySystem improves from its own usageLearning flywheel
Cost VisibilityUser sees cost and tool breakdown after every responseresponse-dashboard.js Stop hook

Stakeholders

StakeholderExpectation
Individual developerFaster, more structured engineering work with Claude Code
Team leadConsistent coding standards and review workflows across the team
clarc maintainerClean component boundaries, CI-validated quality gates

2. Constraints

Technical Constraints

ConstraintReason
Node.js ≥ 22 (ESM modules)All hook scripts use import/export; modern Node.js features required
No runtime databaseAll state lives in flat JSON files (~/.claude/projects/, ~/.clarc/)
No network access during hooksHooks run synchronously in Claude Code's process; outbound HTTP not viable
Markdown-first contentAgents, skills, commands, rules are all plain Markdown — human-readable, git-diffable
Symlinks require same filesysteminstall.sh --symlink fails across filesystems; use --copy for CI/containers

Organizational Constraints

ConstraintReason
MIT LicenseOpen source; no proprietary dependencies in core
No Anthropic API key requiredclarc runs inside Claude Code — does not call the API directly
Single maintainer (pre-launch)All PRs reviewed by Marvin Richter; no external contributors yet

3. System Scope & Context

Context Diagram
Context Diagram
Context summary:
  clarc ←→ Claude Code  (primary integration via ~/.claude/ symlinks)
  clarc ←→ Cursor        (rules → .cursor/rules/)
  clarc ←→ OpenCode      (commands → .opencode/)
  clarc ←→ Codex CLI     (commands → codex/)
  clarc ←→ GitHub        (source via git clone; CI validation on pre-push)
  clarc ←→ MCP clients   (optional: 8 tools via stdio MCP transport)

External systems clarc does NOT directly integrate with:

  • Anthropic API (runs inside Claude Code, not alongside it)
  • Any cloud provider (clarc is a local tool with no cloud backend)
  • Any database (flat-file storage only)

4. Solution Strategy

DecisionChoiceRationale
Storage formatFlat Markdown files + JSONGit-native, human-readable, no database dependency
Install strategySymlinks into ~/.claude/Single git pull updates everything; no re-install
Hook implementationNode.js ESM scriptsCross-platform (macOS/Linux/WSL2); async support; shared lib
Skill formatSKILL.md per directoryNamespace isolation; future: per-skill assets (examples, templates)
Agent formatMarkdown with YAML frontmatterClaude Code native; name, description, tools, model, uses_skills
Multi-editorSeparate install targetsClaude Code = symlinks; Cursor/OpenCode/Codex = copies
LearningInstinct files → promoted skillsIncremental; quality-gated; no auto-promotion without human review
CINode.js validators + pre-push hookFast, language-native, no Docker required

5. Building Block View

Level 1 — Container Diagram

Container Diagram
Container Diagram

Level 2 — Component: Hook System

The Hook System is clarc's most complex container — it coordinates 37 Node.js scripts across 6 event types.

Hook Component Diagram
Hook Component Diagram

Hook Event → Script Mapping

EventMatcherScriptPurpose
PreToolUseBashpre-bash-dispatch.jsBlock dev servers, tmux reminder, push review
PreToolUseWritepre-write-secret-scan.jsBlock writes with secrets (exit 2)
PreToolUseWritedoc-file-warning.jsWarn about non-standard doc file paths
PreToolUseEdit\Writesuggest-compact.jsSuggest compaction at 50-tool threshold (async)
PreToolUseAgentbudget-guard.jsWarn/block Agent calls when daily spend exceeds threshold
PreCompact*pre-compact.jsSave session snapshot before compaction
PostToolUseEdit\Writepost-edit-format-dispatch.jsAuto-format in 15 languages
PostToolUseEditpost-edit-typecheck.jstsc --noEmit (async, debounced)
PostToolUseEditpost-edit-typecheck-rust.jscargo check (async, debounced)
PostToolUseEdit\Writepost-edit-workflow-nudge.js5 advisory nudges with cooldown
PostToolUseBashbuild-failure-router.jsDetect compile errors, suggest agent
PostToolUseEdit\Writeauto-checkpoint.jsGit checkpoint for /undo
PostToolUseAgentagent-tracker.jsTrack agent invocation frequency
SessionStart*session-start.jsLoad context, skills, instincts
SessionEnd*session-end.jsEvaluate session, log per-tool cost, trigger weekly evolve
Stop*response-dashboard.jsShow per-response tool usage, agents, and cost estimate
Stop*check-console-log.jsWarn if console.log found in modified JS/TS files

Shared Libraries (scripts/lib/)

ModulePurpose
utils.jsFile I/O, path helpers, JSON read/write, logging
package-manager.jsDetect npm/pnpm/yarn/bun; project-level override
project-detect.jsIdentify tech stack from lock files and config
skill-search.jsKeyword + domain search across skills/ (used by MCP + CLI)
session-manager.jsRead/write session snapshots in ~/.claude/projects/
session-aliases.jsHuman-readable session name aliases
secret-scanner.jsRegex patterns for AWS keys, GH tokens, PEM, Slack, api_key

6. Runtime View

Scenario 1 — Session Lifecycle

Session Lifecycle
Session Lifecycle

Key invariants:

  • session-start.js injects at most 3000 chars to avoid context waste
  • pre-compact.js always runs synchronously before any compaction — no snapshot loss
  • All PostToolUse hooks are non-blocking (async) except pre-write-secret-scan.js (must block to abort writes)

Scenario 2 — Learning Flywheel

Learning Flywheel
Learning Flywheel

Quality gates:

  • /learn-eval requires minimum confidence 0.7 before persisting an instinct
  • /evolve promotes only instincts with confidence > 0.8 seen ≥ 3 times
  • Contradicting instincts in the same domain go to conflicts.json for human resolution
  • instinct-decay.js reduces confidence of instincts not reinforced for 30+ days

Scenario 3 — CI Validation Pipeline (pre-push)

git push
  └─ scripts/pre-push.sh
       ├─ ESLint               → scripts/ code quality
       ├─ markdownlint         → all *.md files
       ├─ validate-agents.js   → frontmatter, required fields, tool lists
       ├─ validate-hooks.js    → hooks.json schema + script existence
       ├─ validate-commands.js → description frontmatter, After This section
       ├─ validate-skills.js   → SKILL.md existence, frontmatter, size ≤ 600 lines
       ├─ validate-rules.js    → rule format contract (≤ 80 lines, checklist)
       ├─ validate-wiring.js   → uses_skills references resolve to existing skills
       ├─ validate-naming.js   → kebab-case naming, no reserved names
       └─ tests/run-all.js     → unit + artifact tests (~4000 assertions)

7. Deployment View

Deployment Diagram
Deployment Diagram

Installation Modes

ModeCommandUse case
Interactive wizardnpx github:marvinrichter/clarcFirst-time users
Explicit languagenpx github:marvinrichter/clarc typescriptScripted setup
Copy modenpx github:marvinrichter/clarc --copy typescriptCI, containers, cross-filesystem
Cursor targetnpx github:marvinrichter/clarc --target cursor typescriptCursor IDE
OpenCode targetnpx github:marvinrichter/clarc --target opencode typescriptOpenCode
Codex targetnpx github:marvinrichter/clarc --target codexCodex CLI
Checknpx github:marvinrichter/clarc --checkVerify installed rules are current
Doctornpx github:marvinrichter/clarc doctorFull health check

File System Layout After Install

~/.clarc/                          ← git clone (source of truth)
│   agents/, skills/, commands/
│   hooks/, rules/, scripts/
│   mcp-server/, install.sh
│
~/.claude/                         ← Claude Code user directory
│   agents/        → symlinks → ~/.clarc/agents/*.md
│   commands/      → symlinks → ~/.clarc/commands/*.md
│   rules/         → symlinks → ~/.clarc/rules/**/*.md
│   projects/      → session snapshots (JSON), instinct store
│   homunculus/    → agent-instinct overlays
│
<project>/.claude-plugin/          ← per-project plugin
│   plugin.json                    ← declares CLAUDE_PLUGIN_ROOT
│
<project>/.clarc/                  ← optional per-project overrides
    skills/                        ← project-local skills
    hooks-config.json              ← suppress/configure hook nudges

8. Cross-cutting Concepts

8.1 Secret Detection

Two-layer defense:

  1. Pre-write: pre-write-secret-scan.js — blocks the Write tool (exit 2) if content matches: AWS AKIA keys, GitHub tokens (ghp/gho/ghu/ghs/ghr), PEM headers, Slack xox\*, api_key=, token=
  2. Pre-push: pre-bash-dispatch.js scans git diffs on git commit commands

File extension allowlist skips binary/generated files (.png, .jpg, .wasm, .lock, .sum).

8.2 Error Handling in Hooks

All hooks follow the same pattern:

  • Exit 0 → success, continue
  • Exit 2 → block the tool call (Write/Bash)
  • Any exception → caught silently, exit 0 (never block user work due to hook failure)
  • Async hooks → fire-and-forget; errors logged but never block

8.3 Observability

  • hook-logger.js — writes structured JSON to hooks.log per hook invocation
  • scripts/hooks-summary.js — analyzes hooks.log; --heatmap shows most-triggered hooks; --errors shows failures
  • agent-tracker.js — tracks agent invocation frequency

8.4 Validation Strategy

BoundaryValidator
User input (secrets)secret-scanner.js at write time
Component formatCI validators in scripts/ci/ at pre-push
Cross-referencesvalidate-wiring.js + validate-agent-skill-refs.js
File sizeSkill max 600 lines (CI hard limit)
Namingvalidate-naming.js — kebab-case, no reserved Claude Code commands

8.5 Immutability Convention

All hook scripts and shared libraries follow immutable data patterns — functions return new objects rather than mutating inputs. Mutable state is limited to file I/O (session snapshots, cooldown state).

8.6 Context Window Management

  • session-start.js caps context injection at 3000 characters
  • suggest-compact.js nudges manual compaction at 50 tool calls (configurable)
  • pre-compact.js always saves state before compaction so nothing is lost

8.7 Cost Management & Budget Controls

clarc includes a three-layer cost management system:

Per-response dashboard (response-dashboard.js — Stop hook):

  • Fires after every Claude response
  • Parses transcript_path JSONL to find the last human turn as response boundary
  • Counts all tool calls in assistant turns after that boundary
  • Resolves agent model tier from agent frontmatter
  • Outputs a 3-line formatted summary to stderr (non-blocking):

`` ──────────────────────────────────────────────────────── tools: Read×5 Edit×3 Bash×2 Agent×1 agents: typescript-reviewer [sonnet] cost: ~$0.08 · ~9.5k tokens (est.) ──────────────────────────────────────────────────────── ``

  • Suppressible via CLARC_RESPONSE_DASHBOARD=false or .clarc/hooks-config.json

Daily budget guard (budget-guard.js — PreToolUse/Agent):

  • Fires before every Agent tool call (agents are 20–40× more expensive than simple tools)
  • Reads ~/.clarc/cost-log.jsonl to sum today's accumulated estimated spend
  • Warns via stderr if spend exceeds CLAUDE_COST_WARN (default $5)
  • Blocks (exit 2) if spend exceeds CLAUDE_BUDGET_LIMIT (default $20, 0 = disabled)
  • Cost estimates: ±50–100% accuracy; ground truth: console.anthropic.com

Session cost log (session-end.js — SessionEnd hook):

  • Appends one JSON entry to ~/.clarc/cost-log.jsonl per session
  • Uses per-tool token weight table (Agent=8k, Read=1.5k, Bash=400, Grep=300, ...)
  • Accurate within ±50–100%; drives budget-guard.js decisions next session

Per-tool weight table:

ToolInput tokensOutput tokens
Agent8,0002,000
WebFetch2,000100
Read1,50050
Edit600150
Write500100
WebSearch800100
Bash400200
Grep300100
Glob20050

Model tier routing (summarizer-haiku agent):

  • Haiku-tier agent (10–15× cheaper than Sonnet) for text summarization, classification, boilerplate generation
  • Orchestrator routes to summarizer-haiku for subtasks that don't require reasoning
  • Never used for code review, security analysis, or architecture decisions

9. Architecture Decisions

No ADRs in docs/decisions/ yet. Key implicit decisions are captured in Section 4.

Decisions pending formalization:

  • Choice of symlinks over copies as default install strategy
  • Markdown as the agent/skill/command format (vs. YAML-only or JSON)
  • Single flat-file storage (vs. SQLite or local server)
  • Node.js ESM for hooks (vs. Python or Bash)

Run /explore <decision-name> to generate an ADR, then /arc42 decisions to rebuild this index.


10. Quality Requirements

ScenarioStimulusResponseMeasure
InstallDeveloper runs npx github:marvinrichter/clarcInstallation completes, all symlinks healthy< 60s on clean machine
Secret leak preventionDeveloper writes file with AWS keyWrite is blocked with explanationExit code 2 before file is written
Context compactionClaude Code compacts conversationSession state fully preservedAll tasks + touched files in next session
Hook failureA hook script throws an unexpected errorUser work continues uninterruptedHook exits 0, error logged
Component updateDeveloper runs git pull in ~/.clarc/All symlinks immediately reflect new contentZero additional steps
Skill searchMCP client queries skill_searchMatching skills returned ranked by relevance< 100ms
Cost guardDaily Agent spend exceeds CLAUDE_BUDGET_LIMITAgent call is blocked with spend summaryExit code 2 before agent is spawned
Response dashboardClaude finishes a responseTool usage, agents used, and cost estimate shown< 50ms parsing; non-blocking

11. Risks & Technical Debt

Known Risks

RiskLikelihoodImpactMitigation
Claude Code hook API changesMediumHighHooks are thin wrappers; migration is localized to hooks.json + scripts/hooks/
Symlink conflicts on Windows (non-WSL2)HighMedium--copy mode available; documented in README
Instinct quality degradationLowMediumQuality gate (confidence ≥ 0.7) + decay mechanism
Skill corpus size growthLowLowCI hard limit 600 lines/skill; split pattern established
MCP SDK version driftLowLow@modelcontextprotocol/sdk is optional dependency

Known Technical Debt

ItemLocationSeverity
suggest-compact.js counter race conditionscripts/hooks/suggest-compact.jsLow — advisory only, no data loss
Hook matchers can't filter by file extension nativelyhooks/hooks.jsonLow — mitigated by early-exit guards in scripts
No integration tests for install.shtests/integration/Medium — manual testing required on each release
docs/decisions/ has no ADRs yetdocs/decisions/Low — implicit decisions undocumented

12. Glossary

TermDefinition
AgentA specialized Claude Code subagent defined in a Markdown file with YAML frontmatter. Invoked automatically by trigger rules or explicitly via --subagent_type.
SkillA domain knowledge library in skills/<name>/SKILL.md. Loaded on-demand by Claude Code when the context matches. Not always-on (unlike rules).
CommandA user-invocable slash command (e.g. /tdd, /plan) defined in commands/<name>.md. Expands to a full prompt when invoked.
HookA shell command triggered by Claude Code events (PreToolUse, PostToolUse, SessionStart, Stop, PreCompact). Implemented as Node.js scripts in scripts/hooks/.
RuleAn always-on guideline loaded into every session. Defines what to do (standards, checklists). Skills show how to do it.
InstinctA pattern learned from sessions via /learn-eval. Stored as JSON with domain, confidence, and reinforcement count. Can be promoted to a permanent skill via /evolve.
SKILL_MAPA mapping from detected tech stack (languages, frameworks) to relevant skill names. Injected at session start.
CLAUDE_PLUGIN_ROOTEnvironment variable set by .claude-plugin/plugin.json that resolves hook script paths relative to the clarc installation.
clarc-self-dev-nudgeThe hook nudge that fires when .md/.json files in agents/, skills/, or commands/ are modified — suggests the appropriate review agent.
Continuous learning flywheelThe observe → extract → quality-gate → store → evolve → promote cycle that improves clarc from its own usage.
MCPModel Context Protocol — Anthropic's standard for exposing structured tools to AI models. clarc implements an optional MCP server with 8 tools.
Worktree isolationA multi-agent coordination pattern where each agent runs in a separate git worktree to prevent file conflicts.
ADRArchitecture Decision Record — a document capturing the context, options, and rationale for a significant technical choice.
CLARC_ROOTThe root directory of the clarc installation (~/.clarc/ or the local development repo). Used by hooks to resolve component paths.
budget-guardA PreToolUse/Agent hook that reads ~/.clarc/cost-log.jsonl and warns or blocks Agent calls if daily estimated spend exceeds configured thresholds.
response-dashboardA Stop hook that parses the session transcript to produce a per-response summary of tools used, agents invoked, and estimated token cost.
cost-log.jsonlAn append-only JSONL file at ~/.clarc/cost-log.jsonl logging per-session estimated token costs. Used by budget-guard.js to compute daily spend.
summarizer-haikuA Haiku-tier agent (10–15× cheaper than Sonnet) for text summarization, classification, and boilerplate — routes cheap subtasks away from expensive models.