Chapters
On this page
DOC-05 / Technical reference · Chapter 11
Skills, Agents & Hooks
How the harness wires skills, delegable sub-agents and event hooks to enforce doctrine.
Overview
The mothership's harness is wired around a .claude/ directory. Three mechanisms coexist there: the skills (invocable capabilities), the delegable sub-agents, and the event hooks that enforce doctrine — commit-on-the-fly, prod/email safeguards, memory injection.
.claude/
user ──▶ settings.json (versioned) + settings.local.json (local)
/ Atlas hooks PreToolUse / PostToolUse / Stop / UserPromptSubmit...
skills/<name>/SKILL.md ──▶ invoked via the Skill tool
agents/<nickname>.md ──▶ delegated via the Agent tool
│ │
▼ ▼
scripts/hook-*.sh facades + memory injection
(safeguards, nudges)
Two settings files coexist:
| File | Git-versioned | Contents |
|---|---|---|
.claude/settings.json | yes | hooks PreToolUse/PostToolUse/Stop/UserPromptSubmit, env, permissions.defaultMode |
.claude/settings.local.json | no (local) | permissions.allow, hooks SessionStart/UserPromptSubmit/PreToolUse/PostToolUse, autoMode |
Both hook sets are cumulative: for a given event (e.g. PreToolUse matcher Bash), the commands from both files run. This is why the Python safeguards live in the local file and the shell nudges in the versioned one.
Skills
Each skill is a .claude/skills/<name>/ directory holding a SKILL.md — either bare markdown, or with a --- description: ... --- frontmatter. An auto/ subfolder gathers engine-internal skills not meant for manual invocation.
Catalogue by category
| Category | Skill | Role |
|---|---|---|
| Audit / health | audit | Full audit of a site (infra healthcheck, public pages, SEO, perf, security, DB) — score /100. |
audit-hard-floor | Anti-rot check of the immutable P0 whitelist — verifies every named path / section still exists. | |
audit-personas | Drift of the 30 personas vs the current stack; snapshot into sy_personas_drift_history. | |
status | Full check of system state. | |
context-status | State of the current session's context. | |
| Infra / hosts | infra | Infra audit of a host machine (availability / load / services / SSL / backups). |
security | Security audit of a host (mothership or tenant). | |
backup-verify | Checks freshness + integrity of a host's local backups. | |
upgrade | Non-interactive APT upgrade of a host with a Docker hold. | |
bots | Analyses bot hits collected server-side. | |
gsc | Queries the Google Search Console API (opportunities). | |
| Chantier / steering | chantier | Chantier steering (doctrine "1 chantier = N travaux"); sources ps_ac_chantier + ps_ac_chantier_travail; supports new-skeleton (atomic creation). |
idee | Creates a brainstorm idea (sy_brainstorm). | |
revue | The Place des Armes review (each agent reports in). | |
montessori | Post-chantier lesson via the Montessori agent → draft in the Vault's inbox folder. | |
| Email / inbox | inbox | Reads / searches emails in ps_ac_inbox_emails via the facade. |
inbox-direct | Direct IMAP fallback, read-only, does not write to the DB. | |
inbox-find | Ergonomic IMAP wrapper — fetch + .eml, lists attachments without extracting (scan-first). | |
scan-attachment | AV scan of an attachment before opening — dedicated facade (Mitnick agent). | |
propal-verif | QA of a commercial email proposal before sending (pool of 4 agents). | |
| Memory / knowledge | recall | Semantic recall (pgvector RAG) over memory, the Vault and ps_ac_{cicatrices,doctrine,chantier} (1024-dim embeddings, cosine). |
zettel | Splits a monolithic document into atomic notes for the Obsidian Vault. | |
dictionnaire | Adds terms to the technical dictionary. | |
victoire | Engraves a victory into ps_ac_cicatrices (kind='victory'). | |
refresh-persona | Refreshes an agent persona via an LLM + 3-way diff + review (UPDATE sy_agents). | |
| Finance / business | bank | Consults accounts / transactions via the banking facade. |
bank-import-n26 | Manual import of bank transactions (ps_ac_bank_transactions). | |
malt | Fetches prospect conversations from the freelance platform. | |
| Publishing | publish | Publishes a blog article on the showcase site. |
DB sources of truth
Skills do not store business data: they hit the PostgreSQL tables (schema vaisseau_mere_ac). Tables explicitly cited in the SKILL.md files:
chantier→ps_ac_chantier,ps_ac_chantier_travailrecall→ps_ac_cicatrices,ps_ac_doctrine,ps_ac_chantiervictoire→ps_ac_cicatrices(kind='victory')idee→sy_brainstormaudit-personas→sy_personas_drift_historyrefresh-persona→sy_agentsinbox→ps_ac_inbox_emailsbank-import-n26→ps_ac_bank_transactions
A pre-invoke hook reads sy_skill.size_bytes to decide whether to suggest a lazy load (3-tier) rather than injecting a large SKILL.md in full.
Sub-agents
Seven <nickname>.md files are delegable via the Agent tool. Each file is generated from the DB by a script that reads the ps_ac_agents view and writes between AUTO-PERSONA-START / AUTO-PERSONA-END markers. The managed zone is never hand-edited.
ps_ac_agentsis a read-only view over the base tablesy_agents(30 rows). The physical source of truth is thereforesy_agents:refresh-personawrites to it, the generator reads the view — consistent, no two-table divergence.
Each agent's frontmatter: name, description (delegation criterion), tools, model.
| Nickname | Codename | Role | Allowed tools | Cognitive frame |
|---|---|---|---|---|
brunel | infra | DevOps / Infrastructure (Docker, nginx, SSL, DNS, VPS) | Bash, Read, Edit, Write, Grep, Glob | Maximum load |
turing | backend | Backend SRE (headless e-commerce, modules, Python, PG integrity) | Bash, Read, Edit, Write, Grep, Glob | Determinism |
eames | frontend | Frontend (Nuxt / Vue / Tailwind / Design System, hub pages) | Bash, Read, Edit, Write, Grep, Glob | Functionalism |
lovelace | qa | QA — last prod gate, Playwright acceptance, regressions | Bash, Read, Grep, Glob (no write) | Pre-mortem |
mitnick | securite | Offensive/defensive security, attachment scan, secret detection, OWASP | Bash, Read, Grep, Glob (no write) | Attacker |
otlet | seo-technique | Technical SEO (JSON-LD, sitemap, CWV, 301, AI indexability) | Bash, Read, Edit, Write, Grep, Glob | Interlinking |
nightingale | client-success | Customer Success — drafts client comms, NEVER sends directly | Read, Grep, Glob (read-only) | Vital signs |
Verifiable observations:
lovelaceandmitnickhave noEdit/Write(control roles, no mutation).nightingaledoes not even haveBash— strictly read, consistent with the rule "the AI never speaks directly to clients".- Known drift: for some agents the managed zone may show a historical DB stack (older Nuxt versions, an older SQL engine) while the manual zone describes the current stack. This is exactly what
audit-personas/refresh-personatrack. Source of truth = the base tablesy_agents, not the.md.
Delegation doctrine: Atlas self-applies the chantier doctrine (≥ 2 distinct agents for a tenant scope) and delegates via the Agent tool. Mitnick in attachment-scan mode is tooling, not a team recruitment.
Hooks
Event map
SessionStart (local) reset context + brief + scar injection
UserPromptSubmit json+local DB schema sync + email check
PreToolUse Bash json+local shell nudges + python safeguards
PreToolUse Agent json+local reactor + agent scar injection
PreToolUse Skill (json) pre-invoke (suggests lazy-load for large SKILL.md)
PreToolUse Edit|Write (local) scar injection
PostToolUse Bash (json) react-log + deploy-preprod post-commit
PostToolUse Agent (json) reactor + react-log + agent telemetry
PostToolUse Edit|Write... (json) track-session-edits
PostToolUse "" (local) context-hook (token counting)
Stop (json) release-lock → scar → uncommitted-warn → chantier-sync
SessionStart
Three commands (local file), each with a short timeout:
- Resets the session's context counter.
- Session brief: reads a pre-computed report (
ps_ac_audit_reports, typedaily_meet, produced by a scheduled task) and enriches it live (git, crontab, client emails, backlog, scar). SQL piped viadocker exec, no npm dependency. - Injects the relevant scars into the startup context.
There is no
SessionStarthook in the versionedsettings.json— it lives only in the local file.
UserPromptSubmit
settings.json: syncs the DB schema dump (.claude/db_schema.md).- local file: checks incoming emails (inbox facade, short timeout, silent and non-blocking on failure).
PreToolUse — Bash matcher
settings.json (nudges, in execution order):
| Script | Effect |
|---|---|
check-db-mutation.sh | blocks a DB mutation (UPDATE/INSERT/ALTER … ps_ac_*) without an aligned code commit in the last 5 minutes (runtime equivalent of "code BEFORE db"). |
hook-pre-deploy-autocommit.sh | auto-commits before a ./deploy. |
hook-chantier-skeleton-nudge.sh | warns on raw SQL INSERT into a chantier instead of the atomic creation path. |
hook-pre-commit-transcript-scan.sh | anti-leak scan before commit. |
A back-office auth audit script exists on disk but is referenced in no
settings*.json→ a dormant script, not to be assumed active.
Local file (Python safeguards, exit 2 = blocking):
| Script | Effect |
|---|---|
| prod-write guard | blocks any Bash command targeting a tenant's prod (host / database / domain markers) with an SQL write pattern → requires a safe prod-write script. Born from an accidental TRUNCATE scar. Anti-false-positive: preprod and non-destructive SELECT/SHOW are explicitly whitelisted, so a smoke check is not blocked. |
| email-facade guard | blocks any bypass of the email facade (raw SMTP/IMAP clients, message construction outside the facade). Only the authorised facade scripts may send/read. |
| Bash scar injection | injects scars related to the command (short timeout). |
PreToolUse — other matchers
- Agent: a shell reactor (json) + agent scar injection (local).
- Skill: a non-blocking pre-invoke (
exit 0always) that suggests a lazy load whensy_skill.size_bytesexceeds a threshold. - Edit|Write (local): scar injection.
PostToolUse
- Bash: react-log + auto-deploy hook after commit (the
deployauto /shipmanual asymmetry). The hook maps touched paths to the impacted site. For tenants this is a preprod deploy; for the mothership there is no preprod —./deploy= a live rebuild, so the word "preprod" in the hook's name is misleading in that case. Skips: the hook skips the deploy if the commit message contains[skip-deploy]/[no-deploy]or starts withwip:, if the commit is pure docs/markdown/Vault (no runtime file touched), or if the working tree is dirty post-commit. - Agent: reactor + react-log + agent telemetry.
- Edit|Write|MultiEdit|NotebookEdit:
track-session-editswrites the list of files edited by the session — the basis of the session-aware Stop hook. - all tools (local): token / context counting.
Stop — execution order
1. release-chantier-lock releases the session's chantier lock
2. stop-cicatrice scar reminder IF closing keywords
("closing", "end of session", "wrapping up"…)
3. uncommitted-warn BLOCKING: refuses Stop if dirty (files FROM
this session) → enforces commit-on-the-fly
4. chantier-sync reminder to sync chantier ↔ hub DB
Key mechanics of the uncommitted warning:
- session-aware: filters
git statuson the files listed by the session → N parallel Claude sessions do not block each other. - anti-loop: if
stop_hook_active=true(2nd pass), it switches to a non-blocking warning instead of{"decision":"block"}. - worker early-return: a sub-claude spawned by the task worker exits silently with
exit 0— it manages its own commit cycle. - exclusion of
.claude/settings.json(the hook may have edited it).
The stop-cicatrice hook is gated by a keyword in the last user message, otherwise silent; when triggered, it lists the fix(*) / Cicatrice commits since the preprod branch via stderr, then exit 2.
Worker-context convention
A single shared lib under scripts/lib/ is sourced by the four Stop hooks; they exit early when the worker context variable is set (injected by the agent spawner). General rule: a sub-claude spawned by the worker does not trigger the user session hooks (commit-on-the-fly, closing scars).
Permissions & environment
settings.json
"env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "0", "CLAUDE_CODE_NO_FLICKER": "0" }
"permissions": { "defaultMode": "auto" }
defaultMode: auto = execution without a prompt by default (consistent with the AI's autonomous ./deploy doctrine).
settings.local.json
permissions.allow: a long allowlist of pre-approved tools / commands;permissions.denyabsent.env: empty.autoMode: a non-standard structured block describing a DB access policy in natural language —allow(read-only SQL on a staging environment),soft_deny(any write to a tenant's prod → explicit confirmation every time), andenvironment(a reminder not to confuse two VPS of the same tenant: prod vs staging).
This autoMode block is doubled at the executable level by the prod-write guard: the declarative policy + the blocking hook.
Anti-leak
No secret in clear text in the hooks/skills/agents: IMAP/SMTP credentials are referenced by variable name in a gitignored environment file, never by value. The pre-commit transcript scan and the security agent (skill scan-attachment) are the anti-leak / anti-malware nets.
Data model
Summary of the tables touched (schema vaisseau_mere_ac), with their producer and consumer:
| Table | Producer | Consumer |
|---|---|---|
sy_agents (base) / ps_ac_agents (view) | manual edit / refresh-persona | persona generator → .claude/agents/*.md |
ps_ac_chantier, ps_ac_chantier_travail | skill chantier | chantier-sync / lock hooks |
ps_ac_cicatrices | skill victoire, stop-cicatrice hook | recall, SessionStart / PreToolUse injection |
ps_ac_audit_reports (daily_meet) | scheduled audit task | session brief (SessionStart) |
sy_skill (size_bytes) | skill indexing | skill pre-invoke hook |
sy_personas_drift_history | audit-personas | drift review |
sy_brainstorm | idee | brainstorm hub |
ps_ac_inbox_emails | inbox facade | skill inbox |
ps_ac_bank_transactions | bank-import-n26 | skill bank |
Verified via
information_schema:ps_ac_agentsis a view over the base tablesy_agents.refresh-personawritessy_agents, the generator reads the view — consistent, not two divergent tables.