Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,66 @@ The project is small enough that direct read is always the right choice regardle

---

## Senior engineering reflexes

The rules above are the always-on core. The reflexes below are the full senior playbook — apply them proactively, without being asked, scaled to the project's language and risk. They are the canonical source: per-tool configs (`CLAUDE.md`, MiniMax `agent.md`, `.cursorrules`) should reference this file rather than re-state these rules.

### Documentation & decisions

- **ADR** (Architecture Decision Record) — documents a decision *already made*. Retrospective, in `docs/adr/NNNN-short-title.md`: Context · Decision · Rejected alternatives · Consequences. Triggers: new central pattern, lib choice, thread-model constraint, public-API change.
- **RFC** (Request for Comments) — requests feedback *before* a major change. Prospective, in `docs/rfcs/`: Motivation · Detailed proposal · Alternatives · Open questions · Review deadline.
- **`// See ADR-NNNN`** in code — when a block implements a documented decision, link it so a reader reaches the "why" without searching the docs.
- **Documentation proportional to size**: >10 source files → `CLAUDE.md`; >3,000 LOC → `ARCHITECTURE.md` (thread model, data flow, ownership, red zones); >5,000 LOC → `CONTRIBUTING.md` (conventions, how to add a module, PR checklist).
- **Domain glossary** — for any jargon-dense domain (audio, finance, medical, network, games), create `docs/glossary.md` defining terms *operationally* (precise definition + link to the implementing module + concrete in-project example). A dev without domain background introduces subtle bugs by misreading a technical term.
- **Data format versioning & migrations** — every persisted format carries an explicit version + one migration function per delta (`upgradeProjectV6toV7()`). Without migrations a refactor that changes the format makes all old files unreadable.
- **CHANGELOG.md** — on any project with releases, maintain it from Conventional Commits: `## [VERSION] - YYYY-MM-DD` with `### Added/Fixed/Changed/Removed`.

### Testing

- **Propose tests at service creation** — when a stateless service / pure business logic is created or extracted, proactively offer a test (don't wait to be asked). Stateless free functions are the highest-priority, easiest wins.
- **Test naming**: `Component_Scenario_ExpectedBehavior` (e.g. `ProjectReader_LoadCorruptedJson_DoesNotCrash`).
- **Three classified suites**: `*_Unit` (pre-commit + CI, zero I/O, <100ms) · `*_Integration` (CI nightly, mocked devices/files) · `*_Device`/`*_AudioDevice` (manual, real hardware).
- **Integration & golden tests** on deterministic outputs: golden (render a known output, compare checksum/RMS), replay (import → edit → undo → render → verify), session-load (load N historical projects → migrations still work).
- **Fuzz & property-based**: fuzz every parser of external data (libFuzzer / `cargo-fuzz`) — malformed input must fail cleanly, never corrupt state silently. Property-based test algorithms with math invariants (`proptest`/`quickcheck`/`rapidcheck`) — e.g. "audio output stays within [-1.0, 1.0] for any input".
- **Invariants as runtime asserts** — every critical invariant documented in ARCHITECTURE.md has a matching `assert()`/`debug_assert!()` in code. An unverified invariant is just a promise. Free in release, immediate detection in debug.
- **Zero-alloc CI check** — any real-time thread has a test asserting `heap_alloc_count == 0` after N iterations. An accidental allocation in a hot path is invisible until user reports ("crash after 2h").

### Concurrency & systems

- **Ownership graph = DAG** — never an ownership cycle. Upward (child→parent) or lateral (sibling→sibling) references use `weak_ptr`/observer/callback, never a strong ref. Destruction order = reverse of construction.
- **Shutdown sequence** — in any multi-threaded system, document in ARCHITECTURE.md which thread is joined first, in what order queues drain, when OS handles are released. A service destroyed while the audio thread holds a reference = guaranteed crash.
- **Lock hierarchy** — document the mandatory acquisition order (e.g. `ProjectMutex → AudioGraphMutex → TrackMutex`). Never acquire a level-N lock while holding level-N+1. Prevents deadlocks; TSan detects violations.
- **Thread annotations** — comment every method with `// THREAD: audio | ui | any` so the model is explicit in code, not only in ARCHITECTURE.md.
- **RT threads** (audio callback, video decode) — no logging, no mutex, no I/O, no allocation. Communicate via a lock-free ring buffer: RT thread pushes `(EventId, timestamp, value)` with atomics; a low-priority thread drains to log/UI. Without it, "it crackles sometimes" reports are undebuggable.
- **Structured logging** — 4 levels (ERROR irrecoverable · WARN degraded · INFO session events · DEBUG off in release). Per-domain macros when justified (`LOG_AUDIO_WARN`). RT threads log only via the ring buffer above.

### Safety & static analysis

- **Error handling policy** — never swallow silently. Rust: `unwrap()`/`expect()` forbidden in prod except a proven invariant with `// SAFETY:`; prefer `?`/`map_err()`. C++: prefer return codes / `std::optional`/`std::expected` in critical code; never empty `catch(...)`. Errors at system boundaries (I/O, network, user parsing) always handled explicitly.
- **RAII (C++)** — no naked `new`/`delete`; `make_unique`/`make_shared`/stack. FFI opaque handles wrapped in a RAII type immediately (no naked handle circulating).
- **`using namespace` banned at file scope** — in headers (0 exceptions, fully qualify) and production `.cpp` (function scope or explicit alias `namespace fs = std::filesystem;` only).
- **Sanitizers** in dedicated CI builds: ASan (use-after-free, overflow) + UBSan (signed overflow, null deref) can combine; TSan (data races) separate build; MSan (uninit reads). Rust FFI modules: `cargo miri test` (nightly) catches UB at the `extern "C"` boundary that C++ sanitizers miss.
- **Clang-Tidy (C++)** — beyond cppcheck. Priority checks: `bugprone-use-after-move`, `bugprone-dangling-handle`, `performance-unnecessary-copy-initialization`, `modernize-use-override/make-unique`, `readability-function-size`. Ship a `.clang-tidy` + run in pre-commit/CI.
- **Hardware abstraction for testability** — any service touching OS resources consumes an interface, never the hardware directly. Priority interfaces: `IFileSystem`, `IClock` (timers/autosave), `IAudioSink`. Lets CI simulate disk errors / latency without real hardware.

### Supply chain

- **`cargo audit --deny warnings`** (RustSec CVE scan of `Cargo.lock`) and **`cargo-deny`** (crate bans, license policy, duplicate versions) on any serious Rust project.
- **`osv-scanner --recursive .`** or **`trivy fs .`** for vendored/system C++ deps (SDL3, ImGui, FFmpeg, codecs). C++ CVEs are rarer but graver (codec overflow = RCE). Nightly CI.
- **CODEOWNERS** — `.github/CODEOWNERS` assigning ownership by domain + mandatory reviewer on frozen cores / public APIs / CI. Create it even solo: it prepares a second dev with zero ambiguity.

### Process & collaboration

- **Code review checklist** (before approving any PR): Correctness · Security (secret/injection/missing validation) · Thread safety (shared data protected, atomics correct) · Resources (no leak) · Performance (no alloc in hot path, no avoidable O(n²)) · Readability (a senior understands it in 30s) · Tests (logic covered / no broken test).
- **Performance budgets** — document per subsystem and check in CI: audio callback <2ms · UI frame <16.6ms (60fps) · undo/redo <50ms · project load <3s · heavy ops (scan, waveform) async non-blocking.
- **Tech debt SLA** — build/clippy warning: immediate (don't commit) · race condition: 24h · architecture violation: 7 days · legacy TODO: next sprint. "Stop-the-line" on the first two.
- **Feature flags** — isolate unfinished/experimental code behind a runtime flag (preferred, `config.json`) or compile-time `#ifdef` with `// FEATURE: ... — remove when: ...`. `#if 0` is forbidden (that's dead code — delete it or use a real flag).
- **Public interface contracts** (exception to "comments = WHY only") — public interface headers document non-inferable contracts in one line: `// @pre Must NOT be called from audio thread`, `// @thread-safety lock-free, MT-safe`, `// @throws never (noexcept)`.
- **FFI conventions (C++ ↔ Rust)** — the most dangerous boundary. Every `extern "C"`: return an `int32_t`/`ResultCode` error code (never implicit); complex errors via a thread-local `get_last_error_str()`; ownership documented explicitly (`Box::into_raw()` → C++ `unique_ptr` with a deleter calling back into Rust; never `free()` C++-side on Rust-allocated memory). Capture conventions in an "Interop Error Handling + Memory Ownership" ADR.
- **Boy Scout rule** — when editing a file and you spot neighbouring debt fixable in <15 min (un-injected global, over-long function, untested helper), fix it in the same commit with a note. If >15 min: create a TODO/ticket and move on.

---

## Pre-commit checklist

Before marking any task done:
Expand Down
128 changes: 128 additions & 0 deletions PORTABILITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Portability — Transfer the full stack to a new machine or LLM

This guide makes the whole AI-Native Dev Stack reproducible: clone the repo and
wire each AI agent (Claude Code, MiniMax/Mavis, Cursor, Codex, …) to the same
engineering method, hooks, and agents. Nothing here depends on a specific
machine except the few values explicitly listed as machine-local.

## The 3-layer model (why some things live in the repo and some don't)

Per-tool configs mix three natures that must not travel together:

| Layer | What | Where it lives | Shared? |
|---|---|---|---|
| **1 — Engineering method** | The universal rules + senior reflexes | [`AGENTS.md`](AGENTS.md) (this repo) | ✅ canonical, shared to every agent |
| **2 — Tool mechanics** | Skills/commands of a given tool (gstack, graphify, MCP wiring) | Per-agent appendix (this repo's adapters + each tool's config) | ⚠️ per-agent |
| **3 — Personal / machine** | Vault paths, project list, machine PATH, "answer in French", wikilink rules | The agent's own config file (`~/.claude/CLAUDE.md`, Mavis `agent.md`) | ❌ never shared |

**Rule:** Layer 1 has exactly one owner — `AGENTS.md`. Every tool config
*references* it (`@AGENTS.md` include) instead of re-stating the rules. That is
what keeps the three configs from diverging. If you copy the rules into a tool
config by hand, you have just created a fork that will rot.

## What is in the repo (transferable) vs machine-local

| In the repo (clone = you have it) | Machine-local (set up once per machine) |
|---|---|
| `AGENTS.md` — the complete method (Layer 1) | `~/.claude/CLAUDE.md` — Layer 3 + `@AGENTS.md` include |
| `routing-guide.md` — analysis/orchestration routing | Mavis `~/.mavis/agents/mavis/agent.md` — Layer 3 + method ref |
| `hooks/` — universal hooks + per-agent install notes | Obsidian vault (`config.sh` paths, API key in env) |
| `scripts/` — `setup-agents.sh`, `loc_gate.ps1`, `vault_sync*` | The anti-debt agent *link* (created by `setup-agents.sh`) |
| `stack/agents/anti-debt/` — the debt agent + adapters | The hook *registrations* (per-agent, formats differ) |
| `tools/ai_docs/`, `skills/`, `templates/`, `install.sh` | `tools/ai_docs/config.sh` (git-ignored, per-machine) |

---

## New-machine bootstrap (the whole sequence)

```bash
# 1. Clone
git clone https://github.com/Rwanbt/ai-native-dev-stack.git
cd ai-native-dev-stack

# 2. Link the portable agents (anti-debt) into every detected agent root.
# Idempotent, OS-aware (symlink on Linux/macOS, junction on Windows).
bash scripts/setup-agents.sh

# 3. Wire the engineering method into each agent config (Layer 1 include) — see per-agent below.

# 4. (Per project) install the AI-docs maintenance stack into a target repo:
cd /path/to/your/project
bash /path/to/ai-native-dev-stack/install.sh
```

Then set the machine-local values:
- `OBSIDIAN_API_KEY` / `OBSIDIAN_API_URL` env vars (used by the memory hooks).
- `tools/ai_docs/config.sh` in each project (Obsidian vault path, graphify, Claude memory key).

---

## Per-agent setup

### Claude Code

1. **Method (Layer 1)** — add near the top of `~/.claude/CLAUDE.md` (global) or a project `CLAUDE.md`:
```
@/absolute/path/to/ai-native-dev-stack/AGENTS.md
```
Keep only Layer 3 (personal/machine) and a Layer-2 appendix (gstack/graphify) in `CLAUDE.md` itself.
2. **Anti-debt agent** — `scripts/setup-agents.sh` links it to `~/.claude/skills/anti-debt`. Activate by loading `@~/.claude/skills/anti-debt/AGENT.md` and running its tools (see [adapter](stack/agents/anti-debt/adapters/claude-code/README.md)). Note: `/skill anti-debt:...` does **not** work (Claude discovers skills flat).
3. **Hooks** — register in `~/.claude/settings.json` (or project `.claude/settings.json`), absolute paths:
```json
{
"hooks": {
"SessionStart": [{ "matcher": "", "hooks": [{ "type": "command",
"command": "node /abs/path/ai-native-dev-stack/hooks/session-start-memory/run.js" }]}],
"PostToolUse": [{ "matcher": "Edit|Write", "hooks": [{ "type": "command",
"command": "bash /abs/path/ai-native-dev-stack/hooks/posttool-ai-summary/run_hook.sh" }]}]
}
}
```
See [hooks/README.md](hooks/README.md) for the full list and per-hook notes.

### MiniMax (Mavis)

1. **Method (Layer 1)** — Mavis reads its agent's `agent.md`. Reference `AGENTS.md` from it (or include its content) and keep only Mavis-specific Layer 3 there. Do **not** maintain a hand-ported copy of the rules — point at `AGENTS.md`.
2. **Anti-debt agent** — `setup-agents.sh` links it to `~/.mavis/agents/anti-debt`. Run its tools directly (see [adapter](stack/agents/anti-debt/adapters/minimax-code/README.md)):
```bash
python3 ~/.mavis/agents/anti-debt/skills/debt-scan/tools/scan_code.py <repo>
```
3. **Hooks** — Mavis supports SessionStart/SessionEnd natively. Create them from the `.md` definitions:
```bash
mavis hook create session-start-memory --event SessionStart --type script --agent mavis
mavis hook create session-end-save --event SessionEnd --type script --agent mavis
# PreToolUse LOC gate: ~/.mavis/agents/mavis/hooks/pretool-loc-gate.md
```
See per-hook notes in [hooks/](hooks/).

### Cursor

- **Method** — Cursor reads `AGENTS.md` natively at the repo root (and in nested dirs). Cloning the repo into a project, or placing `AGENTS.md` at the project root, is enough. No include needed.
- **Hooks / anti-debt** — run the anti-debt tools manually; Cursor has no SessionStart hook equivalent (use `.cursorrules` for any always-on note).

### Codex

- **Method** — Codex auto-loads `AGENTS.md` at the project root. Same as Cursor.
- **Hooks** — `~/.codex/hooks.json`, same format as Claude Code.

---

## Verifying a transfer

```bash
# Method present and complete:
grep -c "Senior engineering reflexes" AGENTS.md # → 1

# Agents linked:
bash scripts/setup-agents.sh --dry-run # → "already linked correctly" per agent

# Anti-debt runs through an agent path (Claude example):
python3 ~/.claude/skills/anti-debt/skills/debt-scan/tools/scan_code.py .

# AI-docs stack in a project:
# In Claude Code: /verify-ai-docs → OPERATIONAL
```

A correct transfer means: each agent loads `AGENTS.md` (Layer 1), the anti-debt
agent is linked and runnable, the memory hooks are registered, and the only
hand-edited per-machine file is the agent's own Layer-3 config + `config.sh`.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ The usual workarounds (pasting files into context, writing long prompts) don't s
A **self-maintained AI optimization stack** — a set of structured documents, scripts, and hooks that keeps the AI perpetually oriented without human intervention:

```
Engineering method (AGENTS.md) ← single canonical source, shared to every LLM
Per-module AI context files ← updated on every file edit
Dependency graph (graphify) ← re-indexed on demand
Domain rules (standalone) ← single file injected for critical code
Obsidian memory vault ← persistent second brain across sessions
Claude Code memory ← auto-generated session summaries
Skills ecosystem ← domain-specific verification commands
Universal hooks ← session memory load/save, LOC gate (any agent)
Anti-debt agent ← deterministic tech-debt governance
PostToolUse hook ← keeps everything in sync automatically
```

One command audits the entire stack: `/verify-ai-docs`
One command audits the entire stack: `/verify-ai-docs`. Transfer it to any
machine or LLM via **[PORTABILITY.md](PORTABILITY.md)**.

---

Expand Down Expand Up @@ -355,6 +359,24 @@ python tools/ai_docs/generate_all.py
# 6. Verify → /verify-ai-docs should display OPERATIONAL
```

### Whole-stack transfer (method + hooks + agents, any LLM)

The steps above set up the per-project AI-docs stack. To transfer the **full
method** to a new machine or wire a new AI agent (Claude Code, MiniMax/Mavis,
Cursor, Codex) to the same rules, hooks, and the anti-debt agent:

```bash
# Link the anti-debt agent into every detected AI agent (idempotent, OS-aware)
bash scripts/setup-agents.sh

# Then wire the engineering method (@AGENTS.md include) + hooks per agent:
# → see PORTABILITY.md
```

The single source of the engineering method is [`AGENTS.md`](AGENTS.md) — every
tool config references it instead of re-stating the rules, so the configs never
diverge. Full guide: **[PORTABILITY.md](PORTABILITY.md)**.

---

## Quality Standards — AI Optimization and Human Readability
Expand Down
28 changes: 19 additions & 9 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
# Usage:
# bash install.sh [--project-root /path/to/project] [--with-gstack] [--skip-gstack]
#
# What this does:
# What this does (per-project AI-docs stack):
# 1. Copies scripts to tools/ai_docs/
# 2. Copies the verify-ai-docs skill to .claude/skills/
# 3. Installs gstack (global Claude Code skills by Garry Tan / YC) — optional
# 4. Creates config.sh from the template
# 5. Detects Python and validates it works
# 6. Generates all AI_SUMMARY.md files
# 7. Adds config.sh to .gitignore
# 8. Prints next steps
# 2. Copies the verify-ai-docs + verify-standards skills to .claude/skills/
# 3. Copies AGENTS.md (the canonical engineering method) to the project root
# 4. Installs gstack (global Claude Code skills by Garry Tan / YC) — optional
# 5. Creates config.sh from the template
# 6. Detects Python and validates it works
# 7. Generates all AI_SUMMARY.md files
#
# This installer covers the PER-PROJECT stack. The GLOBAL, multi-agent setup
# (engineering-method include, universal hooks, the anti-debt agent link for
# Claude Code / MiniMax / Cursor / Codex) is described in PORTABILITY.md and
# scripted by scripts/setup-agents.sh. See the NEXT STEPS printed at the end.

set -e

Expand Down Expand Up @@ -219,7 +223,13 @@ echo ""
echo "5. Verify the full stack:"
echo " In Claude Code: /verify-ai-docs && /verify-standards"
echo ""
echo "6. GLOBAL multi-agent setup (one-time per machine):"
echo " - Link the anti-debt agent into every AI agent:"
echo " bash $SCRIPT_DIR/scripts/setup-agents.sh"
echo " - Wire the engineering method + hooks per agent (Claude/MiniMax/Cursor/Codex):"
echo " see $SCRIPT_DIR/PORTABILITY.md"
echo ""
if [ "$INSTALL_GSTACK" = "yes" ]; then
echo "6. Add the gstack skills block to your CLAUDE.md (see above)."
echo "7. Add the gstack skills block to your CLAUDE.md (see above)."
echo ""
fi
Loading
Loading