fix(kyberforge): bridge apm content to Claude Code's flat plugin discovery
Claude Code's (and Copilot's) native plugin installer has zero awareness of .apm/ nesting -- it convention-scans only flat skills/, agents/, commands/, hooks.json at each plugin's root. Confirmed via strings on the installed claude binary and live installs of git@holocron/gitea@holocron/kyberforge@ holocron, all reporting Skills(0) Agents(0) Hooks(0) post ADR-0015's apm conversion. Root cause (apm_cli/core/plugin_manifest.py): apm's plugin.json compiler deliberately strips skills/agents/commands keys, assuming the host already auto-discovers those convention directories -- it has no model of .apm/ being host-visible at all. Separately, apm's own bundle exporter (apm_cli/bundle/plugin_exporter.py, behind `apm pack --format plugin`) implements the correct .apm/ -> flat mapping, but only ever targeted build/<name>-<version>/, a path nothing in marketplace.json's source: points at. scripts/sync-plugin-content.sh wraps that bundle exporter and copies its agents/, skills/, commands/, instructions/, extensions/, and merged hooks.json back into each plugin's own root as a second tracked compiled-output category -- same governance status as .claude-plugin/plugin.json: generated from .apm/, never hand-edited. tests/ subdirectories are excluded from the mirror (dev fixtures, not host-visible runtime content; several hardcode a relative repo-root walk-up sized for the .apm/-nested depth, which breaks when duplicated one level shallower). Applied for real across all 6 plugins and verified two ways: `claude plugin validate --strict` passes on every real plugin directory, and a live `claude --plugin-dir <path> -p "list skills/agents"` behavioral test confirms content is now actually discovered. Also, from the same issue #90 review round: - scripts/check-manifests.sh pointed at each plugin's root-level plugin.json (checking skills/hooks/mcpServers/agents pointer fields) -- that file was a stale near-duplicate of .claude-plugin/plugin.json nothing else read or wrote, now deleted across all 6 plugins. check-manifests.sh is rewritten to validate .claude-plugin/plugin.json instead, and drops the pointer-field checks entirely (nothing to check -- those fields are correctly absent by design). Content-presence drift is now check-plugin-content-sync's job, a new pre-push hook wired in .pre-commit-config.yaml. docs/adr/0017 records the root cause and decision in full, including two rejected alternatives (patching plugin.json's path fields directly -- apm's compiler strips them on every run; pointing marketplace.json at apm pack's build/ output -- a version-suffixed non-source directory nothing can install from without an extra build step). ADR-0015 and CONTEXT.md are updated to point at it. Refs: #90
This commit is contained in:
82
plugins/kyberforge/skills/forge/SKILL.md
Normal file
82
plugins/kyberforge/skills/forge/SKILL.md
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: forge
|
||||
description: >
|
||||
Use when the user wants to build, add, or improve something
|
||||
but hasn't yet named which of it (skill, agent, plugin, or marketplace
|
||||
entry) they need — "I want to add something to kyberforge", "not sure if
|
||||
this should be a skill or a plugin", "help me figure out what to build",
|
||||
"I have an idea but don't know where it belongs". Grills the intent first,
|
||||
classifies the target artifact type, then routes to the matching author
|
||||
skill. Do not use when the user already names the target artifact type or
|
||||
skill/agent explicitly (e.g. "run /skill-author on my-skill", "create an
|
||||
agent for X") — route directly to that author skill instead, bypassing
|
||||
forge.
|
||||
metadata:
|
||||
category: factory
|
||||
source_keys:
|
||||
- claude-code-subagents-docs
|
||||
- context7-websites-code-claude
|
||||
- agentskills-spec
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- forge is an optional guided entry point, not a gate — the four existing factory skills (`skill-author`, `skill-audit`, `agent-author`, `agent-audit`) plus `apm-workflow` (for plugin/marketplace-entry artifacts) remain directly invokable and forge does not intercept those calls. `plugin-author` and `marketplace-author` were removed per ADR-0015 once issue #90 landed — `apm-workflow` is their sole successor.
|
||||
- Claude Code's skill-level `context: fork` frontmatter field and the `/fork` subagent command are opposites despite sharing a name — `context: fork` isolates (fresh context, no parent access), while `/fork` inherits the full conversation. Keep this straight when deciding how to invoke a subagent in Step 3.
|
||||
|
||||
## Step 1 — Grill the intent
|
||||
|
||||
Call `bin:grill-with-docs` unless a grill session was already performed and is available in the context.
|
||||
Grilling may surface that the artifact type assumed at the start is wrong, or that the idea splits into more than one artifact.
|
||||
This step always runs inline, in the current conversation — grilling is interactive and a subagent cannot hold the back-and-forth.
|
||||
|
||||
## Step 2 — Classify the artifact type
|
||||
|
||||
Match the grilled intent against exactly one row (or more than one, if the intent genuinely spans several):
|
||||
|
||||
| Intent | Artifact type | Route to |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -----------------------------| ---------------------------------|
|
||||
| A reusable capability or workflow the agent should load inline in the main conversation — triggered automatically by description-matching, not a fresh context, and free to bundle its own `references/`, `scripts/`, or `assets/` | Skill | `kyberforge:skill-author` |
|
||||
| A recurring task needs its own reusable agent/subagent definition — dedicated system prompt, tools, and description, invokable by name across sessions | Agent / subagent definition | `kyberforge:agent-author` |
|
||||
| A new distributable unit is needed — no existing plugin is the right home for the skill/agent/hook/MCP server being built, or the bundle needs its own manifest, versioning, and install lifecycle separate from what already exists | Plugin | `kyberforge:apm-workflow` (configure — `apm plugin init`) |
|
||||
| The plugin itself already exists (or was just created) and only its marketplace-facing metadata needs to change — listing it for the first time, or updating its version/description entry — never the plugin's contents | Marketplace entry | `kyberforge:apm-workflow` (marketplace — `apm marketplace package add`) |
|
||||
|
||||
If the intent is genuinely ambiguous between rows even after grilling, ask the user directly rather than guessing.
|
||||
|
||||
Note: plugin and marketplace-entry artifacts route through `kyberforge:apm-workflow` per ADR-0015 — the former `plugin-author` and `marketplace-author` skills were removed once issue #90 landed.
|
||||
|
||||
This table classifies what to build, not how to run it — a one-off task that merely needs an isolated vs. context-inheriting run (rather than a new, reusable definition) isn't an artifact at all; there's nothing here to route it to.
|
||||
|
||||
## Step 3 — Announce, then route
|
||||
|
||||
State the classification and which skill(s) will run before invoking anything.
|
||||
|
||||
**Invoking the author skill(s).** Default to a fork subagent — it inherits the full grilled-intent conversation, so the author skill doesn't need to be re-briefed. Fall back to an inline invocation (same conversation, no subagent) when either is true:
|
||||
- **Fork is technically unavailable** — already running inside a fork (a fork cannot spawn another fork), a nesting-depth cap is reached, or the environment doesn't support forking.
|
||||
- **The routed flow needs live user interaction mid-run** that a backgrounded fork can't surface in real time — clarifying questions, confirmation checkpoints, or a HITL gate (e.g. `apm-workflow`'s publish/release steps, or its conversational confirmation before removing a marketplace entry). Judge this from context: if nothing about the routed flow signals a live checkpoint, prefer the fork subagent.
|
||||
|
||||
`apm-workflow` routes for plugin/marketplace-entry artifacts always run inline — their flows are short, prompt-heavy, or gated, and get no follow-up audit-recheck step to justify running detached (see below).
|
||||
|
||||
**After a skill or agent route finishes.** `skill-author` and `agent-author` already close out with their own inline audit (`skill-author` runs `/skill-audit`, `agent-author` invokes `kyberforge:agent-audit` directly) in the same context as the authoring work — that's unchanged. Once that author skill's run has finished, spin up a separate **clean-context subagent** (fresh, not forked, no inherited context) to independently re-run the same audit skill against the finished artifact. This is a distinct verification layer, not a duplicate: the inline audit shares context with the work it's checking and can share its blind spots, while the clean rerun has no stake in the result.
|
||||
|
||||
If the clean audit surfaces any unresolved finding — not only a disagreement with the inline pass, any actionable finding on its own — loop: re-invoke the author skill (same fork-vs-inline judgment as the initial invocation) to resolve it, then re-run the clean audit again. Repeat until the clean audit comes back with nothing unresolved. Only then is the route done — the same resolve-before-close discipline `skill-author`/`agent-author` already apply to their own inline audit.
|
||||
|
||||
When the intent spans multiple artifact types (e.g. a new skill inside a new plugin, then registering that plugin via `kyberforge:apm-workflow` marketplace), chain the routes in dependency order — an artifact that must exist on disk before another skill can target it goes first (e.g. `apm-workflow` scaffolds the plugin directory via `apm plugin init` before `skill-author` scaffolds a skill inside it).
|
||||
|
||||
## Step 4 — Bump plugin version (if applicable)
|
||||
|
||||
After the routed skill finishes, check if the artifact was created or updated inside a package by walking up from the artifact's path to the nearest ancestor `apm.yml` that declares a top-level `type:` field (`instructions`/`skill`/`hybrid`/`prompts`). An `apm.yml` with no `type:` field is a marketplace-only manifest (see `plugins/kyberforge/docs/research/docs/microsoft-apm/monorepo-and-repo-shapes.md`) — it does not count as a match; skip it and keep walking up.
|
||||
|
||||
**Skip this step if:**
|
||||
- No ancestor `apm.yml` with a `type:` field is found (the artifact is standalone or scoped to user agent directories)
|
||||
- The author skill already bumped the package version (check the skill's audit output or completion message for version bump evidence)
|
||||
|
||||
**If a typed `apm.yml` is found and no version bump was done:**
|
||||
|
||||
Invoke `kyberforge:apm-workflow` as a **clean-context subagent** (fresh, not forked) with this brief:
|
||||
|
||||
> "The package at `<package-path>` gained a new `<artifact-type>` (`<artifact-name>`). Bump the `version` field in that package's `apm.yml`. Determine whether to bump minor (0.1.0) or patch (0.0.1) based on whether this is a new capability (minor) or a fix/refactor (patch). Do not release or tag — just update `apm.yml` and commit."
|
||||
|
||||
Use a clean-context subagent (not forked) so the version bump decision is made independently without anchoring to the earlier authoring context. This gives apm-workflow a clear, isolated directive.
|
||||
|
||||
Report completion to the user: "Updated `<package-name>` version from X.Y.Z to X.Y.Z to reflect the new `<artifact-name>`."
|
||||
Reference in New Issue
Block a user