diff --git a/docs/porting-to-a-new-harness.md b/docs/porting-to-a-new-harness.md index d288c6b078..c9fab8c8a2 100644 --- a/docs/porting-to-a-new-harness.md +++ b/docs/porting-to-a-new-harness.md @@ -264,19 +264,16 @@ mutating the message array in code. The harness has neither a shell hook nor a code plugin — its session-start surface is a context file that *your installed extension ships and the manifest -declares* (e.g. Gemini's `contextFileName` → the extension's own `GEMINI.md`). +declares*. You can't run code or mutate messages; the extension's context file points at the bootstrap. There is no injector to assemble a string or strip frontmatter — the harness loads the referenced content as-is. **This works only because the file is part of the installed extension** — never substitute "edit the user's global `GEMINI.md`/`AGENTS.md`" for shipping your own (rule 2). -- Reference: `gemini-extension.json` (manifest, with `contextFileName`), - `GEMINI.md` (two `@`-includes — the bootstrap skill and the tool-mapping - reference), `skills/using-superpowers/references/gemini-tools.md`. -- 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. +- No current committed integration is a pure Shape C reference implementation. + If your harness loads an instructions file but has no include syntax, inline + the bootstrap content into the file instead of pointing at another file. - **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 @@ -291,7 +288,7 @@ part of the installed extension** — never substitute "edit the user's global |---|---|---| | runs a shell command at session start and reads its stdout | A (shell-hook) | Cursor (`hooks/session-start` + `hooks/hooks-cursor.json` + `.cursor-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`) | +| ships an extension-declared context file it always loads | C (instructions-file) | No current committed pure Shape C integration; preserve the `@`-include verification rule below | | has a plugin install command and a manifest `contextFileName` (or equivalent) the installer keeps | C via the plugin installer | Antigravity (`.antigravity-plugin/` — `agy plugin install` ships a generated context file; verify the installer preserves it — Part 6) | Most real harnesses fit one row cleanly; the last is the hybrid case (rule 2 still @@ -494,9 +491,9 @@ Where the mapping lives depends on shape: inject (see the `toolMapping` constant in `superpowers.js`). pi keeps it in *both* places — `piToolMapping()` inline **and** `references/pi-tools.md`. If you maintain it in two places, update both, or the port is half-done. -- **Shape C:** put it in `references/-tools.md` and pull it into the - always-loaded instructions file (e.g. `GEMINI.md` `@`-includes - `gemini-tools.md`). +- **Shape C:** put it in `references/-tools.md` and inline or include it + through the always-loaded instructions file, then prove the harness actually + loads that content before any tool call. You may also add a one-line pointer to your harness in `SKILL.md`'s "Platform Adaptation" section so an agent reading the bootstrap knows where its mapping @@ -784,11 +781,10 @@ Use this as the live index; when in doubt, read the files, not this table. | Harness | Entry point | Bootstrap mechanism | Tool mapping | Tests | Distribution | |---|---|---|---|---|---| -| Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` | shell hook → `hooks/session-start` (`hookSpecificOutput.additionalContext`) | native `Skill` tool; `references/claude-code-tools.md` | `tests/hooks/` | marketplace | +| Claude Code | `.claude-plugin/plugin.json` + `hooks/hooks.json` | shell hook → `hooks/session-start` (`hookSpecificOutput.additionalContext`) | native `Skill` tool | `tests/hooks/` | marketplace | | Codex | `.codex-plugin/plugin.json` (declares empty `hooks`) | native skill discovery (no session-start hook) | `references/codex-tools.md` | `tests/codex/`, `tests/codex-plugin-sync/` | fork sync (`scripts/sync-to-codex-plugin.sh`) | -| Cursor | `.cursor-plugin/plugin.json` + `hooks/hooks-cursor.json` | shell hook → `hooks/session-start` (`additional_context`) | `references/claude-code-tools.md` | `tests/hooks/` | hand-authored | -| Copilot CLI | (shares Claude Code hook path; `COPILOT_CLI` env) | shell hook → `hooks/session-start` (`additionalContext`) | `references/copilot-tools.md` | `tests/hooks/` | — | -| Gemini CLI | `gemini-extension.json` + `GEMINI.md` | instructions file `@`-includes bootstrap + mapping | `references/gemini-tools.md` | — | `gemini extensions install` | +| Cursor | `.cursor-plugin/plugin.json` + `hooks/hooks-cursor.json` | shell hook → `hooks/session-start` (`additional_context`) | native skill support plus SessionStart context | `tests/hooks/` | hand-authored | +| Copilot CLI | (shares Claude Code hook path; `COPILOT_CLI` env) | shell hook → `hooks/session-start` (`additionalContext`) | SDK-standard SessionStart context | `tests/hooks/` | — | | Kimi Code | `.kimi-plugin/plugin.json` | manifest `sessionStart.skill` loads `using-superpowers` | inline `skillInstructions` in manifest | `tests/kimi/` | marketplace or `/plugins install` GitHub URL | | OpenCode | `.opencode/plugins/superpowers.js` (declared via root `package.json` `main`) | in-process: `config` hook registers skills dir; `experimental.chat.messages.transform` injects user message | inline in `superpowers.js` | `tests/opencode/` | `opencode.json` plugin git URL | | pi | `.pi/extensions/superpowers.ts` | in-process: `resources_discover` registers skills; `context` event injects user message; lifecycle-flag + compaction-aware | `piToolMapping()` inline **and** `references/pi-tools.md` | `tests/pi/` | repo-root `package.json` fields |