Skip to main content

AgentBoot Concepts

AgentBoot is a harness engineering build tool. It compiles agentic personas β€” the behavioral definitions that make AI agents reliable β€” into platform-native formats for every major coding agent (Claude Code, OpenAI Codex, Copilot, Cursor, Gemini, Windsurf, JetBrains) and the universal AGENTS.md standard.

This document explains the conceptual foundation. Read this before the configuration reference or getting-started guide. The concepts here inform every design decision.


What is a trait​

A trait is a reusable behavioral building block for an AI persona. It captures a single aspect of how an agent should think or communicate β€” a cognitive stance, an output discipline, or an epistemic commitment.

The analogy from software engineering is the DRY principle applied to AI behavior. Before traits, every persona had to independently specify its approach to things like skepticism, output structure, and evidence requirements. In practice, this meant the same concepts were expressed slightly differently in every persona β€” sometimes well, sometimes poorly, always inconsistently. When you wanted to improve how all your personas handle uncertainty, you had to touch every file.

Traits solve this. You write critical-thinking once. Every persona that needs skeptical review simply composes it with a weight. Change the trait definition, and every persona that composes it picks the change up on the next build.

A trait is not:

  • A checklist of domain rules. "Verify that GDPR consent is captured" is not a trait; it is a domain-specific requirement that belongs in a domain layer.
  • A persona. A persona has identity, purpose, and scope. A trait has neither β€” it only modulates behavior.
  • A prompt template. Traits are building blocks, not invocation patterns.

The trait files in core/traits/ are the authoritative definitions. Each one defines the behavior, the anti-patterns to avoid, and the interaction effects with other traits. (The trait weight system supports HIGH / MEDIUM / LOW / MAX / OFF calibration β€” see below.)


What is a lexicon​

A lexicon is a set of domain term definitions β€” ubiquitous language that establishes shared vocabulary between humans and agents. Inspired by Domain-Driven Design, a lexicon ensures that when you say "full-build" or "spoke" or "NIQ," the agent resolves these to the exact same meaning you intend.

Lexicons are context compression primitives. Once defined, every trait, gotcha, instruction, and persona can reference lexicon terms without re-explaining them. This saves tokens on every turn β€” and since CLAUDE.md content costs money per turn (it's injected as a system-reminder, not in the cached system prompt), compression compounds across every session.

Lexicons compile first in the pipeline. They appear at the top of compiled output so the LLM has term definitions resolved before encountering traits and rules that reference them. The compilation order is:

lexicon β†’ traits β†’ instructions β†’ gotchas β†’ personas

Lexicon entries can reference other lexicon entries, enabling hierarchical compression. A deployment entry references canary, blue-green, rollback β€” each defined once, the full semantic tree unpacked from minimal tokens.

The lexicon files in core/lexicon/ use a structured format:

# core/lexicon/project-terms.yaml
terms:
full-build:
definition: Complete validation pipeline. Must pass before any PR.
includes: lint, typecheck, test, build
NIQ:
definition: Project tracking prefix.
format: "NIQ-{N}"
usage: commit messages, branch names
spoke:
definition: A target repo that receives compiled personas from the hub.
see: hub-and-spoke distribution

Composition type: rule by default. Org-level term definitions cannot be silently redefined by teams. Teams can add terms at their scope level, but cannot replace org definitions. (A future abstract/binding mode will allow orgs to define term contracts with team-specific implementations β€” see roadmap.)


What is a persona​

A persona is a complete, deployable agent: a composition of traits plus a specialized system prompt that defines the agent's identity, operating context, and mandate.

AgentBoot uses the agentskills.io SKILL.md format for persona files. This means every persona is a Markdown file with YAML frontmatter that specifies its ID, version, traits, scope, and output format β€” followed by the system prompt in prose. The frontmatter is machine-readable (the build and sync tooling uses it); the prose is human-readable and is what the model receives.

The frontmatter trait block is where trait composition happens:

traits:
critical-thinking: HIGH
structured-output: true
source-citation: true
confidence-signaling: true

Each trait listed here is resolved from the trait definitions at build time and woven into the persona's effective system prompt. This means the persona author writes what makes their persona unique β€” the domain knowledge, the operating context, the mandate β€” and inherits the generic behavioral discipline from the trait definitions.

A persona is not:

  • A chat conversation. Personas are always-on agents that operate within a defined scope, not one-off system prompts.
  • An extension of another persona. Personas compose traits; they do not inherit from each other.
  • A configuration file. The SKILL.md prose is the primary artifact. The frontmatter is metadata, not the definition.

The scope hierarchy​

AgentBoot models your organization as a scope tree. The current model is N-tier nodes β€” arbitrary-depth scopes defined under nodes in agentboot.config.json, each adding personas/traits and able to override config. The classic four-level shape is the common case:

org
└── group
└── team
└── repo

The legacy flat groups/teams config is still supported and converted to nodes internally.

This mirrors the way real organizations are actually structured β€” and the way responsibility and governance work in them.

Org level is where universal rules live. Code review standards that apply to every engineer, security guardrails that the CISO requires on all codebases, output discipline that the organization wants from every AI interaction. Org-level configuration is always active in every repo that is registered with the org.

Group level is for horizontal concerns that cross teams but do not apply to the whole org. A platform engineering group might deploy additional infrastructure review personas to all platform teams. A product group might add user-facing copy review personas that the platform group doesn't need.

Team level is where team-specific customization happens. A team that works in a specific framework, owns a specific kind of system, or has team-level standards that differ from the group default can add configuration at this level. Team-level configuration layers on top of group and org, never replacing it.

Repo level is where path-scoped instructions live. Repos can add instructions that activate only when specific file types or directories are touched. A Lambda functions directory might activate additional serverless-specific review guidance. A database migrations directory might activate schema review guardrails.

Precedence and composition types: Each artifact has a composition type that determines how scope conflicts are resolved. Rule composition (top-down): the highest scope wins β€” an org-level gotcha cannot be overridden by a team. Preference composition (bottom-up): the lowest scope wins β€” a team can customize an org default. Defaults: gotchas, personas, persona-rules, and lexicons are rule (enforced top-down); traits and instructions are preference (customizable by teams). Individual artifacts can override their default composition type via frontmatter (composition: rule).

This hierarchy matters for two reasons. First, it ensures that governance propagates downward automatically β€” a new team that registers with the org immediately gets all org-level and group-level configuration without any manual setup. Second, it preserves team autonomy on things that are genuinely team-specific.


Multi-platform output​

AgentBoot generates platform-native output for every major coding agent. The same personas, traits, gotchas, and instructions compile into the right format for each platform β€” developers use whichever tool they prefer without losing governance.

Output formats:

  • AGENTS.md β€” universal cross-tool standard (Cursor, Copilot, Gemini CLI, etc.)
  • Claude Code β€” full .claude/ directory with agents, skills, rules, traits, hooks
  • OpenAI Codex β€” .codex/ config, hooks, and skills (config.toml with the MCP entry)
  • Copilot β€” copilot-instructions.md, .github/agents/, scoped instructions
  • Cursor β€” .cursor/rules/*.mdc with alwaysApply/globs frontmatter
  • Gemini β€” GEMINI.md project instructions + .gemini/ rules directory
  • Windsurf β€” .windsurfrules flat text file (all personas concatenated)
  • JetBrains β€” .junie/guidelines.md + .aiassistant/rules/
  • SKILL.md β€” agentskills.io cross-platform format

Claude Code-native output​

Claude Code is the most feature-rich platform. Its native output uses the full feature surface β€” agents with tool restrictions, path-scoped rules that re-inject on every matching file access, lifecycle hooks, managed settings, and MCP servers.

Key architectural insight: CLAUDE.md content is injected as <system-reminder> tags (not in the cached system prompt). Rules in .claude/rules/ are re-injected every time a matching file is touched. So a gotcha stays in context for the work it applies to and costs nothing for the work it doesn't.

What Claude Code reads natively (no build step required)​

.claude/
β”œβ”€β”€ CLAUDE.md # Project instructions (supports @imports)
β”œβ”€β”€ settings.json # Hooks, permissions, env vars
β”œβ”€β”€ settings.local.json # Local overrides (gitignored)
β”œβ”€β”€ agents/
β”‚ └── {name}/CLAUDE.md # Custom subagents (not SKILL.md)
β”œβ”€β”€ skills/
β”‚ └── {name}/SKILL.md # Invocable skills (agentskills.io format)
β”œβ”€β”€ rules/
β”‚ └── {topic}.md # Path-scoped rules (paths: frontmatter)
└── .mcp.json # MCP server configuration

@import: the key Claude Code feature AgentBoot must use​

Claude Code's CLAUDE.md supports @path/to/file imports that expand inline at load time. This changes the compilation model fundamentally:

Cross-platform output (current): Traits are inlined into SKILL.md at build time. Each compiled persona is a standalone file with all trait content baked in. This is necessary for platforms that don't support file inclusion.

Claude Code-native output (new): Traits stay as separate files. The generated CLAUDE.md uses @imports to compose them at load time:

# Code Reviewer

@.claude/traits/critical-thinking.md
@.claude/traits/structured-output.md
@.claude/traits/source-citation.md

You are a code reviewer. Your job is to find bugs, quality issues...

This has three advantages over inlined output:

  1. Maintainability β€” traits are maintained in one place. Updates propagate to all composing personas automatically without rebuilding.
  2. Live editing β€” changing a trait file takes effect immediately without rebuilding.
  3. Transparency β€” developers can read each trait file independently instead of wading through a monolithic system prompt.

The build system generates one self-contained folder per platform under dist/. Each platform folder (e.g., dist/claude/, dist/copilot/, dist/cursor/, dist/skill/, dist/agents/, dist/gemini/, dist/windsurf/, dist/jetbrains/) contains everything needed for that platform and nothing it doesn't. The Claude Code folder uses @import-based files; the skill folder uses inlined SKILL.md for cross-platform distribution.

Agent frontmatter: much richer than SKILL.md​

Claude Code's .claude/agents/{name}/CLAUDE.md supports frontmatter fields that the generic SKILL.md format does not:

---
name: review-security
description: Deep security review β€” OWASP, auth, data handling, PHI
model: opus # Per-agent model selection
permissionMode: default # default | acceptEdits | bypassPermissions
maxTurns: 25 # Agentic turn limit
disallowedTools: Edit, Write, Agent # Tool restrictions (read-only reviewer)
tools: Read, Grep, Glob, Bash # Tool allowlist (alternative to denylist)
skills: # Preload these skills into agent context
- hipaa-check
- review-security
mcpServers: # Scoped MCP servers
- compliance-kb
hooks: # Agent-specific hooks
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./hooks/validate-no-phi.sh"
memory: project # Persistent memory scope
isolation: worktree # Git worktree isolation
---

AgentBoot's persona.config.json should map to these fields. The compile step should generate Claude Code agent CLAUDE.md files with the full native frontmatter β€” not just the subset that agentskills.io supports.

Rules use paths:, not globs:​

Claude Code's .claude/rules/ files use paths: in frontmatter (not globs:). The An earlier implementation used globs: which was valid at the time but the current Claude Code documentation specifies paths::

---
paths:
- "src/api/**/*.ts"
- "**/*.sql"
- "**/migrations/**"
---

AgentBoot's gotchas rules and path-scoped instructions should generate paths: frontmatter for Claude Code output and globs: where other platforms expect it.

Hooks belong in settings.json​

Claude Code hooks are configured in .claude/settings.json, not in standalone files. AgentBoot's compliance hooks should generate settings.json entries:

{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/phi-input-scan.sh",
"timeout": 5000
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/phi-output-scan.sh"
}
]
}
]
}
}

The available hook events cover the full agent lifecycle: SessionStart, PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStart, SubagentStop, Notification, and more. AgentBoot should generate hook configurations for compliance, audit logging, and guardrail enforcement as part of the sync output.

Managed settings = HARD guardrails​

Claude Code's managed settings (/Library/Application Support/ClaudeCode/ on macOS, /etc/claude-code/ on Linux) are deployed by MDM and cannot be overridden by any user or project setting. This is the native mechanism for HARD guardrails:

/Library/Application Support/ClaudeCode/
β”œβ”€β”€ managed-settings.json # Non-overridable settings + hooks
β”œβ”€β”€ managed-mcp.json # Non-overridable MCP servers
└── CLAUDE.md # Non-overridable instructions

AgentBoot should generate managed settings artifacts for organizations that deploy via MDM. These map directly to the HARD guardrail tier β€” PHI scanning hooks, credential blocking, audit logging that no developer can disable.

MCP configuration in .mcp.json​

When personas need external tool access (knowledge bases, data detection, domain lookup), AgentBoot should generate .mcp.json entries:

{
"mcpServers": {
"compliance-kb": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@my-org/compliance-kb-server"]
}
}
}

This is synced to target repos alongside the persona files. Agents that reference MCP servers in their frontmatter (mcpServers: [compliance-kb]) will automatically have access.

Skills with context forking​

Claude Code skills support context: fork which delegates the skill to a subagent with an isolated context. This is the native mechanism for reviewer isolation β€” the reviewer doesn't see the generation conversation:

---
name: review-code
description: Code review against team standards
context: fork
agent: code-reviewer
allowed-tools: Read, Grep, Glob, Bash
---

AgentBoot's review personas should use this pattern for Claude Code output. The skill is the invocation surface (/review-code), and it forks to the agent, which runs in isolation with its own tools and permissions.

Summary: per-platform compilation targets​

AgentBoot's compile step produces one self-contained folder per platform under dist/. Each folder has everything needed for that platform, nothing it doesn't. Scope hierarchy (core β†’ groups β†’ teams) is preserved within each platform folder. Duplication across platforms is intentional β€” generated files are cattle not pets. Diffing across platforms (e.g., diff dist/claude/ dist/copilot/) shows exactly what's different between distributions.

dist/
β”œβ”€β”€ claude/ # Self-contained Claude Code distribution
β”‚ β”œβ”€β”€ core/
β”‚ β”‚ β”œβ”€β”€ agents/code-reviewer.md
β”‚ β”‚ β”œβ”€β”€ skills/review-code.md
β”‚ β”‚ β”œβ”€β”€ traits/critical-thinking.md
β”‚ β”‚ β”œβ”€β”€ rules/baseline.md
β”‚ β”‚ β”œβ”€β”€ CLAUDE.md (with @imports)
β”‚ β”‚ └── settings.json (hooks)
β”‚ β”œβ”€β”€ groups/{group}/
β”‚ └── teams/{group}/{team}/
β”‚
β”œβ”€β”€ copilot/ # Self-contained Copilot distribution
β”‚ β”œβ”€β”€ core/
β”‚ β”‚ β”œβ”€β”€ .github/copilot-instructions.md
β”‚ β”‚ └── .github/prompts/review-code.md
β”‚ β”œβ”€β”€ groups/...
β”‚ └── teams/...
β”‚
β”œβ”€β”€ cursor/ # Self-contained Cursor distribution
β”‚ β”œβ”€β”€ core/
β”‚ β”‚ └── .cursor/rules/*.mdc
β”‚ β”œβ”€β”€ groups/...
β”‚ └── teams/...
β”‚
└── skill/ # Cross-platform SKILL.md (agentskills.io)
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ code-reviewer/SKILL.md (traits inlined)
β”‚ └── PERSONAS.md
β”œβ”€β”€ groups/...
└── teams/...

The sync engine reads from dist/{platform}/ and writes to target repos in platform-native locations. Organizations choose which platform to deploy per repo based on their agent toolchain.


Prompts as code​

AgentBoot treats AI agent behavior as infrastructure: defined in files, stored in version control, reviewed in pull requests, with a complete audit history.

This is the same shift that happened with Infrastructure as Code (Terraform, Pulumi) and Configuration as Code (Kubernetes manifests, GitHub Actions workflows). Before IaC, every environment was a snowflake β€” you could not reproduce it, you could not review changes to it, and you could not trace the history of decisions. After IaC, every change is a commit.

Prompts as Code applies the same discipline to AI behavior. Before it, every team's CLAUDE.md was written in isolation, improved informally, and never reviewed. When something went wrong with an agent, there was no diff to examine. When best practice evolved, there was no way to propagate the update.

With AgentBoot:

  • Every change to an agent's behavior is a pull request with a description and a review.
  • Traits and personas have version numbers. You can pin a repo to critical-thinking@1.2 and upgrade deliberately.
  • The sync pipeline means the update propagates to all registered repos automatically after the PR merges.
  • The PERSONAS.md registry is generated from the source files β€” it is always accurate because it cannot drift from the actual definitions.

This is not bureaucracy for its own sake. It is the mechanism by which a small team can govern AI agent behavior across dozens or hundreds of repos without heroic manual effort.


The distribution model​

AgentBoot follows a hub-and-spoke distribution model:

github.com/acme/personas (hub)
└── agentboot build && agentboot sync
β”œβ”€β”€ repo-A/.claude/
β”œβ”€β”€ repo-B/.claude/
└── repo-N/.claude/

Personas hub naming convention​

The hub repo is the org's single source of truth for all agentic personas, traits, and instructions. The recommended naming convention:

PriorityNameWhen to use
DefaultpersonasUse this. The GitHub org already namespaces it (github.com/acme/personas).
Fallbackagent-personasIf personas is already taken (e.g., marketing/UX personas).

Avoid redundant prefixes β€” github.com/acme/acme-personas repeats the org name. Avoid tool-specific names β€” acme-agentboot implies a fork of the build tool. Use short names or abbreviations β€” "ACME Technologies LLC" is just acme.

The agentboot install wizard checks for existing personas repos and suggests agent-personas as the fallback when there's a collision.

Hub contents​

The hub is a single private repository that your organization owns, created from the AgentBoot template. It contains:

  • Your agentboot.config.json
  • Any org-specific persona extensions (traits, gotchas, instructions)
  • repos.json listing the spoke repos that receive compiled output

The spoke repos are your actual codebases. They receive compiled persona files, always-on instruction fragments, and path-scoped instructions via the sync script. They do not contain the source of truth β€” only the compiled output. If a team wants to understand why an agent behaves a certain way, they look at the hub, not their own repo.

The build step (npm run build) resolves all trait compositions, validates frontmatter, generates PERSONAS.md, and produces the compiled output. The sync step (npm run sync) pushes the compiled output to each registered repo and opens a PR. Human review of that PR is the governance checkpoint.

This model has a deliberate property: the spokes are passive. They receive governance; they do not produce it. Teams can add repo-level extensions through the hub's team configuration β€” they do not commit persona files directly to their own repos. This prevents drift and keeps the hub authoritative.

Public repo pattern​

For private repos, sync creates a PR and the compiled .claude/ content is committed normally. But for public repos, committing org-specific personas would leak private content (org traits, internal gotchas, compliance rules) into a public repository.

The public repo pattern solves this:

  1. Compiled output is gitignored in the public repo (.claude/ in .gitignore)
  2. Repo-specific enrichments live in the hub, not in the target repo, under a public-repos/{repo}/ directory
  3. Sync still writes locally β€” developers get the files, they just aren't committed
  4. New developers run agentboot install --connect to pull content from the hub on first clone

The prompts-as-code invariant holds: all content is in version control, reviewed, and audited β€” it's just in the hub's private git instead of the spoke's public git.

Hub structure with public repos:

acme/personas/
β”œβ”€β”€ core/ # org-wide (all repos)
β”œβ”€β”€ groups/
β”œβ”€β”€ teams/
β”œβ”€β”€ public-repos/ # only if org has public repos
β”‚ β”œβ”€β”€ agentboot/
β”‚ β”‚ β”œβ”€β”€ rules/no-runtime.md
β”‚ β”‚ └── gotchas/jsonc-parser.md
β”‚ └── oss-library/
β”‚ └── gotchas/wasm-compat.md
β”œβ”€β”€ agentboot.config.json
└── repos.json

Scope merge order with public repos: core/ β†’ groups/{g}/ β†’ teams/{g}/{t}/ β†’ public-repos/{repo}/

Accepted scope source layouts. The canonical location for scope-level content is nodes/<path>/ (e.g. nodes/platform/api/personas/). Two legacy layouts are equally honored by validate, compile, audit, and sync alike: nested groups/<g>/teams/<t>/ and sibling teams/<g>/<t>/. Pick one and stay consistent β€” all commands see all three, so content can never be guarded by one command and invisible to another.

The public-repos/ scope is the most specific β€” it wins on filename conflict.

Developer experience is identical. A developer inside a public repo runs the same commands as in a private repo:

agentboot add gotcha "JSONC parser doesn't handle block comments"

AgentBoot detects the repo is public (from repos.json or git remote), confirms the hub is available and writable, and routes the content to public-repos/{repo}/ in the hub. The developer never changes directories or thinks about where the file goes.

If the hub is not available or not writable, the command errors:

ERROR: Hub repo not found or not writable. Your gotcha cannot be persisted.
Run `agentboot install --connect` to link your hub, or check permissions.

This is a hard error, not a warning. Content never falls through to the public repo's git. There is no "write it anyway" option.

repos.json marks public repos explicitly:

[
{ "path": "../api", "label": "API", "platform": "claude" },
{ "path": "../agentboot", "label": "AgentBoot", "platform": "claude", "public": true }
]

LLM and deterministic commands​

AgentBoot's CLI has two classes of commands, separated by whether they invoke an LLM.

Deterministic commands are pure Node.js β€” fast, free, predictable, and work offline. They never call an LLM, never cost money, and never require a login beyond npm:

install, uninstall, build, validate, sync, doctor, add, lint, status, config, export, cost-estimate (pricing arithmetic over published rates β€” no LLM call), test (SHA-256 snapshot/regression comparison over dist/), conformance, verify-manifest, drift-check, telemetry-inspect, telemetry-ship, telemetry-verify, evidence-pack, audit

LLM-powered commands use claude -p (Claude Code's non-interactive mode) to invoke the user's existing Claude Code session. They cost money (billed to the user's Claude subscription), produce non-deterministic output, and require an active Claude Code login:

import

That is the whole list at v1.0 β€” exactly one command can cost you money. Behavioral (LLM-judged) persona evaluation was the second candidate and is not part of the v1.0 surface; see prompt-guide Β§ 6 for what agentboot test does instead, and the roadmap for where behavioral evaluation is tracked.

Import is also available conversationally through the /ab skills inside a Claude Code session, using AgentBoot's MCP server as a bridge. The CLI version is batch-oriented; the skill version is conversational. Both use the same personas repo and the same non-destructive guarantees.

This separation is a deliberate architectural decision. A user running agentboot build should never be surprised by an LLM call, a cost, or a login prompt. LLM features are always opt-in and clearly labeled.


The trait weight system​

Implemented (Phase 7, AB-134). persona.config.json supports both array format (backward compatible, all traits at MEDIUM) and object format with named weights. Compile-time calibration preambles are implemented for critical-thinking. Other traits will gain calibration text incrementally.

Several core traits β€” critical-thinking is the primary example β€” expose a weight axis: HIGH, MEDIUM, and LOW. This is not a priority system; it is a calibration system.

The same underlying logic applies at every weight. At HIGH, the threshold for surfacing a concern is very low β€” the persona speaks up about anything it notices. At LOW, the threshold is high β€” the persona surfaces only things that clearly matter. MEDIUM is the calibrated default for ordinary review.

Why not just write separate personas for "strict" and "lenient" review? Because the behavioral logic is identical; only the threshold differs. Separate personas would duplicate that logic and diverge over time. The weight system keeps the logic in one place (the trait definition) while letting persona authors calibrate the stance.

In practice: security reviewers use critical-thinking: HIGH because the cost of missing a vulnerability is high. A documentation reviewer might use critical-thinking: MEDIUM because it needs to flag genuine problems without making authors feel attacked by minor nit feedback. A first-pass code review persona for learning environments might use critical-thinking: LOW to reduce noise and keep the feedback focused.

The weight does not override the severity floor. At any weight, CRITICAL findings must always surface. critical-thinking: LOW reduces noise; it does not create blind spots.


Gotchas rules​

A gotchas rule is a path-scoped instruction that encodes hard-won operational knowledge β€” the kind of information that lives in one engineer's head until they leave and the team rediscovers it the hard way. Every organization has these. AgentBoot makes them a first-class concept.

A gotchas file is a Markdown file with paths: frontmatter that limits when the rule activates. When a developer is working on a file that matches the glob pattern, the gotchas content is automatically included in the agent's context. When working on unrelated files, the gotchas are invisible β€” zero context cost.

---
paths:
- "db/**"
- "**/*.sql"
- "**/migrations/**"
description: "PostgreSQL and RDS gotchas"
---

# PostgreSQL / RDS Gotchas

- **Partitions do NOT inherit `relrowsecurity`.** Enable RLS explicitly on each
partition.
- **Always verify `relrowsecurity` is ON, not just that policies exist.** Policies
without enforcement = no protection.
- **UUID PK causes exponential INSERT slowdown.** Drop ALL indexes before bulk load,
recreate after.

Gotchas rules belong in your domain layer or in team-level extensions β€” they are organization-specific by nature. AgentBoot core does not ship gotchas because they are inherently tied to your stack and your production incidents.

The pattern is powerful because it captures knowledge at the exact moment it is needed. A developer writing a database migration sees the PostgreSQL gotchas. A developer writing a Lambda handler sees the serverless gotchas. No one has to remember to consult a wiki page or ask the right person.


Compliance hooks​

AgentBoot supports a defense-in-depth model for compliance enforcement, using the hook system provided by the target agent platform.

The model has three layers, in decreasing order of enforcement strength:

  1. Input hook (deterministic): A pre-prompt hook that scans user input before the model sees it. If the hook detects a violation (PHI, credentials, internal URLs), it blocks the request with a non-zero exit code. This is the strongest available technical control.

  2. Instruction-based refusal (advisory): An always-on instruction fragment that tells the model to refuse to process sensitive content. This is prompt-level, not deterministic β€” the model may not recognize all violations. But it is active in every interaction and costs nothing when not triggered.

  3. Output hook (remediation-forcing): A post-response hook that scans the model's final message (delivered to the Stop hook as last_assistant_message, with a transcript-file fallback). What blocking means here, stated precisely: the hook cannot retract text that has already rendered to the developer's screen, but with outputScan.blocking enabled it can refuse to let the turn end β€” the model receives the flagged reason and must redact and, where applicable, trigger rotation before it can finish. Without blocking, this layer logs and warns only. The render-then-scan ordering is an architectural constraint of the platform, not a bug. Document it honestly: this is remediation-forcing, not display suppression.

The three layers are complementary. The input hook catches what it can deterministically. The instruction catches what the model can recognize. The output hook provides audit evidence and catches leakage that the instruction missed. No single layer is sufficient alone.

AgentBoot generalizes this from healthcare PHI to any sensitive data pattern β€” PII, credentials, internal API keys, production URLs, customer data. The hook templates are configurable per organization through the domain layer.

Honest limitation: Hook support varies by platform. AgentBoot emits compliance hooks for Claude Code (.claude/settings.json), Codex (.codex/hooks.json), and GitHub Copilot (.github/hooks/agentboot.json), all of which block on exit code 2 β€” with Copilot's ceiling stated: its exit-2 blocking is documented platform behaviour we have not yet verified end to end, and its command-hook timeouts fail open. IDE-based community-tier platforms (Cursor, JetBrains) generally have no hook mechanism, so enforcement there is advisory only. AgentBoot documents these gaps per platform rather than promising universal enforcement β€” see the platform capability matrix.


The capability gate: a control that reaches nothing FAILS the build​

Ruled 2026-08-11, and this is the v1.0 contract: RAISE, not warn. When a control is configured and no configured output format can carry it, agentboot build exits non-zero and names the capability, the formats you configured, and the formats that could have carried it. The alternative β€” emit a warning and build anyway β€” was considered and rejected.

The defect this closes is the product's own signature class. Emission was decided by a scattered set of independent "is this format configured" tests, each with an empty else, so a capability whose test came out false produced no file, no log line and no record that it had ever been asked for. Eight of them were found on a real hub β€” an org PreToolUse gate, a fail-closed DLP scanner, a digest-pinned MCP allowlist, disableBypassPermissionsMode, model overrides and more β€” and all eight passed build, validate --strict and doctor with zero mention. The configuration said the control was on. Nothing anywhere said it was reaching nobody.

Why RAISE rather than warn, stated once so it does not get relitigated at every adopter complaint:

  • The direction of the mistake is asymmetric. Shipping permissive and tightening later breaks builds that had been passing for a whole major version; shipping strict and loosening later breaks nobody. Only one of those two choices is available after the 1.0 tag.
  • A warning on a governance control is a warning nobody reads. The population that hits this gate is, by construction, the population that believed a control was in force. Telling them in yellow is how the original defect got its eight instances.
  • It is a build-time refusal, not a runtime one. Nothing an adopter has already deployed stops working; the next build tells them the truth about what it emits.

This is a BREAKING change and hubs will meet it on upgrade β€” see the CHANGELOG. Two exits, both explicit: add an output format that can express the control, or waive the gap with a capability:<id> entry in agentboot-exceptions.json. A waiver requires an owner and an approver, expires, and still prints on every build β€” see Exception governance below and configuration.md Β§ Capability coverage for the per-capability table of which platforms emit what.

A capability whose severity is warn rather than error still exists β€” the gate is not uniformly fatal, it is fatal for controls whose whole purpose is enforcement. What changed is that no gap is silent.


Exception governance​

When a persona or policy check flags something, and the team intentionally chose to do it differently, the organization needs a mechanism to say "this is an approved exception." Without this, every guardrail violation becomes a battle, and engineers start ignoring findings.

The shipped mechanism is the policy-exception file β€” owned, expiring, reviewable JSON (see configuration.md Β§ Policy exceptions):

  • Hub: agentboot-exceptions.json at the hub root, validated by agentboot validate.
  • Spoke repo: .agentboot-exceptions.json at the repo root, consumed by agentboot drift-check. A modified or missing managed file covered by an unexpired "policy": "drift:<path-or-glob>" exception reports as excepted (with its exception id) instead of failing β€” approved drift is distinguished from unauthorized drift, never hidden.

Every exception requires an id, policy, reason, approver, owner, created, and expires. Because the file lives in git, proposing an exception is a PR, approval is a PR review, and the exception itself is reviewable history. Expiry is enforced: an expired exception is treated as absent β€” the drift or validation failure resurfaces and the report names the owner. Exceptions expiring within 14 days produce warnings. "Just this once" cannot silently become forever.

Design intent, not shipped: a fuller ADR-based lifecycle β€” /create-adr / /propose-exception skills that draft formal Architecture Decision Records, an adrs/index.json the build can reference, and personas that learn to accept an approved deviation for a specific case β€” is a direction under consideration, not a current feature.

This is complementary to the temporary elevation pattern (where a developer needs a one-time bypass for debugging). Policy exceptions handle approved, time-bounded deviations. Temporary elevation handles emergency access with audit trail and auto-expiry. A mature governance system needs both.


Numeric trait weights​

Implemented (Phase 7, AB-134). Numeric weights (0.0–1.0) are supported alongside named weights. resolveWeight() in config.ts handles both forms.

The HIGH / MEDIUM / LOW weight system described earlier is the simplified interface. Under the hood, traits that support calibration use a numeric 0.0–1.0 scale that maps to finer-grained behavior:

NumericNamedTypical Use
0.0OFFTrait inactive
0.3LOWLight review β€” trust the author, flag only clear defects
0.5MEDIUMStandard β€” question choices, verify claims
0.7HIGHThorough β€” actively look for hidden issues
1.0MAXAdversarial β€” assume hostile input, verify everything

In persona.config.json, you can use either form:

{
"traits": {
"critical-thinking": "HIGH",
"creative-suggestion": 0.3
}
}

The build system resolves named weights to their numeric equivalents. The persona's compiled SKILL.md receives the calibration instructions appropriate for its weight.

The creative-suggestion trait (planned) is the counterpart to critical-thinking. Where critical thinking is the tear-down dial (skepticism), creative suggestion is the build-up dial (proactive improvement suggestions). Security reviewers typically use high critical thinking and low creative suggestion. Code reviewers use moderate levels of both.


Self-improvement reflections​

Personas can optionally write a brief reflection after completing their task. The reflection is saved to .claude/reflections/{persona-name}/{timestamp}.md and captures: what the persona was asked to do, what it found, what it was uncertain about, and what it would do differently next time.

Over time, these reflections accumulate into a dataset that reveals patterns: which findings are most common, which areas have the most uncertainty, which personas are invoked most frequently. A /review-reflections skill can summarize these patterns for human review β€” identifying trait calibration opportunities, missing rules, or personas that need additional training data.

The self-improvement loop progresses through three phases:

  • Phase A (current): Humans edit persona definitions based on observed behavior
  • Phase B (design target): Reflections + /review-reflections skill
  • Phase C (future): Automated accuracy tracking

This is opt-in β€” not all agent platforms support file write-back, and not all organizations want the overhead. Enable it in agentboot.config.json when ready.


Reviewer selection​

When a codebase has multiple reviewer personas (code, security, architecture, cost), developers should not have to decide which one to invoke. A reviewer selection config maps file paths and change types to the appropriate reviewer(s):

{
"rules": [
{ "glob": "**/*.sql", "reviewers": ["code-reviewer", "security-reviewer"] },
{ "glob": "infra/**", "reviewers": ["code-reviewer", "cost-reviewer"] },
{ "glob": "src/auth/**", "reviewers": ["security-reviewer"] }
],
"default": ["code-reviewer"]
}

A /review meta-skill reads this config, inspects the current diff, and routes to the appropriate persona(s). The developer invokes /review and the system decides which specialists are needed. This is the orchestrator pattern from the origin designs β€” a lightweight routing layer, not a complex agent-to-agent messaging system.


HARD/SOFT guardrail elevation​

Not all guardrails are equal. Some rules must never be bypassed β€” a PHI scrubber in a healthcare org, a credential scanner in a fintech. Others are important defaults that a senior engineer may need to temporarily override for debugging or experimentation.

AgentBoot distinguishes two tiers:

HARD guardrails are marked required: true in the org config. What that buys you is a composition property, enforced at compile time: a lower scope may not weaken one β€” shadowing it, downgrading it to soft, or zeroing its trait weight are all errors under validate --strict, and a team-level config that attempts to disable a HARD guardrail causes a build failure. HARD guardrails are for rules where violation is a compliance incident, not a judgment call.

Whether a HARD guardrail is also a mechanical control at runtime depends on the target. It is a hard policy everywhere and a hard control only on the three officially supported CLI surfaces, and those three are not equal:

TargetWhat a HARD guardrail actually does at runtime
Claude CodeHard-enforced β€” blocking hooks, plus managed-settings.json, the only non-overridable settings layer any supported platform has (MDM-deployable, Claude Code only)
OpenAI Codex CLIEnforced, known bypasses β€” blocking hooks, but they require a trust review unless deployed as managed, and tool coverage is partial (shell/patch/MCP, not WebSearch)
GitHub Copilot CLIBlocking hooks with a lower ceiling β€” command-hook timeouts fail open, and exit-2 blocking is documented platform behaviour not yet verified end to end
AGENTS.md and the community tier (Cursor, Gemini, Windsurf, JetBrains, SKILL.md)Advisory β€” the content is delivered, nothing blocks

See the platform capability matrix for the full classification, and guardrails.md for the compiled-hook mechanics.

SOFT guardrails are deployed via the shared repo and can be temporarily elevated. The elevation mechanism:

  1. Developer invokes /elevate {guardrail-name} with a reason
  2. The skill grants a time-bounded bypass (default TTL: 30 minutes)
  3. An audit log entry is created: who elevated, what, why, when, TTL
  4. When the TTL expires, the guardrail automatically re-engages
  5. All actions taken during the elevation window are logged

For larger organizations where automated elevation creates audit risk, AgentBoot also supports a manual escalation model: the developer files a GitHub issue requesting bypass, a designated approver grants or denies it, and the decision is recorded. This is the pattern used in a large enterprise design, where the team size and compliance requirements made automated elevation inappropriate.

A mature governance system needs both HARD/SOFT tiers and both temporary elevation (for debugging) and permanent exceptions (ADRs, described above).


Team champions​

Technical distribution of personas is necessary but not sufficient. Adoption requires a human governance layer β€” someone on each team who understands the persona system, syncs updates, files quality feedback, and answers questions from teammates.

AgentBoot calls this role the Team Champion. Each team designates one engineer (typically a tech lead or senior IC) who:

  • Runs npm run sync to pull the latest persona updates into team repos
  • Reviews sync PRs before merging (the governance checkpoint)
  • Files GitHub issues against the personas repo when a persona produces poor findings or misses something it should have caught
  • Onboards new team members on how to use the persona system
  • Proposes new gotchas rules, trait calibration changes, or team-level extensions based on their team's experience

The Team Champion is not a full-time role β€” it is a rotating responsibility that takes minutes per week in steady state. The value is having a named person accountable for the feedback loop between the team and the personas repo.

This pattern was validated in a large engineering organization, where the studio has multiple siloed development teams. Without Team Champions, persona updates would land in team repos without anyone understanding what changed or why. With them, each team has a human bridge between the governance system and the developers who use it daily.


SME discoverability​

When an organization has domain expert personas (compliance SMEs, FHIR experts, architecture advisors), developers need to know they exist before they can use them. A persona that no one knows about delivers no value.

AgentBoot addresses this with a discoverability fragment β€” a lightweight always-on CLAUDE.md section (~100 tokens) that lists all available personas and how to invoke them:

## Available Personas

| Command | What it does |
|---------|-------------|
| `/review-code` | Code review against team standards |
| `/review-security` | Security-focused review (OWASP, auth, data handling) |
| `/gen-tests` | Generate unit and integration tests |
| `/gen-testdata` | Generate realistic synthetic test data |
| `/sme-compliance` | HIPAA/GDPR/SOC2 compliance questions |

This fragment is auto-generated by the build system from the compiled persona registry. It costs virtually nothing per session (the token count is trivial) but makes personas discoverable without consulting external documentation. A developer who did not know the test data expert existed will see it listed and try it.

The fragment is regenerated on every build, so it stays in sync with the actual persona inventory automatically. Personas that are disabled at a scope level are excluded from that scope's fragment.


MCP-first tool integrations​

When personas need to interact with external systems β€” knowledge bases, data detection services, domain lookup APIs, test data generators β€” AgentBoot recommends building these as MCP (Model Context Protocol) servers from day one.

MCP is now GA in Claude Code, VS Code (Copilot), and the CLI. It is also supported by Cursor, Gemini CLI, and other agent platforms. An MCP server built for one agent works identically in all of them β€” with no modification.

This matters for two reasons:

  1. Investment protection. If your organization builds a knowledge base MCP server for Claude Code, it works in Copilot agent mode and Cursor without rework. If you build it as a Claude Code-specific tool, you rebuild from scratch for every platform.

  2. Clean migration path. An MCP server that reads markdown files today can be swapped for one backed by pgvector or a vector DB tomorrow β€” the persona definitions don't change. The MCP interface is the abstraction boundary.

The alternative β€” having personas read files directly via Grep/Glob β€” is simpler for V1 but creates migration work later. The upfront cost of an MCP wrapper is a thin server; the long-term benefit is zero-change migration and multi-platform compatibility.

For AgentBoot, this means: domain layers that need external data access should define MCP server specifications alongside their persona definitions. The build system can generate MCP configuration stanzas that get synced to target repos.


Structured telemetry​

Persona invocations should emit structured JSON logs from day one β€” not plain text. The difference matters when you need to answer questions like "which persona is invoked most often?" or "is the security reviewer actually running?"

AgentBoot's shipped telemetry is NDJSON with a deliberately minimal, versioned schema (canonical in scripts/lib/telemetry-schema.ts). A persona_invocation event contains exactly:

{
"event": "persona_invocation",
"persona_id": "code-reviewer",
"status": "completed",
"timestamp": "2026-03-19T14:30:00Z",
"dev_id": "",
"schema": 2,
"chain": "…sha256 hash-chain link…"
}

Content-bearing fields (prompts, responses, file paths, tool arguments, tokens, cost) are prohibited by schema β€” a conformance test fails if one appears. Run agentboot telemetry-inspect to see exactly what every event type would emit for your configuration. The log is human-queryable with jq from day one β€” no dashboarding infrastructure required to start getting value.

Today's minimal schema supports:

  • Coverage tracking β€” ensure review personas are actually being invoked
  • Adoption signal β€” measure whether the system is in use at all
  • Tamper-evidence β€” the chain field makes post-write log edits detectable (agentboot telemetry-verify)

Richer analytics β€” token costs, finding counts, duration, per-team scoping β€” are a design-future direction, not something the shipped hooks emit. Any schema change must bump the schema version and be called out in release notes.

Plain text log lines (PERSONA_START agent=review-code) are an anti-pattern. They cannot be queried, aggregated, or analyzed without parsing. Start structured.


Persona arbitrator​

When multiple reviewer personas examine the same code, they may produce conflicting findings. A security reviewer might flag a pattern as risky while an architecture reviewer considers it the correct approach for the domain. A code reviewer might suggest refactoring something that the cost reviewer flags as an unnecessary token expenditure.

The persona arbitrator is a dedicated persona that resolves these conflicts. It:

  1. Receives the conflicting findings from both personas
  2. Understands the scope hierarchy and which persona has authority in the conflict
  3. Produces a reasoned resolution β€” either accepting one finding over the other with an explanation, or escalating to human review when the conflict is genuinely ambiguous

The arbitrator is not invoked on every review β€” only when the /review meta-skill detects that two or more reviewers produced contradictory findings on the same code location. This keeps it lightweight.

Without an arbitrator, conflict resolution falls to the developer, who may not have the context to judge between a security concern and an architecture rationale. The arbitrator provides that context by reading both personas' reasoning and the relevant rules at each scope level.

This is a V2+ feature for organizations running multiple reviewer personas. For V1 with a single code reviewer and security reviewer, conflicts are rare enough that human resolution is sufficient.


Autonomy progression​

Not all personas should operate at the same level of independence. A documentation generator might be fully autonomous (generate and commit without human review), while a security reviewer should always require human sign-off on its findings.

AgentBoot models this as a three-phase autonomy progression, tracked per persona:

PhaseNameBehavior
1AdvisoryPersona produces findings. Human reviews and decides what to act on. No automated actions.
2Auto-approvePersona produces findings and applies low-risk fixes automatically (formatting, import ordering, missing type annotations). High-risk findings still require human review.
3AutonomousPersona operates independently β€” produces findings, applies fixes, commits changes. Human reviews the output post-hoc.

The current autonomy phase is declared in persona.config.json:

{
"autonomy": "advisory"
}

Promotion from one phase to the next is a governance decision, not a technical configuration change. It should require evidence: the persona has been operating at Phase 1 for N weeks with an acceptable false-positive rate, so the team approves promotion to Phase 2. This evidence-based progression prevents premature automation and builds trust in the persona system.

Phase 3 (Autonomous) should be reserved for personas with high confidence scores, extensive behavioral test coverage, and explicit team approval. Most organizations will run most personas at Phase 1 indefinitely β€” and that is fine. Advisory mode is the right default for critical review personas.


Two-channel MDM distribution​

For enterprise organizations with managed device fleets, AgentBoot supports a two-channel distribution model that separates non-negotiable enforcement from team-customizable configuration:

Channel 1: MDM (Managed Device Management) Deploys via JumpCloud, Jamf, Intune, or equivalent to:

  • managed-settings.json β€” Claude Code settings that cannot be overridden by any user
  • managed-mcp.json β€” MCP server configurations that are always active

This channel carries HARD guardrails only β€” the rules where organizational compliance requires zero possibility of developer override. PHI scanning hooks, credential blocking, audit logging requirements. MDM-deployed settings take precedence over all other configuration sources.

Channel 2: Git (Shared Repo) Distributes via the standard hub-and-spoke model:

  • SOFT guardrails, traits, personas, skills
  • Team-level customizations
  • Always-on instructions

This channel carries everything that benefits from version control, code review, and team-level customization.

The two channels serve different trust levels. MDM is "the organization enforces this on your machine." Git is "the team agreed to use this in their repos." Both are necessary for enterprise governance; neither is sufficient alone.

This is an enterprise add-on, not a core requirement. Most organizations start with Channel 2 only and add MDM enforcement when compliance requirements or team size demand it. AgentBoot documents the pattern so organizations that need it know exactly how to implement it.


Proactive human action notifications​

When AgentBoot performs an action that requires human follow-up to take effect, it must tell the user what to do. The user should never have to guess why something isn't working after running a command. This is a core value-add.

Examples:

  • After dev-sync or sync changes .claude/ files: "Restart Claude Code to pick up persona changes"
  • After sync changes files in target repos: list which repos were updated
  • After any config change affecting runtime behavior: tell the user what to restart or reload
  • After publish: "Plugin published. Developers run claude plugin install ..."
  • After uninstall: "Removed N files. Restart Claude Code if a session is active."

Every command that produces side effects ends with a "next steps" line if human action is needed. No silent state changes.


Claude as the UX layer​

AgentBoot's CLI is the build tool for architects. Claude is the interface for everyone else. The design principle that follows from this:

Move UX into Claude wherever possible. Teach through clarification, not docs.

Instead of requiring users to learn CLI flags, subcommands, and taxonomy upfront, AgentBoot skills ask clarifying questions that teach the model as a side effect. A developer who has never heard of "group scope" learns it exists because /ab asked: "Should this apply to the whole org or just one team?" The question is the lesson. The user absorbs the mental model by answering, not by reading.

This applies to any concept the user needs to understand to use AgentBoot effectively: scope hierarchy, artifact types, trait weights, persona composition. The right place to teach all of these is inside a skill clarification loop β€” not a getting-started guide.

Practical rules that follow from this principle:

  • When intent is ambiguous, ask β€” never guess and silently proceed
  • When a concept needs to be introduced (scope, artifact type, weight), name it in the clarifying question so the user learns the vocabulary
  • Present a concrete plan before executing β€” the plan is itself a teaching moment showing what AgentBoot does and where it puts things
  • Prefer fewer, more capable skills over many narrow ones β€” the user should need to remember as little as possible
  • The CLI remains the CI and scripting interface; /ab is the human interface β€” most CLI subcommands are soft-deprecated once /ab covers the same ground. No new CLI features or enhancements once a /ab alternative exists; bug fixes only
  • Infer artifact type from description, not from the word the user used. When the inferred type differs from what the user said, surface the mismatch as a teaching moment before proceeding. Example: a user who says "add a rule that when I say GTD you know it means Getting Things Done" used the word "rule" but described a lexicon entry. The right response is: "This looks like a lexicon entry β€” a domain term definition that teaches Claude vocabulary without using up rule space. Want me to create it as a lexicon entry instead?" The correction teaches the distinction between lexicon, gotcha, trait, instruction, and persona without the user having to read about them first.

This is the same philosophy behind great CLI tools that also ship a good REPL: the underlying primitives don't change, but the interaction layer meets the user where they think, not where the implementation lives.

Promotion pathways​

AgentBoot is often described top-down: the org architects behavior, the hub distributes it, developers receive it. That model is real and important. But it is only half the system. The other half flows the opposite direction β€” and this is where orgs actually win or lose with agentic tooling.

The problem with personal scope as a dead end: Developers naturally collect useful prompts, gotchas, and patterns. Claude Code's ~/.claude/ is where most of them live β€” personal, unjournaled, unjournalled, invisible to the org. Each developer ends up with 30 individually optimized setups that evaporate when they leave and never compound into shared knowledge. The org has AgentBoot installed and a sea of isolated solo users.

The core insight: the PR is the permission system. In a git-based model, "writing" at org scope does not mean directly modifying the hub. It means opening a pull request on the hub. That PR can be rejected, questioned, or improved by reviewers. The approval mechanism is already present in the workflow. A separate per-scope ACL layer β€” "developers can only write at team scope" β€” is redundant, paternalistic, and cuts off the contribution signal the org needs.

The implication: /ab and the wider AgentBoot toolchain should never block a contribution attempt based on scope. Anyone can propose anything at any scope. Scope is guidance ("this probably belongs at team level first"), not a gate. Hub owners control what merges β€” not what gets proposed.

What promotion pathways are:

The four-level scope hierarchy (org β†’ group β†’ team β†’ repo) is not only a distribution model β€” it is a career path for an artifact. A new gotcha might earn its place at team scope after one sprint. If it proves universal, a team member or org admin promotes it to group or org scope. Promotion is incremental. No artifact has to justify org-wide scope from day one.

The three promotion mechanisms:

  1. Direct contribution β€” a developer opens a PR to the hub at any scope, via /ab add a gotcha [at org scope]. No permission gate. The PR is the gate.

  2. Explicit promote flow β€” a developer has something working in their personal config and wants to share it. /ab promote [artifact] walks scope selection and opens a PR on the hub with full attribution.

  3. Import as discovery trigger β€” when /ab import scans repos and finds the same pattern in multiple places, it surfaces a promotion suggestion: "This gotcha appears in 4 repos independently. It may be worth promoting to core so everyone benefits from one maintained version." Duplicate detection becomes a contribution signal, not just deduplication.

Demotion is a learning event, not a failure: Promotion goes both directions. An artifact that was promoted to org scope but turns out to be too narrow gets demoted β€” scoped down to the team or group where it actually applies. This is framed as root-cause analysis, never criticism. The demotion trail records why the scope was narrowed ("pattern specific to Redis keyspace expiry, not general cache behavior") so the next person who encounters the same edge case finds the explanation rather than a gap.

Source attribution: Every artifact in the hub carries provenance: who created it, what repo it came from if imported, who promoted it and when, and its full scope history. This is not a trophy case β€” it is institutional memory. When a developer asks /ab "why does this rule exist?", attribution is what makes the answer meaningful: "This gotcha was contributed by the auth team after the 2025-11 session expiry incident. Promoted to org scope in Q1 2026."

Recognition without gamification: the value is not a badge or a leaderboard. An engineer's insight becomes visible in the PERSONAS.md that ships to every developer in the org, and surfaces when developers ask /ab about an artifact's provenance. That is meaningful recognition for engineers who care about craft. No gift cards, no points, no rankings.

The evaluation lens: Every design decision in AgentBoot β€” new features, workflow changes, architectural choices β€” should be evaluated against:

Does this make it easier or harder for developer discoveries to flow upward and become org knowledge?

VerdictExamples
Supports promotionPR-mediated writes at any scope; import duplicate detection as promotion trigger; source attribution in frontmatter; /ab surfacing provenance
NeutralRead-only query operations; build/sync pipeline internals
Detracts from promotionHard scope permission gates; personal config with no path to sharing; org-only import sources; anonymous contributions

This lens applies to new features, workflow choices, and product positioning. A feature that makes individual developers more effective but siloes that effectiveness is net neutral at best and net negative if it displaces time from contributing up the chain.

Anti-patterns​

These patterns were tried in AgentBoot's origin implementations and should be avoided. Each was rejected for a specific reason.

Overcommitting on V1 scope​

An early design specified 25 V1 personas and 8 milestones. For a 2-person founding team, this would have taken months and risked V1 never shipping. A revised design scoped V1 to 6 personas and 6 milestones β€” buildable in weeks.

Rule: Start with 3-6 personas that address your highest-value use cases. Add more after the first ones are deployed, used, and refined. A shipped persona system with 4 personas beats a designed system with 25 that never launches.

Plain text log lines​

An early design used plain text log output (PERSONA_START agent=review-code). This cannot be queried, aggregated, or analyzed without custom parsing. When you need to answer "how many security reviews ran last week?", plain text requires grep and regex. Structured JSON requires jq '.persona_id == "review-security"' | wc -l.

Rule: Use structured telemetry (GELF/NDJSON) from day one. The upfront cost is trivial; the analysis benefit is permanent.

Runtime trait inclusion​

Early designs proposed @include directives that would resolve trait references at runtime β€” the agent would read and compose trait files during each session. This breaks on platforms that don't support file inclusion (Copilot, Cursor) and wastes tokens re-reading trait files on every invocation.

Rule: Traits are composed at build time. The compiled output is complete and standalone. The agent receives a single file with all trait content already inlined. No runtime resolution.

Vendor-locked persona formats​

An enterprise Copilot deployment explicitly rejected Copilot-proprietary prompt files as the primary persona definition format (decision D-01). Prompt files (*.prompt.md) are VS Code-specific and not recognized by CLI agent mode or other tools. The agentskills.io SKILL.md format was chosen instead because it works across 26+ platforms.

Rule: Use open standards for persona definitions. Vendor-specific formats can coexist as convenience layers (e.g., IDE slash commands) but must not be the authoritative definition.

Forking base personas for customization​

When a product team needs to add domain-specific rules to a reviewer, the temptation is to copy the base persona, modify it, and maintain the fork. This creates divergence β€” improvements to the base persona never reach the fork, and the fork accumulates product-specific cruft that makes it unmaintainable.

Rule: Use the per-persona extension pattern instead. The base persona reads its extension file at setup time and incorporates the additional rules. The base definition stays unmodified and receives upstream improvements automatically.

Deep inheritance hierarchies​

Object-oriented inheritance applied to personas ("security-reviewer extends code-reviewer extends base-reviewer") creates fragile chains where changes to a parent persona have unpredictable effects on children. This was explicitly rejected as Design Principle #1 in AgentBoot's earliest design: composition over inheritance.

Rule: Personas compose traits. They do not inherit from each other. If two personas share behavior, that behavior belongs in a trait that both compose.


Monorepo support​

A monorepo is one git repo containing several packages, and .claude/ at the repo root is not always where the agent looks β€” an agent invoked inside packages/api-service/ reads that directory's config. A single repo entry in repos.json can therefore declare a packages[] array, and sync writes into each listed package path instead of the repo root.

monorepo/ ← single .git/
β”œβ”€β”€ packages/
β”‚ β”œβ”€β”€ api-service/ ← .claude/ written here
β”‚ β”œβ”€β”€ web-app/ ← .claude/ written here
β”‚ └── shared-lib/ ← .claude/ written here

packages[] selects WRITE TARGETS, not scope. It answers where the compiled output lands, not what lands there. Content is resolved from the repo entry's group/team β€” one entry has exactly one scope β€” so every package listed under a single entry receives identical content: the same personas, skills, traits and instructions, written to several directories and differing only in the generation timestamp stamped into the output. The [pkg] suffix in sync output labels the destination, not a distinct build.

To get genuinely different rules per package:

  • Path-scoped gotchas β€” gotchas with paths: frontmatter (e.g., paths: ["packages/api-service/**"]) activate only for matching files, giving per-package rules from a single entry. This is the lightest-weight approach, it is the one that works today, and it is usually sufficient on its own.
  • Separate repo entries β€” list the same path twice with different packages[] and different group/team. Each entry is validated and resolved independently, and each package's manifest records its own entry's scope, so wherever scope-level content exists the packages receive different content. The cost is two entries in repos.json instead of one.

Acknowledged design residual (post-GA). Packages are not nodes in the scope hierarchy. There is no way for one repo entry to give each of its packages its own persona set or trait composition; scope resolution stops at the repo entry. Making a package a first-class scope node β€” so packages[] could carry per-package group/team β€” is a design change to the scope model, not a sync change, and it is deliberately deferred past GA rather than approximated.

A second, narrower limit bounds the separate-entries pattern above: per-scope personas are declared under nodes, but a repos.json entry's group is validated against the legacy groups map only, so a nodes-only config rejects the entry with Group "<name>" is not defined in agentboot.config.json. Until those two are joined up, the separate-entries pattern buys independent scope resolution rather than per-package persona sets β€” so read packages[] as fan-out, and reach for path-scoped gotchas first.


See also: