Skip to content

Claude Skill publication runbook

Step-by-step for publishing theaccessible PDF Converter as an Anthropic Skill bundle. Companion to docs/CUSTOM-GPT-PUBLICATION.md (OpenAI Custom GPT) and docs/MCP-AND-CUSTOM-GPT.md (MCP server).

The skill source lives in this repo at skills/pdf-converter/. The public distribution lives at https://github.com/anglinai/theaccessible-skill.

What a Skill is (vs. a Custom GPT)

Custom GPTClaude Skill
Lives whereOpenAI GPT StoreA folder Claude loads on demand
AuthAction API key, pasted in editorTHEACCESSIBLE_API_KEY env var on the user’s machine
Code executionNone β€” model calls Action endpointsYes β€” model can run bundled bash scripts
DiscoverabilityPublic GPT StoreGitHub repo (today); claude.ai upload (when GA)
DistributionOne linkSkill bundle (zip / git clone)

The skill calls the same /api/gpt/* HTTPS surface as the Custom GPT β€” no new server-side endpoints required.

Prerequisites

1. Verify the bundle locally

Terminal window
ls skills/pdf-converter/
# SKILL.md README.md scripts/ references/
# Syntax-check the shell scripts:
for f in skills/pdf-converter/scripts/*.sh; do bash -n "$f"; done && echo OK

2. Smoke-test in Claude Code

Terminal window
mkdir -p ~/.claude/skills
rm -rf ~/.claude/skills/pdf-converter
cp -r skills/pdf-converter ~/.claude/skills/pdf-converter
export THEACCESSIBLE_API_KEY=tap_... # your test key

Open Claude Code in any directory and run all four scenarios:

  1. Public URL. β€œMake this PDF accessible: https://example.com/sample.pdf” Confirm: convert.sh --url, polling, result with three markdown links + reportUrl.
  2. Local file. β€œMake ~/Downloads/sample.pdf accessible.” Confirm the model picks convert.sh --file (not --url with a ~/... path).
  3. Known-bad PDF. Use a PDF with no tags / no language. Confirm conformance.passed=false and the model lists the failed rules without claiming compliance.
  4. Oversize. Try a 30 MB PDF. Confirm convert.sh exits 65 with the size message, surfaced cleanly to the user.

3. Smoke-test scripts directly

Run each script outside the model to confirm exit codes and JSON shape:

Terminal window
cd ~/.claude/skills/pdf-converter
./scripts/convert.sh --url https://example.com/sample.pdf | jq .
fid=$(./scripts/convert.sh --url https://example.com/sample.pdf | jq -r .data.fileId)
./scripts/poll_status.sh "$fid" | jq .data.status
./scripts/get_result.sh "$fid" | jq '.data | keys'
./scripts/get_conformance.sh "$fid" | jq '.data.conformance.passed'

All four should exit 0 on the happy path. poll_status.sh should exit 1 on status=failed and 3 on the 5-minute timeout.

4. Publish to the public repo

The public mirror is a separate repo so external users can clone it without pulling our backend source.

Terminal window
# First time only β€” see step 5 of the original setup, below.
cd ~/Projects
git clone [email protected]:anglinai/theaccessible-skill.git
cd theaccessible-skill
# Sync from the source of truth:
rsync -av --delete \
~/Projects/accessible/skills/pdf-converter/ \
./
git add -A
git commit -m "Sync from accessible@$(cd ~/Projects/accessible && git rev-parse --short HEAD)"
git push origin main

Tag a release for users who pin versions:

Terminal window
git tag -a v0.1.0 -m "Initial public release"
git push origin v0.1.0

5. First-time public-repo setup

Done once, then never again. Documented for completeness.

Terminal window
gh repo create anglinai/theaccessible-skill \
--public \
--description "Claude Skill: convert PDFs into WCAG 2.1 AA / PDF/UA-1 compliant deliverables. Uses theaccessible.org." \
--homepage "https://theaccessible.org" \
--license MIT

Repo settings:

  • License: MIT (the bundle is just a thin wrapper around the public API).
  • Topics: claude, claude-code, claude-skill, accessibility, pdf, wcag, pdf-ua, anthropic.
  • Issues: enabled.
  • Discussions: disabled (route to GitHub Issues).
  • Branch protection on main: required PR review for non-admin.

6. Build the .dxt and skill .zip artifacts

We host two installable artifacts at https://pdf.theaccessible.org/downloads/:

ArtifactWhat it isTarget surface
theaccessible-pdf-converter-<ver>.dxtDesktop Extension wrapping our MCP server (api-pdf.theaccessible.org/api/mcp) via mcp-remoteClaude Desktop (one-click install)
theaccessible-pdf-skill-<ver>.zipZip of skills/pdf-converter/Claude Code, Agent SDK

The build script handles both:

Terminal window
# Install the dxt CLI once
npm install -g @anthropic-ai/dxt
# Build both artifacts
./apps/skills/pdf-converter/build.sh

This:

  1. Validates apps/skills/pdf-converter/dxt/manifest.json.
  2. Runs dxt pack and writes theaccessible-pdf-converter-<ver>.dxt into apps/web/public/downloads/.
  3. Zips skills/pdf-converter/ (excluding the dev-only smoke tests) into theaccessible-pdf-skill-<ver>.zip in the same directory.

Cloudflare Pages serves both with Content-Disposition: attachment (configured in apps/web/public/_headers) so users get a clean download flow.

Bump versions independently:

  • DXT version β†’ apps/skills/pdf-converter/dxt/manifest.json
  • Skill version β†’ reflects the GitHub repo tag (the zip has no embedded version)

Deploy by pushing to main and running the standard apps/web deploy pipeline.

7. Distribute

ChannelStatusAction
pdf.theaccessible.org/downloads/*.dxtDay 1Built in step 6, deploys with apps/web
pdf.theaccessible.org/downloads/*.zipDay 1Built in step 6
Public GitHub repoDay 1Done in step 4
Claude Agent SDK skill bundleDay 1Same folder shape β€” point SDK consumers at the repo
claude.ai Skills uploadWhen GAUpload the same .zip via the Skills UI
Anthropic DXT directoryWhen GASubmit theaccessible-pdf-converter-<ver>.dxt once a directory exists

Promote the repo from:

  • docs/MCP-AND-CUSTOM-GPT.md β€” add a β€œSkills” section linking to the public repo.
  • apps/home β€œTools” section on theaccessible.org β€” add a third card next to Custom GPT and MCP.
  • The dashboard β€œAPI keys” page β€” surface the install snippet alongside the existing OpenAI / MCP instructions.

8. Versioning + updates

  • The skill folder has no version field beyond the git tag β€” Claude loads the live filesystem copy.
  • Bump the tag whenever SKILL.md or any script changes:
    • Patch (v0.1.x): script bug fix or wording tweak in SKILL.md.
    • Minor (v0.x.0): new script, new optional flag, or expanded workflow. Backwards-compatible.
    • Major (v1.0.0+): breaking change to script CLI, env-var name, or required workflow steps. Requires user re-install.
  • When the API surface changes (new endpoint, breaking schema change), update references/api.md and the relevant script in the same PR that ships the API change. Otherwise the skill silently drifts.

9. Failure modes (post-launch)

Symptom (user report)Likely causeFix
”Skill says my key is missing”THEACCESSIBLE_API_KEY not exported in the shell Claude Code spawns scripts inAdd the export to ~/.zshrc and restart the terminal
”Polling exits with TIMEOUT but the job finishes later”Backend queue backed upTell user to re-run poll_status.sh <fileId> β€” the job is still queued server-side
”401 on every call”Revoked key, or --header X-API-Key mis-typedIssue a fresh key
Model bypasses scripts and hand-rolls curlSKILL.md drift after editingRestore from this repo; the workflow section MUST tell the model to call the scripts
Model loops on a failed conversionOld poll_status.sh without status=failed short-circuitUpdate to β‰₯ v0.1.0

10. Monitoring

  • API-key dashboard: skill-driven traffic shows up alongside Custom GPT / MCP usage on the same key. There’s no per-surface attribution today β€” if we want it, add a User-Agent: theaccessible-skill/<ver> header in _lib.sh and log it.
  • [gpt-openapi] workers/api logs show every call β€” filter by userId to debug specific user reports.

When to update this doc

  • New script added or removed: update steps 1, 2, 3, and the bundle inventory in the README.
  • API contract changes: update step 7 and skills/pdf-converter/references/api.md.
  • Anthropic ships a registry / claude.ai Skills GA: update step 6.