Agent Skills › aeonfun/aeon › pack-submit

pack-submit

GitHub

将本地 Agent Skill 打包为独立 GitHub 仓库,生成清单文件,并向 aeon 社区注册中心提交 PR 以完成发布。支持 dry-run 和自定义仓库名等选项。

skills/pack-submit/SKILL.md aeonfun/aeon

Trigger Scenarios

用户希望将某个技能发布到社区注册表 需要创建技能的独立发布仓库并提交 PR

Install

npx skills add aeonfun/aeon --skill pack-submit -g -y
More Options

Use without installing

npx skills use aeonfun/aeon@pack-submit

指定 Agent (Claude Code)

npx skills add aeonfun/aeon --skill pack-submit -a claude-code -g -y

安装 repo 全部 skill

npx skills add aeonfun/aeon --all -g -y

预览 repo 内 skill

npx skills add aeonfun/aeon --list

SKILL.md

Frontmatter
{
    "name": "pack-submit",
    "metadata": {
        "var": "",
        "mode": "write",
        "tags": [
            "dev",
            "meta",
            "packs"
        ],
        "title": "Pack Submit",
        "category": "evolution",
        "requires": [
            "GH_GLOBAL?"
        ],
        "capabilities": [
            "external_api",
            "writes_external_host",
            "sends_notifications"
        ]
    },
    "description": "Package one of this agent's own skills as a standalone community pack and submit it to the aeon registry as a PR"
}

${var} — The local skill to publish as a community pack: a skill slug (a directory name under skills/), optionally followed by flags. Required. Examples:

  • token-movers — package skills/token-movers/ into a fresh public repo and submit it to the aeon registry
  • token-movers --repo myorg/aeon-token-movers — override the pack repo name (default aeon-skill-pack-<slug>)
  • token-movers --no-register — create and push the pack repo, but skip the registry PR against aeonfun/aeon
  • token-movers --dry-run — build and validate the pack locally, write nothing to GitHub

If ${var} is empty, exit PACK_SUBMIT_NO_VAR:

./notify "pack-submit aborted: var empty — pass a skill slug e.g. \"token-movers\""

Then stop.

Today is ${today}. Your task is to take the existing skill named in ${var}, wrap it in a standalone community-pack repo (its own GitHub repo with a skills-pack.json manifest), and submit it to the aeon community registry - a PR against aeonfun/aeon that adds both surfaces the registry demands in one diff: a row in the Listed packs table in docs/community-skill-packs.md AND a matching entry in catalog/skill-packs.json. This is the inverse of install-skill: instead of pulling a community pack in, it pushes one of your own skills out for every other Aeon agent to install with bin/install-skill-pack.

What a community pack is (so you build the right thing)

A community pack is a public GitHub repo that holds one or more skills plus a skills-pack.json manifest that names and versions them. bin/install-skill-pack owner/repo reads that manifest and installs the skills. To be discoverable (listed by bin/install-skill-pack --list and the dashboard's Community Packs panel), the pack must also be registered in aeonfun/aeon's catalog/skill-packs.json + the Listed packs table in docs/community-skill-packs.md. So publishing is two moves: (a) stand up the pack repo, (b) open the registry PR. This skill does both. Full protocol: docs/community-skill-packs.md.

Steps

  1. Parse and validate ${var}. The first whitespace-separated token is the skill slug; the rest are flags (--repo owner/name, --no-register, --dry-run). The slug must match ^[a-z0-9][a-z0-9-]*$ and resolve to a real directory:

    SLUG=$(echo "${var}" | awk '{print $1}')
    FLAGS=$(echo "${var}" | cut -s -d' ' -f2-)
    if ! echo "$SLUG" | grep -qE '^[a-z0-9][a-z0-9-]*$'; then
      ./notify "pack-submit aborted: \"$SLUG\" is not a valid skill slug (lowercase kebab-case)"; exit 0
    fi
    if [ ! -f "skills/$SLUG/SKILL.md" ]; then
      ./notify "pack-submit aborted: skills/$SLUG/SKILL.md not found — run with a slug from \`ls skills/\`"; exit 0
    fi
    

    If validation fails, exit PACK_SUBMIT_BAD_VAR with the notify above and stop. Extract the boolean flags from $FLAGS and the optional --repo value.

  2. Read the source skill's metadata. Everything the manifest and registry entry need is already declared in skills/$SLUG/SKILL.md's frontmatter — read it, don't invent it:

    • Display name — metadata.title; fall back to the top-level name:.
    • Description — the top-level description: (one line).
    • Category — metadata.category. Registry categories are an open vocabulary, but first-party-only values (core, evolution, basics) don't describe a third-party pack — if you see one of those, pick the closest community category (dev, crypto, productivity, research, social) from what the skill actually does. Otherwise pass the category through.
    • Secrets — metadata.requires. An entry ending in ? is optional → secrets_optional; an entry without ? is required → secrets_required. Strip the ?. Registry secrets_required must be UPPER_SNAKE env names.
    • Capabilities — metadata.capabilities, copied verbatim (already the locked taxonomy; see docs/CAPABILITIES.md). Omit if absent.
    fm(){ sed -n '/^---$/,/^---$/p' "skills/$SLUG/SKILL.md"; }
    TITLE=$(fm | sed -n 's/^[[:space:]]*title:[[:space:]]*//p' | head -1)
    [ -z "$TITLE" ] && TITLE=$(fm | sed -n 's/^name:[[:space:]]*//p' | head -1)
    DESC=$(fm | sed -n 's/^description:[[:space:]]*//p' | head -1)
    CATEGORY=$(fm | sed -n 's/^[[:space:]]*category:[[:space:]]*//p' | head -1)
    

    Collect requires:/capabilities: list items (lines under those keys beginning with -) into shell arrays; split requires into required (no ?) and optional (trailing ?, stripped).

  3. Build the pack repo locally. Stage a clean working tree — the manifest at root, the full skill directory copied verbatim (including any helper scripts/config, not just SKILL.md), a README, and an MIT LICENSE:

    PACK_DIR=$(mktemp -d)/pack
    mkdir -p "$PACK_DIR/skills/$SLUG"
    cp -R "skills/$SLUG/." "$PACK_DIR/skills/$SLUG/"
    

    Write $PACK_DIR/skills-pack.json (build it with python3/jq, never string concatenation, so quoting is safe). Include only fields you actually have:

    {
      "name": "<TITLE>",
      "version": "0.1.0",
      "description": "<DESC>",
      "author": "<operator github handle>",
      "license": "MIT",
      "homepage": "https://github.com/<owner>/<pack-repo>",
      "skills": [
        {
          "slug": "<SLUG>",
          "path": "skills/<SLUG>",
          "description": "<DESC>",
          "category": "<CATEGORY>",
          "schedule": "0 12 * * *",
          "default_enabled": false,
          "secrets_required": [ ... ],
          "secrets_optional": [ ... ],
          "capabilities": [ ... ]
        }
      ]
    }
    

    Write a README.md that names the skill, states its schedule assumption, lists required/optional secrets, and shows the one-line install (bin/install-skill-pack <owner>/<pack-repo>). Write a standard MIT LICENSE (year ${today}'s year, copyright the operator handle). Resolve the operator handle once: OWNER=$(gh api user --jq .login).

  4. Pre-flight the pack. Run the repo's own validator against the staged directory — it enforces exactly what bin/install-skill-pack requires (valid JSON manifest, clean slug, no .. in paths, the SKILL.md present, locked-taxonomy capabilities):

    ./scripts/validate-pack.sh "$PACK_DIR" 2>&1 | tee /tmp/pack-validate.txt
    

    Exit non-zero (an ERROR: line) → exit PACK_SUBMIT_INVALID_PACK, notify with the failing line, and stop. Do not push an invalid pack. Warnings are fine to proceed on; surface them in the notify.

    If --dry-run was passed, stop here: notify the operator that the pack built and validated cleanly at $PACK_DIR, list the manifest fields, and exit PACK_SUBMIT_DRY_RUN without touching GitHub.

  5. Create and push the pack repo. Default repo name aeon-skill-pack-$SLUG (or the --repo override). The pack must be public — the installer fetches its tarball, and a private pack can't be installed by anyone else:

    PACK_REPO="${REPO_OVERRIDE:-aeon-skill-pack-$SLUG}"     # owner defaults to $OWNER
    gh repo view "$PACK_REPO" >/dev/null 2>&1 \
      && { ./notify "pack-submit aborted: repo $PACK_REPO already exists — pass --repo to pick another name"; exit 0; }
    ( cd "$PACK_DIR" && git init -q && git add -A \
        && git commit -q -m "Aeon community pack: $SLUG" \
        && gh repo create "$PACK_REPO" --public --source=. --push )
    

    Capture the resulting owner/repo (FULL_REPO=$(gh repo view "$PACK_REPO" --json nameWithOwner --jq .nameWithOwner)). If repo creation fails (permission/name), exit PACK_SUBMIT_REPO_FAILED, notify with the gh error's shortest decisive line, and stop.

  6. Submit the registry PR against aeonfun/aeon (skip this whole step if --no-register was passed - then jump to step 7 reporting only the pack repo). The registry lives in the canonical repo, so work against a fork, not this instance's checkout - this instance's catalog/skill-packs.json and docs/community-skill-packs.md can be stale:

    WORK=$(mktemp -d)
    gh repo fork aeonfun/aeon --clone=true --default-branch-only 2>/dev/null || true
    git clone -q "https://github.com/$OWNER/aeon.git" "$WORK/aeon" || git clone -q https://github.com/aeonfun/aeon.git "$WORK/aeon"
    cd "$WORK/aeon" && git checkout -b "pack-submit/$SLUG"
    

    Make the two edits the validator (scripts/validate-skill-packs.mjs) checks for parity:

    (a) catalog/skill-packs.json — append one object to .packs. Build it with jq from the values you resolved (mirror the pack's own manifest: skills is ["$SLUG"], trust_level is "community", aggregate secrets_required/capabilities from the skill):

    jq --arg repo "$FULL_REPO" --arg name "$TITLE" --arg desc "$DESC" \
       --arg author "$OWNER" --arg homepage "https://github.com/$FULL_REPO" \
       --arg cat "$CATEGORY" --arg slug "$SLUG" \
       '.packs += [ { repo:$repo, name:$name, description:$desc, author:$author,
         license:"MIT", homepage:$homepage, category:$cat, trust_level:"community",
         skills:[$slug] } ]' catalog/skill-packs.json > /tmp/reg.json \
      && mv /tmp/reg.json catalog/skill-packs.json
    

    Add secrets_required / capabilities keys to that object only when the skill declares them (keep it in sync with the pack manifest). Do not use trust_level: trusted — that requires the repo to be in skills/security/trusted-sources.txt, and the validator rejects an unearned trusted.

    (b) docs/community-skill-packs.md - add a table row under the | Pack | Skills | Description | header in the Listed packs section (the last section of the file). The table moved there from .github/README.md in #845; do not edit the README. The row format, matching the existing rows exactly:

    | [<pack-repo-name>](https://github.com/<FULL_REPO>) | 1 | <one-line description, ≤110 chars>. |
    

    Use python3 for a surgical insert. The row must land inside the table's contiguous block - insert it immediately after the last existing | [ row, never after a blank line or other text. The parity validator parses rows only until the first non-| line, so a row placed past the table is invisible to it and the PR fails CI with "in the registry but has no row in the Community Packs table". Verify with a re-read that the row sits among the other rows:

    import re
    lines = open("docs/community-skill-packs.md").read().split("\n")
    sec = next(i for i,l in enumerate(lines) if re.match(r'^#+\s+Listed packs\s*$', l))
    hdr = next(i for i in range(sec,len(lines)) if re.match(r'^\|\s*Pack\s*\|\s*Skills\s*\|\s*Description\s*\|', lines[i]))
    i = hdr + 2; last = i
    while i < len(lines) and lines[i].startswith("|"): last = i; i += 1   # last data row
    lines.insert(last + 1, f"| [{PACK_NAME}](https://github.com/{FULL_REPO}) | 1 | {DESC} |")
    open("docs/community-skill-packs.md","w").write("\n".join(lines))
    

    Validate parity before committing — this is the exact CI gate the PR will hit:

    node scripts/validate-skill-packs.mjs
    

    A non-zero exit → fix the reported mismatch (skill count, a missing row, or a --path flag) and re-run until it prints validate-skill-packs: OK. Never open the PR on a red validator.

    Then commit both files together, push the branch to your fork, and open the PR against the canonical repo:

    git add catalog/skill-packs.json docs/community-skill-packs.md
    git commit -m "feat: list $TITLE community pack ($FULL_REPO)"
    git push -u origin "pack-submit/$SLUG"
    PR_URL=$(gh pr create --repo aeonfun/aeon --title "feat: list $TITLE community pack" --body "$(cat <<BODY
    ## New community pack
    
    **Pack:** [$FULL_REPO](https://github.com/$FULL_REPO)
    **Skill:** \`$SLUG\` — $DESC
    **Author:** @$OWNER · **License:** MIT · **Category:** $CATEGORY
    
    Adds a row to the Listed packs table in \`docs/community-skill-packs.md\` and a matching \`catalog/skill-packs.json\` entry (both in this diff, per the publishing checklist). \`node scripts/validate-skill-packs.mjs\` passes locally.
    
    Install once merged:
    \`\`\`
    bin/install-skill-pack $FULL_REPO
    \`\`\`
    BODY
    )")
    

    Capture PR_URL. If gh pr create fails because a PR already exists for the branch, capture the existing URL instead of erroring. This PR is not self-merging — it lands in someone else's repo and is reviewed by the aeon maintainers.

  7. Log. Append to memory/logs/${today}.md:

    ### pack-submit
    - Skill: {SLUG} ({TITLE})
    - Pack repo: https://github.com/{FULL_REPO}
    - Registry PR: {PR_URL or "skipped (--no-register)"}
    - Secrets: {required list or "none"} · Capabilities: {list or "none"}
    - Exit: PACK_SUBMIT_OK (or the code that applied)
    
  8. Notify. Send one concise line via ./notify (≤4000 chars, clickable URLs):

    *pack-submit — {TITLE}*
    Pack repo: https://github.com/{FULL_REPO}
    Registry PR: {PR_URL}
    Install: `bin/install-skill-pack {FULL_REPO}`
    {"Requires: X, Y" if any required secrets, else omit}
    

    On --no-register, say the pack repo is live and give the exact PR checklist link (docs/community-skill-packs.md#pack-maintainers-publishing-checklist) so the operator can list it manually.

Exit taxonomy

Code When Action
PACK_SUBMIT_OK Pack repo pushed and registry PR opened (or --no-register completed) Notify with pack repo + PR link
PACK_SUBMIT_NO_VAR ${var} empty Notify abort reason; stop
PACK_SUBMIT_BAD_VAR Slug malformed or skills/<slug>/SKILL.md missing Notify with the slug; stop
PACK_SUBMIT_INVALID_PACK validate-pack.sh reported an ERROR Notify with the failing line; stop (nothing pushed)
PACK_SUBMIT_DRY_RUN --dry-run — built + validated, wrote nothing to GitHub Notify with the staged path + manifest summary
PACK_SUBMIT_REPO_FAILED gh repo create failed (name taken, permission) Notify with the gh error; stop
PACK_SUBMIT_REGISTRY_FAILED Fork/clone/validate/PR step failed after the pack repo was pushed Notify: pack repo is live, registry PR did not open, with the failing step

Network note

There is no network sandbox — git and gh reach GitHub directly. gh is authenticated in Actions (via GH_GLOBAL when set; the ambient GITHUB_TOKEN otherwise, which cannot create repos or cross-repo PRs — surface that as PACK_SUBMIT_REPO_FAILED rather than looping). Every irreversible outward write — creating the public pack repo (step 5) and opening the registry PR (step 6) — happens in-run and is fail-closed: a failed pre-flight (validate-pack.sh) or a failed parity check (validate-skill-packs.mjs) stops before any push. Confirm reachability with gh api repos/aeonfun/aeon --jq .full_name before deciding a fork/clone failure is real vs transient.

Constraints

  • Publish only skills that already exist in skills/. This skill packages and distributes; it does not author. To create a new skill, use create-skill.
  • The pack repo must be public — the installer fetches its tarball; a private pack is uninstallable by others.
  • Never register with trust_level: trusted — that is earned via skills/security/trusted-sources.txt, and the validator rejects a self-declared trusted. Community packs use trust_level: community.
  • Never open the registry PR on a red validate-skill-packs.mjs — a broken registry entry takes down bin/install-skill-pack --list and the dashboard panel for everyone.
  • Keep the two registry surfaces in lockstep - the Listed packs row in docs/community-skill-packs.md and the skill-packs.json entry ship in one diff, with matching skill counts. That is what the CI gate enforces.
  • Don't leak secret values. The manifest lists secret names only (from the skill's requires:), never values.

Version History

  • 531f575 Current 2026-09-27 15:14

    修复 CI 验证逻辑,使其读取 docs/community-skill-packs.md 而非旧版 README;更新 pack-submit 技能以将注册行写入新文档位置并移除废弃的计数器检查。

  • fc05537 2026-08-05 22:15

Same Skill Collection

skills/action-converter/SKILL.md
skills/aeon-doctor/SKILL.md
skills/aeon-update/SKILL.md
skills/arc-studio/SKILL.md
skills/article/SKILL.md
skills/auto-merge/SKILL.md
skills/auto-workflow/SKILL.md
skills/autoresearch/SKILL.md
skills/bd-radar/SKILL.md
skills/changelog/SKILL.md
skills/code-health/SKILL.md
skills/competitor-monitor/SKILL.md
skills/compute-resell/SKILL.md
skills/cortx-reliability/SKILL.md
skills/cost-report/SKILL.md
skills/create-prove/SKILL.md
skills/create-skill/SKILL.md
skills/ctrl/SKILL.md
skills/defi-overview/SKILL.md
skills/deploy-prototype/SKILL.md
skills/deploy-uni-hook/SKILL.md
skills/digest/SKILL.md
skills/distribute-tokens/SKILL.md
skills/ecosystem-pulse/SKILL.md
skills/executor-mcp/SKILL.md
skills/fear-divergence/SKILL.md
skills/feature/SKILL.md
skills/fetch-tweets/SKILL.md
skills/finance-district-mcp/SKILL.md
skills/fleet-control/SKILL.md
skills/fork-fleet/SKILL.md
skills/github-monitor/SKILL.md
skills/github-trending/SKILL.md
skills/glim-mcp/SKILL.md
skills/heartbeat/SKILL.md
skills/higgsfield/SKILL.md
skills/hunter-22/SKILL.md
skills/idea-forge/SKILL.md
skills/idea-pipeline/SKILL.md
skills/inbox-triage/SKILL.md
skills/install-skill/SKILL.md
skills/investigation-report/SKILL.md
skills/issue-triage/SKILL.md
skills/last30/SKILL.md
skills/memory-flush/SKILL.md
skills/mention-radar/SKILL.md
skills/monitor-polymarket/SKILL.md
skills/narrative-convergence/SKILL.md
skills/narrative-tracker/SKILL.md
skills/okf-export/SKILL.md

Metadata

Files
0
Version
531f575
Hash
606fe922
Indexed
2026-08-05 22:15

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-02 11:20
浙ICP备14020137号-1