The uniform-folder refactor made every reference a <name>/ directory, but the naming-convention prose in AGENTS.md, CONTRIBUTING.md, and the check_router_reachability.py docstring still wrote framework-<name>.md etc. Update them to directory form for consistency with the shipped layout.
10 KiB
Contributing
We appreciate feedback and contribution to this repo! Before you get started, please see Auth0's general contribution guidelines.
How to Contribute
Adding a New Skill
- Create a new directory under
plugins/auth0/skills/ - Add a
SKILL.mdfile following the Agent Skills specification - Optionally add additional reference files
- Update the README.md to list your skill in the appropriate table
- Submit a pull request
Skill Structure
Per the Agent Skills specification, only SKILL.md may live in the skill root. All other content must go in one of these subdirectories:
plugins/auth0/skills/my-skill/
├── SKILL.md # Required: Main skill file (the ONLY file allowed in root)
├── references/ # Optional: Additional documentation (kebab-case .md files)
│ ├── setup.md
│ ├── integration.md
│ └── api.md
├── scripts/ # Optional: Executable helper code
│ └── helper.js
├── assets/ # Optional: Static resources (templates, images, data files)
└── tests/ # Optional: Validation artifacts (test transcripts, fixtures)
Markdown files in subdirectories must be kebab-case (e.g. route-protection.md). Framework integration skills conventionally split their reference docs into setup.md, integration.md, and api.md — follow that naming so skills stay consistent.
SKILL.md Requirements
Your SKILL.md must include:
-
YAML Frontmatter with the following fields.
name,description,license,metadata.author, and the fullmetadata.openclawblock (withemojiandhomepage) are required and enforced by the linter — a skill missing any of them will fail validation:--- name: my-skill description: Brief description of what this skill does and when to use it. license: Apache-2.0 metadata: author: Auth0 <support@auth0.com> # required, must be "Name <email>" format version: '1.0.0' # recommended; most skills pin this openclaw: # required block emoji: "\U0001F510" homepage: https://github.com/auth0/agent-skills requires: # optional: declare external dependencies bins: - auth0 # declare `auth0` if the skill runs CLI commands os: # optional: darwin, linux, win32 - darwin - linux install: # optional: how to install required bins - id: brew kind: brew formula: auth0/auth0-cli/auth0 bins: [auth0] label: 'Install Auth0 CLI (brew)' ---Notes:
licensemust beApache-2.0unless a specific package requires otherwise (matches the repositoryLICENSE).metadata.authormust followName <email>; separate multiple authors with commas, not semicolons.- The
requires,os, andinstallfields undermetadata.openclaware ClawHub metadata used when installing the skill vianpx clawhub install. If your skill's workflow invokesauth0CLI commands, declarerequires.bins: [auth0](and the matchinginstallblock) so ClawHub can prompt the user to install the CLI. Apply this consistently.
-
Clear Instructions: Step-by-step guidance for the AI agent
-
Code Examples: Working code samples for each SDK where applicable
-
Error Handling: Common errors and how to handle them
Code Style
- Use TypeScript for examples where applicable
- Include comments explaining complex logic
- Follow Auth0's coding conventions
- Test code examples before submitting
Updating Existing Skills
- Fork the repository
- Make your changes
- Ensure all code examples are correct
- Update version in metadata if significant changes
- Submit a pull request with clear description of changes
Local Development
Validating Skills
This repository uses skillsaw to enforce frontmatter and structure conventions. The same check runs in CI (.github/workflows/skillsaw.yml) and must pass before a PR can merge, so run it locally first:
# Validate the whole repository in strict mode (matches CI)
uvx skillsaw --strict
Rules are configured in .skillsaw.yaml, with repository-specific custom rules in .skillsaw/rules.py.
Testing with AI Assistants
Test your skills work correctly with AI assistants:
- Install the plugin/skill locally:
# Install entire plugin npx skills add ./plugins/auth0 # Or copy to Claude skills directory cp -r ./plugins/auth0/skills/my-skill ~/.claude/skills/ - Ask an AI assistant to use the skill
- Verify the generated code is correct
Pull Request Process
- Ensure your changes follow the contribution guidelines
- Update documentation as needed
- Add your changes to CHANGELOG.md (if applicable)
- Request review from maintainers
- Address any feedback
Code of Conduct
Please follow Auth0's Code of Conduct.
Questions?
If you have questions about contributing, please open an issue with the "question" label.
Adding a Capability to the Unified Skill
All Auth0 guidance ships in the single auth0 skill
(plugins/auth0/skills/auth0/). See docs/architecture.md
for why. To add or change coverage:
Pick the right reference prefix
Every reference is a directory <name>/ with an index.md (see "Adding a
reference"); pick the prefix that fits:
feature-<name>/— a capability spanning frameworks (e.g. mfa, dpop).framework-<name>/— a single SDK/framework integration.tooling-<name>/— a provisioning tool (cli, mcp, terraform).pattern-<name>/— cross-cutting guidance.
Make it routable (required — CI enforces this)
Every reference in references/ MUST be reachable from SKILL.md. Navigation is
a depth-2 tree: every reference is a directory <name>/ with an index.md.
An index-only reference puts its whole content in index.md and has no
leaves (one hop from the router). A large reference is a leaf group whose
index.md is a hub plus document-section leaves (see "Adding a reference" below).
An index-only index.md and any leaf inside a leaf group may contain no link
to any .md file — they are sinks; inline the content instead of linking. The
only second hop allowed is a leaf-group hub index.md dispatching to leaves in
its own directory; cross-group links are forbidden. Claude Code follows the
router to index.md (and, for a leaf group, on to one leaf) — nothing deeper is
guaranteed.
- New feature: add an intent row in Step 1 and a load block in Step 4 of
SKILL.md. - New framework: add detection in all three tiers of Step 2 — Tier 1
(Auth0 SDK package), Tier 2 (non-Auth0 workspace dependency), Tier 3 (prompt
keyword) — and, if it has a web-vs-API split, a row in "Variant
disambiguation." The reachability checker derives routable slugs directly from
these router tables (the backticked value column), so simply naming your
<slug>in a table makesframework-<slug>/index.mdreachable — there is no separate list to update.
Adding a reference
Every reference is a directory named after its stem, containing an index.md.
Adding a new reference means creating references/<name>/index.md. Start
index-only — the whole reference lives in index.md — and only split it into a
leaf group once it grows large (roughly >40K) so the router pulls just the
slice a task needs instead of the whole file:
references/framework-<name>/
├── index.md # hub: shared prerequisites + intent→leaf dispatch table
├── integrate.md # document-section leaves (one per section, not per intent)
├── api-reference.md
├── patterns.md
├── setup.md
└── migration.md # only if the SDK has a major-version migration
Rules for splitting a large reference into a leaf group:
- Leaves are document sections, not intents (
integrate,api-reference,patterns,setup,migration, …). Feature references split by sub-topic (guide,api-reference,advanced,examples). index.mdis a lean hub: shared setup every leaf needs, then a dispatch table with one row per router intent, each an imperative`Read: references/<stem>/<leaf>.md`pointing at that intent's primary leaf. Intent strings must match Step 1 exactly (feature:mfa, notmfa). A "Then, as needed" list ofRead:bullets makes the secondary leaves reachable. Every leaf must appear in at least oneRead:line or it's an orphan.- Lossless + self-contained: every line of the original file lands in exactly one destination; leaves repeat any shared context inline rather than linking to the hub or each other. If two sections cross-reference too heavily to separate, merge them into one leaf rather than add a link.
- Add a routing case in
evals/routing-cases.jsonwith the two-hopexpect_refs(<name>/index.md+ the intent leaf [+ tooling]), and move the slug from the index-only presence check invalidate-skill.shto its grouped loop. For an index-only reference, the presence check is simply<name>/index.md.
The router always emits Read: references/{framework}/index.md (or
{feature} / {tooling}) regardless of whether the target is index-only or a
leaf group — a global note in Step 4 tells the agent to follow the index.md's
dispatch table to a leaf if it has one. The reachability and routing-eval
checkers resolve a leaf-group slug automatically; you don't edit SKILL.md's
routing tables.
Validate
bash plugins/auth0/skills/auth0/scripts/validate-skill.sh
python3 scripts/check_router_reachability.py plugins/auth0/skills/auth0
python3 scripts/check_routing_evals.py plugins/auth0/skills/auth0
uvx skillsaw --strict