Se rendre au contenu

Capability Cards: why every module of mine gets one

An agent suggested a flag to me that doesn't exist. Since then, every module gets a machine-readable card instead of prose.
6 août 2026 par
Capability Cards: why every module of mine gets one
IT-Guy
Capability Card AI Agents Documentation Odoo Developer Tools

Capability Cards: why every module of mine gets one

An agent suggested a flag to me that doesn't exist. Since then, every module gets a machine-readable card instead of prose.

M
Martin Schmid
2026-08-06

An agent suggested a flag to me last week that doesn't exist. Plausibly named, in the right place in the command, cleanly justified. It just doesn't exist anywhere in the code. He had read the README and interpolated the rest.

Interpolation looks exactly like knowledge in a language model. That's not a model flaw, that's a material flaw.

Since then, every module and every tool of mine gets a Capability Card: a single Markdown file that tells an AI what a tool can do, how to call it, and where it gets dangerous. Currently there are 98 of them in the repository, 88 for Odoo modules and 10 for command-line tools.

What goes on a Capability Card

For a CLI tool, the card is located at usage/AGENT.md, for an Odoo module under doc/capability_card.md. The structure is always the same.

First, what the thing can do, formulated in tasks rather than model names. Then the complete surface as a table: every command, every field, every route. After that, three to eight recipes for tasks that actually come up. Finally, the guardrails, meaning everything that destroys data or must exist beforehand.

English, always. Even if the help pages next to it are bilingual.

And with a budget. Around 300 lines is the maximum, my cards are at a median of 7.9 KB.

The script owns the facts, I own the meaning

The most important part is a division of labor that I underestimated at the beginning. I don't write names, flags, fields, and methods. An introspection script retrieves them deterministically from the code, statically with Odoo and entirely without a running server.

The fact that this works without a server is due to Odoo itself. A module declares its surface in files rather than at runtime. Models and fields appear as class attributes in the Python code. Views and menus are in XML, the access rights in a CSV next to it.

The script reads the Python part as an abstract syntax tree, without executing a single line of it, and parses the rest directly from the files. Two results come out. A structured JSON against which the validation step later checks, and a Markdown with finished tables that I take over unchanged into the card. All that's needed for this is Python version 3.10 or later, no database, and no Odoo import.

For command-line tools, the same runs via the command tree: The script goes through the Click structure and collects every subcommand with its options. If the tool isn't built with Click, the path via --help, but then with the note in the map that the flag coverage is only as good as the help text.

What I contribute is everything that isn't in the code: what the thing is used for, in what order, and where it hurts.

If that sounds like bureaucracy to you, it did to me too. In truth, it's the whole safeguard. A hand-typed flag table drifts from the day it's created. A generated one can't drift because it's recreated on the next run. It was precisely this drift that whispered the invented flag to my agent.

Why not just have it read the source code?

Because the math doesn't add up. An agent can read files, but it pays for every line read with context that it then lacks for the actual work.

An example from my inventory: eq_helper has 98 KB of source code in 24 files, the map for it is 12.9 KB in size. Anyone who answers the question "what can this module" via the source code burns eight times as much for an answer that turns out worse because it was cobbled together from implementation details.

The second reason weighs heavier. Source code says what happens. It doesn't say what you should do.

Why map and help page don't belong together

In Odoo modules, the map sits right next to the help pages for humans, and this regularly leads to the question of why one doesn't merge them. The answer is that the two files have opposite readers.

The help page explains to a clerk where she needs to click. It's bilingual, it's allowed to ramble, it shows screenshots. The map explains to a model which method it should call via call_kw is allowed to call and which access rule applies.

Therefore the card is deliberately not registered in the help navigation. The viewer never displays it, the chatbot retrieves it via its own method. Same directory, opposite audience. Both files get worse as soon as you merge them.

The card is a build artifact, not documentation

The point at which the procedure actually holds up is a verification step. Before a card is written, a script compares the introspection data against the card content. If a command, field, or route is missing, it aborts.

For me, this goes even further. My afterwork-workflow evaluates a flag that exists in the code but is not on the card as a workflow violation. The card thus has the same status as a failed test.

And because nobody manually reviews 88 modules, an upstream step takes over the discovery: it checks per module whether card, help page, README, and icon are present, and retrofits the missing ones in a bundled version bump. Only then does a good idea become an asset.

The tool carries its card with it

For custom Python tools, there is one more step. They get a command named capability-card that prints its own card to stdout. odoodev has been doing this since version 0.52.0.

This means no agent needs access to my repository or my website anymore. It installs the tool and asks it what it can do. The version number is injected live from the package when printing, so the card header cannot become stale.

An outdated map is worse than none

Being honest is part of it. A map takes effort, and an outdated map is more harmful than none at all, because it radiates authority it no longer deserves.

That's why I have a rule that I found strange at first: If introspection and handwritten docs contradict each other, introspection wins. Not because the script is smarter, but because it doesn't forget.

If you want to start yourself, start with the tool your AI most frequently misuses. The first map pays off within an afternoon.

The actual thinking error lies elsewhere. People treat the map as documentation because it looks like documentation. But it's an interface. And interfaces aren't written in prose.

Capability Cards: why every module of mine gets one
IT-Guy 6 août 2026
Archives
ai-workbench: From Claude Cockpit to Backend Switcher
Three months of development on a terminal multiplexer – interchangeable AI backends, multi-line input, and a security release that took a feature with it.