From 7c2c9b1e16806eda8f495333c5b7f8df3c6a8007 Mon Sep 17 00:00:00 2001 From: Ako Date: Tue, 1 Sep 2026 20:45:15 +0000 Subject: [PATCH 1/3] docs(proposal): project brain, with the brief's assumptions verified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Response to mendixlabs/mxcli#1017, which asks for a proposal and for its four stated assumptions to be checked against the codebase rather than trusted. All four needed amending and one is wrong outright. - Documentation via MDL: available for domain-model objects via doc comments and ALTER … SET DOCUMENTATION, but uneven — `create … comment` was a dead option on seven doctypes and was removed rather than wired. Phase 3 now opens with a per-doctype audit. - The catalog: the objects view unions 43 document types with a QualifiedName, and resolution measured at 0.038 ms on a real 382-object project, so speed should not shape the design. Two caveats do: the view indexes only describable types, so a missing anchor is not proof of staleness, and member-level anchors need attributes_data. - Starlark: rules are discovered from files, so a generated rule is just a generated file and no engine work is needed — but `mxcli init` writes into the same directory, so generated rules need a reserved prefix. - Release mechanics: THERE IS NO GORELEASER. Releases run `make release`; skills ship by go:embed from cmd/mxcli/skills, mirrored with rsync --delete from .claude/skills/mendix. The proposal also brings evidence from mxcli's own store of this shape — the bug findings and their wiki digest — because it has already failed in four ways reachable from the brief as written: it grew past being readable, its digest went three months without a trigger, append-only plus merge=union produced 256 silent duplicates that are on main right now, and claims about the mechanism (including "it runs in CI") went stale. Those failures argue for the brief's caps and human-in-the-loop promote, not against the feature. Three open questions are recorded rather than answered, including that THEORY.md — which the issue says to read and update — does not exist anywhere in the repository. No implementation. The issue asks for review before code. Co-Authored-By: Claude Opus 5 --- docs/11-proposals/PROPOSAL_project_brain.md | 401 ++++++++++---------- docs/11-proposals/README.md | 9 +- 2 files changed, 196 insertions(+), 214 deletions(-) diff --git a/docs/11-proposals/PROPOSAL_project_brain.md b/docs/11-proposals/PROPOSAL_project_brain.md index 00f96f6887..466ac88a3a 100644 --- a/docs/11-proposals/PROPOSAL_project_brain.md +++ b/docs/11-proposals/PROPOSAL_project_brain.md @@ -1,232 +1,211 @@ --- -title: Project Brain — Persistent Knowledge and Session Scaffolding for Long-Term AI Collaboration +title: Project brain — an opt-in store for what mxcli cannot compute status: draft +date: 2026-09-01 +related: + - .claude/skills/fix-issue.md + - .claude/skills/maintain-wiki.md + - docs/13-decisions/0003-mdl-is-sql-shaped.md + - PROPOSAL_ai_capability_dataset.md --- -# Proposal: Project Brain — Persistent Knowledge and Session Scaffolding for Long-Term AI Collaboration +# Project brain — an opt-in store for what mxcli cannot compute -## Problem Statement +> Written in response to mendixlabs/mxcli#1017. The issue asks that the brief's +> assumptions be verified against the codebase and that conflicts be flagged +> rather than followed. §2 does that; four of the four assumptions needed +> amending, and one of them is wrong outright. -mxcli is developed with significant AI involvement, yet the project's knowledge infrastructure is built for static human reading rather than persistent, connected memory. Three related friction points compound over time: +## 1. Problem -1. **Documentation goes stale without detection** — Proposals describe features as future work after they have already shipped (e.g., the registry implementation predating its own proposal by weeks). There is no mechanism to detect or prevent this drift. +An agent working on a Mendix project accumulates knowledge it loses each +session: why a pattern was chosen, which marketplace version broke what, which +mxbuild error means what *here*. The usual answers — a hand-maintained +`CLAUDE.md`, a memory-bank tool — rot, and duplicate what mxcli can already +answer. -2. **No orientation layer for new contributors or agent sessions** — Skills files cover specific tasks well, but there is no single place that answers: *what is the current state of the project, what is actively being worked on, and what is the path for adding something new end-to-end?* A new human contributor or an AI agent dropped into a fresh session must reconstruct this from scattered files, CLAUDE.md, and git history. +The governing principle from the brief is right and is what makes this +Mendix-specific rather than another memory tool: **store only the negative +space.** Anything derivable from the model must be answered by a command and +never written down. mxcli can already query entities, microflows, pages, +bindings and references; a store that transcribes any of that is a store that +will disagree with the project. -3. **Knowledge is not connected** — The internals documentation in `docs-site/src/internals/` covers the pipeline and key subsystems, but the pages are isolated documents rather than a traversable network. There is no way to navigate from "executor" to "backend interface" to "MPR backend" as a linked path, and no graph view for humans to explore topics. +## 2. Assumptions verified -These are not separate problems. They share the same root: the project has grown to a point where implicit conventions and scattered documents work for a small team in a single session but break down for parallel development, onboarding, and long-running AI collaboration across many sessions. +### 2.1 Can MDL read and write `Documentation`? — Partly, and unevenly -## Current State +Yes for domain-model objects, through two spellings: a `/** … */` doc comment +before a statement (`findDocCommentText`, wired per-statement in +`mdl/visitor/`), and `ALTER ENTITY … SET DOCUMENTATION` / `SET COMMENT` +(`MDLDomainModel.g4:214`). -The project already has several knowledge layers that are good individually but unconnected: +But the surface is uneven, and there is a recorded finding about exactly this: +`create … comment 'text'` was accepted and **wrote nothing** on `create entity`, +`enumeration`, `module`, `microflow`, `nanoflow`, `rule` and `association`. The +dead option was removed rather than wired, on the grounds that two spellings — +one of which lies — are worse than one. `COMMENT` remains live on constants, +JSON structures, image collections, database connections and workflows. -| Layer | Location | Audience | Character | -|---|---|---|---| -| Kitchen-sink AI context | `CLAUDE.md` | AI agents | Procedural, comprehensive, monolithic | -| Maintainer task skills | `.claude/skills/*.md` | AI agents (mxcli-dev) | Procedural ("how to do X") | -| User task skills | `.claude/skills/mendix/*.md` | AI agents (shipped to users) | Procedural ("how to do X") | -| Internals docs | `docs-site/src/internals/` | Curious users + contributors | Explanatory, isolated pages | -| Proposals | `docs/11-proposals/` | Contributors | Forward-looking, no lifecycle | -| Architecture docs | `docs/01-project/`, `docs/03-development/` | Contributors | Structural, sparse | +**Consequence for the design.** Tier 1 ("attach knowledge to the object it +concerns") is the right preference and is *not* uniformly available today. Phase +3 must open with a per-doctype audit of what can actually carry documentation +and round-trip it, and the proposal should not assume a microflow can be +annotated from MDL until that audit says so. -The gaps are: links between topics (graph), decision lifecycle (why things are the way they are), extension guides (how to add new things end-to-end), a raw material inbox, and a live "what's next" layer connected to GitHub data. +### 2.2 What does the catalog give us, and how fast? — Everything needed, and it is free -## Proposed System: Four Connected Layers +The `objects` view (`mdl/catalog/tables.go:1028`) unions **43 document types** +with a `QualifiedName` column — module, entity, association, microflow, +nanoflow, rule, page, snippet, layout, workflow, and so on. Resolving +`Sales.ACT_Order_Approve` is one equality query. -### Layer 1: Raw Inbox (`docs/raw/`) +Measured against a real project's catalog (`/home/vscode/ord`, 382 objects, +1.6 MB SQLite): -An immutable drop zone for unprocessed source material: GitHub issue exports, research notes, discussion transcripts, external references. Files land here and are never edited after landing. The `/brain-ingest` command processes them into the wiki and marks each file as processed via frontmatter. The raw material remains as provenance. - -This separates input from synthesised knowledge cleanly. An agent or contributor drops a file here; the brain processes it on the next ingest run. - -### Layer 2: The Wiki (`wiki/`) - -A contributor-facing wiki at the repo root. The character is **explanatory** — how things work and why — distinct from skills (procedural) and proposals (decisions in flight). One concept per file, explicit links between topics, with a Mermaid index in `README.md` that renders as a graph. - -Both humans and agents write to the wiki. The agent drafts and updates via commands; humans edit directly. The wiki is not agent-owned — it is collaboratively maintained, with the agent doing the bulk of routine updates. - -The `docs-site/src/internals/` pages are good raw material; overlapping topics link to the wiki or migrate into it. The distinction is audience: docs-site explains internals to curious users, the wiki explains them to contributors who need to change things. - -**Structure:** - -``` -wiki/ - README.md # visual index: Mermaid graph of clusters + entry points - log.md # chronological record of all wiki operations - MAP.md # source path → wiki topic manifest (drives freshness hooks) - - pipeline/ # the journey from MDL text to MPR write - overview.md # full pipeline diagram, links to each step - grammar.md # ANTLR4, domain split, make grammar - ast.md # statement node hierarchy, how kinds map to types - visitor.md # ANTLR listener → AST construction - executor.md # registry, dispatch, ExecContext, register_stubs.go - backend.md # hexagonal boundary, interface design, why it exists - mpr.md # BSON, reader/writer, storage names, v1 vs v2 - - design/ # why things are the way they are (ADRs) - mdl-syntax-principles.md # design guidelines, anti-patterns, decision framework - backend-boundary.md # no sdk/mpr in executor, why enforced by checklist - registry-explicit-wiring.md # why init() was rejected, emptyRegistry() testing - grammar-domain-split.md # how the domain split reduces conflict surface - - subsystems/ # key components in isolation - catalog.md # SQLite catalog, what it indexes, query interface - lsp.md # LSP capabilities, how diagnostics flow, wiring - widget-engine.md # widget registry, .def.json, template loading - version-awareness.md # feature registry, checkFeature(), version gates - repl.md # REPL architecture, session state - - extending/ # end-to-end contributor guides - new-command.md # full path: grammar → AST → visitor → executor → backend → MPR - new-document-type.md # adding a new Mendix document type - new-backend-method.md # interface → MPR implementation → mock stub - new-lint-rule.md # rule registration, Starlark vs Go rules - new-widget.md # .def.json, widget registry, template extraction -``` - -**ADR format for `design/`:** Each decision file uses: -- **Context** — what problem prompted this decision -- **Decision** — what was chosen and what was explicitly rejected -- **Status** — `accepted` | `superseded` | `under review` -- **Consequences** — what the decision implies for contributors and agents - -**Links to skills:** Each `extending/` guide links to the relevant maintainer skill for the step-by-step checklist. The wiki provides narrative and rationale; the skill provides the checklist and gotchas. - -**`MAP.md` — the source-to-topic manifest:** -Maps source paths to wiki topics, enabling automated freshness checking: ``` -mdl/executor/registry.go → wiki/pipeline/executor.md -mdl/grammar/domains/ → wiki/pipeline/grammar.md -mdl/backend/ → wiki/pipeline/backend.md -sdk/mpr/ → wiki/pipeline/mpr.md +resolve one anchor: 0.038 ms (mean of 1000, no index on QualifiedName) ``` -### Layer 3: Live Project State (Connected to GitHub) - -The wiki provides static knowledge. Current project state — what is in progress, ready to pick up, blocked — lives in GitHub (issues, milestones, project board) and must not be duplicated in the wiki, where it would go stale immediately. - -A scheduled Claude Code agent generates `wiki/CURRENT.md` periodically — not raw GitHub data, but a synthesised briefing: given open issues, active PRs, and recent decisions, what does the project need next and why. This gives contributor personal second-brain systems a pull-able summary, and gives AI agents dropping into a fresh session an orientation point without querying the GitHub API themselves. - -### Layer 4: CDC Feed (`feed/brain.xml`) - -An Atom feed that publishes insight events whenever the wiki gains new or significantly revised knowledge. This is the machine-readable layer that other brains — personal (meowary) or project — subscribe to and integrate. - -**Feed schema** uses a `brain:` namespace for knowledge-specific metadata: - -```xml - - - mxcli Project Brain - CDC feed — insight events from the mxcli knowledge base - - [PAGES_URL]/feed/brain.xml - [ISO8601] - mxcli Brain Agent - - -``` - -Each entry includes: -- `brain:event_type` — `concept-created` | `concept-revised` | `adr-added` | `adr-superseded` | `divergence-detected` | `synthesis-updated` -- `brain:confidence` — 0.0–1.0 (agent confidence in the insight) -- `brain:trigger` — `empirical` | `discussion` | `research` | `contradiction` | `synthesis` -- `brain:supersedes` — URI of the previous entry if this revises an earlier one - -**Feed entries are append-only.** Never delete or modify existing entries. The feed is the immutable audit log of the project brain's evolution. - -A `feed/.feedmeta` file holds feed configuration and the list of external brain feed URLs to sync from (e.g., meowary feeds from contributors). - -**Emission rules** — a feed entry must be emitted when: -- A new page is created in `wiki/design/` (ADR) or `wiki/pipeline/` -- An existing ADR is superseded or deprecated -- A `wiki/extending/` guide is substantially revised -- A DIVERGENCE is detected during `/brain-sync` -- `wiki/CURRENT.md` is regenerated with a materially different project state - -## Agent Commands - -### `/brain-ingest` -Processes new files in `docs/raw/`: -1. Read each unprocessed file -2. Extract key concepts, decisions, insights -3. Create or update relevant wiki pages with cross-links to existing pages -4. Mark source file as processed (add `processed: true` to frontmatter) -5. Update `wiki/log.md` -6. Evaluate each changed wiki page against feed emission rules; append entries to `feed/brain.xml` - -### `/brain-sync` -Consumes external brain feeds listed in `feed/.feedmeta`: -1. For each new feed item since last sync, determine if it extends, confirms, or contradicts current wiki knowledge -2. If extends: draft wiki update (propose, do not auto-commit) -3. If contradicts: create a DIVERGENCE entry in `wiki/synthesis/open-questions.md` -4. If confirms: note corroboration on the relevant wiki page -5. Emit a feed event summarising what was integrated - -This is the primary mechanism for meowary (retran's personal second brain) to contribute knowledge back to the project brain, and for the project brain to receive updates from contributor systems. - -### `/mxcli-dev:update-wiki` -End-of-feature wiki update command. Reads the current diff, identifies affected topics via `MAP.md`, and drafts updates to relevant wiki pages. Invoked intentionally at the end of a feature as part of the definition of done. - -### `/brain-lint` -Health-checks the wiki: -- Verify all `[[wikilinks]]` resolve -- Check `wiki/README.md` lists all pages -- Flag concepts mentioned across multiple pages but without their own topic page -- Flag ADRs that may be invalidated by recent wiki changes -- Flag MAP.md entries whose source path no longer exists -- Report `wiki/design/` entries whose status has not been reviewed in 90 days - -## Freshness Enforcement - -**Hook — flag on edit:** -A `PostToolUse` hook on writes to mapped source paths looks up `MAP.md` and surfaces which wiki topics may be affected. It flags the connection; it does not generate content. - -**Review integration:** -The existing `/mxcli-dev:review` command checks wiki freshness: for each source file changed in the PR, verify the corresponding wiki topic has been touched or explicitly noted as unaffected. - -**CI check:** -A Makefile target compares modification dates of source files against their mapped wiki topics and warns when source is newer than documentation by more than a threshold. Staleness becomes visible at PR time. - -## Skill Level Mapping - -| | Maintainer (mxcli-dev) | User (mendix/) | -|---|---|---| -| **Procedural skills** | `.claude/skills/*.md` | `.claude/skills/mendix/*.md` | -| **Explanatory wiki** | `wiki/` (this proposal) | `docs-site/src/` (exists) | -| **Live state** | `wiki/CURRENT.md` (generated) | — | -| **CDC feed** | `feed/brain.xml` | — | - -## Relationship to Meowary and Federated Brains - -Retran's meowary system (https://github.com/retran/meowary) is a personal second brain with GitHub CLI integration, PARA structure, and session-planning scaffolding. The project brain is the *supply side* that feeds meowary and equivalent systems: - -- **Project brain publishes:** `feed/brain.xml` (knowledge events), `wiki/CURRENT.md` (project state) -- **Meowary subscribes:** adds `feed/brain.xml` to `feed/.feedmeta` subscribed_feeds; `/brain-sync` pulls new entries and integrates them into meowary's knowledge base -- **Meowary contributes back:** decisions and insights from retran's sessions can be published to meowary's own feed, which the project brain pulls via `/brain-sync` and proposes as wiki updates - -This is the federated model: each brain (project or personal) publishes a CDC feed; `/brain-sync` connects them bidirectionally. The `brain:` namespace makes feeds from different systems structurally compatible. - -## What Is Not Changing - -- **`CLAUDE.md`** — remains the primary AI context file as-is. This proposal does not replace or restructure it. The wiki complements CLAUDE.md; it does not supersede it. -- **`.claude/skills/`** — remain the procedural task references. The wiki's `extending/` guides are the narrative counterpart, not a replacement. -- **`docs-site/src/`** — remains the user-facing published documentation. Overlapping internals topics link between the two rather than merging. -- **`docs/11-proposals/`** — remains for in-flight feature proposals. Accepted proposals that establish lasting architectural decisions migrate to `wiki/design/` as ADRs. - -## Summary and Priority - -| Component | Problem solved | Effort | +A hundred anchors is under 4 ms. **Speed is a non-issue and should not shape the +design.** + +Two caveats that do: + +- **The `objects` view indexes only describable types.** A recorded finding says + it in as many words — "do not measure coverage from the catalog… enumerate raw + unit `$Type`s instead". An anchor to a document type outside the view resolves + as *missing*, which is a false staleness signal. `check` must distinguish + "resolved", "not found", and **"cannot be resolved by this index"**, and only + the middle one is a failure. +- **Member-level anchors need a second query.** `@Sales.Order` resolves through + `objects`; `@Sales.Order.Status` does not — attributes live in + `attributes_data` (`EntityQualifiedName` + `Name`, 254 rows in the sample + project). Support both or document that anchors are document-scoped; do not + let an attribute anchor silently fail. + +**Staleness of the catalog itself** is an `.mpr` **mtime** comparison +(`cmd_catalog.go:296`). `brain check --ci` on a fresh clone gets fresh mtimes, so +CI rebuilds the catalog every run. That cost is unmeasured here and needs a +number before `--ci` is promised. + +### 2.3 Does the Starlark engine support generated rules? — The question does not arise + +Rules are **discovered from files**: `FindLintRulesDir` walks up for +`.claude/lint-rules/`, and every `*.star` in it is loaded. There is no compiled-in +registry to extend, so "a rule generated at runtime from a template" is just **a +generated file**. No engine work is needed. + +One hazard the brief does not mention: `mxcli init` writes the bundled rules into +that same directory with `os.WriteFile` per file (`init.go:351`). It does **not** +wipe the directory, so a generated rule survives an upgrade — *unless its +filename collides with a shipped one*. Generated rules therefore need a reserved +prefix (`brain_*.star`) and a rule-ID namespace outside the shipped `ARCH` / +`CONV` / `QUAL` / `SEC` / `MDL` sets. + +### 2.4 Release and skill mechanics — the brief's premise is wrong + +**There is no goreleaser.** No `.goreleaser.yml` exists. Releases run +`make release` from `.github/workflows/release.yml`. + +Skills ship by embedding: `//go:embed all:skills` over `cmd/mxcli/skills/` +(`skills_content.go:26`), which `make sync-skills` mirrors from +`.claude/skills/mendix/` with **`rsync --delete`**. So shipping a skill means +adding `.claude/skills/mendix//SKILL.md` and nothing else — and editing the +embed directory directly is always wrong, because the next sync deletes it. The +`all:` prefix is load-bearing (a plain `go:embed` skips `_`-prefixed files). + +`.mxcli/` **is** gitignored by `mxcli init` (`constant_gitignore.go`), so the +brief's split between committed docs and tool-owned state holds as written. + +## 3. Evidence from mxcli's own attempt at this + +mxcli already runs a store of exactly this shape — the bug findings under +`.claude/skills/fix-issue/findings/`, digested into `docs-wiki/bug-patterns/`. +It has been running for months and has failed in four ways that this design +should be built against, because every one of them is reachable from the brief +as written. + +**It grew until it could not be read.** The findings began as a Markdown table +inside a skill file and reached **1.05 MB across 630 rows** — past a context +window, past what GitHub's web editor will open, and past what the digest step +could consume. The instruction to "read it before diagnosing" was unfollowable +for months and nobody noticed, because an unread file has no failure mode. +*→ The brief's caps are the single most important thing in it. Keep them, and +enforce them in `promote` as it says.* + +**The digest nothing triggered stopped.** Three pattern pages were written on one +day in May and none was re-synced for three months while the corpus grew 200×. +The sync was on-demand and no step demanded it. +*→ A trigger has to fire where work already happens. What eventually worked was +printing the gap from a command that already runs on every fix, not adding a +report someone must remember.* + +**Append-only plus union merge produced silent duplicates.** `merge=union` was +added so parallel fixes would not conflict. It cannot distinguish a genuine +parallel append from a re-append of the same content, and nothing compared lines: +`main` currently holds **885 records of which 629 are distinct** — the executor +shard is essentially the same 247 findings twice. +*→ `staged.jsonl` and the committed `decisions.md` are both append-only stores +with the same exposure. Whatever check they get must compare entries, not just +validate each one.* + +**Claims about the mechanism went stale, including "it runs in CI".** A README +and a PR body both said the findings check ran in CI. It did not. Coverage +percentages written into prose were stale within days. +*→ Anything the brain reports about itself should be computed by a command, not +written into a file.* + +None of this argues against the feature. It argues that the parts of the brief +that look like restraint — caps, no auto-promotion, human-in-the-loop `promote` — +are the parts that carry the design, and the parts that look like plumbing are +where it will fail. + +## 4. Design + +Adopt the brief as written, with the following amendments, each traceable to §2 +or §3. + +| # | Amendment | Because | |---|---|---| -| `wiki/pipeline/` + `wiki/extending/` | Orients contributors; raw material exists in docs-site | Low | -| `wiki/design/` (ADRs) | Captures why; prevents decision re-litigation | Low per decision | -| `MAP.md` + hook | Freshness enforcement without manual discipline | Low | -| `docs/raw/` + `/brain-ingest` | Structured intake of source material | Low | -| `feed/brain.xml` + emission rules | CDC feed for federated brain subscriptions | Low | -| `/brain-sync` | Bidirectional meowary ↔ project brain connection | Medium | -| `wiki/CURRENT.md` (scheduled agent) | Live session briefing from GitHub data | Medium | -| `/brain-lint` | Automated health checks | Medium | - -**Recommended order:** `wiki/pipeline/` and `wiki/extending/` first — highest immediate value, raw material already exists. Add `MAP.md` and the hook immediately after. Then `docs/raw/`, `feed/brain.xml`, and `/brain-ingest` together as a batch — they form one coherent intake workflow. `/brain-sync`, CURRENT.md, and `/brain-lint` are independent and can follow in any order. +| A1 | `check` reports three anchor states — resolved, **not found**, **not indexable** — and fails only on the middle one | §2.2: the `objects` view is not a complete inventory | +| A2 | Anchors resolve at document *and* member granularity (`objects` + `attributes_data`) | §2.2: `@Mod.Entity.Attr` is the natural thing to write | +| A3 | Generated lint rules use a `brain_` filename prefix and a `BRAIN###` ID namespace | §2.3: `mxcli init` writes into the same directory | +| A4 | Phase 3 opens with a per-doctype documentation audit; no promotion to model documentation before it | §2.1: `create … comment` was a dead option on seven doctypes | +| A5 | `staged.jsonl` and every committed store get a **duplicate check**, not only a shape check | §3: 256 duplicate findings reached `main` unnoticed | +| A6 | `brain show`'s size figure and any coverage number are computed, never written into a committed file | §3: prose figures went stale within days | +| A7 | The gap that motivates curation is printed by a command that already runs, not only by `brain check` | §3: the on-demand digest went three months without a run | + +Everything else — the three tiers, the storage layout, the CLI surface, the +promote-only-through-a-human rule, the non-goals — stands as written. The +non-goals in particular should be treated as load-bearing. + +**The skill.** Ship it under `.claude/skills/mendix/project-brain/SKILL.md`; the +embed and `mxcli init` handle the rest (§2.4). The brief is right that the +description decides whether it is ever used and should be phrased around +symptoms. Worth adding: mxcli's own skills are synced with `rsync --delete`, so +the source of truth is `.claude/skills/mendix/`, never the embed directory. + +## 5. Phasing + +Unchanged from the brief, with A4 inserted: + +1. Storage, anchors, `init` / `capture` / `staged` / `promote` / `drop` / + `check` / `show`, plus the skill. Markdown destinations only. +2. The mxbuild error → resolution trigger. +3. **Documentation audit**, then promotion into model documentation and lint-rule + generation. + +## 6. Open questions + +1. **What does `brain check --ci` cost on a cold clone?** It needs a catalog, and + catalog validity is an mtime comparison that a fresh checkout always fails. + Unmeasured. If a full build is expensive, `--ci` may need a cheaper anchor + index than the catalog. +2. **Is `docs/` the right home?** The brief argues for reviewability in PR diffs, + which is correct. But a Mendix project's `docs/` may already be Studio Pro's + or a customer's. `init`'s adoption step should cover "there is a `docs/` and it + is not ours". +3. **THEORY.md does not exist.** The issue says to read it and to update it if the + working theory changes. There is no such file anywhere in the repository. Is it + expected to be created, or was another document meant? diff --git a/docs/11-proposals/README.md b/docs/11-proposals/README.md index a14affc701..8d4f8ed6cf 100644 --- a/docs/11-proposals/README.md +++ b/docs/11-proposals/README.md @@ -26,7 +26,7 @@ for display in this README): -## Active Proposals (98) +## Active Proposals (103) ### In Progress (partial) (12) @@ -90,13 +90,15 @@ for display in this README): | [VS Code Search — Quick Pick + Workspace Symbol](PROPOSAL_vscode_search.md) | Proposed | Full-text search exists in mxcli (mxcli search) but is only accessible via the terminal. | | [Workflow Improvements: ALTER WORKFLOW + Cross-References](PROPOSAL_workflow_improvements.md) | Proposed | Workflow support in mxcli has full CREATE/DESCRIBE/DROP/SHOW coverage with 13 activity types and BSON round-trip fidelity. | -### Draft (42) +### Draft (45) | Proposal | Status | Summary | |----------|--------|---------| | [Agent Document Type Support in MDL](PROPOSAL_agent_document_support.md) | Draft | Mendix 11.9 introduces Agents as a first-class concept for building agentic AI applications. | | [Architecture Graph Visualization (communities, layers, god-nodes)](PROPOSAL_architecture_graph_visualization.md) | Draft | Issue: TBD (file before implementation) | | [Association Mapping in IMPORT](PROPOSAL_import_associations.md) | Draft | Parent: PROPOSAL_mxcli_sql.md (Phase 3 extension) | +| [Authorable layouts, page templates and building blocks — CREATE, not COPY](PROPOSAL_authorable_layouts.md) | Draft | An app built entirely through MDL cannot put anything in its own topbar. | +| [Authorable message definitions — the last mapping source MDL cannot write](PROPOSAL_authorable_message_definitions.md) | Draft | A mapping is bound to one of four schema sources. | | [Backend Strategy — adopt engalar's modelsdk base + multi-backend (MCP first)](PROPOSAL_backend_strategy.md) | Draft | - Adopt engalar's modelsdk foundation as the base rather than merging 1109 | | [Bulk Change Custom Widget Properties](PROPOSAL_bulk_widget_property_updates.md) | Draft | Custom widgets (pluggable widgets) in Mendix have complex nested property structures. | | [Bulk External Action Support from OData Contracts](PROPOSAL_external_actions_bulk_create.md) | Draft | Issue #143 requests importing all entities and actions from a consumed OData service. | @@ -106,6 +108,7 @@ for display in this README): | [Expression Type Checking for mxcli check](PROPOSAL_expression_type_checking.md) | Draft | mxcli check is currently a syntactic validator only. | | [Extend UPDATE WIDGETS to Built-in Widgets via Schema Registry](PROPOSAL_update_builtin_widget_properties.md) | Draft | update widgets currently only works for pluggable widgets (ComboBox, DataGrid2, etc.) — it cannot modify properties on built-in widgets like | | [GitHub Actions MDL Integration Tests](proposal-github-mdl-integration.md) | Draft | Add a GitHub Actions workflow that validates MDL example scripts against a real Mendix project after every merge to main. | +| [Import/export mapping coverage — what real mappings use, and the MDL to express it](PROPOSAL_mapping_coverage.md) | Draft | Measured against: 327 mapping documents in 8 demo/marketplace apps | | [Integration Pane — Unified View of External Service Assets](integration-pane-proposal.md) | Draft | Mendix Studio Pro has an Integration Pane that shows all connected services and lists the available assets from their contracts (OData $meta | | [MCP Backend — execute MDL against a live Studio Pro via its MCP server](PROPOSAL_mcp_backend.md) | Draft | Today mxcli writes model changes by editing the .mpr/mprcontents files | | [MCP BSON Benchmark — Correctness Oracle + Efficiency Measurement](PROPOSAL_mcp_bson_benchmark.md) | Draft | Use the Studio Pro MCP server as a dual-purpose tool: | @@ -127,7 +130,7 @@ for display in this README): | [mxcli Playground](mxcli-playground.md) | Draft | A public GitHub repository (mendixlabs/mxcli-playground) containing a ready-to-use Mendix project pre-configured with mxcli, Claude Code ski | | [Owning the modelsdk/gen codegen — why the vendored generator cannot be adopted as-is](PROPOSAL_codegen_ownership.md) | Draft | Constraint set by the maintainer (2026-08-13): the reflection data is an | | [Playwright Session Reuse and Lifecycle Control](PROPOSAL_playwright_session_reuse.md) | Draft | Builds on proposal-playwright-cli.md, which | -| [Project Brain — Persistent Knowledge and Session Scaffolding for Long-Term AI Collaboration](PROPOSAL_project_brain.md) | Draft | mxcli is developed with significant AI involvement, yet the project's knowledge infrastructure is built for static human reading rather than | +| [Project brain — an opt-in store for what mxcli cannot compute](PROPOSAL_project_brain.md) | Draft | An agent working on a Mendix project accumulates knowledge it loses each | | [RENAME with Reference Refactoring](PROPOSAL_rename_refactoring.md) | Draft | Renaming entities, microflows, pages, and modules is one of the most common refactoring operations. | | [Replace Generated Playwright Tests with playwright-cli](proposal-playwright-cli.md) | Draft | The current approach (documented in proposal-playwright-testing.md) has Claude Code generate TypeScript test files (.spec.ts), then run them | | [Self-Describing Syntax Feature Registry](syntax-feature-registry.md) | Draft | Branch: research/recursive-help-discovery | From c45d0685ccbbe6f4fd7c702bdba663d66c8681c3 Mon Sep 17 00:00:00 2001 From: Ako Date: Tue, 1 Sep 2026 20:58:01 +0000 Subject: [PATCH 2/3] docs(proposal): correct the audience and the documentation finding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two corrections from review, and a measurement that changes a conclusion. **Audience.** The proposal conflated two stores. The bug findings and their wiki digest are for developing mxcli itself — a Go repo, many parallel agent sessions, hundreds of entries. This brain is for USERS of mxcli, in their own Mendix project: one developer and their agent, tens of lines, reviewed by someone who may never see mxcli's source. Stated up front now, and §3 is reframed as an analogy with the differences named rather than as a precedent. Three of its failures transfer (unbounded growth, an untriggered curation step, stale self-reported claims); the duplicate-merge one does not, and the earlier draft over-weighted it. **Documentation.** `create … comment` was removed BECAUSE javadoc-style comments exist and reach the .mpr — not because the capability was missing. Verified: a /** … */ header on a microflow and on an entity lands in the stored .mxunit and comes back through DESCRIBE. Wired at 28 sites across mdl/visitor. The earlier draft drew the wrong inference from the removal. But testing the next question found worse: a rewrite DESTROYS it. microflow doc entity doc after create PRESENT PRESENT after replace mf ABSENT PRESENT <- control holds after modify entity ABSENT ABSENT Each rewrite destroys its own object's documentation and leaves the other alone, and mx check is clean throughout because a document with no documentation is valid. So a statement that says nothing about documentation silently deletes whatever was promoted there. Tier 1 — the strongest idea in the brief — is blocked until mxcli's writers preserve documentation they do not restate, which is a writer fix and belongs in its own issue. The first version of that test chained `&& echo SURVIVED` to `head -1`, which exits 0 on empty input, and reported success regardless of what grep found. Recorded in the proposal, because it is the same shape as the failures §3 catalogues. Co-Authored-By: Claude Opus 5 --- docs/11-proposals/PROPOSAL_project_brain.md | 174 +++++++++++++------- docs/11-proposals/README.md | 2 +- 2 files changed, 115 insertions(+), 61 deletions(-) diff --git a/docs/11-proposals/PROPOSAL_project_brain.md b/docs/11-proposals/PROPOSAL_project_brain.md index 466ac88a3a..36ef7328f1 100644 --- a/docs/11-proposals/PROPOSAL_project_brain.md +++ b/docs/11-proposals/PROPOSAL_project_brain.md @@ -1,5 +1,5 @@ --- -title: Project brain — an opt-in store for what mxcli cannot compute +title: Project brain — an opt-in store, in a user's Mendix project, for what mxcli cannot compute status: draft date: 2026-09-01 related: @@ -9,7 +9,7 @@ related: - PROPOSAL_ai_capability_dataset.md --- -# Project brain — an opt-in store for what mxcli cannot compute +# Project brain — an opt-in store, in a user's Mendix project, for what mxcli cannot compute > Written in response to mendixlabs/mxcli#1017. The issue asks that the brief's > assumptions be verified against the codebase and that conflicts be flagged @@ -18,6 +18,13 @@ related: ## 1. Problem +**Audience: users of mxcli building Mendix projects** — not mxcli's own +development. The store lives in the user's Mendix project, is maintained by that +developer and their agent, and is read by people who may never see mxcli's +source. This matters throughout: it sets the scale (tens of lines, not +hundreds of entries), the number of writers (one developer, not many parallel +sessions), and the review audience (a Mendix developer reading a pull request). + An agent working on a Mendix project accumulates knowledge it loses each session: why a pattern was chosen, which marketplace version broke what, which mxbuild error means what *here*. The usual answers — a hand-maintained @@ -33,25 +40,66 @@ will disagree with the project. ## 2. Assumptions verified -### 2.1 Can MDL read and write `Documentation`? — Partly, and unevenly +### 2.1 Can MDL read and write `Documentation`? — Yes, via doc comments, and it is the supported spelling + +A `/** … */` comment before a statement becomes the object's `Documentation` and +is written into the model. Measured on Mendix 11.13, executing against a real +project and then searching the **stored bytes**, not a read-back: + +``` +create microflow … with a /** … */ header + -> text present in mprcontents/d4/a4/….mxunit +create entity … with a /** … */ header + -> text present in mprcontents/84/77/….mxunit +describe microflow … + -> the comment comes back verbatim, above `create or modify microflow` +``` + +`create … comment 'text'` was removed **because this exists**, not because the +capability was missing — two spellings, one of which wrote nothing, is worse +than one. Reading the removal as evidence of a gap is the wrong inference, and +the earlier draft of this proposal made it. -Yes for domain-model objects, through two spellings: a `/** … */` doc comment -before a statement (`findDocCommentText`, wired per-statement in -`mdl/visitor/`), and `ALTER ENTITY … SET DOCUMENTATION` / `SET COMMENT` -(`MDLDomainModel.g4:214`). +The doc comment is wired at **28 sites** across `mdl/visitor/`, covering entity, +microflow, page, association, enumeration, workflow, scheduled event, queue, +regular expression, JSON structure, image collection, OData, REST, business +events and the agent-editor documents. -But the surface is uneven, and there is a recorded finding about exactly this: -`create … comment 'text'` was accepted and **wrote nothing** on `create entity`, -`enumeration`, `module`, `microflow`, `nanoflow`, `rule` and `association`. The -dead option was removed rather than wired, on the grounds that two spellings — -one of which lies — are worse than one. `COMMENT` remains live on constants, -JSON structures, image collections, database connections and workflows. +**But a rewrite destroys it.** Writing works; *surviving* does not. Measured on +the same project, checking the stored bytes after each step, with the untouched +object as the control: -**Consequence for the design.** Tier 1 ("attach knowledge to the object it -concerns") is the right preference and is *not* uniformly available today. Phase -3 must open with a per-doctype audit of what can actually carry documentation -and round-trip it, and the proposal should not assume a microflow can be -annotated from MDL until that audit says so. +``` + microflow doc entity doc +after create PRESENT PRESENT +after `create or replace` the microflow + ABSENT PRESENT <- control holds +after `create or modify` the entity + ABSENT ABSENT +``` + +Each rewrite destroys **its own** object's documentation and leaves the other +alone. So a statement that says nothing about documentation — adding an +attribute, changing a flow — silently deletes whatever was promoted there. +`mx check` is clean throughout: a document with no documentation is valid. + +This is the guard-don't-drop class, and it is **fatal to tier 1 as the brief +describes it**. "Knowledge attached to the object travels with the object and is +deleted with it" is true, and the unstated half is that it is also deleted by an +ordinary edit that has nothing to do with the knowledge. An agent that promotes a +decision into a microflow's documentation and later adds a parameter has thrown +the decision away, with every signal reporting success. + +**Consequence for the design.** Tier 1 is the strongest idea in the brief and is +**blocked** until rewrites preserve documentation the statement does not restate. +That is a fix in mxcli's writers, not in the brain, and it should be a +precondition of phase 3 rather than a task inside it. Until then the brain's +preference order starts at tier 2. + +A caveat on this measurement: it was made with a corrected test. The first +version chained `&& echo SURVIVED` to `head -1`, which exits 0 on empty input, so +it reported success regardless of what grep found — the same shape as the test +failures catalogued in §3. ### 2.2 What does the catalog give us, and how fast? — Everything needed, and it is free @@ -118,48 +166,50 @@ embed directory directly is always wrong, because the next sync deletes it. The `.mxcli/` **is** gitignored by `mxcli init` (`constant_gitignore.go`), so the brief's split between committed docs and tool-owned state holds as written. -## 3. Evidence from mxcli's own attempt at this +## 3. Evidence from an analogous store — with the differences stated -mxcli already runs a store of exactly this shape — the bug findings under +mxcli maintains a store of a similar shape: the bug findings under `.claude/skills/fix-issue/findings/`, digested into `docs-wiki/bug-patterns/`. -It has been running for months and has failed in four ways that this design -should be built against, because every one of them is reachable from the brief -as written. - -**It grew until it could not be read.** The findings began as a Markdown table -inside a skill file and reached **1.05 MB across 630 rows** — past a context -window, past what GitHub's web editor will open, and past what the digest step -could consume. The instruction to "read it before diagnosing" was unfollowable -for months and nobody noticed, because an unread file has no failure mode. -*→ The brief's caps are the single most important thing in it. Keep them, and -enforce them in `promote` as it says.* - -**The digest nothing triggered stopped.** Three pattern pages were written on one -day in May and none was re-synced for three months while the corpus grew 200×. -The sync was on-demand and no step demanded it. -*→ A trigger has to fire where work already happens. What eventually worked was -printing the gap from a command that already runs on every fix, not adding a -report someone must remember.* - -**Append-only plus union merge produced silent duplicates.** `merge=union` was -added so parallel fixes would not conflict. It cannot distinguish a genuine -parallel append from a re-append of the same content, and nothing compared lines: -`main` currently holds **885 records of which 629 are distinct** — the executor -shard is essentially the same 247 findings twice. -*→ `staged.jsonl` and the committed `decisions.md` are both append-only stores -with the same exposure. Whatever check they get must compare entries, not just -validate each one.* - -**Claims about the mechanism went stale, including "it runs in CI".** A README -and a PR body both said the findings check ran in CI. It did not. Coverage -percentages written into prose were stale within days. -*→ Anything the brain reports about itself should be computed by a command, not -written into a file.* - -None of this argues against the feature. It argues that the parts of the brief -that look like restraint — caps, no auto-promotion, human-in-the-loop `promote` — -are the parts that carry the design, and the parts that look like plumbing are -where it will fail. + +**It is not this feature and the audience is different.** That store is for +developing *mxcli itself* — a Go repository, many parallel agent sessions, +hundreds of entries accumulated over months, read by people working on the tool. +The brain proposed here is for a *user's Mendix project*: one developer and their +agent, a few dozen lines, read by someone who may never see mxcli's source. The +scale differs by two orders of magnitude and the number of concurrent writers by +more. + +So this is an analogy, not a precedent. Three of its failures transfer, one does +not, and saying which is the point of including it. + +**Transfers — unbounded growth destroys the artifact.** The findings began as a +table inside a skill file and reached 1.05 MB across 630 rows: past a context +window, past what GitHub's web editor will open. The instruction to read it +before diagnosing was unfollowable for months and nobody noticed, because an +unread file has no failure mode. This transfers *more* strongly here, not less: +a project brain is loaded into an agent's context every session, so its size is a +recurring tax rather than an occasional one. **The brief's caps are the single +most important thing in it**, and `promote` refusing when a cap would be exceeded +is the right enforcement point. + +**Transfers — a curation step with no trigger stops.** Three digest pages were +written on one day and none was re-synced for three months while the corpus grew. +The step was on-demand and nothing demanded it. The brain has the same shape: +`staged.jsonl` fills automatically and `promote` is manual. What eventually +worked in the analogous case was printing the gap from a command that already +runs, rather than adding a report someone must remember to invoke. + +**Transfers — self-reported claims go stale.** A README and a PR body both said a +check ran in CI when it did not; coverage figures written into prose were stale +within days. Anything the brain says about itself — its size, its staleness — +should be computed by `brain show` / `brain check`, never written into a +committed file. + +**Does not transfer — silent duplicates from union merges.** `merge=union` let +256 duplicate findings reach the shared corpus unnoticed. That is a +many-parallel-writers problem; a single developer on one project has little +exposure to it. It justifies a cheap duplicate check on `staged.jsonl` and +nothing more, and the earlier draft over-weighted it. ## 4. Design @@ -171,8 +221,8 @@ or §3. | A1 | `check` reports three anchor states — resolved, **not found**, **not indexable** — and fails only on the middle one | §2.2: the `objects` view is not a complete inventory | | A2 | Anchors resolve at document *and* member granularity (`objects` + `attributes_data`) | §2.2: `@Mod.Entity.Attr` is the natural thing to write | | A3 | Generated lint rules use a `brain_` filename prefix and a `BRAIN###` ID namespace | §2.3: `mxcli init` writes into the same directory | -| A4 | Phase 3 opens with a per-doctype documentation audit; no promotion to model documentation before it | §2.1: `create … comment` was a dead option on seven doctypes | -| A5 | `staged.jsonl` and every committed store get a **duplicate check**, not only a shape check | §3: 256 duplicate findings reached `main` unnoticed | +| A4 | **Tier 1 is blocked** until a rewrite preserves documentation it does not restate. Until then the preference order starts at tier 2 | §2.1: measured — `create or replace` destroys the doc comment, `mx check` clean | +| A5 | `staged.jsonl` gets a cheap duplicate check | §3: cheap insurance, but a many-writers problem that mostly does not apply here | | A6 | `brain show`'s size figure and any coverage number are computed, never written into a committed file | §3: prose figures went stale within days | | A7 | The gap that motivates curation is printed by a command that already runs, not only by `brain check` | §3: the on-demand digest went three months without a run | @@ -209,3 +259,7 @@ Unchanged from the brief, with A4 inserted: 3. **THEORY.md does not exist.** The issue says to read it and to update it if the working theory changes. There is no such file anywhere in the repository. Is it expected to be created, or was another document meant? +4. **Who fixes documentation preservation?** §2.1 measures that `create or + replace` / `create or modify` destroys an object's doc comment. That is an + mxcli writer defect independent of this feature and worth its own issue; the + brain merely cannot use tier 1 until it is fixed. diff --git a/docs/11-proposals/README.md b/docs/11-proposals/README.md index 8d4f8ed6cf..a6b78f60ca 100644 --- a/docs/11-proposals/README.md +++ b/docs/11-proposals/README.md @@ -130,7 +130,7 @@ for display in this README): | [mxcli Playground](mxcli-playground.md) | Draft | A public GitHub repository (mendixlabs/mxcli-playground) containing a ready-to-use Mendix project pre-configured with mxcli, Claude Code ski | | [Owning the modelsdk/gen codegen — why the vendored generator cannot be adopted as-is](PROPOSAL_codegen_ownership.md) | Draft | Constraint set by the maintainer (2026-08-13): the reflection data is an | | [Playwright Session Reuse and Lifecycle Control](PROPOSAL_playwright_session_reuse.md) | Draft | Builds on proposal-playwright-cli.md, which | -| [Project brain — an opt-in store for what mxcli cannot compute](PROPOSAL_project_brain.md) | Draft | An agent working on a Mendix project accumulates knowledge it loses each | +| [Project brain — an opt-in store, in a user's Mendix project, for what mxcli cannot compute](PROPOSAL_project_brain.md) | Draft | Audience: users of mxcli building Mendix projects — not mxcli's own | | [RENAME with Reference Refactoring](PROPOSAL_rename_refactoring.md) | Draft | Renaming entities, microflows, pages, and modules is one of the most common refactoring operations. | | [Replace Generated Playwright Tests with playwright-cli](proposal-playwright-cli.md) | Draft | The current approach (documented in proposal-playwright-testing.md) has Claude Code generate TypeScript test files (.spec.ts), then run them | | [Self-Describing Syntax Feature Registry](syntax-feature-registry.md) | Draft | Branch: research/recursive-help-discovery | From 4c59ea088df2220bfcb5d3463656ee4bc3168800 Mon Sep 17 00:00:00 2001 From: Ako Date: Tue, 1 Sep 2026 21:06:01 +0000 Subject: [PATCH 3/3] docs(proposal): link the documentation-preservation defect to its issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filed as mendixlabs/mxcli#1018. Also records the second control found while writing the repro: ALTER ENTITY … ADD ATTRIBUTE preserves the doc comment, which localises the defect to the rewrite paths and gives users a workaround today. Co-Authored-By: Claude Opus 5 --- docs/11-proposals/PROPOSAL_project_brain.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/11-proposals/PROPOSAL_project_brain.md b/docs/11-proposals/PROPOSAL_project_brain.md index 36ef7328f1..d61be5bffd 100644 --- a/docs/11-proposals/PROPOSAL_project_brain.md +++ b/docs/11-proposals/PROPOSAL_project_brain.md @@ -259,7 +259,9 @@ Unchanged from the brief, with A4 inserted: 3. **THEORY.md does not exist.** The issue says to read it and to update it if the working theory changes. There is no such file anywhere in the repository. Is it expected to be created, or was another document meant? -4. **Who fixes documentation preservation?** §2.1 measures that `create or - replace` / `create or modify` destroys an object's doc comment. That is an - mxcli writer defect independent of this feature and worth its own issue; the - brain merely cannot use tier 1 until it is fixed. +4. **Documentation preservation is filed as `mendixlabs/mxcli#1018`.** It is an + mxcli writer defect independent of this feature. The brain cannot use tier 1 + until it is fixed, and `ALTER ENTITY … ADD ATTRIBUTE` is measured to preserve + documentation — so the workaround, and the shape of the fix, is to carry the + stored value the way the rewrite paths already carry folder, allowed module + roles and element identity.