mirror of
https://github.com/getcargohq/cargo-skills.git
synced 2026-09-14 19:17:15 +08:00
55d2eaf660
* Hold the sending skill out of the OpenAI package The directory review rejected two skills under "Spam mass abuse". cargo-mailbox-management is a true positive on category: it provisions sending mailboxes and runs a 5-to-40/day warm-up ramp, which is the shape of cold-email infrastructure whatever the gates around it. So the package now ships without it — EXCLUDED_SKILLS — and says so by shipping eighteen skills rather than by rewording the nineteenth. The alternative, deleting the refusal lists and ramp documentation until the keywords stop matching, would ship a less guarded skill in order to pass a safety review. cargo-gtm looks like a false positive on negation: its description ended "bulk unsolicited messaging, purchased or scraped lists, and consumer targeting are refused", which hands a keyword classifier four spam nouns in one clause. The packaged description now states the same policy as what the skill does — documented lawful basis, suppression screening, per-recipient relevance, sends nothing itself — and keeps every routing trigger. That did not clear review — gtm was rejected again with the new card live, so the trigger is the skill body or the capability itself, not the description. The reframed card is kept because it is the more accurate of the two, not because it fixed anything. Excluding a skill is not just skipping a directory. Fifteen of the remaining skills link to it: a router table row, an ASCII diagram box, a recap section, the domain list, defineMailbox/defineDomain in cargo-cdk, a routing row in cargo-mcp, three passages in cargo-gtm's acceptable-use. PACKAGE_EDITS removes each one in the staged copy, and every find must match exactly once or the build fails — they are anchored to prose that will drift, and a silent no-op would ship a dangling link. Skill counts renumber from the real packaged total, so the router reads "18 skills ... fifteen capability skills" without anyone maintaining the number. Backstopping all of that, zipgrep asserts after zipping that no packaged file names an excluded skill anywhere. That check does not care whether the edits above were written correctly. Every edit applies to the staging copy under dist/. The repo files are read-only inputs, so Claude Code, Cursor, skills.sh and Hermes still install all nineteen skills with every mailbox reference intact. Also fixes the packaged manifest description, which claimed 17 skills — stale since two were added. It derives from the packaged count now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Narrow cargo-gtm's person-level surface for the OpenAI package Second rejection, with the reframed description already live in the listing — so the card was never the trigger. Reading the skill body as a policy reviewer would, five capabilities carry most of the risk, and on those the reviewer is not wrong: snitcher de-anonymising website visitors aiArk.analyzePersonality OCEAN/DISC inference from a profile forager personal email and personal phone from a URL linkedin.extractEventAttendees harvesting a platform's attendee list x reading a social platform's posts and profiles "We gate it" is a weak answer to visitor de-anonymisation and personality inference. So the packaged skill no longer offers them: three playbooks leave the tree, and the actions are removed from the stack table, the cost table, the stage map, the alternatives table, the finding guide's decision tree, two recipes, the aiArk playbook and the router's glossary. Thirty-four edits, each asserted to match exactly once. What remains is the same skill minus a person-level edge: company research, work-email enrichment from licensed providers, verification, scoring, signal monitoring, CRM sync. That is a real narrowing of what the package can do rather than a rewording of what it says it does, which is also what makes the appeal behind it checkable. REMOVED_TERMS asserts against the built archive that nothing survived, scoped by path — extractEventAttendees stays in cargo-connection, which documents the catalog rather than recommending the action, and which the directory already approved. Metadata is regenerated with the repo's own skills-metadata.mjs over the staged tree: three files left and a dozen changed, so every packaged skill-metadata.json was stale by construction, content hash included. Repo copies are untouched, as before. Every other channel still ships all nineteen skills with the full provider stack. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Give the packaged quickstart a company-level demo Third rejection, same category: the quickstart's headline pull is 25 named people with titles and a "recently hired" flag. Sixteen skills that never touch a person passed on the first try; the three that were rejected are the three that do. Rather than drop the onboarding skill, the package now ships a variant that runs the same two-minute arc against company-level hiring intent — theirStack.searchCompanies on the persona's role, postings inside 30 days. This is the skill's own fallback rung 2, which it already describes as "same wow, different angle". The receipt is unchanged at ~0.5 credits, because searchCompanies bills per call rather than per row, so `limit` is free to set. The demo names no individuals. It ships as a whole file rather than as edits. The spine is rewritten — action, filter, output fields, headline, fallback ladder, next steps — and a dozen brittle anchors through a rewritten section would fail on the next upstream wording change with nothing useful to say about it. The copy is tied to the repo skill's frontmatter version instead. Bump cargo-quickstart and this build fails, naming both versions and asking for the port. That is the maintenance cost of an override, made loud on purpose. Step 3 reads the first row's keys and renders from them rather than hardcoding a shape: the payload of this action is not something I have run, and a demo that dies on line 3 is worse than one that spends a second looking. Worth one 0.5-credit run against a live workspace before the package is resubmitted. Repo copies untouched, as with the two commits before this. Every other channel still ships the leads demo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Rebuild the quickstart demo on aiArk, against a live run theirStack was the wrong pick and the reason is not taste: it needs its own API-key connector, so on the fresh workspace a quickstart exists for it dead-ends on rung 1. It got chosen because the fallback ladder named it, not because anything checked it. aiArk.searchCompanies is better on every axis that matters here. It runs on cargo's managed connection, so a workspace with nothing wired up can still complete the demo. At 0.01 per returned record, 25 rows cost 0.25 credits — half what the leads demo cost. And it answers the persona question with accounts rather than people. The demo also opens on countCompanies, which is fixed-cost 0. Sizing the whole addressable market for free and then sampling it for a quarter of a credit is a better first beat than 25 rows with no denominator, and it puts the pack's own count-first rule in the first thing a new user sees. Everything here is verified against a real run rather than a playbook: countCompanies free, returns {"count": N} — 1,904 on the example searchCompanies 25 rows for 0.25 credits employeeRole employee_title_or / employee_seniority_or / employee_department_or industry industry_or takes plain lowercase strings ("software development") — no autocomplete needed, and it halved the pool to 840 row fields name, industry, employee_count, city, country, domain, linkedin_url, revenue, founded_year, technologies So step 4 renders named columns now instead of printing the keys and hoping. theirStack keeps a place as rung 3, where its own-key connector is a known cost rather than a surprise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Remove only the mailbox bullet from the CDK critical rules The drop_block helper takes the blank-line-delimited block around a marker, which is right for a standalone diagram and wrong for a markdown bullet list: consecutive bullets have no blank line between them, so the whole list is one block. The cargo-cdk edit anchored on the defineMailbox bullet and took all of "## 6) Critical rules" with it — 71 lines instead of 12. The packaged CDK skill shipped an empty heading, losing the state-file, secrets, handle-wiring, --yes, paid-play sample and alert cost-gate rules. Caught by Bugbot on #120, not by the build: every assertion here checks that a find matched exactly once and that removed things left no trace. Nothing checked that what remained was still there. A repo-vs-package line-count diff over the whole archive now reconciles: every SKILL.md is -12 for the dropped metadata block, and each further delta matches a specific edit. cargo-cdk is the only file that was wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Document aiArk's three undocumented actions Bugbot flagged the quickstart override for calling aiArk.countCompanies, an action absent from the packaged playbook. The action is real — the demo was verified against a live run — so the gap is in the documentation, and it is a repo gap rather than a packaging one. The playbook described six actions and asserted "all six are credits-based". The integration exposes nine: enrichCompany 0.01 the cheapest company enrich in the catalog countCompanies free {"count": N} for a searchCompanies filter countPeople free same, for searchPeople The count pair is the more useful omission. Cost discipline tells an agent to size a pool before paying per record, and on this provider that check costs nothing — but only if the agent knows the actions exist. Added alongside the per-record billing warning, where the question actually comes up. Also corrects the override's claim that industry_or takes ordinary lowercase strings, which contradicted the same playbook two files away. Both are true and neither said so: the enum members are LinkedIn-style lowercase names, identical to the strings each row returns in its own industry field, so a value copied off a result matches while a guess empties the pool. The override now says that, and points at listIndustries for anything less obvious. Repo change, so every channel gets it, not just the OpenAI package. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Remove the personality pitch, not just its slug REMOVED_TERMS asserted on "analyzePersonality" and passed, while the packaged playbook went on selling the capability in prose that named no action: an intro pitching "a personality-analysis action nothing else in the catalog has", and a reason-to-reach-for-it clause offering "personality/selling guidance". A slug-only check waved both through. The counts were wrong too. The repo playbook says nine actions, seven credits-based; the package removes one, so it ships eight and six. Now stated as such, and the packaged action table has exactly eight rows to match. The assertion now looks for "personality" itself. It cannot collide with "personalization", which is a different word, and the sweep it flagged on the first run is what found the second clause — the fix caught its own gap before the archive shipped. Also adds .github/package-overrides/** to the Codex package workflow's path filter. The package depends on that file now, so a change touching only the override needs to run the build and the version guard, and did not. Both found by Bugbot on #120. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C * Fetch the count, drop the attendee pitch, fail a broken sweep Three from Bugbot on #120, all correct. The quickstart's headline number was never fetched. Step 1 wrote the countCompanies run object to a file and step 4 told the agent to lead with the pool size, but the run object holds no results — the same skill says so two paragraphs earlier — and nothing ever called download-outputs for that run. The demo would have opened on an empty variable. Both steps now go through one fetch_output helper, so the retrieval that was already correct for the search is correct for the count too, and the headline reads $POOL. The linkedin playbook still pitched event-attendee harvesting in prose after the action row was removed: an engagement-sourcing bullet and the per-item billing note. Same failure as the personality pitch — the slug left, the capability stayed. The new assertion is scoped to that one file on purpose: "event attendees" appears four more times in cargo-gtm as a lawful BASIS for contacting someone, and that must stay exactly where it is. And the sweeps themselves could not fail. Every throw was read as "nothing matched", so a missing binary or an unreadable archive reported a clean package. grep-family exit codes distinguish these: 1 is no match, anything else is an error. Verified by putting a zipgrep that exits 2 on PATH — the build now stops with "could not verify ... zipgrep exited 2" where it previously passed. That last one is the pattern worth naming: three of the five findings on this PR were assertions that were true and conclusions that were wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YL6YdzRFUf27A2WChKxr1C --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
86 lines
3.0 KiB
YAML
86 lines
3.0 KiB
YAML
name: Codex package
|
|
|
|
# The OpenAI Plugins Directory has no submission API — the portal is the only
|
|
# path and every version is human-reviewed, so the upload itself stays manual.
|
|
# Everything before it does not have to be:
|
|
#
|
|
# - on a release: build the archive and attach it, so publishing is
|
|
# "download the asset, drop it in the portal" rather than "find whoever
|
|
# built the zip last time".
|
|
# - on a PR touching skills or the builder: run the same build, so a change
|
|
# that would fail OpenAI's validator fails here instead — months before
|
|
# someone spends a review cycle discovering it.
|
|
|
|
on:
|
|
release:
|
|
types: [published]
|
|
pull_request:
|
|
paths:
|
|
- "*/SKILL.md"
|
|
- "assets/**"
|
|
- ".claude-plugin/plugin.json"
|
|
- ".github/scripts/build-codex-package.mjs"
|
|
- ".github/package-overrides/**"
|
|
- ".github/workflows/codex-package.yml"
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
with:
|
|
node-version: "20"
|
|
|
|
# The builder measures icons with `sips`, which is macOS-only. Everything
|
|
# else is portable, so shim it with ImageMagick on the runner rather than
|
|
# paying for a macOS runner to check two PNGs.
|
|
- name: Provide a sips shim
|
|
run: |
|
|
sudo apt-get update -qq && sudo apt-get install -y -qq imagemagick
|
|
sudo tee /usr/local/bin/sips >/dev/null <<'SHIM'
|
|
#!/usr/bin/env bash
|
|
# Minimal stand-in for macOS sips: only -g pixelWidth/pixelHeight.
|
|
file="${@: -1}"
|
|
read -r w h < <(identify -format "%w %h" "$file[0]" 2>/dev/null)
|
|
[ -z "$w" ] && exit 1
|
|
echo "$file"
|
|
echo " pixelWidth: $w"
|
|
echo " pixelHeight: $h"
|
|
SHIM
|
|
sudo chmod +x /usr/local/bin/sips
|
|
|
|
- name: Build and validate the package
|
|
run: node .github/scripts/build-codex-package.mjs
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: cargo-skills-codex
|
|
path: dist/cargo-skills-codex.zip
|
|
if-no-files-found: error
|
|
|
|
attach:
|
|
needs: build
|
|
if: github.event_name == 'release'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: cargo-skills-codex
|
|
|
|
- name: Attach to the release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh release upload "${{ github.event.release.tag_name }}" \
|
|
cargo-skills-codex.zip --clobber \
|
|
--repo "${{ github.repository }}"
|
|
echo "::notice::Attached to ${{ github.event.release.tag_name }}. Upload it at https://platform.openai.com/plugins — the directory has no API."
|