mcode — C++23 coding-agent harness. Luau is the extension layer.
Spec: docs/00-index.md. Where code and docs disagree, the docs win.
| Path | Contents |
|---|---|
docs/ |
41 design, research and workstream docs — the authoritative spec |
src/mcode/ |
Library sources: core/ support/ ext/ fs/ net/ proc/ agent/ |
src/main.cxx |
Startup smoke test; exit code = number of failed checks |
tests/ |
Catch2 unit tests |
cmake/ |
Warning set, per-platform target config |
conan/profiles/ |
Per-platform Conan profiles |
conan/recipes/luau/ |
Private Luau recipe — upstream ships CMake, so this is a thin wrapper |
scripts/ |
bootstrap.ps1 / bootstrap.sh — dev setup, builds from source |
install.sh, install.ps1 |
The one-line installers: download, verify, install, hand off to mcode setup |
.github/workflows/ci.yml |
Three-platform CI matrix |
Dependencies point downward only, from agent/ toward core/.
No agent behaviour yet: no model client, no tool implementations, no TUI.
- Docs and code move together. Changing a decision, budget or interface means updating the doc that owns it.
- Deviations go in
docs/40-non-obvious-constraints.md— never only in a code comment. - Every claim needs a source or an explicit
[UNVERIFIED]. Never invent a benchmark, API name or URL. - Terse. Tables and bullets over prose. No filler, no marketing, no restating the request.
- Decisions are stated as decisions — "we chose X because Y". If evidence is split, show both sides and pick one.
- One topic per file. No merged docs, no near-duplicates.
- No emoji, except
✓/✗in TUI mockups. - Build is green before the commit, not after.
- Stage explicit paths. Never
git add -A. Never a broadgit checkout -- <list>. - No build or temp artifacts in the tree. Scratch goes to
%TEMP%.
- Research docs (
02,04–15): ≤250 lines,# Title→> TL;DR→## State of the field→## What works / what doesn't→## Recommended design for mcode→## Traps→## Open questions→## Sources. - Design docs (
17–25) and synthesis docs (00,01,03,16):# Title→> TL;DR→## Sources, plus whatever sections the content needs. ## Sourceslists only URLs actually retrieved. Label vendor claims[VENDOR].- Changing a decision: update the doc,
docs/00-index.md, and every doc referencing it. - Changing a budget: update
docs/01-north-star.mdfirst — it is the single source of truth. - Never leave a stale claim. If two docs contradict, fix both or document the disagreement explicitly.
- Extensions:
.cxxfor implementation,.hxxfor headers. Never.cppor.hpp. - Files, classes, structs, enums, methods, functions: lowercase snake_case.
tool_registry,read_file. - No abbreviated identifiers.
length, notlen;offset, notoff;index, noti. Domain terms of art are exempt (modrm,rel32,utf8). - Constants:
SCREAMING_SNAKE_CASE,inline constexpr. Globals and file-scope state:g_prefix. - No magic numbers. Every limit, offset, flag and status is a named
inline constexpr. - A header exists only when ≥2 consumers need it.
- ≤600 lines per file.
Default is none. A comment is justified only when a reader would otherwise get the code wrong: a hidden constraint, an invariant, a non-obvious "why". Anything a reader can see by reading the code is deleted, not reworded.
Most of these are enforced by tools/comment_lint.py, which runs in CI. The
checks are mechanical on purpose — judgment is what let the ratio drift. The
line bound is the one the gate cannot judge: it fails a block longer than four
lines, but one line is the target and two is the most a reader should normally
need.
- Never narrate history. "used to", "was set only on", "this replaced", "previously" — the reader has the current source; what it did before is in the log. This is the single most common violation.
- Never narrate the next line, restate a name, or describe the obvious.
- Rationale belongs in
docs/, not in code. A paragraph explaining why a design was chosen is a design doc in the wrong file. One line of "why" that a reader would get wrong is fine; a block is not. - Never a banner, a section divider, a trailing comment restating the name, or commented-out code.
- Max one line, lowercase, except a comment whose grammar genuinely needs two.
- No
docs/NNcitations. The doc cites the code; the code does not cite the doc, because the doc moves and the comment does not. - When code and comment disagree, one of them is a bug — fix it in the same change.
- Tabs for indent. Namespace bodies are indented.
- Blank line between control-flow blocks.
if/for/while/switch/tryare never stacked. breakandcontinuehug their statement — no blank line above them. This is the one exception above.switchbodies are indented one level; blank line between case groups.- Trailing return types everywhere:
auto name( args ) -> type {, including-> void. - Space inside every paren pair:
fn( arg ),fn( ),if ( x ). Templates:T< U >. - ≤4 positional parameters; beyond that take a request/options struct.
autofor any local initialized at its declaration.std::expectedfor a fallible non-throwing path;std::optionalfor "absent". Never a sentinel value in the success domain.enum classalways.[[nodiscard]]on every query (const member function). Not on status-returning actions.conston every by-value parameter, except an assignment cursor, a writable-address cast, or a moved-from value.- Structured bindings;
std::spanover pointer+length; concepts over SFINAE. - A class owns its state. No all-public bags, no internals in a public header.
- Ownership is explicit. Name which object is charged for every resource with a lifetime, and which path releases it.
- Make the guard actually guard. A re-entrancy flag is test-and-set. A bounds check uses 64-bit arithmetic — a 32-bit
offset + lengthwraps and passes. Check against real capacity, not a larger enclosing size. - No silent-skip branch. No empty
else, no path that leaves a caller waiting forever. - A recovery path must not turn a failure into a success. Zero is not neutral when zero is the success encoding.
- Fail closed. Missing input, unreadable state or unexpected error hard-fails.
- No empty
catch. Useresult<T>,std::optional, or a named handler. - No exception escapes a destructor — that is
std::terminate, not a caught error. - One strategy per path. A compatibility fallback only where the OS forces it.
- One implementation per concept. A duplicated parser or loader that drifts returns a wrong value.
- Delete dead design. Fields nothing reads or writes are removed, not carried.
- A diagnostic set is bounded. An ever-growing set with no eviction is a leak.
- Unknown CLI flags are not ignored silently.
- Never satisfy a check with a no-op such as
(void)0;. Fix the cause.
- Count-guarded edits. Assert the match count, then read the region back. A bare
str.replaceno-ops on a whitespace mismatch and rewrites string literals. - Renames are identifier-scoped. A blind replace of a short name is a rewrite.
Use exactly, as defined in docs/01-north-star.md:
Harness · Session · Turn · Step · Run · Subagent · Skill · Extension · Tool · Artifact · Compaction
C++ provides the runtime primitives. Lua provides the ecosystem.
The core knows four abstractions — ModelClient, Context, ToolRegistry, EventBus — and nothing about Lua, MCP, skills, or the terminal. New capability attaches to a registry or the event bus, never to the loop.
Defined in docs/01-north-star.md. Never redefine them; reference them.
| Constraint | Budget |
|---|---|
| Cold start | ≤ 15 ms |
| Idle RSS | ≤ 30 MB |
| Static binary (with TLS) | ≤ 25 MB (target ~5–9 MB) |
| Direct third-party deps | ≤ 12, with size as the binding constraint |
| Always-loaded tool schema | ≤ 3K tokens core (≤3.5K with default extensions) |
| Harness-added TTFT overhead | ≤ 5 ms |
| Extension load cost | O(1) in extension count |
| System prompt | ~1,200 words core (excl. tool descriptions, instruction chain) |
| Session-start context | ≤8.5K tokens: prompt ≤1.5K + tools ≤3.5K + instructions ≤2K + skill index ≤1.5K |
| Read viewport | 100 lines default (measured optimum) |
| Platform tiers | Windows, Linux, macOS — all tier-1 |
pwsh -File scripts/bootstrap.ps1 # once per machine
cmake --build build/Release
ctest --preset windows-msvc
./build/Release/bin/mcode.exe # exit code = number of failed checks
python tools/comment_lint.py # comment discipline; exit 1 on a findingLinux and macOS: ./scripts/bootstrap.sh, ctest --preset linux-gcc or macos-clang.
Strict build: -DMCODE_WARNINGS_AS_ERRORS=ON. Fast iteration: the dev preset.
tools/comment_lint.py takes any mix of files and directories (default src) and reports the comment/code ratio. tools/dead_code_scan.py lists header-declared functions nothing references — verify each with a grep before deleting, because a virtual override or a function pointer is a false positive.
MSVC is only on PATH inside a developer prompt. A MinGW link.exe on the same machine shadows the linker and produces confusing errors.
| Question | Doc |
|---|---|
| Decisions, reading order | docs/00-index.md |
| Hard constraints, vocabulary | docs/01-north-star.md |
| Prior art | docs/02-prior-art.md |
| Architecture, layers | docs/03-architecture.md |
| Loop and termination | docs/04-agent-loop.md |
| Context budgeting, compaction | docs/05-context-engineering.md |
| Core tool set | docs/06-tools.md |
| MCP client | docs/07-mcp.md |
| Skills and AGENTS.md | docs/08-skills-and-agents-md.md |
| Memory | docs/09-memory.md |
| Subagents | docs/10-subagents.md |
| Reliability, evals | docs/11-reliability-and-evals.md |
| Permissions, trust boundary | docs/12-security.md |
| Terminal UI | docs/13-cli-and-tui.md |
| Stack, build, libraries | docs/14-cpp23-stack.md |
| Providers and cost | docs/15-model-layer.md |
| Milestones, risks | docs/16-roadmap.md |
| Current work plan — read before starting | docs/26-first-batch.md |
| Traps and deviations — cited by number | docs/40-non-obvious-constraints.md |
| Extension runtime, API, lifecycle | docs/17-lua-runtime.md … docs/23-first-party-extensions.md |
| Cross-platform, packaging | docs/24-cross-platform.md, docs/25-distribution.md |
| Contributing, style rules, CI traps | CONTRIBUTING.md |
| Security policy, what ships vs. what is designed | SECURITY.md |
| What changed in each release | CHANGELOG.md |
| Third-party attribution, licenses | THIRD-PARTY-NOTICES.md |
Each design doc carries a ## Traps section. Open disagreements between sources are recorded in the doc that owns the decision — read it before "fixing" one.