docs(omp): replace native bootstrap with marketplace setup guide

OMP installs the existing Claude Code marketplace plugin and routes skills
natively, so the bootstrap extension stacked a second router (see #574).
Drop the extension, root package.json, and its test; keep the setup guide
and README entry, now pointing at the marketplace install, with the OMP
tool mapping as a doc section.
This commit is contained in:
Andre Brait committed 2026-10-02 05:49:38 +00:00
1 parent 0786408fe8
commit 9941ff26ca
8 files changed
+24 -222

No files matched your search

@@ -31,9 +31,6 @@ jobs:
- name: Test manifest version validator
run: node --test scripts/validate-versions-test.js
- name: Test native OMP bootstrap
run: node --test scripts/omp-bootstrap-test.js
- name: Test skill eval runner
run: node --test scripts/run-evals-test.js
+4 -3
View File
@@ -100,13 +100,14 @@ claude --plugin-dir /path/to/agent-skills
<details>
<summary><b>Oh My Pi (OMP)</b></summary>
Install the native extension and shared skills:
OMP installs this repository's Claude Code marketplace plugin:
```bash
omp plugin install github:addyosmani/agent-skills
omp plugin marketplace add addyosmani/agent-skills
omp plugin install agent-skills@addy-agent-skills
```
Restart OMP after installation. The extension loads the canonical discovery workflow for each new user run; invoke individual skills with `/skill:<name>`. See [docs/omp-setup.md](docs/omp-setup.md) for local installs, lifecycle behavior, and verification.
Restart OMP after installation; skills are discovered from their descriptions. See [docs/omp-setup.md](docs/omp-setup.md) for local clones and the OMP tool mapping.
</details>
+20 -41
View File
@@ -1,60 +1,39 @@
# Using agent-skills with Oh My Pi
Agent Skills includes a native [Oh My Pi (OMP)](https://github.com/can1357/oh-my-pi) extension. It uses the same root `skills/` directory as the other integrations, with no copied skill bodies or marketplace dependency.
[Oh My Pi (OMP)](https://github.com/can1357/oh-my-pi) installs Claude Code marketplace plugins, so it uses this repository's existing `.claude-plugin/` manifests and the root `skills/` directory. No OMP-specific files are needed.
## Install
Use OMP with native TypeScript extensions and `before_agent_start` system-prompt blocks. The target host baseline is integration commit `6aef0e8ad51b3bc5ea7a5f2a255c3d48e4c5af72`, which includes the external-input and promoted-queue startup fixes. Its reported version is `18.1.17`, but that version string alone does not establish that an installation includes those fixes.
Install the package:
```bash
omp plugin install github:addyosmani/agent-skills
omp plugin marketplace add addyosmani/agent-skills
omp plugin install agent-skills@addy-agent-skills
```
For a local clone:
The first command registers this repository as the `addy-agent-skills` marketplace. The second installs the `agent-skills` plugin from it. Restart OMP, or run `/reload-plugins` in an open session, so the skills are discovered.
Local clones work too:
```bash
git clone https://github.com/addyosmani/agent-skills.git
omp plugin link /absolute/path/to/agent-skills
omp plugin marketplace add /path/to/your/clone
omp plugin install agent-skills@addy-agent-skills
```
Restart OMP after installing. To try a checkout for one session without installing it:
```bash
omp --extension /absolute/path/to/agent-skills
```
Pass the **repository directory**, not just `omp/agent-skills.ts`, so OMP also discovers the sibling `skills/` directory. Do not additionally enable the bootstrap through another configuration entry or copy repository `AGENTS.md` / `CLAUDE.md` into your project.
Check the result with `omp plugin list`.
## Usage
Describe your task and let the agent follow the skill discovery flowchart. To select a skill explicitly, use `/skill:spec-driven-development` (with skill commands enabled). The agent can load it with `read` on `skill://spec-driven-development`.
Describe the task and let OMP pick the skill. OMP lists each skill's `name` and `description` in its system prompt and loads the full `SKILL.md` only when a skill is selected. To select a skill explicitly, use `/skill:spec-driven-development` (available unless `skills.enableSkillCommands` is disabled), or ask the agent to read `skill://spec-driven-development`.
The bootstrap supplies native OMP tool mappings. This integration does not register aliases such as `/spec` or `/build`, or port Claude's shell hooks. Invoke the underlying skills directly. Existing Claude Code, Codex, and other platform integrations remain unchanged.
OMP already routes skills natively. Do not also paste `using-agent-skills/SKILL.md` into `AGENTS.md`, `APPEND_SYSTEM.md`, a rule, or an extension that adds it to every run. That stacks the pack's meta-router on OMP's own router; see [Getting Started](getting-started.md).
## How it works
## Tool mapping
- `package.json` explicitly declares `omp.extensions` and `omp.skills`. OMP prefers the `omp` manifest over Pi metadata and discovers the conventional root `skills/` directory. The package allowlist includes the extension, canonical skills, their scripts, shared `references/`, and agent personas.
- `omp/agent-skills.ts` resolves the canonical `skills/using-agent-skills/SKILL.md` relative to itself, never relative to the project being worked on or a personal plugin cache.
- On each new user run, `before_agent_start` reads the canonical skill and adds one transient system-prompt block. It replaces only its own marked blocks, preserving other extensions' policy. Successful bootstrap policy is not persisted in the session history.
- There is no per-session cache: subsequent runs, session switches, branches, and tree navigation use the current installed skill. Promoted queued prompts use OMP's normal startup hook; the extension does not replay input or refresh policy per provider request.
- A missing, unreadable, or empty canonical skill removes stale bootstrap policy and produces a visible `agent-skills-bootstrap-error` message. Restoring the file recovers on the next run; individually discoverable skills may remain usable.
Skills and docs in this pack use Claude Code tool names. In OMP, use the native equivalents:
Install only packages you trust. OMP loads extension code with your user permissions; its current `isProjectTrusted()` compatibility API is not an enforced project sandbox. This extension reads only its own installed canonical skill, not project configuration.
## Troubleshooting and verification
If the bootstrap is missing, check `omp plugin list` and OMP's extension-loading errors, then restart. If skill names are missing, ensure skill discovery is enabled and that you passed the package directory rather than the extension file. Remove duplicate older adapters before enabling this one.
From a development checkout, Node.js 24 can run the focused regression proof without installing dependencies:
```bash
node --test scripts/omp-bootstrap-test.js
node scripts/validate-versions.js
npm pack --dry-run --json --ignore-scripts
```
The regression proof covers package-relative loading, repeat runs and session navigation, non-duplication, stale-policy removal on read failure, and recovery. The package preview should include `omp/agent-skills.ts`, `skills/using-agent-skills/SKILL.md`, and `references/definition-of-done.md`.
For host verification, start OMP with the package-directory command above, confirm `skill://spec-driven-development` resolves, and submit a second user prompt after switching or branching the session. The discovery policy should remain active without another bootstrap message in history.
| Skill instruction | OMP equivalent |
| --- | --- |
| Invoke another skill | `read` on `skill://<name>`, or `/skill:<name>` from the prompt |
| Spawn a subagent (`Agent` tool) | the `task` tool; only use agents OMP lists |
| Track tasks (`TodoWrite`) | the `todo` tool |
| Ask the user a question (`AskUserQuestion`) | the `ask` tool |
| Read, edit, write, search files | the native `read`, `edit`, `write`, `grep`, and `glob` tools |
-59
View File
@@ -1,59 +0,0 @@
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
const START = "<omp-agent-skills-bootstrap>";
const END = "</omp-agent-skills-bootstrap>";
const skillPath = fileURLToPath(new URL("../skills/using-agent-skills/SKILL.md", import.meta.url));
// "Failure Modes" restates "Core Operating Behaviors". The discovery flowchart and quick reference
// restate skill descriptions, so they are dropped only when OMP already renders its skills list.
const RESTATED = ["Failure Modes to Avoid"];
const RESTATED_BY_SKILL_LIST = ["Skill Discovery", "Quick Reference"];
function withoutSections(body: string, titles: readonly string[]): string {
return body
.split(/^(?=## )/m)
.filter((section) => !titles.includes(section.slice(3, section.indexOf("\n")).trim()))
.join("");
}
export default function agentSkills(omp: ExtensionAPI): void {
// OMP runs this once per new user run, including promoted queued prompts.
// Keep policy transient and reread it: session navigation needs no cached state.
omp.on("before_agent_start", async (event) => {
const systemPrompt = event.systemPrompt.filter((block) => !(block.startsWith(START) && block.endsWith(END)));
try {
const source = await readFile(skillPath, "utf8");
const listsSkills = systemPrompt.some((block) => block.includes("<skills>"));
const drop = listsSkills ? [...RESTATED, ...RESTATED_BY_SKILL_LIST] : RESTATED;
const body = withoutSections(source.replace(/^\uFEFF?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, ""), drop).trim();
if (!body) throw new Error("canonical skill is empty");
systemPrompt.push(`${START}
agent-skills loaded. ${listsSkills ? "Pick workflows from the skills list" : "Use the skill discovery flowchart to find the right skill for your task"}.
The using-agent-skills skill below is already loaded for this OMP run. Do not load it again.
Canonical skill: ${skillPath}
Resolve relative references in this skill from its containing directory.
${body}
## Oh My Pi tool mapping
- Invoke another skill with the native read tool on skill://<name>. Users can invoke /skill:<name> when skill commands are enabled.
- Use OMP's native task tool for delegated work when available, not Claude Code's Agent tool or subagent_type. Do not assume a named agent exists unless OMP lists it.
- Use the native todo tool for task tracking when available; do not invent tools or commands that this session does not expose.
- Use native read, edit, write, bash, grep, and glob tools when exposed in this session. Follow OMP's tool schemas rather than Pi or Claude-specific APIs.
${END}`);
return { systemPrompt };
} catch (error) {
return {
systemPrompt,
message: {
customType: "agent-skills-bootstrap-error",
content: `agent-skills activation unavailable: cannot load ${skillPath}: ${error instanceof Error ? error.message : String(error)}. Skills may still be available individually.`,
display: true,
},
};
}
});
}
-23
View File
@@ -1,23 +0,0 @@
{
"name": "agent-skills",
"version": "0.6.11",
"description": "Production-grade engineering skills for AI coding agents.",
"author": "Addy Osmani",
"license": "MIT",
"homepage": "https://github.com/addyosmani/agent-skills",
"repository": {
"type": "git",
"url": "https://github.com/addyosmani/agent-skills.git"
},
"files": [
"omp/agent-skills.ts",
"skills/",
"references/",
"agents/",
"docs/omp-setup.md"
],
"omp": {
"extensions": ["./omp/agent-skills.ts"],
"skills": ["./skills"]
}
}
-91
View File
@@ -1,91 +0,0 @@
"use strict";
const assert = require("node:assert/strict");
const { copyFile, mkdir, mkdtemp, rm, writeFile } = require("node:fs/promises");
const { tmpdir } = require("node:os");
const path = require("node:path");
const { pathToFileURL } = require("node:url");
const test = require("node:test");
async function sandbox(t) {
const root = await mkdtemp(path.join(tmpdir(), "agent-skills-omp-"));
t.after(() => rm(root, { recursive: true, force: true }));
const extension = path.join(root, "omp", "agent-skills.ts");
const skill = path.join(root, "skills", "using-agent-skills", "SKILL.md");
await mkdir(path.dirname(extension), { recursive: true });
await mkdir(path.dirname(skill), { recursive: true });
await copyFile(path.join(__dirname, "..", "omp", "agent-skills.ts"), extension);
const { default: register } = await import(pathToFileURL(extension).href);
const handlers = new Map();
register({ on: (event, handler) => handlers.set(event, handler) });
const emit = (type, event = {}) => handlers.get(type)?.({ type, ...event }, { cwd: process.cwd() });
return { root, skill, emit };
}
const START = "<omp-agent-skills-bootstrap>";
const END = "</omp-agent-skills-bootstrap>";
const ownedBlocks = (blocks) => blocks.filter((block) => block.startsWith(START) && block.endsWith(END));
test("bootstrap uses its package root and refreshes once per run across session navigation", async (t) => {
const { skill, emit } = await sandbox(t);
const other = `Another extension quotes ${START} without owning this block.`;
const original = Object.freeze(["Base policy", other]);
let blocks = original;
let previousBody;
for (const lifecycle of ["session_start", "session_switch", "session_tree", "session_branch"]) {
const body = `# Canonical workflow for ${lifecycle}\nRead the matching skill.`;
await writeFile(skill, `\uFEFF---\r\nname: using-agent-skills\r\ndescription: Discovery\r\n---\r\n${body}\n`);
await emit(lifecycle);
const result = await emit("before_agent_start", { prompt: "A new user run", systemPrompt: blocks });
blocks = result.systemPrompt;
assert.deepEqual(blocks.slice(0, 2), original);
assert.equal(ownedBlocks(blocks).length, 1);
assert.ok(blocks[2].includes(body));
assert.ok(blocks[2].includes(skill));
assert.ok(!blocks[2].includes("description: Discovery"));
if (previousBody) assert.ok(!blocks[2].includes(previousBody));
assert.equal(result.message, undefined);
// A chained invocation must replace its own block, not grow the prompt.
const repeated = await emit("before_agent_start", { prompt: "Another run", systemPrompt: blocks });
assert.deepEqual(repeated.systemPrompt, blocks);
previousBody = body;
}
});
test("a failed read removes stale policy, reports the error, and recovers next run", async (t) => {
const { skill, emit } = await sandbox(t);
await writeFile(skill, "# Previous policy\n");
const first = await emit("before_agent_start", { prompt: "First run", systemPrompt: ["Base policy"] });
await rm(skill);
const failed = await emit("before_agent_start", { prompt: "Next run", systemPrompt: first.systemPrompt });
assert.deepEqual(failed.systemPrompt, ["Base policy"]);
assert.equal(failed.message.display, true);
assert.ok(failed.message.content.includes(skill));
assert.ok(failed.message.content.includes("ENOENT"));
await writeFile(skill, "# Recovered policy\n");
const recovered = await emit("before_agent_start", { prompt: "Retry", systemPrompt: failed.systemPrompt });
assert.equal(ownedBlocks(recovered.systemPrompt).length, 1);
assert.ok(recovered.systemPrompt[1].includes("# Recovered policy"));
assert.equal(recovered.message, undefined);
});
test("drops restated sections, keeping discovery aids when OMP lists no skills", async (t) => {
const { skill, emit } = await sandbox(t);
await writeFile(
skill,
"# Using\n\n## Skill Discovery\nflowchart\n\n## Core Operating Behaviors\n### 1. Surface\nkeep\n\n## Failure Modes to Avoid\nrestated\n\n## Quick Reference\ntable\n",
);
const listed = (await emit("before_agent_start", { prompt: "Run", systemPrompt: ["<skills>\n- tdd: x\n</skills>"] })).systemPrompt[1];
const unlisted = (await emit("before_agent_start", { prompt: "Run", systemPrompt: ["Base policy"] })).systemPrompt[1];
for (const block of [listed, unlisted]) {
assert.ok(block.includes("### 1. Surface\nkeep"));
assert.ok(!block.includes("Failure Modes"));
}
assert.ok(!listed.includes("flowchart") && !listed.includes("## Quick Reference"));
assert.ok(unlisted.includes("## Skill Discovery\nflowchart") && unlisted.includes("## Quick Reference\ntable"));
});
-1
View File
@@ -5,7 +5,6 @@ const { readFileSync } = require("node:fs");
const test = require("node:test");
const manifestPaths = [
"package.json",
"plugin.json",
".codex-plugin/plugin.json",
".claude-plugin/plugin.json",
-1
View File
@@ -5,7 +5,6 @@
const { readFileSync } = require("node:fs");
const manifestPaths = [
"package.json",
"plugin.json",
".codex-plugin/plugin.json",
".claude-plugin/plugin.json",