Adapter Surfaces & Plugins¶
An adapter surface is a thin adapter: its only integration with the core is the ea CLI
(JSON on stdout + exit codes — cli.md); it holds judgment, never business logic. Two
surfaces exist — a Claude Code plugin (plugins/ea-claude/) and a Google Antigravity
plugin (plugins/ea-antigravity/) — hosting the same judgment agents. The core is
surface-independent: both hosts drive the identical engine, and neither requires any core
change to exist.
The boundary rule (non-negotiable)¶
A plugin never:
- serializes YAML, computes confirmation tokens, or decides validity — those are core;
- writes the repository directly — only via guarded
eacommands; - keeps authoritative state outside the source of truth;
- holds hardcoded artifact/method/field vocabulary in its prompt — it learns everything at
runtime from the core (
ea method list,scaffoldguidance,ea type show/method show,--list-fields,preset list/pack show).
The raw ea CLI remains the contract's reference interface underlying every surface.
The authoring contract (scaffold + commit)¶
Authoring one artifact is two complementary guarded writes sharing one addressing
(<type> --id <id> + scope + optional --domain):
| Step | Command | Produces |
|---|---|---|
| Scaffold | ea scaffold <type> --project <id> --id <id> [--domain <d>] [--name <n>] |
the deterministic skeleton file from the type alone + authoring guidance |
| Commit | ea commit <type> --project <id> --id <id> [--domain <d>] --input - |
the skeleton filled with judgment (field values, relationship targets, body prose) |
scaffoldcreates (refuses if the file exists);commitupdates (refuses if absent, hint "runea scaffoldfirst"). Identity (domain/type/id— the path key) is set once at scaffold and immutable thereafter;commitcarries only content.- Domain inference: the manifest's domain→types map decides — permitted in exactly one
domain → inferred; in more than one →
--domainrequired (usage error naming the candidates); in none → usage error. - Scaffold derivation (from the type alone, no templates): envelope from the args; type
fields keyed only when required (typed-empty placeholder) or carrying a schema
default; optional fields without a default omitted; every relationship id present as[]— never pre-filled with targets (which target a reference points at is judgment, even with one candidate). Body empty. Guidance is returned in the plandata, never written into the file:
{ "plan": { "creates": ["projects/payments/business/capability/billing.md"] },
"confirmation_token": "sha256:…",
"stub": { "domain": "business", "type": "capability", "id": "billing", "name": "billing",
"owner": "", "governed-by": [] },
"guidance": { "fields": [ { "name": "owner", "description": "Owning team or function." } ],
"relationships": [ { "name": "governed-by", "target_type": "principle",
"cardinality": "1..*",
"candidates": [ { "scope": "payments", "type": "principle",
"id": "data-locality", "name": "…" } ] } ],
"steps": [ { "guide": "State the principle(s) that govern each capability.",
"produces": "principle" } ] } }
candidates are the existing artifacts of an allowed target type visible from this scope
(own scope + Org), so the agent picks targets from a concrete list. steps are the active
methods' steps whose produces matches the type.
- Commit stdin payload (the judgment — the core serializes, never the agent):
{ "front_matter": { "name": "Billing", "owner": "finance",
"governed-by": [ { "type": "principle", "id": "data-locality" } ] },
"body": "Billing handles invoicing and dunning.\n" }
front_matter is a patch merged over the skeleton; it MUST NOT restate domain/type/
id (identity is the address — restating it is a usage error). body is stored verbatim.
- Commit dry-run returns data.plan, the token, a preview of the assembled artifact, and
data.diff — a deterministic unified diff against the file currently on disk (skeleton →
filled for a first commit; exactly the delta for a re-commit; "" on a no-op; dry-run only).
The update token binds the prior on-disk fingerprint as well as the new content, so a
concurrent edit is caught.
Single-artifact validation boundary¶
commit validates the artifact in isolation — everything decidable from the artifact +
active definitions + manifest, with no other artifact loaded:
| Check | At commit? |
|---|---|
| Envelope present & path-consistent | blocks |
type active; (domain, type) permitted |
blocks |
| Type field schema | blocks |
| Relationship cardinality + target_type + reference shape | blocks |
reference_resolves, unique, must_be_referenced, acyclic, layering |
deferred to ea validate |
A self-invalid artifact returns status: invalid (exit 3) with no confirmation token — a
broken write cannot be confirmed; the agent revises and re-plans. Cross-artifact rules staying
with validate keeps authoring order free (commit billing before data-locality exists;
validate flags the dangling reference until it's authored).
Propose → review → confirm¶
Every write every surface performs is one loop, identical interactive and headless:
- Propose. Run the command (dry-run). Parse
data.plan+data.confirmation_token(forcommit, alsopreviewanddiff). - Review. Render the plan to the user: files touched, the preview/diff, any diagnostics.
On
status: invalid(exit 3, no token), surface the errors and re-plan after revising. - Confirm. On explicit user approval, re-run the identical command with
--confirm <token>. On exit 4 (drift), re-plan.
Token ergonomics: derive a fresh token immediately before each confirm — never hold one across another write (every write moves the repo and stales held tokens).
Plugin packages¶
plugins/ea-claude/
.claude-plugin/plugin.json # host manifest (author, keywords)
commands/ea.md # /ea launcher — minimal non-negotiable write rules
skills/ea-architect/ # the judgment + advisory agent
SKILL.md # lean spine
reference/*.md # flow files, loaded on demand
skills/ea-methodologist/ # the pack-authoring agent (see packs.md)
SKILL.md + reference/*.md
plugins/ea-antigravity/
plugin.json # host manifest (skills/commands path arrays)
commands/ea.md # byte-identical to ea-claude's
skills/ea-architect/ … # same skills, same structure
skills/ea-methodologist/ …
Host-sync invariant (guarded by tests): all reference/ files are 100% host-agnostic and
byte-identical across the two plugins, synced by verbatim copy. The two SKILL.md bodies are
identical except a single marked <!-- host: … --> comment under the H1; plugin.json is
per-host. commands/ea.md is byte-identical and host-agnostic.
Antigravity packaging notes: a plugin is a directory bundle staged under
~/.gemini/antigravity-cli/plugins/<name>/; plugin.json accepts name, version,
description, and path arrays skills/commands/agents/hooks/mcpServers — a thin adapter
uses only skills + commands. A skill's front-matter is only name + description (the
trigger); a command is sugar for an entry-point skill. There is no always-on rules layer in
the installed format, so the boundary lives in the skill + command, loaded on trigger.
agy plugin validate is the binding schema check.
The ea-architect skill¶
The judgment + advisory agent: an EA guide that tailors, authors, promotes, migrates, reads, and advises — entirely over the CLI. One skill, multi-file progressive disclosure (spine < 500 lines; references one level deep; no bundled scripts):
ea-architect/
├── SKILL.md # lean spine — identity, boundaries, contract + exit-code map,
│ # the one write protocol, a flow index, the self-check
└── reference/
├── discovery.md # presets & packs (list/show; discover-and-offer, never default)
├── tailoring.md # Flow A — adopt archetype; manifest domain/relationship/rename verbs
├── authoring.md # Flow B — scaffold → draft → commit (+ read-before-draft,
│ # token ergonomics, showing data.diff at review)
├── promotion.md # Flow C — promote to Org
├── migration.md # ea migrate (archetype + pack@version)
├── reading.md # validate / report / graph + projection
├── advising.md # state synthesis ("where am I") + grounded next-steps
└── running-methods.md # guided method run (see below)
Key taught behaviours (all runtime-discovered, nothing hardcoded):
- Discover-and-offer: asked to tailor, enumerate the real archetypes with
ea preset list/preset showand offer the actual choices — never default to a familiar name or shell tols/find. - Read-before-draft: before scaffolding/committing,
ea type show <type>— follow itssectionsto compose a well-structured multi-section body and its field guidance for the front-matter; before working a method,ea method show <id>and learn it from thedetailsteps. - Reading efficiently: project subtractively (
--fields), discover the vocabulary at runtime (--list-fields; a wrong guess self-corrects via the enumerated usage error); projection never changesstatus/exit code, so it is always safe. Headline saver:report coverage --fields summary. - Advising: answer "what is the current state?" by composing the read verbs (projected) into a coherent narrative — never a raw envelope dump — and recommend concrete next actions justified by that state. Every fact is the core's; the agent interprets, never computes a verdict.
- Review narration: render each plan (and
data.diff— especially for a re-commit, where the delta is otherwise invisible) and proceed only on explicit confirmation. Explain diagnostics; never decide validity.
Guided method run (reference/running-methods.md)¶
A method's data is already a script for a walk-through (steps[] with guide/produces/
detail); this flow runs it as a method-agnostic, eliciting session. Triggered by "walk
me through the X method" (vs. Flow B's "author a capability"):
- Read the method once —
ea method show <id>. - Ground on live state, never guess —
report coverage(--fields summary) +validate; skip steps whose produced types are already satisfied; resume a half-finished method from the first real gap. - Walk each step in dependency order — read
guide+detailto the user; elicit the substance from the user first, in their words (at most one or two seed suggestions to react to — never a pre-written set); author that step's artifacts via the Flow B inner loop, each propose → review → confirm; loop within a step for as many artifacts as the user's judgment sets. - Re-ground after each write (fresh token; re-read coverage between steps).
- Close with an advisory summary — where the method landed you + the grounded next step.
Named forbidden anti-pattern: pre-drafting the whole architecture and taking one bulk approval. Elicit-first is the rule, not a footnote — the confirm guard covers the write, not the substance, which must be the org's, drawn out one step at a time.
There is deliberately no core cursor/method run verb: coverage already implies "where am
I" (a step produces a type; coverage says whether it's satisfied), a persisted cursor can go
stale, and the valuable part — the user's intent — is judgment the core can't legitimately hold.
Resume is just an advising read that feeds the walk.
The ea-methodologist skill¶
The inverse of ea-architect: helps a user author a method pack (ideate → model types →
build methods → wire rules → review + validate), one linear flow. Full description in
packs.md. Same structure (lean spine + reference/), same host-sync invariant; its
boundary differs deliberately — it may draft pack YAML directly (a pack is reviewed, versioned
source), but ea pack validate is the mandatory gate and it holds no hardcoded schema.
End-to-end example¶
The canonical task, from an empty directory to a validated architecture:
ea init→ repo.- Tailor:
ea manifest adopt startup-light(dry-run) → present the domains and the materialized method as deliberate defaults → user accepts →--confirm. - Author a
principle(scaffold → draft → commit) and acapabilitywhosegoverned-bypicks the principle from the guidance candidates. - Promote the principle to Org (plan shows: Org artifact created, project copy removed, outbound-reference pre-check clean) → confirm.
- Validate:
ea validate --all→status: ok, exit 0.
Every write confirmed before it lands; every default accepted deliberately; the agent held only judgment and drove the unchanged core through the contract.