Mesa Documentation Audit
Mesa's docs are well-organized around a Jujutsu-inspired model with a published llms.txt and OpenAPI spec, but the docs ship with self-admitted feature gaps, broken internal links, inconsistent terminology, and a glossary that's invisible to agents.
1. Glossary page exists but is omitted from llms.txt (critical)
Location: /content/core-concepts/glossary vs. https://docs.mesa.dev/llms.txt
Problem: The Glossary page is real and defines Mesa's core vocabulary (Commit, Change, Bookmark), and other pages (e.g. cli-mount) explicitly link to it via tooltips: href="/content/core-concepts/glossary#bookmark". But it is not listed in the canonical llms.txt index under "Core Concepts" (which only lists patterns-best-practices, versioning, and virtual-filesystem).
Consequence: Agents indexing Mesa via llms.txt never load the glossary, so they parse downstream pages that say "Equivalent to git branch" without the authoritative definition. Worse, the glossary contradicts the rest of the docs (see issue #2) — and the version agents miss is the one that would explain the contradiction.
The fix: Add /content/core-concepts/glossary.md to the llms.txt Core Concepts section. Confirm it is also reachable from llms-full.txt if one exists.
2. "Commit" vs "Change" terminology is internally contradictory (critical)
Location: /content/core-concepts/glossary vs. /content/core-concepts/versioning vs. /content/mesafs/cli-mount
Problem: The glossary defines Commit as "an atomic change in your repo" and Change as "a collection of nodes within one simple path of the history graph" — i.e. they are different concepts, with Change being the Git-commit analog. But the Versioning page's mapping table says the opposite:
| Mesa Concept | Git | JJ |
|---|---|---|
| Change | Commit | Change |
And the CLI Mount page introduces a <CommitTt /> tooltip alongside <ChangeTt /> and <BookmarkTt /> as if "Commit" were a first-class Mesa noun (Create a new detached <CommitTt /> from a <BookmarkTt /> or <ChangeTt /> ID).
Consequence: A developer (or agent) reading the glossary believes Mesa has both Commits and Changes as distinct objects. A developer reading the Versioning page believes "Change" is Mesa's commit. The CLI page uses both interchangeably. Anyone writing code against the REST API or SDK has no idea which noun maps to which resource.
The fix: Pick one. Either retire "Commit" from Mesa's vocabulary (since the model is Jujutsu and JJ uses Change/Bookmark) or define both with a clean delineation in the glossary and use the terms consistently across CLI, SDK, and API reference pages.
3. Broken internal links to non-existent guide paths (significant)
Location: /content/mesafs/cli-mount
Problem: The CLI Mount page links to /content/guides/working-with-sandboxes ("See Working with Sandboxes for provider-specific guides") and to /content/mesa/mount-modes ("see Mount Modes"). Neither path appears in llms.txt. The actual mount-modes page lives at /content/mesafs/advanced/mount-modes, and there is no /content/guides/ namespace at all — sandbox guides live under /content/integration-guides/{daytona,e2b,...}.
Consequence: Users following the CLI mount instructions to learn how to restrict mounted repos or run inside a sandbox hit 404s on the two most-likely next clicks. Agents that resolve relative links will fail to load referenced context.
The fix: Update the CLI Mount page links to /content/mesafs/advanced/mount-modes and to an actual sandbox landing page (e.g. an index of /content/integration-guides/), or create the missing /content/guides/working-with-sandboxes aggregator.
4. Beta feature gap shipped in docs without a workaround (significant)
Location: /content/core-concepts/versioning ("Dealing with conflicts" section)
Problem: The docs state: "Mesa beta doesn't currently have APIs for conflict resolution. These are coming in the next week." The same page sells non-blocking conflicts as a headline feature ("conflicts are non-blocking… you can resolve the conflicts later"). There is no timestamp on "the next week," no link to a tracking issue, and no documented manual workaround for unblocking a conflicted change today.
Consequence: A developer evaluating Mesa for an agent product reads that conflicts are non-blocking, builds around it, then discovers there is no API to actually resolve them — and no documented escape hatch. "Coming in the next week" with no anchor date becomes stale immediately and is unverifiable for any reader landing on the page later.
The fix: Replace the time-relative promise with a dated status line ("As of 2026-MM-DD…") plus a link to the public changelog/issue tracker. Document at least one workaround (e.g. force-overwriting one side via the CLI or REST API) so users have a path forward in the meantime.
5. SDK install commands and package naming patterns are inconsistent (significant)
Location: /content/mesafs/application-mount vs. llms.txt Python SDK section
Problem: The Application Mount install snippet shows:
npm install @mesadev/sdk
pip install mesa-sdk
The TypeScript package uses the @mesadev npm scope, but the Python package is named mesa-sdk (no mesadev prefix). Meanwhile the SDK reference URLs in llms.txt live under /content/reference/py/... and /content/reference/ts/... with no Rust install snippet alongside, even though the Introduction FAQ lists Rust as an official SDK (/content/reference/sdk-rust).
Consequence: An agent that has read the Introduction expects three SDKs at parity, but the canonical install page only documents two, and the naming convention (@mesadev/sdk vs mesa-sdk vs unspecified Rust crate name) gives no reliable heuristic for guessing the Rust crate. Copy-paste from the install code block will not produce a working Rust project.
The fix: Add a Rust tab to the install <CodeGroup> with the exact cargo add command (or crate name) and unify the naming story (either mesa-sdk everywhere, or @mesadev/*/mesadev-* everywhere with a documented rationale).
6. Quickstart skips the "create an account" → "get an API key" mechanics (significant)
Location: /content/getting-started/quickstart Step 1
Problem: Step 1 reads in full: "Create an account at app.mesa.dev. Create an organization for your product (example: acme). Generate an API key with admin scope." There is no link from this step to /content/getting-started/auth-and-permissions, no mention that admin is broader than the default read+write scopes, and no warning that admin is required only for API-key/webhook management — meaning the quickstart actively recommends an over-scoped key for the basic flow.
Consequence: Every developer doing the quickstart provisions an admin key when write would suffice for the workflows the quickstart actually demonstrates. That key gets pasted into .env files, committed, leaked. The Auth page (which documents scope hierarchy and expires_in_seconds between 100s and 1 year) is never linked from the place developers first generate a key.
The fix: Downgrade the recommendation to write (the default), link directly to the Auth & Permissions page on the line that says "Generate an API key," and mention expires_in_seconds so first-time users default to expiring keys.
7. Role/scope matrix contradicts itself on member key creation (significant)
Location: /content/getting-started/orgs-and-members vs. /content/getting-started/auth-and-permissions
Problem: The Roles table says a Member can create API keys "up to write scope only." The Auth page says: "When creating a key without specifying scopes, the default is: read and write." So a Member calling the create-key endpoint with no scopes specified should succeed (default = write). But the Auth page also lists "Manage API keys" as requiring admin scope in its "Scope Requirements by Operation" table — without clarifying whether this applies to creating keys at all, or only to creating admin-scoped keys.
Consequence: A developer writing a key-provisioning flow as a Member cannot tell from the docs whether key creation will 403, succeed with default write scope, or succeed only if their own key happens to be admin. Agents calling /api-keys/create programmatically will hit unpredictable authorization behavior.
The fix: In the Auth page's operation table, split "Manage API keys" into "Create keys (≤ caller's max scope)" and "Manage admin keys / revoke any key (admin)." Cross-reference the Member role row.
8. "No way to change a role" is a UX cliff with data-loss implications (significant)
Location: /content/getting-started/orgs-and-members
Problem: "There is no way to change a member's role after they join — remove and re-invite with the correct role instead." There's no discussion of what happens to that user's API keys, webhooks, or in-flight bookmarks when they're removed. Combined with the rule that only Owners can delete an org and only Owners/Admins can manage webhooks, the consequences of a remove-and-reinvite are unspecified.
Consequence: An admin promoting a member to admin will, by following the docs literally, remove the member — potentially orphaning that member's API keys mid-flight, breaking webhooks they own, and invalidating any automation tied to their identity. Nowhere in the docs is the blast radius described.
The fix: Document exactly what is preserved/destroyed across a remove-reinvite cycle (keys revoked? webhooks transferred? bookmarks reassigned?), or ship a real role-change endpoint and remove this instruction.
9. "Default scope = read and write" wording invites bugs (minor)
Location: /content/getting-started/auth-and-permissions
Problem: "When creating a key without specifying scopes, the default is: read and write." Since the scopes are documented as hierarchical ("Each level includes all permissions from the levels below it"), write already implies read. Listing them as "read and write" suggests scopes might be a set rather than a level, which contradicts the hierarchy description on the same page.
Consequence: Developers and agents constructing API-key creation requests pass ["read", "write"] as an array when the API likely expects a single level. Without an explicit schema example on this page, both interpretations look plausible.
The fix: State the default as the single value write (which subsumes read by hierarchy) and include the exact JSON shape the create-key endpoint expects.
10. llms.txt is truncated/oversized signal with no llms-full.txt mentioned (minor)
Location: https://docs.mesa.dev/llms.txt
Problem: The llms.txt index lists "157 total URLs" but the visible structure shows it as a flat link dump grouped by section, with no companion llms-full.txt referenced. For a 157-page documentation set, agents that fetch llms.txt get only URLs, then must fetch each page individually — at which point pages like /content/core-concepts/glossary that aren't in the index (see issue #1) are invisible.
Consequence: Agents pay 157 round-trips to assemble what should be a single-shot context load, and still miss pages omitted from the index.
The fix: Publish llms-full.txt with inlined page contents, and treat its generation as the source of truth so omissions like the glossary can't happen.
What they do well
- Publishes both
llms.txtandopenapi.jsonat predictable URLs — strong baseline for agent consumption. - The Auth & Permissions page has a real operation-to-scope matrix and explicit key expiration bounds (100s to 1 year), which is more rigor than most platforms ship.
- Pattern pages like "Approvals (proposal bookmark + diff)" give concrete agent workflows rather than just primitives.
Top 3 recommendations
- Fix the Commit/Change terminology contradiction across the glossary, versioning, and CLI pages — pick one mental model and enforce it everywhere. This is the single biggest blocker for agents trying to map Mesa's vocabulary to its API.
- Add the glossary to
llms.txtand ship anllms-full.txtso agents load Mesa's vocabulary in one shot rather than 157 fetches. - Repair the broken
/content/guides/...and/content/mesa/mount-modeslinks on the CLI Mount page, and replace "coming in the next week" promises with dated status lines linking to a public tracker.