This session proved agy does not need a bespoke scaffold: `agy plugin
install <repo-url>` imports the Claude Code plugin's skills AND its
SessionStart hook, which agy runs — so the bootstrap fires the Shape-A way
with no new files (verified: brainstorming auto-triggers on agy 1.0.3).
Replace the doc's now-false 'agy ships a generated ANTIGRAVITY.md context
file via .antigravity-plugin/install.sh' framing throughout:
- Part 2: Antigravity is the marquee 'you may not need a new directory'
case; install the existing plugin and run the acceptance test before
building anything.
- Part 4: add the inverse-of-a-fork-warning (a derived harness may inherit
the parent's hook execution); replace the routing row with
'installs an existing plugin directly, including its hook'.
- Step 5 / Part 6: bootstrap escalation now leads with 'check for an
inherited hook'; if a manifest names a context file, point it at the real
using-superpowers/SKILL.md — never generate a wrapped copy at install time.
- Appendix A: add the Antigravity row. Appendix B: add two gotchas.
Note: references to references/antigravity-tools.md and tests/antigravity/
depend on PR #1657 landing on dev.
An evergreen guide for adding support for a new harness (IDE, CLI, or agent
runner). Teaches the invariants — automatic session-start bootstrap, skill
discovery/invocation, tool mapping, the acceptance test — and points at the
closest reference integration shape (shell-hook, in-process plugin,
instructions-file / declared context file) to copy. Covers discovery, build,
local install, tmux-driven verification, distribution, and PR submission, with a
live reference-integration index and a gotchas appendix.
Two non-negotiable rules: (1) never edit skill bodies; (2) everything ships
through the harness's own install mechanism — never edit the user's config. When
a plugin installer strips undeclared files, declare the bootstrap as a recognized
component (a manifest contextFileName-style context file the installer preserves
and the harness loads every session), generated at install time from the live
SKILL.md + tool mapping. Surfaced-skill-description bootstrap is the softer
fallback.
Hardened against real end-to-end ports (Antigravity CLI): shapes can compose; a
fork doesn't inherit its parent's behavior; a hook system != a usable
session-start event; verify @-includes AND context-file preservation with a
marker; web-search the docs and study existing plugins; reverse-engineer
undocumented harnesses; print/headless modes may hang; workspace-trust gates
stall tmux; declared context files survive plugin install while undeclared files
are stripped; skills-path registration is per-harness.
2026-06-01 10:07:38 -07:00
6 changed files with 864 additions and 178 deletions
This guide explains how to add support for a new harness — an IDE, CLI, or
agent runner that isn't Claude Code — so that Superpowers skills auto-trigger
there the same way they do natively.
It is written in two layers. **Part 1–3** explain how the system works and how
to tell whether a harness can be supported at all; read these before you touch
anything. **Part 4–8** are a prescriptive procedure for an agent (supervised by
a human partner) to execute the port end to end, through distribution. An
appendix indexes the current reference integrations so you can copy the closest
one.
The integration mechanism differs across harnesses, and it will keep changing.
This guide deliberately teaches the **invariants** — the things that must be
true no matter the mechanism — and points you at a live reference implementation
to copy. When this guide and the code disagree, the code wins; fix the guide.
## Before you start
Adding a harness is the highest-stakes contribution type in this repo. Before
writing anything:
- Read `CLAUDE.md` and `.github/PULL_REQUEST_TEMPLATE.md` in full — the
contributor rules and the new-harness PR requirements are not optional.
- Search open **and closed** PRs for a prior attempt at this harness. If one
exists, understand why it stalled before starting your own.
---
## Part 1 — How Superpowers works across harnesses
Superpowers is the same content everywhere. What changes per harness is the thin
layer that delivers that content to the model and translates its instructions
into the harness's native tools. Three components:
1.**Skills (harness-agnostic).** Everything in `skills/` is the source of
truth, shared verbatim by every harness. Skills are written to describe
*actions* — "invoke a skill", "read a file", "dispatch a subagent", "create a
todo" — and never name a specific tool. This is what lets one skill body run
on Claude Code, Codex, Gemini, pi, and the rest without edits.
2.**Tool mapping (per-harness).** Each harness needs the action vocabulary
translated into its real tool names. That translation lives in
`skills/using-superpowers/references/<harness>-tools.md` and/or inline in the
harness's bootstrap injector (see Part 5). It says, e.g., "*dispatch a
subagent* → call `task` with `subagent_type`."
3.**Bootstrap (per-harness).** At the start of every session, the full
`skills/using-superpowers/SKILL.md` is injected into the model's context,
wrapped in `<EXTREMELY_IMPORTANT>` tags, with the tool mapping appended. That
injected skill is what teaches the model that skills exist and that it must
check for a relevant skill before acting. **The bootstrap is the entire
integration.** Without it, the skill files are inert — present on disk, never
invoked.
### Two rules that make this work
**1. Skills name actions, not tools.** Do **not** edit skill bodies to fit your
harness. Porting adds a tool-mapping reference and a bootstrap injector; it
never reaches into `skills/*/SKILL.md` to swap tool names. (The project's
contributor guidelines treat skill content as carefully-tuned behavior-shaping
code; rewording it for "compliance" is rejected on sight.)
**2. Everything ships through the harness's own install mechanism. Never edit the
user's files.** The bootstrap, the skills, and the tool mapping all get delivered
*as part of what the harness installs* — a plugin, an extension, a marketplace
entry, an extension-bundled context file. A port **must not** reach into a user's
global or personal config (`~/.gemini/config/AGENTS.md`, `settings.json`,
`trustedFolders.json`, a hand-edited `~/.bashrc`, etc.) to inject anything. The
harness owns what it loads; your install artifact is the only thing you get to
write. If the install mechanism genuinely can't carry the bootstrap, that is a
limitation to surface (Part 6) — never a license to hand-edit the user's config.
(Shape C is *not* an exception: Gemini's context file is fine because it ships
*inside the installed extension* and is declared by the manifest's
`contextFileName` — the harness loads the extension's own file, not a file you
edited in the user's home.)
---
## Part 2 — Can this harness be supported?
A harness can support Superpowers only if it can do all of the following. Check
these before writing code — if the first one fails, stop.
### Hard requirement: automatic session-start injection
The harness must let you inject text into the model's context **at the start of
every session, with no per-session opt-in by your human partner.** This is the
one non-negotiable capability. It can take any form:
- a **hook/event system** that runs a shell command at session start and reads
its stdout (Claude Code, Codex, Cursor, Copilot CLI), or
- an **in-process plugin/extension** with a session-start or message lifecycle
callback that can mutate the message array (OpenCode, pi), or
- an **instructions-file** convention where the harness loads a context file that
*your installed extension ships and declares* (e.g. Gemini's `contextFileName`
pointing at the extension's own `GEMINI.md`) — not a file you edit in the user's
home.
If the only way to get Superpowers in front of the model is for your human
partner to opt in each session (paste a prompt, run a command, enable a mode),
the harness
**cannot** be properly supported. The acceptance test in Part 3 will fail, and
the PR will be closed. This is the single most common reason a "port" isn't a
real port.
### The rest of the capability checklist
| Capability | Why it's needed | If absent |
|---|---|---|
| **Skill discovery + invocation** | The model must be able to load a skill's full content on demand | If there's no native skill tool, the sanctioned fallback is to `read` the relevant `SKILL.md` directly — see Part 5. A harness with neither a skill tool nor file-read cannot work. |
| **File read / write / edit** | Nearly every skill manipulates files | Essential. No workaround. |
| **Subagent / task dispatch** | `dispatching-parallel-agents`, `subagent-driven-development` | Degradable: if unavailable, those specific skills tell the model to do the work inline or report the missing capability — *never* to invent a `Task` call. Some harnesses gate this behind a config flag (e.g. Codex needs multi-agent enabled). |
| **Todo / task tracking** | Progress tracking in several skills | Degradable: fall back to a plan file or `TODO.md`. |
| **Web fetch / search** | A few skills | Degradable. |
| **Shell or polyglot script execution (Windows)** | Only for the shell-hook shape, only if you want Windows support | See Part 7. In-process-plugin harnesses sidestep this entirely. |
"Degradable" means: the skill already has fallback wording for the missing
tool. Your job in the tool mapping is to point at the real tool when it exists
and reuse that fallback wording when it doesn't.
### You may not need a new directory at all
Some "new harnesses" are really existing integrations under a different
installer. Factory's Droid consumes the Claude Code plugin via its own `plugin
install` command and needs no new files here. Antigravity (`agy`) goes further:
`agy plugin install <repo-url>` imports the Claude Code plugin's skills **and its
`SessionStart` hook, which agy then runs** — so the bootstrap fires the Shape-A
way (Part 4) with no new manifest, hook config, or installer. Its entire
integration is a tool-mapping reference plus a README section.
**So before building anything, install the existing Claude Code (or Gemini)
plugin into the harness and run the acceptance test (Part 3).** If the harness
already loads the skills and runs the hook, you are done — a port that adds
nothing to this repo but a tool mapping and a README paragraph is a perfectly
good outcome. Don't assume a derived harness needs its own bootstrap mechanism
until you've watched the existing one fail.
---
## Part 3 — Definition of done
A port is finished when **all** of these are true:
1. The `using-superpowers` bootstrap loads at session start, every session, with
no per-session opt-in.
2. A tool mapping exists for the harness (in
`references/<harness>-tools.md`, inline in the bootstrap, or both — per Part 5).
3. Skills can actually be invoked — natively, or via the documented
read-`SKILL.md` fallback — and the model follows them.
4.**The acceptance test passes.** In a clean session, the user message:
> Let's make a react todo list
auto-triggers the `brainstorming` skill *before any code is written*. Capture
the full transcript — the PR requires it.
5. Tests cover the integration (Part 5) and pass.
6. A real user can install it through the harness's own mechanism (not by
hand-copying files), and the version is tracked in `.version-bump.json` where
applicable (Part 6). Note that some installers rewrite or strip the manifest on
install (one drops it to just `{"name": …}`), so "the *installed* files report
the repo version" is not always achievable — track the version at the source
manifest and don't treat a rewritten installed manifest as a failure.
A quick smoke check before the full acceptance test: start a session and ask the
model to describe its superpowers. If the bootstrap injected, it knows it has
- Note: `@`-include is a Gemini feature. If your harness loads an instructions
file but has no include syntax, you must inline the bootstrap content into the
file instead.
- **Don't trust that an `@`-include is actually expanded — prove it.** A
Gemini-*derived* harness can accept `@./path` syntax yet treat it as a *hint
the model may choose to read* (it emits a file-read tool call) rather than a
guaranteed inline expansion. That's the difference between the bootstrap being
reliably present every session and the model maybe-reading it. Run a
unique-marker test: if the marker isn't in context *without* a tool call,
**inline the content** rather than `@`-include it.
### Routing table
| If the harness… | Use shape | Copy from |
|---|---|---|
| runs a shell command at session start and reads its stdout | A (shell-hook) | Codex (`hooks/session-start-codex` + `hooks/hooks-codex.json` + `.codex-plugin/`) |
| is a JS/TS plugin host with session/message lifecycle callbacks | B (in-process) | OpenCode (`.opencode/`) — or pi (`.pi/`) if it has no native skill tool |
| ships an extension-declared context file it always loads | C (instructions-file) | Gemini (`gemini-extension.json` + `GEMINI.md` + `references/gemini-tools.md`) |
| installs an existing harness's plugin directly, including its hook | none — no new files | Antigravity (`agy plugin install <repo-url>` imports the Claude Code `skills/` + `hooks/` and runs the `SessionStart` hook), Factory Droid |
Most real harnesses fit one row cleanly. The last row is the cheapest outcome and
the one to rule out first (Part 2): if the harness just runs the existing plugin,
you write almost nothing. Rule 2 still holds in every row — the bootstrap rides
the install mechanism, never a user-config edit.
---
## Part 5 — The porting procedure
### Step 1 — Study the closest reference implementation
Open the files named in Part 4 for your shape and read them end to end. The
patterns below are summaries; the code is the spec.
### Step 2 — Create the manifest / entry point
Create whatever the harness uses to recognize the plugin. Match the existing
ones in spirit:
- **Shape A:** a `*-plugin/plugin.json` (see `.codex-plugin/plugin.json`) with
tmux gotchas that bite here: wait after launch before the first capture; send the
prompt text and `Enter` as *separate*`send-keys` calls with a short `sleep`
between them (sending them together races on some TUIs), and `Enter` is a key name
not `\n`; the agent's turn takes time, so **poll `capture-pane` in a loop** rather
than capturing once; `capture-pane` shows only the visible pane, so for a long
conversation use the harness's own transcript/log file as the record of truth;
always `kill-session` when done.
If the smoke check shows the model *doesn't* know it has superpowers, the
bootstrap isn't loading — fix that before bothering with the acceptance test.
---
## Part 6 — Distribution and release
A working integration in this repo isn't usable until a real user can install
it. Distribution differs per harness ecosystem — find yours:
| Channel | Example | What you do |
|---|---|---|
| Native plugin marketplace | Claude Code | Register in `.claude-plugin/marketplace.json`; users `/plugin install`. The external `superpowers-marketplace` repo is the source of truth users install from — see the release steps in `CLAUDE.md`. |
| External marketplace fork, synced by script | Codex | `scripts/sync-to-codex-plugin.sh` rsyncs the tracked plugin files into a separate fork repo and opens a PR. Read its include/exclude list so you ship the right tree (it deliberately drops repo-internal dirs and other harnesses' dotdirs). |
| Git-URL extension install | Gemini, OpenCode | Users install from a git URL (`gemini extensions install …`; an `opencode.json``plugin` array entry). Document the exact command. |
| Package-manifest fields | pi | Declared through fields in the repo-root `package.json`; users install via the harness's package command. |
| Existing plugin, installed directly | Antigravity (`agy`), Factory Droid | The harness installs another harness's committed plugin from a git URL — `agy plugin install <repo-url>` imports the Claude Code `skills/` + `hooks/` and runs the `SessionStart` hook. No installer script, no new manifest: document the one-line install command. |
Then:
- **A plugin installer may silently strip *undeclared* files — so make the
bootstrap a file the installer *recognizes*, never a user-config edit.** A
`plugin install` typically copies only the components it knows about
(skills/agents/commands/mcp/hooks/context) and discards anything else, so a
file the manifest doesn't declare just vanishes from the install. The fix is
**not** to give up and write into the user's config (**rule 2**) — it's to make
the bootstrap a recognized component. In escalation order:
- **Check for an inherited hook first.** If `plugin install` imports an existing
Claude Code plugin's `hooks/` and the harness runs the `SessionStart` hook,
the bootstrap is already delivered and you ship nothing. Antigravity does
exactly this — `agy plugin install <repo-url>` brings in the skills and the
hook, and a clean session loads `using-superpowers`, triggers `brainstorming`,
and enters the brainstorming flow before any code. Verify with the acceptance
test. This is the cheapest and most robust path; rule it out before the rest.
- **Otherwise, if the manifest declares a context file, point it at the real
skill.** A `contextFileName`-style field names a file the installer preserves
and the harness loads every session. Point it straight at
`using-superpowers/SKILL.md`, or at a tiny committed `@`-include file like
`GEMINI.md` if the harness expands includes (prove the expansion — Shape C
caveat). **Do not generate a wrapped copy of the bootstrap at install time:**
that needs an installer and can drift from source. You get to name the file,
so name the real one. **Verify with a marker** that the installer keeps the
file and the harness loads it — an undeclared file is stripped as unrecognized.
- **Otherwise lean on the installed `using-superpowers` skill itself.** If the
harness surfaces each installed skill's name + description at session start,
the `using-superpowers` description ("Use when starting any conversation…")
can prompt the model to load it — installing the skill *is* the bootstrap.
Softer (no guaranteed wrapper; it carries triggering but not the tool mapping
— see Step 5), so prefer an inherited hook or a declared context file when
available.
- If none works, the harness cannot be cleanly supported yet — **say so**
and raise it, rather than hand-editing the user's config.
- **Write install docs.** A `docs/README.<harness>.md` and/or a
`.<harness>/INSTALL.md` (see `docs/README.opencode.md` and
`.opencode/INSTALL.md`), plus an install section in the top-level `README.md`.
The only supported install action is **running the harness's own install
@@ -41,7 +41,7 @@ If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "alw
## Platform Adaptation
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file") rather than naming any one runtime's tools. For per-platform tool equivalents and instructions-file conventions, see [claude-code-tools.md](references/claude-code-tools.md), [codex-tools.md](references/codex-tools.md), [copilot-tools.md](references/copilot-tools.md), [gemini-tools.md](references/gemini-tools.md), [pi-tools.md](references/pi-tools.md), and [antigravity-tools.md](references/antigravity-tools.md). Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file") rather than naming any one runtime's tools. For per-platform tool equivalents and instructions-file conventions, see [claude-code-tools.md](references/claude-code-tools.md), [codex-tools.md](references/codex-tools.md), [copilot-tools.md](references/copilot-tools.md), [gemini-tools.md](references/gemini-tools.md), and [pi-tools.md](references/pi-tools.md). Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
| Edit a file in several places at once | `multi_replace_file_content` |
| Run a shell command | `run_command` |
| Search file contents | `grep_search` |
| Find files by name / list a directory | `list_dir` (no dedicated glob tool — combine `list_dir` with `grep_search`) |
| Fetch a URL | `read_url_content` |
| Search the web | `search_web` |
| Pose a structured question to your human partner | `ask_question` |
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_subagent` with a built-in `TypeName` — `self` for full-capability work, `research` for read-only (see [Subagent support](#subagent-support)) |
| Multiple parallel dispatches | Multiple entries in one `invoke_subagent` call's `Subagents` array |
| Task tracking ("create a todo", "mark complete") | a **task artifact** — `write_to_file` with `IsArtifact: true` and `ArtifactType: "task"` (see [Task tracking](#task-tracking)). **Not**`manage_task`, which manages background processes. |
## Invoking a skill — read its `SKILL.md`
Antigravity surfaces every installed skill's `name` + `description` to you at the
start of each session, but it has **no `Skill`/`activate_skill` tool**. To load a
skill, **read its `SKILL.md` with `view_file`, setting `IsSkillFile: true`** when
the skill applies — e.g. `view_file` on
`.../plugins/superpowers/skills/<skill-name>/SKILL.md` with `IsSkillFile: true`.
(`IsSkillFile` is agy's own signal that you're reading a file to *execute its
instructions*, not to edit or preview it — set it whenever you load a skill.)
This is the blessed skill-loading mechanism on this harness. The general rule
"never read skill files manually" means "don't bypass your platform's
skill-loading mechanism" — and on Antigravity, reading `SKILL.md`*is* that
mechanism. Reading it honors the rule rather than breaking it.
You already know which skills exist and what they're for: their names and
descriptions are in front of you at session start. When a description matches
what you're about to do, read that skill's `SKILL.md` before acting.
## Subagent support
Antigravity dispatches subagents with `invoke_subagent`, passing each one a
`TypeName` in the `Subagents` array. Two `TypeName`s are **built in** — use them
directly, no `define_subagent` needed:
- **`self`** — a full clone of you, with every tool you have (including
`write_to_file`/`replace_file_content`/`run_command`). The safe default for
general-purpose work: implementing, fixing, anything that edits files or runs
`./implementer-prompt.md`) or supply an inline prompt. On Antigravity:
| Skill dispatch form | Antigravity equivalent |
|---------------------|----------------------|
| An implementer-style `*-prompt.md` template (writes code, runs tests) | Fill the template, then `invoke_subagent` with `TypeName: "self"` and the filled prompt |
| A read-only reviewer template (`spec-reviewer`, `code-quality-reviewer`, `code-reviewer`, `requesting-code-review`'s `./code-reviewer.md`) | `invoke_subagent` with `TypeName: "research"` and the filled review template |
| Inline prompt (no template referenced) | `invoke_subagent` with `TypeName: "self"` (or `"research"` if the task only reads) and your inline prompt |
### Prompt filling
Skills provide prompt templates with placeholders like `{WHAT_WAS_IMPLEMENTED}` or
`[FULL TEXT of task]`. Fill all placeholders before passing the complete prompt to
`invoke_subagent`. The prompt template itself contains the agent's role, review
criteria, and expected output format — the subagent will follow it.
### Parallel dispatch
Put multiple entries in a single `invoke_subagent` call's `Subagents` array to run
independent subagent work in parallel. Keep dependent tasks sequential, but do not
serialize independent subagent tasks just to preserve a simpler history.
## Task tracking
Antigravity has **no todo / `TodoWrite` tool** (`manage_task` manages background
processes — `list`/`kill`/`status`/`send_input` — it is *not* a checklist). When a
skill says to create a todo list or track tasks, maintain a **task artifact**: a
markdown checklist saved with `write_to_file` (`IsArtifact: true`,
`ArtifactMetadata.ArtifactType: "task"`), edited with `replace_file_content` /
`multi_replace_file_content` as you go.
At the start of any multi-step task, create the task artifact listing every step of
your plan. As you complete each step, edit the artifact to mark it done (`- [x]`).
If the plan changes, update the checklist. Keep it current — it is your source of
truth for what remains; once the conversation gets long, re-read it before starting
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.