140. Editors and agents read projections of the layer, and cargo embeds none of it
Context
Three operator briefs (campaigns/majordomus-editor-intelligence-pack,
campaigns/majordomus-antigravity-pack, campaigns/majordomus-antigravity-v2) ask for Zed and
Google Antigravity to read this repository's skills, workflows, rules and MCP server from the
canonical layer, with no second catalogue, no personal setting touched, and — in the third —
a typed, content-addressed derivation and a measured decision on whether build.rs should
embed any of it. On 2026-10-12 none of the first two had landed: master carried no .zed/,
no .agents/ and no editor concept, and an open branch (feature/gemini-is-a-provider,
#964) carried a hand-written .agents/ beside a generated GEMINI.md.
What the products read was verified against the installed releases, not the briefs:
| Zed 1.23.2 | Antigravity 2.22.0 | |
|---|---|---|
| instructions | first of .rules … AGENTS.md … GEMINI.md | AGENTS.md, GEMINI.md, .agents/rules/*.md (front matter trigger required) |
| skills | .agents/skills/<name>/SKILL.md, name and description required | the same directory; .agents/skills.json may name more |
| tasks | .zed/tasks.json, an array of {label, command, args, …} | none at project level |
| MCP | context_servers in .zed/settings.json, needs a command Zed can start | .agents/mcp_config.json on the web; absent from the guide 2.22.0 ships |
| workflows | — | .agents/workflows/ stops working 2026-10-19 |
Sources: the Zed source at tag v1.23.2 (settings_content/src/project.rs,
task/src/task_template.rs, prompt_store/src/prompts.rs), zed.dev/docs, the guide text
inside Antigravity's language server, and antigravity.google/docs with its changelog.
Decision
One projection, two adapters. crate::editors reads the environment — the active skills
from the index, the public recipes of the tracked justfile — and two adapters map it onto
what their product reads. Where both read the same file it is written once: every active skill
becomes .agents/skills/<id>/SKILL.md, carrying the name and description both require and
a link to its definition, never a copy of the procedure. Every public recipe without
[confirm] becomes a task in .zed/tasks.json that runs just <recipe>. Instructions are the
provider bootstrap AGENTS.md, which both read and which generate providers already owns.
Through majordomus generate, not beside it. The projection is the target editors of the
existing pipeline: written by majordomus generate editors, compared by generate --check,
indexed by the manifest with its hash, merged as derived. A skill's banner follows its front
matter and the task list's is a // comment (Zed reads .zed/**/*.json as JSONC); the
artifact contract accepts exactly those two forms for documents under editors/.
Ownership is the banner. A file at a projected path without it — or reached through a
symbolic link — is someone's: generate refuses and names it. A banner-carrying skill
projection the plan no longer contains is the generator's and stale: --check reports it and
generate removes it. generate::write now writes through a temporary sibling and a rename,
and leaves a file whose bytes are already right untouched.
What is not verified is not written. No workspace MCP file for Antigravity, no
context_servers for Zed (the launcher is a relative path whose resolution Zed does not
document), no .zed/settings.json (no policy here differs from Zed's defaults), no
.agents/workflows/, no permission or approval mode. editors.status reports each with its
support state (supported, unsupported, unknown, deprecated, requires_user_action),
the evidence, and what a person can do instead.
The tracked justfile, not the checkout's. The root justfile imports the command-graph
bridge each checkout materialises under .ai/local/; read in place it adds 44 groups to the 5 tracked ones on
a machine that has the bridge and none on one that does not. The recipes are read through
just --dump over a private copy of justfile and .just/*.just, so the committed task list
is the same on every machine and in CI.
Content addresses, no cache. Each projected file's key is SHA-256 over the projection
version, its document and its inputs' paths and hashes in path order — the formula the third
brief asks for, and what editors.status explains. No cache is persisted: the projection is
one index walk and one just --dump (milliseconds against an index the process already holds),
and rule project.cache-is-invisible asks a cache to prove itself byte-equivalent before it is
kept. Nothing measured earns one.
No build-time embedding. Measured in this worktree on 2026-10-12 (machine load 7–17): a
no-op cargo build 0.21 s; after touching .ai/repo/policy.yaml 0.19 s, because nothing under
.ai/ is a build input; after touching one source file 19.4 s. Embedding any layer file through
build.rs would have to declare it with rerun-if-changed, turning every edit of a skill or a
rule into a 19-second recompile of the crate for a projection that costs milliseconds at run
time — and would make the binary's answer depend on the tree it was built from rather than the
tree it reads. The existing build.rs is left as it is; it embeds facts of the build (target,
profile, commit, generation), which is what a build script is for.
Consequences
Adding a skill under .ai/repo/skills/ or a recipe to the justfile changes .agents/skills/ or
.zed/tasks.json at the next majordomus generate, and generate --check fails until it does;
no adapter, list or registration is edited. A product release that changes a format is a
change to its adapter module, whose header names the release its claims were verified against.
A hand-written .agents/ (as on #964) is never taken over: generate editors stops at it and
editors.status reports what Antigravity would do with it — a .agents/skills.json naming
.ai/repo/skills loads canonical files without the name the shipped guide requires, and a
rule without a valid trigger is discarded.