From 1e39e7403f1332f0d920b590ccb6c7fc3c001dbd Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Fri, 11 Sep 2026 20:18:51 +0000 Subject: [PATCH 1/4] feat: add native OMP bootstrap without duplicated skills --- .github/workflows/test-plugin-install.yml | 3 + README.md | 13 ++++ docs/omp-setup.md | 60 ++++++++++++++++++ omp/agent-skills.ts | 46 ++++++++++++++ package.json | 23 +++++++ scripts/omp-bootstrap-test.js | 74 +++++++++++++++++++++++ scripts/validate-versions-test.js | 1 + scripts/validate-versions.js | 1 + 8 files changed, 221 insertions(+) create mode 100644 docs/omp-setup.md create mode 100644 omp/agent-skills.ts create mode 100644 package.json create mode 100644 scripts/omp-bootstrap-test.js diff --git a/.github/workflows/test-plugin-install.yml b/.github/workflows/test-plugin-install.yml index 6256f41d..a6472a9a 100644 --- a/.github/workflows/test-plugin-install.yml +++ b/.github/workflows/test-plugin-install.yml @@ -31,6 +31,9 @@ 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 diff --git a/README.md b/README.md index 6361def4..639d0704 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,19 @@ claude --plugin-dir /path/to/agent-skills +
+Oh My Pi (OMP) + +Install the native extension and shared skills: + +```bash +omp plugin install github:addyosmani/agent-skills +``` + +Restart OMP after installation. The extension loads the canonical discovery workflow for each new user run; invoke individual skills with `/skill:`. See [docs/omp-setup.md](docs/omp-setup.md) for local installs, lifecycle behavior, and verification. + +
+
Cursor diff --git a/docs/omp-setup.md b/docs/omp-setup.md new file mode 100644 index 00000000..9f60d0f0 --- /dev/null +++ b/docs/omp-setup.md @@ -0,0 +1,60 @@ +# 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. + +## 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 +``` + +For a local clone: + +```bash +git clone https://github.com/addyosmani/agent-skills.git +omp plugin link /absolute/path/to/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. + +## 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`. + +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. + +## How it works + +- `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. + +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. diff --git a/omp/agent-skills.ts b/omp/agent-skills.ts new file mode 100644 index 00000000..58ec0124 --- /dev/null +++ b/omp/agent-skills.ts @@ -0,0 +1,46 @@ +import { readFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent"; + +const START = ""; +const END = ""; +const skillPath = fileURLToPath(new URL("../skills/using-agent-skills/SKILL.md", import.meta.url)); + +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 body = source.replace(/^\uFEFF?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, "").trim(); + if (!body) throw new Error("canonical skill is empty"); + systemPrompt.push(`${START} +agent-skills loaded. 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://. Users can invoke /skill: 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, + }, + }; + } + }); +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..e3ed9d0f --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "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"] + } +} diff --git a/scripts/omp-bootstrap-test.js b/scripts/omp-bootstrap-test.js new file mode 100644 index 00000000..540feffa --- /dev/null +++ b/scripts/omp-bootstrap-test.js @@ -0,0 +1,74 @@ +"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 = ""; +const END = ""; +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); +}); diff --git a/scripts/validate-versions-test.js b/scripts/validate-versions-test.js index 6814ad94..13abe8c3 100644 --- a/scripts/validate-versions-test.js +++ b/scripts/validate-versions-test.js @@ -5,6 +5,7 @@ const { readFileSync } = require("node:fs"); const test = require("node:test"); const manifestPaths = [ + "package.json", "plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json", diff --git a/scripts/validate-versions.js b/scripts/validate-versions.js index 68bf72ec..3544bc51 100644 --- a/scripts/validate-versions.js +++ b/scripts/validate-versions.js @@ -5,6 +5,7 @@ const { readFileSync } = require("node:fs"); const manifestPaths = [ + "package.json", "plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json", From c00f58ef9def2311ed1cdab52ca6a74bc20824a6 Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Thu, 24 Sep 2026 09:29:00 +0000 Subject: [PATCH 2/4] feat(omp): skip bootstrap sections OMP already renders Failure Modes restates Core Operating Behaviors; the discovery flowchart and quick reference restate skill descriptions, so drop them when the system prompt already carries OMP's list. --- omp/agent-skills.ts | 17 +++++++++++++++-- scripts/omp-bootstrap-test.js | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/omp/agent-skills.ts b/omp/agent-skills.ts index 58ec0124..eba45f3f 100644 --- a/omp/agent-skills.ts +++ b/omp/agent-skills.ts @@ -5,6 +5,17 @@ import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent"; const START = ""; const END = ""; 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. @@ -13,10 +24,12 @@ export default function agentSkills(omp: ExtensionAPI): void { const systemPrompt = event.systemPrompt.filter((block) => !(block.startsWith(START) && block.endsWith(END))); try { const source = await readFile(skillPath, "utf8"); - const body = source.replace(/^\uFEFF?---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/, "").trim(); + const listsSkills = systemPrompt.some((block) => block.includes("")); + 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. Use the skill discovery flowchart to find the right skill for your task. +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} diff --git a/scripts/omp-bootstrap-test.js b/scripts/omp-bootstrap-test.js index 540feffa..e29b6ab2 100644 --- a/scripts/omp-bootstrap-test.js +++ b/scripts/omp-bootstrap-test.js @@ -72,3 +72,20 @@ test("a failed read removes stale policy, reports the error, and recovers next r 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: ["\n- tdd: x\n"] })).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")); +}); From 9941ff26caece714a16b3bdb59fdf4e397e46825 Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Fri, 2 Oct 2026 05:48:14 +0000 Subject: [PATCH 3/4] 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. --- .github/workflows/test-plugin-install.yml | 3 - README.md | 7 +- docs/omp-setup.md | 61 +++++---------- omp/agent-skills.ts | 59 --------------- package.json | 23 ------ scripts/omp-bootstrap-test.js | 91 ----------------------- scripts/validate-versions-test.js | 1 - scripts/validate-versions.js | 1 - 8 files changed, 24 insertions(+), 222 deletions(-) delete mode 100644 omp/agent-skills.ts delete mode 100644 package.json delete mode 100644 scripts/omp-bootstrap-test.js diff --git a/.github/workflows/test-plugin-install.yml b/.github/workflows/test-plugin-install.yml index 83ff1702..b25ba319 100644 --- a/.github/workflows/test-plugin-install.yml +++ b/.github/workflows/test-plugin-install.yml @@ -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 diff --git a/README.md b/README.md index d3115686..d4132142 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,14 @@ claude --plugin-dir /path/to/agent-skills
Oh My Pi (OMP) -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:`. 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.
diff --git a/docs/omp-setup.md b/docs/omp-setup.md index 9f60d0f0..296974c5 100644 --- a/docs/omp-setup.md +++ b/docs/omp-setup.md @@ -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://`, or `/skill:` 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 | diff --git a/omp/agent-skills.ts b/omp/agent-skills.ts deleted file mode 100644 index eba45f3f..00000000 --- a/omp/agent-skills.ts +++ /dev/null @@ -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 = ""; -const END = ""; -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("")); - 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://. Users can invoke /skill: 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, - }, - }; - } - }); -} diff --git a/package.json b/package.json deleted file mode 100644 index e3ed9d0f..00000000 --- a/package.json +++ /dev/null @@ -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"] - } -} diff --git a/scripts/omp-bootstrap-test.js b/scripts/omp-bootstrap-test.js deleted file mode 100644 index e29b6ab2..00000000 --- a/scripts/omp-bootstrap-test.js +++ /dev/null @@ -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 = ""; -const END = ""; -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: ["\n- tdd: x\n"] })).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")); -}); diff --git a/scripts/validate-versions-test.js b/scripts/validate-versions-test.js index 13abe8c3..6814ad94 100644 --- a/scripts/validate-versions-test.js +++ b/scripts/validate-versions-test.js @@ -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", diff --git a/scripts/validate-versions.js b/scripts/validate-versions.js index 3544bc51..68bf72ec 100644 --- a/scripts/validate-versions.js +++ b/scripts/validate-versions.js @@ -5,7 +5,6 @@ const { readFileSync } = require("node:fs"); const manifestPaths = [ - "package.json", "plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json", From d4d860282546fb4de466025fcd8f36704df00f7c Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Fri, 2 Oct 2026 06:00:47 +0000 Subject: [PATCH 4/4] docs(omp): note namespaced commands and persona agents --- docs/omp-setup.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/omp-setup.md b/docs/omp-setup.md index 296974c5..630cc4e1 100644 --- a/docs/omp-setup.md +++ b/docs/omp-setup.md @@ -26,6 +26,8 @@ Describe the task and let OMP pick the skill. OMP lists each skill's `name` and 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). +The same install also loads the slash commands and the personas in `agents/`. OMP namespaces plugin commands, so run `/agent-skills:spec`, `/agent-skills:ship`, and so on; a bare `/spec` is not expanded. The personas (`code-reviewer`, `security-auditor`, `test-engineer`, `web-performance-auditor`) are listed as `task` agents, which `/agent-skills:ship` and `/agent-skills:webperf` dispatch. + ## Tool mapping Skills and docs in this pack use Claude Code tool names. In OMP, use the native equivalents: