agentleFS
AznatkoinyAznatkoiny/plugin-forge/skills/ship/SKILL.md

ship

Skill1 starsChanged 3 months agoMITView on GitHub

Package and release a verified forge-built plugin: claude plugin validate --strict, frontmatter/scoped-name/freshness lints, README with the permission story, versioning decision (SHA vs pinned semver), distribution menu (skills-dir, private marketplace, community), and installing the trace-capture flywheel. Use when the user says ship, release, publish, or distribute the plugin.

194 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use ios-sync, open-gstack-browser and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • Saqlain-811Skill

    ios-sync

    Regenerate the iOS debug bridge against the latest upstream gstack templates. (gstack)

    Also in 6 projects that use this

  • seek888Skill

    open-gstack-browser

    Launch GStack Browser — AI-controlled Chromium with the sidebar extension baked in. Opens a visible browser window where you can watch every action in real time. The sidebar shows a live activity feed and chat. Anti-bot stealth built in. Use when asked to "open gstack browser", "launch browser", "connect chrome", "open chrome", "real browser", "launch chrome", "side panel", or "control my browser". Voice triggers (speech-to-text aliases): "show me the browser".

    Also in 10 projects that use this

  • ayudaySkill

    setup-deploy

    Configure deployment settings for /land-and-deploy. Detects your deploy platform (Fly.io, Render, Vercel, Netlify, Heroku, GitHub Actions, custom), production URL, health check endpoints, and deploy status commands. Writes the configuration to CLAUDE.md so all future deploys are automatic. Use when: "setup deploy", "configure deployment", "set up land-and-deploy", "how do I deploy with gstack", "add deploy config".

    Also in 19 projects that use this

  • ShreyRaviSkill

    landing-report

    Read-only queue dashboard for workspace-aware ship. Shows which VERSION slots are currently claimed by open PRs, which sibling Conductor workspaces have WIP work likely to ship soon, and what slot /ship would pick next. No mutations — just a snapshot. Use when asked to "landing report", "what's in the queue", "show me open PRs", or "which version do I claim next". (gstack)

    Also in 9 projects that use this

  • zebbernSkill

    debug-fix

    Find and fix a bug or issue — from any source (GitHub issue, error message, user report, or observed behavior)

    Also in 4 projects that use this

  • ramybarsoumSkill

    document-release

    Post-ship documentation update. Reads all project docs, cross-references the diff, updates README/ARCHITECTURE/CONTRIBUTING/CLAUDE.md to match what shipped, polishes CHANGELOG voice, cleans up TODOS, and optionally bumps VERSION. Use when asked to "update the docs", "sync documentation", or "post-ship docs". Proactively suggest after a PR is merged or code is shipped.

    Also in 23 projects that use this

The file

We split this skill into the rules it gives an agent

5 rules. 0 are common, 0 are distinctive, and 5 are very specific to this project.

  • 0

    Common

    Most of the 180 edited versions we read keep these.

  • 0

    Distinctive

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If the line above shows a policy notice instead of JSON (org setting disableSkillShellExecution), read .forge/state.json with the Read tool …

    line 23
  2. Very specific:

    Every hit in hook matchers, permission rules, agent tools lists, or skill allowed-tools is a FAIL — unless it names an EXTERNAL server the …

    line 100
  3. Very specific:

    Ask via AskUserQuestion unless $ARGUMENTS pre-selects a path:

    line 231
  4. Very specific:

    If CONTRACT.md says the plugin runs in cloud sessions or scheduled routines, personal installs are invisible there (cloud sessions never …

    line 272
  5. Very specific:

    Leave .forge/ in place: it is the flywheel's memory (freeze hash, change requests, run history).

    line 301

“Common” is measured: kept by at least 6 in 10 of the 180 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Ship — validate, lint, document, version, distribute

Current forge state: !cat .forge/state.json 2>/dev/null || echo NO_STATE

If the line above shows a policy notice instead of JSON (org setting disableSkillShellExecution), read .forge/state.json with the Read tool before continuing.

Phase gate (hard)

Proceed only when phase is ship — verification must already be green. For any other state, run NOTHING and reply with exactly the remediation below, then stop:

Injected stateReply and stop
NO_STATE"No forge run in this project. Run /plugin-forge:forge to start one."
interview"Interview incomplete. Run /plugin-forge:forge."
contract"No approved contract yet. Run /plugin-forge:write-contract."
evals"Suite not armed. Run /plugin-forge:build-evals, then /plugin-forge:arm-evals."
armed"Nothing built yet. Run /plugin-forge:build-loop."
building"Build loop has not gone green. Run /plugin-forge:build-loop."
smoke or verify"Verification is not complete. Run /plugin-forge:verify."

Inputs to read before Step 1: plugin_name and plugin_dir from the injected state; design/CONTRACT.md (C6 distribution decisions, runtime answers — cloud/routine or local, version floors, permission story, cost sheet); the latest runs/<ts>/verify-report.md (baseline numbers for the README); and .forge/freeze.json (suite version).

Step 1 — Static gates (all four pass before anything is written)

1a. Strict validation — the same check the community pipeline runs:

claude plugin validate --strict <plugin_dir>

1b. Frontmatter YAML lint on every generated SKILL.md. Malformed YAML fails silently: the body loads with no metadata, so the skill never auto-triggers. Run:

python3 - <plugin_dir> <<'EOF'
import sys, re, pathlib
root, bad = pathlib.Path(sys.argv[1]), []
files = sorted(root.glob('skills/**/SKILL.md')) + sorted(root.glob('SKILL.md'))
for f in files:
    t = f.read_text(encoding='utf-8')
    m = re.match(r'\A---\r?\n(.*?)\r?\n---\r?\n', t, re.S)
    if not m:
        bad.append(f'{f}: frontmatter fence missing or unclosed'); continue
    fm = m.group(1)
    tops = [(k.group(1), k.start()) for k in re.finditer(r'^([A-Za-z][\w-]*):', fm, re.M)]
    names = [k for k, _ in tops]
    for req in ('name', 'description'):
        if req not in names: bad.append(f'{f}: missing required key {req}:')
    if '\t' in fm: bad.append(f'{f}: literal tab in frontmatter (YAML hazard)')
    for b in re.finditer(r':\s*(yes|no|on|off)\s*$', fm, re.M | re.I):
        bad.append(f'{f}: boolean "{b.group(1)}" needs >=2.1.218 - use true/false')
    def block(key):
        d = dict(tops)
        if key not in d: return ''
        starts = sorted(s for _, s in tops); i = starts.index(d[key])
        return fm[d[key]:starts[i+1]] if i + 1 < len(starts) else fm[d[key]:]
    if len(block('description')) + len(block('when_to_use')) > 1536:
        bad.append(f'{f}: description+when_to_use exceed the 1536-char listing cut')
for b in bad: print('FAIL', b)
print('frontmatter lint:', 'FAIL' if bad else 'PASS')
sys.exit(1 if bad else 0)
EOF

1c. Scoped-name lint — bundled-MCP references using a bare server name never fire; they must be mcp__plugin_<plugin>_<server>__<tool> (and plugin:<plugin>:<server> in mcp_tool hook server fields):

grep -rnE 'mcp__' <plugin_dir> --include='*.md' --include='*.json' | grep -v 'mcp__plugin_'

Every hit in hook matchers, permission rules, agent tools lists, or skill allowed-tools is a FAIL — unless it names an EXTERNAL server the plugin does not bundle (check against the plugin's .mcp.json before failing).

1d. Freshness lint — deprecated shapes must not ship:

grep -rnE '"decision"[[:space:]]*:[[:space:]]*"(approve|block)"' <plugin_dir>
grep -rn '/mnt/skills' <plugin_dir>

Both greps must return nothing. The decision-JSON hook shape is deprecated (current discipline: stderr + exit 2 to block, or hookSpecificOutput); /mnt/skills paths are foreign-environment rot that never resolves in Claude Code. Fix at the source, never by weakening the lint.

Step 2 — Install the flywheel (trace capture)

mkdir -p <plugin_dir>/hooks/scripts
cp "${CLAUDE_PLUGIN_ROOT}/templates/hooks/trace-capture.sh" <plugin_dir>/hooks/scripts/trace-capture.sh
chmod +x <plugin_dir>/hooks/scripts/trace-capture.sh

Merge ${CLAUDE_PLUGIN_ROOT}/templates/hooks/hooks-snippet.json into <plugin_dir>/hooks/hooks.json: create the file from the snippet when the plugin ships no hooks yet; otherwise append the snippet's PostToolUse entry to the existing array — never clobber existing entries. Confirm the merged entry is exec-form and references "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/trace-capture.sh" — at the generated plugin's runtime that variable resolves to ITS root, not to plugin-forge's.

Why this ships in every generated plugin: the hook appends tool args/results/errors to ${CLAUDE_PLUGIN_DATA}/traces/*.jsonl, so production failures become eval tasks — /plugin-forge:build-evals mine converts traces to tasks, /plugin-forge:arm-evals re-freezes vN+1, and /plugin-forge:build-loop rebuilds until green. Document the loop in the README (Step 4).

Step 3 — Optional observability (fleet/long-job plugins)

Offer when the generated plugin dispatches subagent fleets or long jobs; otherwise skip.

  • subagentStatusLine — a plugin settings.json supports ONLY the agent and subagentStatusLine keys:
{"subagentStatusLine": {"type": "command",
  "command": "${CLAUDE_PLUGIN_ROOT}/scripts/status.sh"}}

with the script reading a ${CLAUDE_PLUGIN_DATA}/status.json the plugin's long-running jobs update.

  • Monitor — pair each long-job skill with monitors/monitors.json:
[{"name": "<job>-watch", "command": "tail -F <log path>",
  "description": "streams <job> progress into the session",
  "when": "on-skill-invoke:<skill-name>"}]

State the caveats wherever this is offered: monitors are experimental, interactive-CLI only, do not load from project-scope skills-dir installs, reject ${user_config.*} in commands, and need a session restart after plugin updates.

Step 4 — README for the generated plugin

Instantiate ${CLAUDE_PLUGIN_ROOT}/skills/generation-standards/templates/readme.tmpl.md into <plugin_dir>/README.md. Required sections:

  1. Overview + invocations — what the plugin does; every user-facing skill as /<plugin_name>:<skill> with its argument hint.
  2. Permission story — a permissions.allow list covering EVERY command the plugin's skills and agents run. allowed-tools grants are turn-scoped (cleared on the next user message), so long flows need standing allows in the consumer's .claude/settings.json: {"permissions": {"allow": ["Bash(<cmd> *)", "..."]}}.
  3. Minimum Claude Code version — the highest floor among features used (from CONTRACT C6). Known floors: ${CLAUDE_SKILL_DIR} in allowed-tools 2.1.129; defaultEnabled 2.1.154; marketplace renames 2.1.193; --json-schema hard errors / LSP restartOnCrash 2.1.205; worktree resume 2.1.212; frontmatter name segment override 2.1.216; yes/no boolean forms and background-fork default 2.1.218.
  4. Headless recipe — the claude -p invocation for CI/routines, using the suite's sandbox settings profile (never --dangerously-skip-permissions), plus CLAUDE_CODE_PLUGIN_SEED_DIR for network-free container loading.
  5. How to run your evals — the evals/ layout; evals/bin/run.py is vendored and stdlib-only, so the suite runs WITHOUT plugin-forge installed; red baseline via the no-plugin target; the final FORGE_EVAL: line and exit code as the CI signal; run the regression suite in CI; cost honesty (--max-cost-usd); current baseline for future battle A/B: suite version from .forge/freeze.json, pass^3 and cost from verify-report.md.
  6. Flywheel — traces land in ${CLAUDE_PLUGIN_DATA}/traces/; feed failures back with /plugin-forge:build-evals mine.

Step 5 — Versioning decision (ask the user)

Present exactly two options via AskUserQuestion:

  • Still iterating — OMIT version from plugin.json. The git SHA becomes the version: every pushed commit reaches users.
  • Releasing — pin semver in plugin.json, add a CHANGELOG entry, and run claude plugin tag --push (creates the <name>--v<version> tag that dependency constraints resolve against).

Explain the trap before they choose: a pinned semver means users update ONLY when the field is bumped — pushing commits under a stale pin does nothing ("already at latest version"). A plugin pinned at 1.0.0 and then iterated strands every installed user on the first build. Never pin without a release process that bumps it.

Also state: the plugin name is a permanent public identifier (the marketplace renames map is the only migration path, 2.1.193+); displayName is the safe-to-change label.

Step 6 — Final re-validation

Steps 2–4 added files. Re-run on the FINAL tree:

claude plugin validate --strict <plugin_dir>

and repeat the Step 1c/1d greps over the added files. Ship nothing that is not green here.

Step 7 — Distribution menu

Ask via AskUserQuestion unless $ARGUMENTS pre-selects a path:

A. skills-dir plugin (lightest) — copy <plugin_dir> (with .claude-plugin/plugin.json) to ~/.claude/skills/<plugin_name>/ (personal) or <repo>/.claude/skills/<plugin_name>/ (project). It loads as <plugin_name>@skills-dir next session; SKILL.md edits are live, hooks/MCP changes need /reload-plugins. Warn: project scope is trust-gated, does NOT walk up to the repo root (launch Claude from the root), and monitors do not load.

B. Private marketplace — add or extend .claude-plugin/marketplace.json in the hosting repo:

{"name": "<marketplace-name>", "owner": {"name": "<owner>"},
 "plugins": [{"name": "<plugin_name>", "source": "./<relative-path>",
              "description": "<one line>", "category": "<category>"}]}

Validate the marketplace repo with claude plugin validate .. Consumers run:

claude plugin marketplace add <org>/<repo>
claude plugin install <plugin_name>@<marketplace-name>

Maintenance: claude plugin marketplace update <marketplace-name>; inspection: claude plugin marketplace list --json. Warn: marketplace names collide globally per user (a second add replaces the first) and several names are reserved — pick something distinctive.

C. Community submission — pre-submission requirements: kebab-case plugin name (the claude.ai marketplace sync REJECTS non-kebab names); claude plugin validate --strict clean (the community pipeline runs the same check as Step 1a); README and LICENSE present; semver pinned and tagged via claude plugin tag --push; public repo. Then submit the repo through the community marketplace submission form, with the marketplace-entry fields (name, source, description, category, tags) prepared to paste.

Step 8 — Repo-declared settings (cloud/routine contracts)

If CONTRACT.md says the plugin runs in cloud sessions or scheduled routines, personal installs are invisible there (cloud sessions never read ~/.claude/skills) — the consuming repo must declare the plugin. Instantiate ${CLAUDE_PLUGIN_ROOT}/skills/generation-standards/templates/settings-snippet.tmpl.json into the consuming repo's .claude/settings.json:

{"extraKnownMarketplaces": {"<marketplace-name>": {"source":
   {"source": "github", "repo": "<org>/<repo>"}}},
 "enabledPlugins": {"<plugin_name>@<marketplace-name>": true}}

Teammates get a one-time trust prompt, then auto-install. When the contract includes long headless runs, fold the Step 4 permissions.allow block into the same snippet.

Step 9 — Wrap up

Report to the user:

  • Gates re-passed on the final tree (Step 6).
  • Files added: hooks/scripts/trace-capture.sh, the hooks.json entry, README.md, plus settings.json/monitors/monitors.json if chosen.
  • Version strategy chosen and why; distribution path with the exact consumer commands; settings snippet emitted (or why not).
  • Baseline carried into the README: suite vN, pass^3, cost, run timestamp.
  • The honest claim: the plugin is "green + holdout + triaged" against suite vN — not proven "correct".

Leave .forge/ in place: it is the flywheel's memory (freeze hash, change requests, run history). Phase stays ship. To start a fresh forge run in this project later, forge-eval doctor clears stuck state safely.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.