Skip to content
Draft
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
34ccf8a
docs: design for reference depth (hub + leaves for large references)
frederikprijck Jul 16, 2026
8c47b04
docs: implementation plan for reference depth
frederikprijck Jul 16, 2026
807aa08
docs: correct plan's two-level link-detection mechanism (add SIDEWAYS…
frederikprijck Jul 16, 2026
d5b5654
feat: two-level (group) support in router reachability checker
frederikprijck Jul 16, 2026
c453310
feat: resolve grouped slugs to hub+leaf in routing-evals checker
frederikprijck Jul 16, 2026
b0caded
feat(auth0): split framework-swift into hub+leaf group (proof case)
frederikprijck Jul 16, 2026
1c830f0
refactor(auth0): add default-leaf fallback row to swift hub (rollout …
frederikprijck Jul 16, 2026
c470f2d
feat(auth0): split framework-android into hub+leaf group
frederikprijck Jul 16, 2026
9666ef6
feat(auth0): split framework-go into hub+leaf group
frederikprijck Jul 16, 2026
c8bc623
feat(auth0): split framework-php-api into hub+leaf group
frederikprijck Jul 16, 2026
d115b8e
feat(auth0): split framework-react into hub+leaf group
frederikprijck Jul 16, 2026
231ecba
feat(auth0): split framework-java-mvc into hub+leaf group
frederikprijck Jul 16, 2026
6f4c80f
feat(auth0): split framework-ionic-angular into hub+leaf group
frederikprijck Jul 16, 2026
fa47bca
feat(auth0): split framework-php into hub+leaf group
frederikprijck Jul 16, 2026
dddddcd
feat(auth0): split framework-ionic-vue into hub+leaf group
frederikprijck Jul 16, 2026
d81a96b
feat(auth0): split framework-aspnetcore-auth into hub+leaf group
frederikprijck Jul 16, 2026
f9e352f
feat(auth0): split framework-expo into hub+leaf group
frederikprijck Jul 16, 2026
a0fa961
feat(auth0): split framework-nuxt into hub+leaf group
frederikprijck Jul 16, 2026
9854e38
feat(auth0): split feature-custom-domains into hub+leaf group
frederikprijck Jul 16, 2026
f77e991
feat(auth0): split feature-branding into hub+leaf group
frederikprijck Jul 17, 2026
756fa7d
feat(auth0): split feature-acul into hub+leaf group
frederikprijck Jul 17, 2026
e99d0d5
docs: document two-hop-through-hub reference grouping
frederikprijck Jul 17, 2026
9332641
docs: update PLUGIN.md + reachability docstring to depth-2 model (fin…
frederikprijck Jul 17, 2026
d2859a8
docs: remove superpowers spec/plan from shipped tree
frederikprijck Jul 20, 2026
f808820
Merge remote-tracking branch 'origin/main' into worktree-reference-depth
frederikprijck Jul 20, 2026
eacfcee
fix(auth0): port #144 placeholder-URL swaps into leaf files
frederikprijck Jul 20, 2026
815f07a
Merge remote-tracking branch 'origin/main' into worktree-reference-depth
frederikprijck Jul 20, 2026
0995e80
feat(checker): reachability enforces uniform-folder (directories-only…
frederikprijck Jul 20, 2026
8edb90b
feat(checker): routing-evals resolves every reference through its group
frederikprijck Jul 20, 2026
b2a63db
refactor(auth0): convert 35 flat references to index-only group direc…
frederikprijck Jul 20, 2026
0fc9af9
feat(auth0): router emits references/<name>/index.md uniformly
frederikprijck Jul 20, 2026
7517228
test(evals): routing-cases expect_refs use uniform <name>/index.md paths
frederikprijck Jul 20, 2026
2953ca7
chore(auth0): validate-skill.sh checks the uniform-folder shape
frederikprijck Jul 20, 2026
596abb0
docs: describe the uniform-folder (every reference is a directory) model
frederikprijck Jul 20, 2026
bd1b08e
test+docs: lock in discard("index") guard; refresh compute_route docs…
frederikprijck Jul 20, 2026
d849e62
refactor(auth0): re-carve framework-swift to standard leaf axis
frederikprijck Jul 24, 2026
971d3eb
docs: fix routing-cases path in CONTRIBUTING (evals/, not tests/)
frederikprijck Jul 24, 2026
704d23f
docs: drop stale .md suffixes now every reference is a directory
frederikprijck Jul 24, 2026
edec431
fix(auth0): repair dangling patterns-leaf pointers in nuxt integrate …
frederikprijck Jul 24, 2026
e506a07
fix(auth0): sharpen nuxt hub pointer so page-level protection is disc…
frederikprijck Jul 24, 2026
a9fb663
refactor(auth0): collapse framework-swift to index + integrate + api-…
frederikprijck Jul 24, 2026
77e137b
refactor(auth0): collapse all leaf groups to index + 2 content leaves
frederikprijck Jul 24, 2026
3755f65
refactor(auth0): restore standalone framework-swift index.md (quick s…
frederikprijck Jul 24, 2026
762c07d
refactor(auth0): restore standalone index.md for 11 framework groups
frederikprijck Jul 24, 2026
dc35e60
refactor(auth0): restore standalone index.md for feature groups (orie…
frederikprijck Jul 24, 2026
04216e2
refactor(auth0): dedup framework-go hub — drop pre-Quick-start setup …
frederikprijck Jul 24, 2026
3b66dbc
docs(auth0): drop leading HTML author-comments from hub index.md files
frederikprijck Jul 24, 2026
0c7be19
docs(auth0): drop internal hub/leaf jargon from user-facing skill con…
frederikprijck Jul 24, 2026
25cb4d0
docs(auth0): drop redundant Reference-layout callout from SKILL.md
frederikprijck Jul 24, 2026
ddeb560
chore(auth0): untrack behavioral test package-lock.json
frederikprijck Jul 24, 2026
58e9af7
chore(auth0): merge framework smoke-check loops into one roster
frederikprijck Jul 24, 2026
82c998c
chore(auth0): merge feature smoke-check loops into one roster
frederikprijck Jul 24, 2026
4caf753
chore(auth0): match main's ordering for EXPECTED_FRAMEWORKS/FEATURES
frederikprijck Jul 24, 2026
f310fae
chore(auth0): restore plain '# Feature file checks' comment
frederikprijck Jul 24, 2026
624e722
fix(auth0): use SDK-native ISSUER_BASE_URL/AUDIENCE env vars in Expre…
frederikprijck Jul 24, 2026
0d69dc9
fix(auth0): remove stray paren in ionic-vue logout snippet (#159)
frederikprijck Jul 24, 2026
baae507
fix(auth0): restore Nuxt runtimeConfig auto-population guidance (#160)
frederikprijck Jul 24, 2026
0d1603e
fix(android): correct logout callback onSuccess signature to Void? (#…
frederikprijck Jul 24, 2026
9389b7c
fix(auth0): remove hardcoded Auth0.getInstance init from Android refe…
frederikprijck Jul 24, 2026
eb30528
fix(auth0): correct Swift ID token claims-reading API (#153)
frederikprijck Jul 24, 2026
2223940
fix(auth0): warn against passing credentials in code for Swift (#161)
frederikprijck Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ An **Agent Skill** that teaches coding assistants how to implement Auth0
authentication that follows Auth0's documented SDK usage and passes this
repo's routing and behavioral evals. It ships as a single Claude Code / Cursor / Copilot
plugin (`auth0`) containing **one** consolidated skill at
`plugins/auth0/skills/auth0/`: a router `SKILL.md` over a flat pool of on-demand
reference files. The deliverable is the skill itself.
`plugins/auth0/skills/auth0/`: a router `SKILL.md` over a pool of on-demand
reference files, some of which are grouped into hub+leaf directories. The
deliverable is the skill itself.

## Repository layout

```
plugins/auth0/skills/auth0/
├── SKILL.md # Required: the router (only file allowed in skill root)
├── references/ # Flat pool of on-demand docs, each reachable from SKILL.md:
│ # framework-<name>.md, feature-<name>.md,
│ # tooling-<name>.md, pattern-<name>.md (kebab-case)
├── references/ # On-demand docs, each reachable from SKILL.md. Every
│ # reference is a directory — framework-<name>/,
│ # feature-<name>/, tooling-<name>/, pattern-<name>/
│ # (kebab-case) — with an index.md that is either the
│ # whole reference (index-only) or a hub + document-
│ # section leaves (leaf group).
├── scripts/ # Optional: executable helpers
└── assets/ # Optional: static resources (templates, data)

Expand All @@ -42,12 +46,14 @@ Key top-level docs:
1. Read [`CONTRIBUTING.md`](./CONTRIBUTING.md). The conventions there are
enforced and not optional.
2. Match the patterns of the existing reference files rather than inventing new
structure. The flat naming convention (`framework-<name>.md`,
`feature-<name>.md`, `tooling-<name>.md`, `pattern-<name>.md`) and the
router-in-`SKILL.md` layout exist on purpose — keep them consistent. Every
new reference file must be reachable from `SKILL.md` and must not link to
another reference file (the one-hop rule, enforced by
`scripts/check_router_reachability.py`).
structure. The naming convention (`framework-<name>`, `feature-<name>`,
`tooling-<name>`, `pattern-<name>`) and the router-in-`SKILL.md` layout
exist on purpose — keep them consistent. Navigation is a **depth-2 tree**:
every reference must be reachable from `SKILL.md`; an index-only `index.md`
or a group leaf must not link to any other `.md`; the only allowed second hop
is a leaf-group hub `index.md` dispatching to leaves in its own directory.
Enforced by `scripts/check_router_reachability.py`. See CONTRIBUTING.md →
"Adding a reference" before splitting a large one into a leaf group.

## Required SKILL.md frontmatter

Expand Down
73 changes: 64 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,25 @@ All Auth0 guidance ships in the single `auth0` skill
for why. To add or change coverage:

### Pick the right reference prefix
- `feature-<name>.md` — a capability spanning frameworks (e.g. mfa, dpop).
- `framework-<name>.md` — a single SDK/framework integration.
- `tooling-<name>.md` — a provisioning tool (cli, mcp, terraform).
- `pattern-<name>.md` — cross-cutting guidance.
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 file in `references/` MUST be reachable from `SKILL.md`, and no reference
file may contain a link to any `.md` file (reference files are self-contained —
inline the content instead of linking, since Claude Code follows only one hop
from the router).
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`.
Expand All @@ -158,12 +167,58 @@ from the router).
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 makes `framework-<slug>.md` reachable — there is no
`<slug>` in a table makes `framework-<slug>/index.md` reachable — 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.md` is 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`, not `mfa`).
A "Then, as needed" list of `Read:` bullets makes the secondary leaves
reachable. Every leaf must appear in at least one `Read:` 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.json` with the two-hop
`expect_refs` (`<name>/index.md` + the intent leaf [+ tooling]), and move the
slug from the index-only presence check in `validate-skill.sh` to 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
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
```
27 changes: 16 additions & 11 deletions PLUGIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,25 @@ pool**:
loads the 2–3 matching reference files. Routing is file-based and
deterministic (it reads `package.json`, `composer.json`, `go.mod`,
`*.csproj`, `pubspec.yaml`, etc.), not a model guess.
- `references/` is a flat pool of self-contained Markdown files:
- `feature-*.md` — a capability spanning frameworks (MFA, Organizations,
- `references/` is a pool of on-demand Markdown docs. Every reference is a
directory `<stem>/` with an `index.md` — either the whole reference
(index-only) or, once a reference grows large, a hub `index.md` +
document-section leaves (leaf group):
- `feature-*/` — a capability spanning frameworks (MFA, Organizations,
custom domains, ACUL, branding, migration, DPoP).
- `framework-*.md` — one SDK/framework integration (React, Next.js, Vue,
- `framework-*/` — one SDK/framework integration (React, Next.js, Vue,
Nuxt, Angular, Express, Flask, FastAPI, Spring Boot, Go, Swift, Android,
Flutter, Laravel, PHP, ASP.NET Core, React Native, Expo, Ionic, .NET MAUI,
WinForms, WPF, and more).
- `tooling-*.md` — CLI / MCP / Terraform.
- `pattern-*.md` — cross-cutting guidance (security, token handling,
- `tooling-*/` — CLI / MCP / Terraform.
- `pattern-*/` — cross-cutting guidance (security, token handling,
multi-tenant, rate limiting, common errors).

One skill means one `description` competing for activation, and reference files
never link to each other (the router loads them in one hop). See
[`docs/architecture.md`](./docs/architecture.md) for the full rationale, routing
flow, and the CI-enforced reachability invariant.
One skill means one `description` competing for activation. Navigation is a
depth-2 tree: an index-only `index.md` or a leaf-group leaf links to nothing, and
the only second hop is a leaf-group's hub `index.md` dispatching to a leaf in its
own directory. See [`docs/architecture.md`](./docs/architecture.md) for the full
rationale, routing flow, and the CI-enforced reachability invariant.

---

Expand All @@ -70,8 +74,9 @@ auth0/agent-skills/
│ └── skills/
│ └── auth0/ # The single unified skill
│ ├── SKILL.md # Router (intent → framework → tooling)
│ ├── references/ # Flat pool: feature-*, framework-*,
│ │ # tooling-*, pattern-* .md files
│ ├── references/ # feature-*/, framework-*/, tooling-*/,
│ │ # pattern-*/ — every <stem>/ has index.md
│ │ # (index-only or hub + leaves)
│ ├── assets/ # Templates (e.g. ACUL screens)
│ └── scripts/ # validate-skill.sh, reachability check
├── docs/
Expand Down
47 changes: 34 additions & 13 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,40 @@
- Routing is **file-based and deterministic**: the router reads `package.json`,
`composer.json`, `go.mod`, `*.csproj`, `pubspec.yaml`, etc. — code-driven, not
a model guess.
- **No reference file links to any `.md` file.** Claude Code loads the router,
then the files it names — one hop. Links between references (or to now-deleted
sub-files) are not guaranteed to be followed, so all detection and navigation
logic lives in `SKILL.md`, and reference files are self-contained.
- **Navigation is a depth-2 tree.** Claude Code loads the router, then the files
it names. Every reference is a directory `<stem>/` with an `index.md`. An
**index-only** reference puts its whole content in `index.md` (one hop from the
router, no leaves). A large reference is a **leaf group**: `index.md` is a hub
(shared prerequisites + an intent→leaf dispatch table) over document-section
leaves. For a leaf group the router reads `index.md`, whose imperative `Read:`
dispatch sends the agent to exactly one leaf — two hops. A hub may dispatch
**only** to leaves in its own directory; leaves and index-only `index.md` files
link to nothing (they are sinks); cross-group links are forbidden. All
framework/tooling detection still lives in `SKILL.md`. Leaf groups exist so a
large reference doesn't force the agent to load the whole file when it needs
one section's worth.

## Structure
`plugins/auth0/skills/auth0/`
- `SKILL.md` — the router (intent → framework → tooling → load).
- `references/feature-*.md` — a capability spanning frameworks (mfa,
- `references/feature-*/` — a capability spanning frameworks (mfa,
organizations, custom-domains, acul, branding, migration, dpop).
- `references/framework-*.md` — one SDK/framework integration.
- `references/tooling-*.md` — cli / mcp / terraform.
- `references/pattern-*.md` — cross-cutting guidance (security, token-handling,
- `references/framework-*/` — one SDK/framework integration.
- `references/tooling-*/` — cli / mcp / terraform.
- `references/pattern-*/` — cross-cutting guidance (security, token-handling,
multi-tenant, rate-limiting, common-errors).
- `assets/` — templates (e.g. ACUL screen templates).
- `scripts/validate-skill.sh` — local structure + routing gate.

Every `framework-*`, `feature-*`, `tooling-*`, and `pattern-*` reference is a
directory of the same stem (e.g. `framework-swift/`, `feature-branding/`)
containing an `index.md`. An **index-only** reference has just `index.md`; a
**leaf group** — when the content is large enough to split — adds document-
section leaves (`integrate.md`, `api-reference.md`, `patterns.md`, `setup.md`,
`migration.md`, …) alongside a hub `index.md`. The router routes to the stem
either way; it always lands on `index.md`, which either *is* the content or
dispatches to the leaf the task needs.

## Routing flow
1. **Intent** — what the developer wants (integrate, feature:*, guidance, debug,
migrate).
Expand All @@ -33,11 +50,15 @@
4. **Load** 2–3 reference files and follow them.

## Reachability invariant (CI-enforced)
`scripts/check_router_reachability.py` asserts every `references/*.md` is
routable from `SKILL.md` (via template expansion over the known framework and
tooling value sets) and that no reference file contains an intra-references
`.md` link (existing target or dead). This runs in the `skillsaw` GitHub Actions
workflow and inside `validate-skill.sh`.
`scripts/check_router_reachability.py` asserts the depth-2 tree holds: every
reference directory is routable from `SKILL.md` (via template expansion over the
known framework and tooling value sets) and has an `index.md`; every leaf-group
leaf is reachable from that hub's dispatch; no route points at a missing file;
and the only second-hop links allowed are a hub `index.md` dispatching to leaves
**in its own group** — index-only `index.md` files and leaves may contain no
intra-references `.md` link (existing target or dead), and cross-group links are
forbidden. This runs in the `skillsaw` GitHub Actions workflow and inside
`validate-skill.sh`.

To add or extend a capability, see
[CONTRIBUTING.md](../CONTRIBUTING.md#adding-a-capability-to-the-unified-skill).
Loading