Skip to content

Harness reference

Every piece of the harness, catalogued. For the reasoning behind the structure, start at the AI harness; for the ordering of events, see lifecycle.

Each family opens by stating two things that apply to every entry under it:

  • its layerdeterministic (the harness executes it), contextual (the harness loads it) or judgement (the model applies it);
  • whether it ships, meaning whether catalyst new puts it in your project. Everything ships except the plugin installations.

The five moments declared in .claude/settings.json.

Fires once when a session starts. Two entries, distinguished by matcher.

MatcherOrderCommandTimeout
startup1generate-skills-index.ts30 s
startup2daily-tip.sh5 s
startup3catalyst-dev-mode.sh5 s
startup4check-required-plugins.ts15 s
startup|clear5wipe of .claude/.cache/5 s

Cannot block.

Fires once per instruction file loaded, carrying a load_reason: session_start, nested_traversal, path_glob_match, include or compact.

CommandTimeoutNotes
instructions-loaded-log.ts10 snotification-only; output and exit code are ignored

Cannot block and cannot inject context.

Fires on every prompt submitted.

CommandTimeoutNotes
inject-prompt-context.ts15 sanything on standard output is injected ahead of the prompt

Can block.

Fires before a matching tool call executes.

MatcherCommandTimeoutAuthority
Writearchitecture-checkpoint.ts15 snudge — blocks once per path, then steps aside
Write|Edit|MultiEditharness-rules-content-guard.ts15 sblock

Fires after a matching tool call completes.

MatcherCommandTimeoutAuthority
Write|Edit|MultiEditformat-with-prettier.ts30 sadvisory
Write|Edit|MultiEditlint-barrels.ts30 sblock on one rule, informational on the other

Seven hooks, all in .claude/hooks/, all deterministic, all shipped. Every one of them degrades to doing nothing when it fails on its own, so no failure of theirs can degrade a session.

HookTrigger pointAuthorityWhat it does
generate-skills-index.tsSessionStartadvisoryrewrites the [Project Skills Index] block inside every CLAUDE.md, and regenerates .claude/skills-triggers-index.json, both from what is on disk
check-required-plugins.tsSessionStartadvisorychecks the required plugins are installed and enabled, reading merged runtime state rather than settings files
instructions-loaded-log.tsInstructionsLoadednoneappends one line per loaded instruction file to .claude/.cache/instructions-loaded.log
inject-prompt-context.tsUserPromptSubmitadvisoryinjects up to 3 business rules, up to 3 harness rules and up to 3 skill pointers matching the prompt — rule bodies capped at 4 000 characters each, all three on separate budgets; skill pointers carry a path and matched terms only, never a skill’s body
architecture-checkpoint.tsPreToolUse (Write)nudgesurfaces path classification, the governing project-structure skill and applicable rules when a new architectural file is created
harness-rules-content-guard.tsPreToolUseblockblocks a write whose content matches an active rule’s detection pattern inside that rule’s governed paths
lint-barrels.tsPostToolUsemixedlints barrel imports on the file just written; one rule blocks, the other informs

harness-rules-content-guard sees only the assistant’s edit tools and only the incoming text. Content written through a shell command, or an existing violation relocated into a governed path, passes unseen. The exhaustive check over the working tree is the backstop.

Nine files in .claude/rules/, all contextual, all shipped. Each declares paths: globs in its frontmatter and loads when a matching file is read — with a load_reason of path_glob_match.

Two families:

Scope rules route to the conventions of a whole workspace.

RuleGoverns
scope-backend.mdbackend/src/**, backend/test/**
scope-frontend.mdfrontend/src/**, frontend/libs/**
scope-cli.mdpackages/cli/**

Route rules route to the skill that covers one kind of file.

RuleGoverns
route-aurora-components.mdfrontend/src/@aurora/components/**
route-aurora-yaml.mdcliter/**/*.aurora.yaml
route-backend-test.mdbackend/**/*.spec.ts, backend/**/*.e2e-spec.ts
route-drizzle-schema.mdbackend/**/*.schema.ts, the migrations tree, the Drizzle config and the drift-check workflow
route-eta.md**/*.eta
route-skill-md.md**/.claude/skills/*/SKILL.md, .claude/skills/REGISTRY.md

Scope rules route instead of duplicating because a scoped CLAUDE.md is not re-injected after a compaction, while a rule is re-evaluated on every later matching read.

Four entries in .claude/scripts/, all deterministic, all shipped.

ScriptRuns atWhat it does
generate-skills-index.tsSessionStartregenerates the skills index inside every CLAUDE.md and the skill-trigger index at .claude/skills-triggers-index.json
daily-tip.shSessionStartprints one tip from daily-tips.txt
catalyst-dev-mode.shSessionStartinjects the active development mode
status-line.shcontinuouslyrenders the status line; configured outside the hooks block, so it is not a trigger point

The hooks also draw on shared code under scripts/: the catalogue runtime that loads and validates rule indexes, and the barrel-lint core. Both ship with the template.

Thirty-eight skills, contextual, all shipped. They are scoped: a skill lives with the workspace it serves, and the scope rule for that workspace routes to it.

A skill activates through judgement by default: the model reads its description and decides it applies. Seven skills in the monorepo scope also declare a metadata.triggers array in their SKILL.md frontmatter — an explicit, curated list of keywords, kept separate from the prose description on purpose: a description is a paragraph aimed at persuading the model, not a list of terms with a match threshold, and deriving one from the other would let a wording tweak silently change what fires.

generate-skills-index.ts consolidates every SKILL.md, in any scope, that declares the field into .claude/skills-triggers-index.json — a repo-root file, sibling of skills/, hooks/ and scripts/, never inside skills/ itself. The index is deterministic: no timestamp, entries sorted by path, byte-identical across runs for the same set of SKILL.md files on disk. Nothing is hard-coded — any skill anywhere in the monorepo that adds the field joins the index on the next SessionStart.

inject-prompt-context.ts reads that index and scores it against the prompt with the same keyword primitive the business-rule and harness-rule blocks use (a term under 4 characters never matches), plus a +50 bonus when the prompt names the skill literally. It injects up to 3 matches as pointers — never skill bodies.

The seven skills currently indexed: business-rules-guard, catalyst-delegation, catalyst-langs, catalyst-query-dsl, catalyst-report-creator, catalyst-skill-creator, judgment-day.

typescript deliberately opts out, and says so in its own SKILL.md: its real trigger is “any .ts/.tsx file”, which as a keyword vocabulary would fire on almost every prompt or none — a non-discriminating trigger is worse than no trigger at all. It stays discoverable through the [Project Skills Index] and its description instead.

.claude/skills/

SkillCovers
business-rules-guardthe business-rule catalogue: adding, changing, derogating, citing by identifier
catalyst-cliconsuming the CLI: generation, .origin reconciliation, what belongs in YAML versus code
catalyst-delegationdelegation contracts: skill discovery, escalation protocol, model assignment
catalyst-langsthe language mechanism: panel versus data, adapters, adding a language
catalyst-query-dslthe query DSL wire contract shared by both stacks
catalyst-report-creatorturning a reporting need into the minimal reporting artifact
catalyst-schemaauthoring and validating the Aurora YAML schemas
catalyst-skill-creatorwriting a new skill
catalyst-update-skill-registryregenerating the skill registry after any skill changes
harness-rules-guardthe harness-rule catalogue
judgment-daydual adversarial review
openspec-exploreexploring an idea before committing to a change; searches the change archive for prior decisions on the topic before laying out options
openspec-proposecreating a change and its artifacts
openspec-apply-changeimplementing the tasks of a change
openspec-archive-changeclosing a change and syncing specs
typescriptstrict TypeScript patterns

backend/.claude/skills/

SkillTriggered by
catalyst-project-structure”where does this file go”, the layer boundaries
catalyst-handler-composerbusiness logic inside a handler, composite protocol-flow handlers
catalyst-field-schemaschema and formatting decorators, query statements inside a handler
catalyst-nestjs-primitivesguards, interceptors, pipes, filters, decorators, permissions
catalyst-cross-bounded-context-portsone bounded context reading from or writing to another
catalyst-provider-compositionchoosing the concrete provider behind a port: storage, mailer, queue
catalyst-toolsruntime configuration, feature flags, secrets, database procedures, declarative migrations
catalyst-schema-migrationsa schema change or a migration
catalyst-backend-testingwriting tests
catalyst-review-modulecoherence review of a finished module

frontend/.claude/skills/

SkillTriggered by
catalyst-data-layerreading or mutating server data: list and detail screens, resolvers, queries, mutations
catalyst-component-catalogcomposing a screen from the framework components
catalyst-data-table-managementdata-table columns, cells and infrastructure
catalyst-form-composer-auditorcomposing or auditing a form or detail view
layout-design-systemspacing, visual hierarchy, density
transloco-i18ntranslations, scopes, language switching
catalyst-widget-creatordashboard widgets
spartanthe Spartan UI components
catalyst-project-structure”where does this file go”
catalyst-review-modulecoherence review of a finished module
catalyst-component-story-composerauthoring stories for framework components

packages/cli/.claude/skills/

SkillTriggered by
eta-templatingediting a codegen template

Thirteen command files in .claude/commands/, contextual, shipped. They load only when you type them.

CommandPurpose
/catalyst-dev-modeswitch between Framework and Solution mode
/create-schemaanalyse or create an Aurora YAML schema
/load-skillload a skill by name, or list them
/review-moduledeep coherence review of a module
/opsx:explorethink an idea through before committing to it — checks the change archive for prior decisions before laying out options
/opsx:proposecreate a change and generate its artifacts
/opsx:applyimplement the tasks of a change
/opsx:archiveclose a completed change
/business-rules:auditaudit the business-rule catalogue
/business-rules:checkvalidate against the business-rule catalogue
/business-rules:documentdocument rules implicit in existing code
/business-rules:promotecrystallise rules declared in an archived change
/harness-rules:auditaudit the harness-rule catalogue

Two of these files are both named audit.md, in different directories. The generated skills index deduplicates by file name, so it reports twelve commands where thirteen files exist; the commands themselves are distinct and both work.

One agent in .claude/agents/, contextual, shipped.

AgentPurpose
catalyst-schema-manageranalyses Aurora YAML schemas and proposes improvements to names, descriptions and semantics; creates, edits and deletes fields on request

Four plugins. This is the one family that does not fully ship. The declarations travel inside settings.json, so your editor offers to install them when you trust the project folder — but the installations themselves are per user, which is exactly why check-required-plugins verifies them at every startup.

PluginRequiredWhy
engramyespersistent memory across sessions
superpowersyesbase skills and test-driven-development discipline
code-reviewyesthe verification gate
context7noup-to-date library documentation

engram lives in a custom marketplace, also declared in the shipped settings.

These are not files under .claude/. They are instructions in CLAUDE.md, applied by the assistant’s reasoning, and they ship because the template carries its own CLAUDE.md.

The first gate. Before classifying anything, the assistant confirms it understands the request. An ambiguous request — a vague goal, a missing constraint, two plausible readings — is clarified in conversation before any work begins, and then re-triaged. A clear request skips the gate entirely.

Classifies every request as Minor, Medium or Complex, and the tier decides whether the spec-driven workflow is involved and which quality gates run. Re-run whenever scope grows mid-task; when torn between two tiers, the heavier one wins.

For Medium and Complex work, before the first code change: an offer to isolate the work in a git worktree on its own branch, closing with a pull request. Recommended, never imposed, never done silently. Minor work never triggers it.

Test-driven development and code review, scaled by tier: nothing for Minor, a single review pass for Medium, dual adversarial review for Complex. A separate security review fires on its own criterion — whether the change touches the security surface — regardless of tier.

The rules governing work handed to sub-agents: how skills are discovered and injected as explicit paths, how a sub-agent escalates when it needs guidance instead of guessing, and which model handles which kind of task.

The project instructions themselves, contextual, shipped. The root file loads at session start; the scoped ones load through nested traversal when a file under their directory is read.

Each one carries a generated [Project Skills Index] block, rewritten at every session start by generate-skills-index.ts. Editing that block by hand has no effect — it is regenerated from disk.

A scoped CLAUDE.md is not re-injected after a compaction. That limitation is what the scope rules exist to compensate for.