Skip to content

CortexBuild — Implementation & Extension Guide (v0.1)

Practical guide for engineers and agents implementing and extending cortexbuild-core. Companion to 01-TECHNICAL_SPEC.md. Tracks GitHub issue #92. Everything below is verified against the real tree and the live cortexbuild --help surface; concrete claims cite file: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

  1. 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:
  2. load_registry() → enabled targets + model tiers + adaptive list.
  3. load_rules(foundational, adaptive, adaptive_enabled=...) (render/rules.py:108) — foundational always; adaptive only if listed.
  4. load_agents() (render/agents.py:119) — auto-discovers *.md, skips README.md.
  5. load_skills() / load_hooks() then an SSoT guard: resolve_skill_references / resolve_hook_references fail if a skill/hook references a rule or agent id that does not exist (render/engine.py:115-119).

  6. Frontmatter parsing. Both loaders share a frontmatter regex (\A---\n(.*?)\n---) and validate strictly:

  7. Rules: id must start rule-, severity ∈ {critical,high,medium,low}, filename must equal <id>.md (render/rules.py:82-96).
  8. Agents: id/name/description non-empty, tools/agents must be lists, filename must equal <id>.md (render/agents.py:81-102).

  9. Render. renderer.render_all(rules, registry, agents, …) is a pure function returning dict[Path, str] (render/renderer.py:3). It prepends the DO NOT HAND-EDIT banner (renderer.py:22) and fans out to the enabled targets from registry.yaml (Copilot, Claude, Codex, Cursor).

  10. Write / Check. engine.render_to_disk_scoped writes non-destructively (managed regions or sidecars); engine.check_drift_scoped compares only owned/managed content (render/engine.py:1-11). Results are RenderResult / DriftResult dataclasses (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

  1. Create cortexbuild_core/rules/foundational/rule-<slug>.md (use adaptive/ for detection-gated rules). The filename must equal the frontmatter id (render/rules.py:92).

  2. 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 all by 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_enabled in registry.yaml:224 (or let cortexbuild init enable it on detection); a rule in adaptive/ 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

  1. Create cortexbuild_core/agents/<id>.md. Filename must equal the frontmatter id (render/agents.py:90); the loader auto-discovers *.md and skips README.md (render/agents.py:128).

  2. 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.

  1. Body — open with the persona role, then a "Cross-Cutting Non-Negotiables (rendered from rules/)" section and the agent's method, as planner.md does.

  2. Register the agent + its non-negotiables in registry.yaml under agents: (registry.yaml:28) so the orchestrator knows its scope and recommended model tier. Every rule id you list there must resolve (SSoT guard).

  3. Render targets. On cortexbuild render the agent renders to .github/agents/<id>.agent.md (Copilot), .claude/agents/<id>.md (Claude), and is referenced from .cursor/ — per registry.yaml:153-181.

  4. 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 strictdisallow_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

  1. Branch naming. Feature work: feature/<ticket>-<slug>; agent-rule guards from a post-mortem: chore/agents/<postmortem-id> (foundational rule-draft-only-no-merge).
  2. SSoT discipline — never hand-edit rendered files. Edit the source under cortexbuild_core/rules/ or cortexbuild_core/agents/ (or registry.yaml) and re-render. Every rendered surface starts with a DO NOT HAND-EDIT banner (render/renderer.py:24).
  3. Drift gate. Run cortexbuild render --check before pushing; CI fails on drift (render/cli.py:99). Re-run cortexbuild render to fix.
  4. Quality gate. ruff check . && ruff format --check . && mypy cortexbuild-core/cortexbuild_core && pytest must be green.
  5. Co-authored-by trailer. Every commit ends with:

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6. Reversibility. Schema/standards/infra changes ship a downgrade or atomic snapshot path (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):

  1. Create cortexbuild_core/providers/<name>.py implementing ProviderAdapter (invoke, stream, estimate_cost, capabilities, rate_limit_status, health_check).
  2. Register it in cortexbuild_core/providers/__init__.py: REGISTERED_ADAPTERS.
  3. Add the ModelTier mapping table to the module docstring (mirror the registry tiers, registry.yaml:20).
  4. Declare capabilities() (CODE_EXECUTION, VISION, LONG_CONTEXT_*, …).
  5. Add the credential schema to cortexbuild_core/providers/credentials.py.
  6. Add the SDK/CLI to the VM installers; add a UI key-input form.
  7. Add a smoke test fixture and a nightly health check.
  8. 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).