CortexBuild — Implementation & Extension Guide (v0.1)¶
Practical guide for engineers and agents implementing and extending
cortexbuild-core. Companion to01-TECHNICAL_SPEC.md. Tracks GitHub issue #92. Everything below is verified against the real tree and the livecortexbuild --helpsurface; concrete claims citefile:line. Phase tags: P0 = scaffolding/SSoT, P1 = analyser/lifecycle, P2 = adopt/standards/conformance. Control-plane (server/web/vm) and live provider adapters are planned.
1. Repository layout¶
The OSS engine lives under cortexbuild-core/cortexbuild_core/. Annotated tree
(verified against the directory listing):
cortexbuild-core/
├── README.md # engine readme (Phase 0 note, Python 3.12+)
├── cortexbuild_core/
│ ├── __init__.py / _version.py # package version (0.0.1)
│ ├── console.py # Rich console + ASCII glyph fallback (get_console/glyph)
│ ├── concurrency.py # portable advisory file locks (advisory_lock, lock_sibling)
│ ├── session.py # session-start ledger-consult summary (build_session_start_summary)
│ ├── session_handshake.py # cross-tool session bundle (build_session_handshake)
│ ├── selfhost.py # self-bootstrap personas + pointer instructions
│ ├── registry.yaml # ⭐ SSoT registry: agents, render targets, model tiers, lifecycle
│ ├── recurrence-ledger.template.yaml
│ │
│ ├── render/ # ⭐ SSoT → multi-tool fan-out (P0/P2)
│ │ ├── rules.py # load/validate rule-*.md frontmatter (load_rules, parse_rule_file)
│ │ ├── agents.py # load/validate agent *.md frontmatter (load_agents, parse_agent_file)
│ │ ├── skills.py / hooks.py # skill + hook loaders with SSoT reference resolution
│ │ ├── registry.py # parse registry.yaml (load_registry, Registry/AgentDef/RenderTarget)
│ │ ├── renderer.py # pure fan-out: render_all(...) -> dict[Path, str]
│ │ ├── ownership.py # managed-region markers + ownership.json manifest
│ │ ├── standards.py # merge org/customer standards into the rule set
│ │ ├── engine.py # load→render→write/check (render_to_disk*, check_drift*)
│ │ └── cli.py # `cortexbuild render` / `--check`
│ │
│ ├── rules/
│ │ ├── foundational/ # 43 always-on rule-*.md (the non-negotiables)
│ │ └── adaptive/ # detection-enabled rules (empty until init turns some on)
│ ├── agents/ # 10 agent personas (planner.md … recurrence-guard.md)
│ ├── skills/ hooks/ # reusable skills + lifecycle hooks
│ │
│ ├── ledger/ # recurrence ledger schema + CRUD + CLI (P0-05)
│ │ ├── schema.py # LedgerEntry / RecurrenceLedger (pydantic)
│ │ ├── store.py # load_ledger/save_ledger/add_entry/update_status
│ │ └── cli.py # `cortexbuild ledger`
│ │
│ ├── analyser/ # brownfield passes 1/2/4 (no-LLM)
│ │ ├── structural.py # Pass 1: scan() -> StructuralReport
│ │ ├── graph.py # Pass 2: tree-sitter graph + Louvain communities
│ │ ├── debt.py # Pass 4: compute_heatmap() -> DebtHeatmap
│ │ └── debt_cli.py # `cortexbuild debt-heatmap`
│ ├── synthesis/ # Pass 3: LLM rule synthesis (propose-only) + `synthesize-rules`
│ ├── init/ # `cortexbuild init` brownfield onboarding orchestrator
│ │
│ ├── conformance/ # `cortexbuild conformance` (report.py: compute_conformance)
│ ├── insights/ # `cortexbuild report` ROI + trend (roi.py, trend.py)
│ ├── context/ # Project Context Profile: schema/score/interview/wizard/gate
│ ├── standards/ # org standards: sync/lock/upgrade/downgrade/migrate/semver/signing
│ ├── precedence/ # foundational>org>customer>oss precedence + provenance (model.py)
│ ├── adopt/ reconcile/ # P2-04/05 import quarantine + conflict reconciliation
│ ├── rollout/ # P2-24 multi-repo/org rollout engine
│ ├── lifecycle/ # P1-11 lifecycle verbs → skills (resolver.py)
│ ├── learning/ # P1-18 propose-only skill extraction (`cortexbuild skills`)
│ ├── memory/ # pluggable memory backend (P1-20/P2-19)
│ ├── security/ # egress.py: redact_for_egress + telemetry/egress consent
│ ├── audit/ # append-only governance audit log (.cortexbuild/audit-log.yaml)
│ ├── eject/ # `cortexbuild eject` reversible removal
│ ├── lint/ # project-agnostic lint helpers
│ ├── llm/ # LLM client glue (opt-in)
│ ├── providers/ # ⛔ stub — adapter interface lands in P1-01
│ ├── orchestrator/ # ⛔ stub — wave sequencer lands in P1
│ ├── cli/ # main.py (Typer app) + onboard.py wizard
│ ├── init/ adopt/ … templates/ # supporting subpackages
│ └── templates/ # file templates emitted by init/adopt
└── tests/ # 64 test_*.py (unit + integration + fixtures)
(⭐ = the SSoT/render core you will touch most; ⛔ = not yet implemented.)
2. Dev environment setup¶
Python. pyproject.toml:11 requires >=3.11; the engine README targets
3.12+ (cortexbuild-core/README.md:35); classifiers list 3.11/3.12/3.13
(pyproject.toml:20-22).
Install (editable, with extras + dev group):
# From the repo root
pip install -e ".[graph,postgres,redis]" --group dev
Optional dependency groups (pyproject.toml:40-65):
| Extra | Pulls in | Use |
|---|---|---|
graph |
networkx, tree-sitter (+python/javascript/typescript/go grammars) | Pass-2 graph extraction |
postgres |
asyncpg, sqlalchemy[asyncio], alembic | control-plane data layer (planned) |
redis |
redis[hiredis] | prompt cache / queue broker |
memory |
mem0ai | pluggable memory backend |
llm |
openai | Pass-3 synthesis / live LLM |
signing |
cryptography | standards-pack signing |
Dev group (pyproject.toml:75-83): pytest, pytest-asyncio, pytest-cov,
ruff, mypy, pre-commit.
Runtime deps (pyproject.toml:28-38): pydantic v2, pyyaml, typer, rich,
httpx, structlog, tenacity, anyio, platformdirs.
Pre-commit. A .pre-commit-config.yaml exists at the repo root — install
hooks with pre-commit install and run all with pre-commit run -a.
Tooling baselines (all from pyproject.toml):
| Tool | Config | Highlights |
|---|---|---|
| ruff | [tool.ruff] (:90) |
line-length 100, target py311, lint select E W F I B C4 UP RUF SIM TCH PTH, ignore E501 B008 |
| mypy | [tool.mypy] (:106) |
strict = true, disallow_untyped_defs, warn_unused_ignores, pydantic plugin; tests exempt from untyped-def |
| pytest | [tool.pytest.ini_options] (:123) |
--strict-markers --strict-config, testpaths = cortexbuild-core/tests, asyncio_mode = auto |
| coverage | [tool.coverage] (:137) |
branch coverage, source cortexbuild_core, omits tests/__main__ |
3. The render pipeline in depth¶
cortexbuild render is the engine's beating heart: it turns the SSoT
(rules + agents + skills + hooks + registry) into per-tool files, without
clobbering user content.
Load → render → write/check¶
- Load.
engine._load_default_state(render/engine.py:92) reads the bundled pack:DEFAULT_FOUNDATIONAL,DEFAULT_ADAPTIVE,DEFAULT_AGENTS,DEFAULT_SKILLS,DEFAULT_HOOKS,DEFAULT_REGISTRY(render/engine.py:51-56). It calls: load_registry()→ enabled targets + model tiers + adaptive list.load_rules(foundational, adaptive, adaptive_enabled=...)(render/rules.py:108) — foundational always; adaptive only if listed.load_agents()(render/agents.py:119) — auto-discovers*.md, skipsREADME.md.-
load_skills()/load_hooks()then an SSoT guard:resolve_skill_references/resolve_hook_referencesfail if a skill/hook references a rule or agent id that does not exist (render/engine.py:115-119). -
Frontmatter parsing. Both loaders share a frontmatter regex (
\A---\n(.*?)\n---) and validate strictly: - Rules:
idmust startrule-,severity ∈ {critical,high,medium,low}, filename must equal<id>.md(render/rules.py:82-96). -
Agents:
id/name/descriptionnon-empty,tools/agentsmust be lists, filename must equal<id>.md(render/agents.py:81-102). -
Render.
renderer.render_all(rules, registry, agents, …)is a pure function returningdict[Path, str](render/renderer.py:3). It prepends the DO NOT HAND-EDIT banner (renderer.py:22) and fans out to the enabled targets fromregistry.yaml(Copilot, Claude, Codex, Cursor). -
Write / Check.
engine.render_to_disk_scopedwrites non-destructively (managed regions or sidecars);engine.check_drift_scopedcompares only owned/managed content (render/engine.py:1-11). Results areRenderResult/DriftResultdataclasses (render/engine.py:59,76).
Non-destructive writes¶
Single-file Markdown surfaces (.github/copilot-instructions.md, CLAUDE.md,
AGENTS.md) are edited only between <!-- BEGIN/END CORTEXBUILD MANAGED -->
markers; everything outside is preserved byte-for-byte (render/ownership.py:5-9).
The matchers are whitespace-tolerant so a formatter that reflows the comment
does not break detection; malformed/duplicate markers raise
ManagedRegionError and the file is flagged needs-attention rather than
overwritten (render/ownership.py:18-23,56). ownership.json
(MANIFEST_RELPATH = .cortexbuild/ownership.json, ownership.py:52) records
owned paths, marker ids, content hashes, and the user-content flag.
CLI options (captured from source / --help)¶
cortexbuild render (render/cli.py:27):
| Option | Default | Effect |
|---|---|---|
-r, --repo-root PATH |
cwd | Repo root to render into |
--check |
off | Check-only; exit 1 on any drift, no writes (cli.py:62) |
--no-prune |
off | Keep stale .cursor/rules/*.mdc files |
--separate-files |
off | Write a CortexBuild-owned sidecar instead of in-file regions (cli.py:46) |
Example CI gate:
cortexbuild render --check # fails the build if any surface drifted from SSoT
4. How to add a new RULE¶
-
Create
cortexbuild_core/rules/foundational/rule-<slug>.md(useadaptive/for detection-gated rules). The filename must equal the frontmatterid(render/rules.py:92). -
Frontmatter — mirror an existing rule (
rules/foundational/rule-source-citation.md:1-7):
---
id: rule-<slug> # MUST start with "rule-"
severity: high # critical | high | medium | low
applies_to: [builder, pr-reviewer]
enforced_by: [agent system prompts, pr-reviewer]
render_to: all
---
- severity sets render order (
critical=0 … low=3,render/rules.py:27). - applies_to lists the agent ids whose system prompts embed this rule.
-
render_to is
allby default (registry.yaml:220). -
Body — a clear
# Title, a why, and where useful a Builder gate (a copy-pasteable grep/command the agent can run). Follow the structure of existing foundational rules. -
(Adaptive only) add the rule id to
adaptive_rules_enabledinregistry.yaml:224(or letcortexbuild initenable it on detection); a rule inadaptive/not listed there is simply not loaded (render/rules.py:133). -
Re-render and verify:
cortexbuild render # write the new rule into every surface
cortexbuild render --check # must exit 0
pytest cortexbuild-core/tests/unit/test_p0_02_rule_pack.py
Duplicate ids or a filename/id mismatch raise RuleLoadError
(render/rules.py:146,94).
5. How to add a new AGENT¶
-
Create
cortexbuild_core/agents/<id>.md. Filename must equal the frontmatterid(render/agents.py:90); the loader auto-discovers*.mdand skipsREADME.md(render/agents.py:128). -
Frontmatter — mirror
agents/planner.md:1-11:
---
id: <id>
name: <Display Name>
description: "When to use this agent (one sentence)."
tools: [read, search, todo, agent]
agents: [explore] # sub-agents it may delegate to
model: default
user_invocable: true
argument_hint: "What to pass when invoking."
applies_to: [generic]
---
Required: id, name, description (non-empty, else AgentLoadError,
render/agents.py:81-88). tools/agents must be lists.
-
Body — open with the persona role, then a "Cross-Cutting Non-Negotiables (rendered from
rules/)" section and the agent's method, asplanner.mddoes. -
Register the agent + its non-negotiables in
registry.yamlunderagents:(registry.yaml:28) so the orchestrator knows its scope and recommended model tier. Every rule id you list there must resolve (SSoT guard). -
Render targets. On
cortexbuild renderthe agent renders to.github/agents/<id>.agent.md(Copilot),.claude/agents/<id>.md(Claude), and is referenced from.cursor/— perregistry.yaml:153-181. -
Verify:
cortexbuild render && cortexbuild render --check
pytest cortexbuild-core/tests/unit/test_p0_04_agents.py
6. Coding standards¶
| Area | Standard | Source |
|---|---|---|
| Lint | ruff, line-length 100, rule families E W F I B C4 UP RUF SIM TCH PTH; E501,B008 ignored |
pyproject.toml:90-100 |
| Format | ruff format, double quotes, space indent | pyproject.toml:102-104 |
| Types | mypy strict — disallow_untyped_defs, disallow_incomplete_defs, no_implicit_optional, warn_unused_ignores; pydantic plugin |
pyproject.toml:106-117 |
| Type hints | from __future__ import annotations; TYPE_CHECKING imports for non-runtime types (see every module head) |
e.g. render/rules.py:15-24 |
| Docstrings | Module + public-symbol docstrings; describe behaviour, not restate the signature | e.g. render/engine.py:1 |
| Immutability | Prefer frozen dataclasses for value types (@dataclass(frozen=True)) |
render/rules.py:32, agents.py:34 |
| Errors | Raise typed ValueError subclasses (RuleLoadError, AgentLoadError, ManagedRegionError, SupplyChainError) instead of bare exceptions |
render/rules.py:57 |
| Determinism | No wall-clock in emitted bytes; relativise paths; route free text through redact_for_egress |
security/egress.py:171 |
Run the full gate before pushing:
ruff check . && ruff format --check .
mypy cortexbuild-core/cortexbuild_core
pytest
7. Testing¶
The suite lives under cortexbuild-core/tests/ (testpaths, pyproject.toml:131)
with 64 test_*.py files split into unit/, integration/, fixtures, and
reconcile_cases/. asyncio_mode = auto means async def test_* needs no
decorator (pyproject.toml:132).
Run:
pytest # whole suite
pytest cortexbuild-core/tests/unit/test_p0_03_render.py # one file
pytest -k conformance # by keyword
pytest --cov # with coverage (pytest-cov)
Coverage map (by ticket prefix): test_p0_* cover scaffolding, rule pack,
render, agents, ledger, adaptive pack, structural scan, graph extraction, init
orchestrator; test_p1_* cover tree-sitter extractors, Louvain communities,
skills/lifecycle, session-start hook, rule synthesis, debt heatmap, self-host,
memory; test_p2_* cover non-destructive render, adopt/reconcile, precedence,
context profile + completeness + interview, missing-context gate, standards
sync/upgrade/signing, conformance, ROI, egress redaction, audit log, rollout,
eject, advisory locking, monorepo packages, air-gapped pipeline.
Adding a test. Name it test_<ticket>_<slug>.py under tests/unit/, use the
fixture builders in tests/fixture_builder.py / tests/fixtures_spec.py, and
assert on primary evidence (e.g. captured SQL, rendered bytes, computed
scores) rather than restating mocked return values — this matches the engine's
anti-gaming/isolation conventions.
8. CLI command reference¶
The Typer app is cortexbuild_core.cli.main:app (entry point
pyproject.toml:73; assembled in cli/main.py:16-135). Top-level commands as
emitted by cortexbuild --help:
| Command | Purpose | Key options |
|---|---|---|
version |
Print installed version | — |
info |
High-level install info | — |
render |
Render SSoT into all enabled surfaces | -r/--repo-root, --check, --no-prune, --separate-files |
ledger |
Manage .cortexbuild/recurrence-ledger.yaml |
subcommands (init/add/update/list) |
init |
Onboard a brownfield repo (analyse + select adaptive rules + render) | -r/--repo-root |
lifecycle |
Verbs spec/plan/build/test/review/ship/simplify → skills |
verb arg |
skills |
Propose new skills from project signals (propose-only) | — |
synthesize-rules |
Pass-3 LLM rule synthesis (propose-only, opt-in, offline default) | — |
debt-heatmap |
Pass-4 deterministic debt heatmap (no LLM) | -r/--repo-root |
context |
Manage the Project Context Profile | subcommands |
precedence |
Inspect precedence + provenance (foundational > org > customer > oss) | — |
adopt |
Quarantine pre-existing tool configs into .cortexbuild/imported/ |
— |
reconcile |
Reconcile imports vs active pack → MERGE_REPORT.md |
— |
onboard |
Interactive wizard: harvest → score → interview → mission → render → lifecycle | — |
standards |
Pull/sync/upgrade/downgrade/drift-check the org standards layer | upgrade: --source, --apply, --confirm; downgrade: --backup-id |
conformance |
Deterministic 0–100 maturity report | --fail-under N (fail-closed gate) |
report |
Deterministic ROI/insights report + conformance trend | --record-trend, --commit <sha> |
rollout |
Run adopt/standards-sync/conformance across many repos | --base, --glob, --apply, --json, --max-repos |
self-bootstrap |
Render personas + pointer Copilot instructions into <repo>/.github/ |
repo_root arg |
session-start |
Surface live recurrence-ledger entries (session hook) | -r/--repo-root, --json |
session-handshake |
Boot the cross-tool session bundle (ledger + profile + memory digest) | -r/--repo-root, --json |
eject |
Reversibly remove CortexBuild from a repo | --dry-run, --keep-backups, --yes, -r/--repo-root |
Global option: --ascii forces ASCII-only output (cli/main.py:29) — useful on
legacy Windows consoles that cannot encode box-drawing glyphs.
9. Contribution workflow¶
- Branch naming. Feature work:
feature/<ticket>-<slug>; agent-rule guards from a post-mortem:chore/agents/<postmortem-id>(foundationalrule-draft-only-no-merge). - SSoT discipline — never hand-edit rendered files. Edit the source under
cortexbuild_core/rules/orcortexbuild_core/agents/(orregistry.yaml) and re-render. Every rendered surface starts with a DO NOT HAND-EDIT banner (render/renderer.py:24). - Drift gate. Run
cortexbuild render --checkbefore pushing; CI fails on drift (render/cli.py:99). Re-runcortexbuild renderto fix. - Quality gate.
ruff check . && ruff format --check . && mypy cortexbuild-core/cortexbuild_core && pytestmust be green. - Co-authored-by trailer. Every commit ends with:
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rule-schema-migration-safety, rule-rollback-readiness;
standards/snapshot.py).
10. Extending providers (planned subsystem)¶
providers/__init__.py is a P1 stub; implement against the
ProviderAdapter Protocol specified in
../architecture/03-PROVIDER_ADAPTER.md
and summarised in 01-TECHNICAL_SPEC.md §8. The
documented checklist (docs/architecture/03-PROVIDER_ADAPTER.md:202):
- Create
cortexbuild_core/providers/<name>.pyimplementingProviderAdapter(invoke,stream,estimate_cost,capabilities,rate_limit_status,health_check). - Register it in
cortexbuild_core/providers/__init__.py: REGISTERED_ADAPTERS. - Add the
ModelTiermapping table to the module docstring (mirror the registry tiers,registry.yaml:20). - Declare
capabilities()(CODE_EXECUTION, VISION, LONG_CONTEXT_*, …). - Add the credential schema to
cortexbuild_core/providers/credentials.py. - Add the SDK/CLI to the VM installers; add a UI key-input form.
- Add a smoke test fixture and a nightly health check.
- Document in
docs/providers/<name>.md.
Health-check expectation. Every adapter must implement
health_check() -> HealthStatus; the nightly CI smoke test iterates
REGISTERED_ADAPTERS, calls health_check(), and pages on-call if any returns
healthy=false (docs/architecture/03-PROVIDER_ADAPTER.md:166). Cross-provider
guarantees are deliberately narrow — tool-call schemas, streaming granularity,
vision, context window, and cost differ and are surfaced via capabilities() /
estimate_cost() (docs/architecture/03-PROVIDER_ADAPTER.md:215).
Cross-links¶
01-TECHNICAL_SPEC.md— the canonical spec../architecture/00-ARCHITECTURE_OVERVIEW.md— C4 + Mermaid, engine internals (§4), render pipeline (§5)../architecture/03-PROVIDER_ADAPTER.md— adapter Protocol + provider matrix../architecture/04-BROWNFIELD_ONBOARDING.md— analyser passes +.cortexbuild/artifactscortexbuild-core/README.md— engine quick start