35 Commits

Author SHA1 Message Date
Garen Torikian e5b8d82641 Add WorkOS MCP setup and recovery guidance (#39)
* feat(workos): add MCP setup recovery guidance

* fix(workos): scope MCP recovery guardrail and add MCP eval coverage

Narrow the MCP-recovery guardrail so it only applies when the user wants
MCP or a configured server is broken, instead of diverting intentional
CLI workspace-management requests away from the supported CLI fallback.

Add eval cases covering direct Codex MCP recovery and a management
request with MCP intentionally absent, so regressions in the new
first-match MCP route surface as negative deltas.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(workos): defer MCP specifics to docs

* test(workos): add MCP setup and scope-selection eval case

The MCP route covered recovery (mcp-codex-startup-interrupted) and the
no-MCP management fallback (mcp-management-cli-no-mcp), but nothing
exercised first-time setup or the user-global vs per-repo scope decision
that references/workos-mcp.md guards.

Expectations are pinned to the shipped CLI rather than memory: workos/cli
src/commands/mcp.ts exposes install|remove|status, and src/lib/mcp-clients.ts
installs the Claude Code server at --scope user because the management MCP is
account-level.

Anti-patterns and hallucinations are drawn from the failure both arms
actually produced on a live run: a fabricated stdio server
({"command": "workos"}) written into a Claude Desktop config path. The case
currently scores ~77/76 (delta +1) — it detects the failure, but the skill
does not yet prevent it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(workos): restore load-bearing MCP anchors in the reference

7671643 deferred every MCP specific to the docs. When the docs are
unreachable the model has nothing to fall back on, so it invents: both eval
arms of mcp-setup-client-scope produced a local stdio server
({"command": "workos"}) written into a Claude Desktop config path, and both
still scored ~90 because the composite gives full credit for the empty
methods/imports/params/envVars dimensions.

Restore the two facts that failure hinged on — the server is remote HTTP at
https://mcp.workos.com/mcp with OAuth and no API key, and the workos CLI
configures it via mcp install|remove|status — and scope guardrail 1 so
everything else still defers to the docs.

mcp-setup-client-scope: 76% without / 91% with, delta +15%. Hallucinated
method and security issue both drop to zero in the with-skill arm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(workos): score the MCP scope step on substance, not a flag

The step asked for `--scope user`, a flag the endorsed CLI path never
surfaces — `workos mcp install` sets it internally. Worse, the matcher's
1-of-2 keyword fallback let a bare "user" anywhere in the output satisfy it,
so the without-skill arm collected credit for guessing a config location it
had otherwise gotten wrong.

Ask instead for user scope plus the account-level reason, which needs 2 of 3
keywords co-occurring. Replayed against the previous run's transcripts:
without-skill flow drops 0.50 -> 0.20, with-skill holds at 0.53.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: add lint-pr-title workflow

Enforces conventional-commit PR titles via
amannn/action-semantic-pull-request, matching the
conventional commit style this repo already follows.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 14:10:55 -04:00
Nick Nisi 2f57863afe feat: add FGA, Pipes, Feature Flags, and Radar references + evals (#19)
* feat: add FGA, Pipes, Feature Flags, and Radar reference files and evals

Close coverage gaps for four WorkOS products that had no reference files
or routing in the skill router.

New reference files (references/*.md):
- workos-fga.md — Fine-Grained Authorization (new API, not legacy warrants)
- workos-pipes.md — Pipes / Connected Apps (OAuth integrations)
- workos-feature-flags.md — Feature Flags (access token claims)
- workos-radar.md — Radar (bot/fraud detection)

New eval cases (scripts/eval/cases/*.yaml):
- fga.yaml (5 cases), pipes.yaml (4 cases),
  feature-flags.yaml (4 cases), radar.yaml (4 cases)
- Total cases: 42 → 60

Skill router updates (SKILL.md):
- Added 4 rows to Features routing table
- Updated frontmatter description to trigger on new products
- Expanded routing decision tree with new product slugs
- Added FGA vs RBAC disambiguation

Eval results (2-sample, Sonnet):
- Pipes: +21% avg delta (strongest new product)
- FGA: +11% avg delta
- Radar: +10% avg delta (after blocklist case fix)
- Feature Flags: ~+1% avg delta (model already knows most of this)
- No regressions in existing products

* fix(workos): correct feature-flags and pipes reference inaccuracies

Feature flags: clarify that the SDK exposes management APIs
(addFlagTarget, removeFlagTarget, enableFeatureFlag, disableFeatureFlag),
not just runtime evaluation via token claims. The previous gotcha and
matching eval case incorrectly treated all targeting as Dashboard-only,
which would have rejected correct API-based solutions.

Pipes: distinguish the Node SDK response shape (camelCase accessToken
on a discriminated union) from the raw REST payload (snake_case
access_token). Update pipes-node-get-token flow steps to branch on the
active boolean instead of probing fields that only exist on one branch.

Verified against workos-node source for both modules.

* fix(eval): tighten feature-flags-node-refresh antipatterns

Previous antipatterns ("poll a feature flags API", "invalidate cache")
were too vague to catch the actual wrong approach: implementing a
custom in-memory cache with TTL instead of refreshing the session
token. Tightened to four explicit antipatterns that match the failure
mode observed in the without-skill transcript.

* fix(workos): correct Next.js helper, add namespace gotchas for FGA and Radar

Three quality issues caught while reviewing reference files against eval
transcripts and SDK source:

1. feature-flags: AuthKit Next.js exposes flags via `withAuth()`, not
   `getUser()`. Soften the loadSealedSession prohibition — the README
   doesn't actually forbid it, just doesn't surface it. Updated the
   feature-flags-nextjs-check eval case to match.

2. fga: Add explicit gotcha that SDK methods live under
   `workos.authorization.*`, NOT `workos.fga.*`. Eval transcripts show
   the model inventing `workos.fga.assignRole` despite the product being
   called FGA — verified workos-node has no `fga` directory under src/.

3. radar: Add explicit gotcha that there is NO `workos.radar.*`
   namespace at all. Verified workos-node has no radar directory.
   The standalone Radar API is direct-HTTP only.
2026-04-26 22:20:22 -05:00
Nick Nisi 5ce9743e49 feat(workos): add CLI upgrade-path topic and tarball smoke test (#26)
* feat(workos): add CLI upgrade-path topic and tarball smoke test

Closes the loop on a customer friction case where claude diagnosed an
outdated `workos` CLI but had no skill content telling it how to
recommend an upgrade. Adds:

- `references/workos-cli-upgrade.md`: router-style reference covering
  npm/pnpm/yarn install commands plus the `npx workos@latest` no-install
  fallback. Includes explicit guardrails against fabricating "the
  latest version" — instructs the agent to run `npm view workos version`
  rather than reproduce a number from memory.

- `SKILL.md`: new row in the topic→reference map and a Rule 6 sub-case
  routing outdated-CLI symptoms (old `--version`, `unknown command`
  after following recent docs) to the new reference.

- `references/workos-management.md`: "Detecting and recommending CLI
  upgrades" subsection right after the "what the CLI can do" section,
  so agents reaching for `workos --help --json` also consider whether
  the user is just on an old version.

- `evals/evals.json` (id 11, `cli-upgrade-recommendation`): asserts the
  agent points users at `npm view workos version`, provides a concrete
  upgrade command using `@latest`, and does not pin to a fabricated
  version number.

- `scripts/smoke-test-tarball.sh` + `release.yml` step: pnpm-packs the
  package, extracts it, and asserts a hardcoded canary list of skill
  files is present. Catches the failure mode where `references/` stops
  shipping in the published tarball — a silent break for downstream
  consumers (CLI auto-install) that Read these files at runtime.

* fix(workos): align CLI upgrade topic with file conventions and drop yarn

Address Devin review feedback on PR #26:

* Restructure `workos-cli-upgrade.md` to match the convention used by
  every other topic file in `references/`: `# Title` directly into
  `## Docs`, then URL list, then the standard "If this file conflicts
  with fetched docs, follow the docs." line. The "Use this when..."
  intro paragraph moves to after the boilerplate.

* Restore the standardized boilerplate verbatim ("If this file conflicts
  with fetched docs, follow the docs.") instead of the bespoke
  "...published release notes, follow the release notes." variant. The
  exact phrasing is what consumers / the LLM at runtime use to identify
  the authoritative source.

Drop yarn from the upgrade-path content per maintainer preference:

* Remove the two yarn rows from the upgrade-commands table; npm and
  pnpm only, with `npx workos@latest` as the no-install fallback for
  anyone on a different package manager.
* Drop yarn from the management subsection's mention of supported
  package managers.
* Drop the two yarn needles from the eval entry's positive-assertion
  list (it's `content_contains_any`, so the assertion still passes
  on any of npm/pnpm/npx; yarn was just unreachable noise).

Other yarn references in the repo (authkit-sveltekit, node, etc.) are
about installing `@workos-inc/*` SDK packages, not the WorkOS CLI —
out of scope for this change.
2026-04-26 15:44:03 -05:00
Nick Nisi dc9dfb093c fix(workos): tighten auth guidance and risky eval reruns (#25)
* fix(workos): include required --org flag in portal generate-link examples

The "Not in the CLI" table in workos-management.md listed
`workos portal generate-link --intent=sso` and
`workos portal generate-link --intent=dsync` as the correct way to
reach the Admin Portal for connection creation. Both omit the
required --org flag and fail before opening the Portal. This is the
same hallucination shape the PR is trying to prevent agents from
producing — caught in review.

Add --org=<org_id> to both rows, matching the Quick Reference
entry at the top of the file.

* test(workos): tighten no-CLI assertion in connection-create evals

The first assertion in evals 8 and 9 was titled "States connection
creation is NOT in the CLI" but its needles included Admin Portal
and WorkOS Dashboard. An answer that only said "Use the Admin
Portal" without ever stating CLI support is absent passed the
assertion. Since the second assertion in each eval already checks
for the Admin Portal/Dashboard destination, the first was both
redundant and weakened.

Remove destination terms from the first assertion so it genuinely
checks for the explicit no-CLI signal.

* test(workos): improve risky eval coverage

Add targeted recipes for SSO, AuthKit, and RBAC cases that showed negative or noisy eval deltas. Tighten brittle flow-step expectations where the previous wording rewarded incidental prose ordering instead of the intended behavior.

Add multi-case eval filtering and an eval:risk helper so the latest triage cases can be rerun with more samples and saved outputs.

* Fix explicit triage handling in risk reruns

* fix: format:check script incorrectly using prettier

* chore: format files for oxfmt check
2026-04-26 09:06:35 -05:00
Nick Nisi c66e0d04c6 feat(workos): add terminology reference for docs URL lookups (#21)
* feat(workos): add terminology reference for docs URL lookups

New `references/workos-terms.md` maps WorkOS-specific terms
(Sign-in endpoint, initiate_login_uri, Redirect URI, Organization ID,
Admin Portal intent, JWKS, Sealed session, WORKOS_COOKIE_PASSWORD, etc.)
to canonical docs URLs. 10 seed rows, all URLs verified via WebFetch.

Router gains **Rule 0** for lookup-shaped queries ("what is X",
"docs URL for X") with explicit anti-triggers against setup phrasing
("set up Vault", "enable Admin Portal") so feature-setup requests
still route to Rule 3.

SKILL.md tightening:
- Frontmatter description shortened to ~485 chars, terminology-first
- How-to-Use rewritten as imperative MUST, not advisory
- llms.txt prohibition scoped to Rule 0 (Rules 7/8 still use it
  for vague/no-match cases)
- "suggest open a PR" rather than "add a row" (agents can't persist
  edits across sessions reliably)

New eval cases (`scripts/eval/cases/terminology.yaml`):
- terms-initiate-login-uri
- terms-sign-in-endpoint

Fixes the failure mode where agents fetched llms.txt blind on
"what is X" queries instead of using curated references.

* test(workos): add skill-creator eval harness + prompt/assertion spec

Adds `plugins/workos/skills/workos/evals/evals.json` — four realistic
terminology lookup prompts with assertion-level grading (content-contains-any/all/none
checks including explicit anti-pattern URLs the agent should NOT invent).

Complements the existing substring-based `scripts/eval/cases/terminology.yaml`:
the assertion format catches failure modes that flowStep substring matching
misses (e.g., "does the answer mention 'Dashboard' AND 'Redirects'",
"does it avoid inventing `/docs/initiate-login-uri`").

Workspace outputs under plugins/**/*-workspace/ are gitignored — iteration
results are ephemeral, only the spec is committed.

Iteration 1 result (4 evals × 2 arms, graded via grade.py):
  With skill:    100% (17/17 assertions)
  Without skill: 77.5% (13/17)
  Delta:         +22.5%

* chore: gitignore skill-creator eval workspaces
2026-04-20 16:08:04 -05:00
Nick Nisi 21853e2cd5 fix: harden Next.js AuthKit skill against Server Component cookie violations (#13)
* fix: harden Next.js AuthKit skill against Server Component cookie violations

- Rewrite Step 8 UI Integration with explicit NavAuth client component
  pattern using useAuth() + refreshAuth({ ensureSignedIn: true })
- Add useAuth import from @workos-inc/authkit-nextjs/components
- Warn against raw getAuthorizationUrl() usage (returns object, not string)
- Add error recovery sections for [object Object] and OAuth state mismatch
- Add verification checks for unsafe auth URL patterns
- Add anti-pattern checks to authkit-nextjs-protected eval case
- Add authkit-nextjs-nav-auth-pkce regression eval case
- Add scorer regression test (broken: 59, fixed: 98)

Addresses Alexander Southgate's friction log: getSignInUrl() in Server
Components, [object Object] redirect, and PKCE state mismatch.

* chore: formatting
2026-03-31 15:11:27 -05:00
Nick Nisi f8a36b452a feat: consolidate all skills into single-source references (#6)
* feat: consolidate all skills into references with single router entry point

Move all 17 CLI skill files (AuthKit frameworks, backend SDKs, management)
into references/ as the single source of truth. Delete 6 AuthKit skill
directories — CLI canonical versions replace them entirely.

- Add 17 new reference files from CLI (authkit-*, node, python, dotnet,
  go, ruby, php, php-laravel, kotlin, elixir, sveltekit, management)
- Delete workos-authkit-{base,nextjs,react,react-router,tanstack-start,
  vanilla-js} skill directories
- Update router (workos/SKILL.md) with progressive disclosure for all
  references: AuthKit frameworks, backend SDKs, language detection,
  management
- Add ESM package entry point (plugins/workos/index.ts) exporting
  getReferencePath, getSkillsDir, getSkillPath helpers
- Add exports field to package.json
- Simplify eval runner — all skills now load from references/
- Remove dead HAND_CRAFTED_SKILLS constant

Only 2 registered skills remain: workos (router) and workos-widgets.
Everything else is a reference file dispatched by the router.

* chore: remove AGENTS.md

* docs: add Do/Don't and PR checklist to CLAUDE.md

* docs: rewrite README for consolidated architecture and npm usage

* feat: add async getReference/getSkill helpers to package exports

* chore: add release-please with version sync for plugin.json

Configure release-please to bump versions in package.json,
plugin.json, and marketplace.json together. Uses extra-files
with jsonpath to keep all three in sync on each release.

Also syncs plugin.json and marketplace.json to 0.1.0 to match
the current package.json version.
2026-03-07 15:17:42 -06:00
Nick Nisi 059fc5deda Replace generation pipeline with lean topic files (doc URLs + gotchas) (#5)
* feat: add lean topic files for skills simplification (phase 1)

Replace generated 7-11KB guides with ~30-line topic files containing
doc URLs + extracted gotchas. Evals showed the real value comes from
"fetch docs first" directives and encoded traps, not the scaffolding.

22 topic files created alongside existing files (phase 2 will delete
old files and rename .topic.md → .md).

* feat: simplify skills — delete pipeline, replace guides with lean topic files (phase 2)

Delete the generation pipeline (scripts/generate.ts, scripts/lib/),
all guide files, summary files, API ref stubs, and feedback files.
Rename .topic.md → .md. Update router to point to new topic files.
Update CLAUDE.md and package.json.

113 files changed: +553 / -10,739 lines. The 7-11KB generated guides
are replaced by ~30-line topic files containing doc URLs + gotchas.
The eval framework showed these two things drive all the value.

Inline HAND_CRAFTED_SKILLS in eval runner (was importing from deleted
scripts/lib/config.ts). All 182 tests pass.

* fix: add implementation-level gotchas to directory-sync topic

Eval regression (-6.5% vs old pipeline avg) traced to missing
webhook handler pattern details. Added: verify→200→async ordering,
Ruby raw_post trap, and upsert idempotency pattern.
2026-03-07 10:09:18 -06:00
Nick Nisi 39269e0698 feat: add workos-widgets skill with on-demand OpenAPI spec querying (#4)
* Add claude skill to create WorkOS widgets

* Add guidelines about styling existing ui components and where to implement the widget

* Optimize some skills

* Add list of endpoints to fetching api docs

* fix: resolve widget skill conflicts and route to hand-crafted skill

- Delete hallucinated generated widget files (fabricated workos.widgets.mount() API)
- Route widget requests via Skill tool instead of generated references
- Add workos-widgets to HAND_CRAFTED_SKILLS, skip widgets in SECTION_CONFIG
- Move OpenAPI spec from always-loaded to on-demand in SKILL.md
- Add error response documentation to fetching-apis.md
- Add strip-openapi-spec.ts script and strip boilerplate (3375 → 2774 lines)
- Fix paths.spec.ts and splitter.spec.ts for new config

* feat: add on-demand OpenAPI spec query script

Replace always-loaded/stripped spec with a query script that extracts
just the endpoints and resolved schemas for a specific widget.

- Add references/scripts/query-spec.ts (--widget, --path, --list modes)
- Revert spec to original unstripped version
- Update SKILL.md to reference query script instead of raw spec
- Remove strip-openapi-spec.ts (no longer needed)

* feat: add query-spec tests and fix  resolution in arrays

- Add 36 tests for query-spec (resolveRef, resolveSchema, extractEndpoints,
  formatEndpoint, groupPathsByWidget, WIDGET_PREFIXES, integration)
- Fix resolveSchema to recursively resolve $refs inside arrays (oneOf, anyOf)
- Revert OpenAPI spec to original unstripped version
- Remove strip-openapi-spec.ts

* feat: bundle query-spec as self-contained .cjs for portability

- Add esbuild to bundle query-spec.ts → query-spec.cjs (includes yaml dep)
- Update SKILL.md to use 'node references/scripts/query-spec.cjs' (no tsx needed)
- Add build:query-spec script to package.json
- Fix __dirname resolution to support both ESM and CJS contexts

* chore: add .oxlintrc and ignore built file in it and oxfmt

* fix: point fetching-apis.md references to query script, remove redundant SKILL.md mention

* chore: remove unused strip-openapi-spec.ts

Superseded by the on-demand query-spec approach.

* fix: address final review findings

- token-strategies.md: point elevated access to fetching-apis.md markers
  instead of raw spec, use explicit verify endpoint path
- fetching-apis.md: update objective line, hardcode base URL fallback
  to https://api.workos.com instead of referencing spec
- query-spec.ts: add SKILL.md slug aliases (user-management,
  user-profile, admin-portal-sso-connection, admin-portal-domain-verification)
- query-spec.ts: update source comments to reference .cjs bundle
- Rebuild query-spec.cjs

---------

Co-authored-by: Lucas Motta <mail@lucasmotta.com>
2026-03-06 14:07:46 -06:00
Nick Nisi 874f809808 chore: formatting 2026-02-27 09:47:41 -06:00
Nick Nisi a66de91677 feat: add transcript diff view and calibration metrics
Transcript diff (pnpm eval:diff) shows with/without outputs with
ANSI-highlighted signals — green for matched methods, red for
hallucinations, yellow for anti-patterns.

Calibration (pnpm eval:calibrate) compares scorer ship/no-ship
decisions against human labels with 80% agreement gate integrated
into --fail-on-regression (requires 10+ labels to activate).
2026-02-27 09:09:30 -06:00
Nick Nisi 5004296b5b feat: add eval transcript tooling — triage report, review labels, save-all-samples
Triage report surfaces top 10 risky cases per run (negative delta,
high σ, hallucination regression). Review labels store enables
append-only human judgments in JSONL for scorer calibration.
--save-all-samples persists all N sample outputs for high-variance
case debugging.
2026-02-27 09:02:48 -06:00
Nick Nisi b420a3b5d1 feat: add --samples=N for eval variance measurement and improve scorer accuracy
Add multi-sample support to the eval framework: each case runs N times
with mean/stddev reported per case and per product. This distinguishes
real skill regressions from LLM non-determinism (e.g., authkit-nextjs-15-fix
confirmed at +34% δ with σ=0.5%).

Also adds negation-aware hallucination counting, transcript persistence
for manual review, and improved flow step matching with minimum
co-occurrence thresholds.
2026-02-27 08:41:59 -06:00
Nick Nisi 60969251e9 chore: add oxfmt/oxlint and apply formatting + lint fixes 2026-02-26 11:49:05 -06:00
Nick Nisi beee54aa35 feat: eval framework for measuring skill effectiveness (#3)
* refactor: port runtime from Bun to Node (tsx + vitest)

Replace Bun-specific APIs (Bun.file, Bun.write, Bun.sleep) with Node
equivalents (node:fs/promises, node:timers/promises). Swap test runner
from bun:test to vitest. Use tsx for TypeScript execution without a
build step.

* docs: use pnpm in CLAUDE.md command examples

* feat: add eval harness for measuring skill effectiveness

A/B testing framework that runs identical prompts with and without
skill content, scoring outputs against expected signals (methods,
env vars, imports, flow steps, hallucinations). Answers whether
skills actually improve Claude's code generation quality.

- Deterministic scorer (100-point scale, 30 unit tests)
- Content-addressed response cache (SHA-256 keyed)
- Console table + JSON report output
- CLI: bun run eval [--product, --case, --dry-run, --no-cache]

* feat: add eval test cases, fix scorer false positives, tune generation pipeline

Eval harness phase 2: 12 YAML test cases across 5 products (SSO,
AuthKit/Next.js, DSync, Audit Logs, RBAC) with concurrent execution.

Pipeline fixes based on eval findings (SSO was -5% delta):
- Scorer: negation-aware anti-pattern matching (isNegated, 30-char lookback)
- Refiner: hard 150-line cap, implementation-level decision trees, bash verification
- Refiner: MAX_TOKENS 4096 for feature guides (was 8192)
- Template: cap scaffold extraction at 30 lines, skip non-actionable headings
- Quality gate: reverse size scoring (reward ≤4KB), bash/decision-tree bonuses

Results: SSO delta moved from -5% to +1%, no skills with negative delta.

* refactor: regenerate all skills with leaner pipeline

Full regeneration with updated refiner prompts (150-line cap,
implementation-level decision trees, bash verification commands)
and trimmed template scaffolds.

Net -1,769 lines across 64 skills. Guide sizes reduced toward
3-6KB range. 62/64 passing quality gate (same 2 persistent
standalone-sso-api semantic failures as before).

* fix: eval scorer false positives for anti-patterns and flow ordering

- Add isInEnvBlock() guard to skip anti-pattern matches inside .env
  blocks and placeholder values (fixes sk_test false positive)
- Replace single-keyword indexOf in scoreFlowOrder() with proximity-
  based window search to prevent keyword collisions across sections
- Fix dead Related Skills cross-refs in 3 migration guides: point
  workos-organizations → workos-api-organization, remove non-existent
  workos-user-management refs

* chore: format codebase and refactor eval runner output

- Run prettier across all files
- Refactor eval runner to print results after batch completion
- Add HAND_CRAFTED_GUIDES protection to generate pipeline

* feat: add 5 SSO eval cases targeting skill-specific knowledge gaps

New cases test scenarios where LLMs fail without the skill guide:
- error-handling: error field check order, code expiry (+22% delta)
- domain-routing: domainHint param for email→IdP routing (+30%)
- social-login: provider param for Google OAuth via WorkOS (+30%)
- state-csrf: state="" edge case for IdP-initiated (+25%)
- python-basic: cross-language snake_case SDK coverage (+25%)

SSO eval: 3 cases → 8, avg delta 0% → +17%

* fix: correct domainHint misuse in SSO guide and eval cases

domainHint is a supplementary UX param (pre-fills domain field),
NOT a connection selector. The three mutually exclusive selectors
are: connection, organization, provider.

SSO guide changes:
- Add /docs/sso/guide and API reference to doc fetch list
- Rewrite decision tree: organization is the primary selector,
  app must map email domain to org_id itself
- Clarify domain_hint and login_hint as optional UX params
- Fix trap warning and error recovery references

Eval case changes:
- sso-node-domain-routing: expect organization param instead of
  domainHint, update flow steps and anti-patterns accordingly

SSO eval: 8 cases, avg delta +12% (down from +17% which included
false positive from rewarding wrong domainHint usage)

* fix: correct RBAC eval cases with verified expected signals

Old cases had wrong expected methods (getUser, singular
getOrganizationMembership) causing methodAccuracy=0 on both arms,
producing artificial 0% delta.

Fixed cases:
- check-permission: no SDK method (reads from session/JWT), expect
  permissions param and session-based flow
- role-assignment: listOrganizationMemberships + update (verified
  against WorkOS API reference)

New cases targeting RBAC-specific knowledge:
- permission-vs-slug: permission checks vs role slug checks
- idp-override: IdP group mapping silently reverts API assignments
- org-vs-env-roles: organization-level vs environment-level role scoping

Result: RBAC composite 69% → 96%, delta +1%. Low delta is genuine —
Sonnet 4.5 already knows RBAC well (100% on methods, params, env
vars, anti-patterns on both arms). Skill value is marginal for this
domain.

* feat: add dsync and audit-logs eval cases for broader coverage

Directory Sync (2 → 6 cases, +6% avg delta):
- directory-deleted: dsync.deleted cascade trap (0% delta — LLM knows)
- inactive-users: state:inactive vs user.deleted (0% delta — LLM knows)
- user-identity: email vs directory_user_id for matching (+4%)
- group-membership: group events and webhook verification (+7%)

Audit Logs (2 → 5 cases, +4% avg delta):
- event-naming: group.object.action convention (+5%)
- system-events: actor.type=system for automated actions (0%)
- admin-portal: self-service SIEM config via Admin Portal (+3%)

Both products confirmed as low-delta domains — LLMs already handle
these well. Skill value concentrated in webhook patterns (dsync +29%)
and Dashboard-specific config (audit-logs log-streams +10%).

* feat: add importAccuracy scoring, invocation-aware method matching, and fix error categories

- Add importAccuracy as new ScoreCard dimension (weight 10, redistributed
  from methods 25→20 and flow 25→20)
- Add methodRatioFound with 4-pass matching: full invocation → last-segment
  invocation → full substring → last-segment substring
- Fix wrong_params error category to check params instead of methods
- Add missing_method error category for missing expected methods
- Consolidate system prompt construction in runner.ts, remove redundant
  prompt building from api.ts
- Add 12 new tests (62 total, up from 50)

* feat: add Python and Ruby eval cases for all 5 products

12 new cases (6 Python + 6 Ruby) covering SSO, RBAC, Directory Sync,
Audit Logs, and AuthKit. Tests SDK-specific method names, imports, and
conventions per language. Total eval cases: 39 (up from 27).

* feat: add reporting distributions, language breakdown, CLI flags, and regression gates

- Add --lang flag to filter cases by language (python, ruby, node)
- Add --report flag to control output format (table, json, both)
- Add --fail-on-regression flag with hard gates: no negative product
  delta, hallucination reduction >= 50%
- Add median/p80/min/max delta to ProductSummary
- Add per-language breakdown to report output
- Add error reduction table (both-arm error categorization)
- 20 new reporter tests (201 total tests)

* feat: add CI wrapper script, skill content hash, and eval runbook

- Add scripts/eval-ci.sh for CI environments (env validation, gates enabled)
- Add skillHash to EvalReport JSON for cache provenance (SHA-256 of
  loaded skill file contents)
- Add eval framework runbook to CLAUDE.md with commands, interpretation,
  and troubleshooting

* fix: correct Ruby SDK method names and SSO state anti-pattern false positive

- Fix WorkOS::SSO.get_authorization_url → authorization_url (Ruby SDK
  doesn't use get_ prefix) in 2 SSO Ruby cases
- Fix WorkOS::UserManagement.get_authorization_url → authorization_url
  in authkit-ruby case
- Tighten SSO state-csrf anti-patterns to avoid matching conditional
  advice ("skip state verification when state is empty string")

* fix: anti-pattern index mismatch, unbounded 429 retry, and JSDoc errors

- Fix negationAwareRatioFound index drift: search lowerOutput first
  (aligned indexes) before falling back to normalized match. Prevents
  false positive anti-pattern detection after camelCase content.
- Cap 429 retries at 3 with linear backoff (was unbounded recursion)
- Fix JSDoc: "Three-pass" → "Four-pass", "60 chars" → "30 chars"
- Remove unused RATE_LIMIT_DELAY_MS constant

* feat: add 3 Ruby SSO edge cases and fix state-csrf flow step volatility

- Add sso-ruby-idp-initiated: IdP-initiated empty state handling
- Add sso-ruby-error-handling: invalid_grant and consent denied
- Add sso-ruby-domain-routing: email domain to organization routing
- Remove volatile "skip state verification" flow step from state-csrf
  case — was causing -18% swings due to output structure variance when
  skill elaborates on the IdP-initiated exception

* fix: align state-csrf case expectations with prompt intent and fix Ruby method in guide

- Remove getAuthorizationUrl from state-csrf expected methods — prompt
  asks about callback CSRF handling, not auth URL generation. Was
  penalizing focused expert answers (-20% delta).
- Simplify flow steps to match callback-focused prompt
- Fix Ruby Quick Checklist: get_authorization_url → authorization_url

* feat: add Ruby webhook example to dsync guide and relax Ruby method matching

- Add Rails webhook handler example to directory-sync guide with
  WorkOS::Webhooks.verify_event and signature error handling
- Accept construct_event as alternative method name in dsync-ruby case
- Fix anti-pattern wording: "no signature verification" → "skip
  signature verification"

* fix: replace Bun-specific APIs with Node equivalents

- Replace Bun.CryptoHasher with crypto.createHash in cache.ts
- Replace Bun.file/Bun.write with fs/promises readFile/writeFile
- Replace bun:test imports with vitest in eval test files
2026-02-26 10:22:53 -06:00
Nick Nisi 8b07190618 refactor: restructure to clean marketplace plugin pattern
Separate marketplace root from plugin root per Claude Code docs so only
the plugin directory gets cached on install, not the entire repo.

- Move skills/ → plugins/workos/skills/ (plugin root)
- Add plugins/workos/.claude-plugin/plugin.json (plugin manifest)
- Simplify marketplace.json to single plugin entry with source: "./plugins/workos"
- Remove per-skill plugin.json files (auto-discovery via skills/ directory)
- Remove obsolete scripts (build-plugin-manifests, sync-marketplace)
- Update all pipeline write paths, feedback loader, refiner, and tests
- Strip frontmatter from reference files
2026-02-23 16:51:53 -06:00
Nick Nisi 64e9eccb43 fix: strip frontmatter from reference files and fix plugin descriptions
Reference .md files with YAML frontmatter may interfere with plugin
skill discovery. Strip frontmatter from all reference files (they're
loaded via Read, not by the plugin system). Remove em dashes from
plugin descriptions. Update quality gate and templates to match.
2026-02-19 23:10:33 -06:00
Nick Nisi cde35113ab chore: formatting 2026-02-19 22:08:12 -06:00
Nick Nisi dc6c37ba86 refactor: move bundled skills into references/ subdirectory
Separates the SKILL.md router (entry point) from bundled reference
files. All file references now use `references/{name}.md` paths —
portable across any agent platform, no hardcoded install paths.

- Move 67 skill files from skills/workos/ to skills/workos/references/
- Update generator write paths and content references
- Update guide pointers, quality gate regexes, feedback loader
- Update all tests for new directory structure
2026-02-19 21:49:38 -06:00
Nick Nisi 78a61d6f4b Skill quality framework: progressive disclosure, feedback system, V2 improvements (#2)
* fix: correct dsync rule to acknowledge Events API polling

The dsync-webhooks-mandatory rule was enforcing the incorrect claim
that "webhooks are mandatory and polling is not supported." WorkOS
supports both webhooks (recommended) and the Events API for directory
sync events. Inverts the rule and updates skill content accordingly.

* feat: add feedback mechanism, content taxonomy, and quality gate evolution (Phase 1)

Replace rules-based refiner injection with markdown feedback files and content
taxonomy. Feedback files (`.feedback.md`) let domain experts provide corrections
in plain markdown. Quality gate now penalizes behavioral assertions without doc
deferrals and supports LLM semantic checks during --refine.

* feat: add directory sync feedback file for refiner guidance

Backfills the dsync domain corrections (Events API support, webhook
non-mandatory) that were previously injected via .rules.yml into the
new .feedback.md format consumed by the refiner.

* refactor: replace rules system with feedback files, promote semantic check (Phase 2)

Migrate all 5 .rules.yml files to .feedback.md format. Remove rules.ts,
rules.spec.ts, and SkillRule/RuleViolation types entirely. Semantic check
failures are now hard blocks in the quality gate during --refine runs.

* chore: run the new generation

* feat: parallelize refinement, fix --refine-only scoping

- Refine skills with concurrency 5 (~6x faster)
- Scope write phase to targeted skill when --refine-only is set,
  preventing accidental overwrite of other refined skills
- Scope quality gate to targeted skill when --refine-only is set,
  preventing false semantic check failures on unrefined scaffolds
- Strengthen standalone SSO API migration feedback

* feat: progressive disclosure — split skills into summary + guide

Each generated skill now produces two files:
- summary (.md, 1-2KB): when to use, key concepts, guide pointer
- guide (.guide.md, 8-16KB): implementation steps, verification, errors

Reduces context usage 60-80% for exploratory workflows. Agents load
summaries during exploration, guides only when implementing.

Adds summary-specific refiner prompt for key concepts extraction,
dual scoring in quality gate, and SUMMARY_VALIDATION size constraints.

* fix: add legacy scoring for single-file skills, bump summary limit to 5KB

Router and integration router have frontmatter but no type field — they
were being scored by scoreGuide() which penalizes frontmatter. Added
scoreLegacy() for untyped single-file skills. Bumped summary size limit
from 3KB to 5KB since the refiner consistently produces 3-5KB summaries.

* chore: regenerate skills with progressive disclosure (summary + guide)

32 summaries (2-5KB) + 32 guides (6-20KB) + router + integration router.
Summaries contain When to Use, Key Concepts, guide pointer.
Guides contain implementation steps, verification, error recovery.

* refactor: tune prompts — summaries as routing docs, guides as doc supplements

Summary refiner: strict routing-document framing. Hard rules against
verification commands, SDK methods, behavioral claims, decision trees,
and trap warnings in summaries. Target 500-1000 bytes. Key Concepts
renamed to Key Vocabulary (entity names + ID prefixes only, max 10).

Guide refiner: reframed as "value beyond docs." Don't restate what docs
say — add decision trees, trap warnings, verification commands, and
error recovery that docs don't provide. Target 80-150 lines. No SDK
method names (vary by language).

* chore: regenerate skills with lean routing summaries

Summaries now 1-1.7KB (down from 3-5KB). Key Vocabulary limited to
entity names and ID prefixes. No verification commands, SDK methods,
behavioral claims, or decision trees in summaries. Guides are leaner
too — 6-12KB focused on value beyond docs.

* fix: preserve Documentation section in summary refinement

The summary refiner prompt listed 4 sections but omitted Documentation,
causing the LLM to strip doc URLs during refinement. All summaries lost
15 quality gate points. Now lists 5 sections with Documentation as #2
and reinforces PRESERVE in the user prompt. Also removed dashboard
navigation paths from allowed vocabulary.

* chore: regenerate skills with doc URLs preserved in summaries

Summary scores jump from 85 to 95-100 now that Documentation section
is preserved through refinement. 60/64 pass quality gate.

* fix: tiered doc URLs, broader verification, smarter semantic check

Quality gate:
- 2 doc URLs now scores 15pts (was 10) for thin API domains
- Verification section with bash blocks accepted (not just checkboxes)
- Semantic check: feedback emphasis overrides taxonomy, agent-directed
  instructions (STOP, BLOCKING, MUST PASS) aren't behavioral claims

Refiner:
- Remove env vars (WORKOS_API_KEY etc) from allowed Key Vocabulary
- Exclude generic protocol concepts and behavioral claims from vocab

* chore: regenerate skills with cleaner vocab and fixed rubric

63/64 pass. Summaries have no env vars in vocabulary. API ref guides
now score 85+ with tiered doc URLs. Descope passes semantic check.

* feat: skill quality V2 — code examples, API ref stubs, leaner summaries, path tests

- Refiner: allow ONE language-agnostic SDK code example (10-25 lines) per feature guide
- Template: add renderApiRefStub() for deterministic ~500B API ref guide stubs
- Generator: route workos-api-* specs to stubs, skip refinement for them
- Quality gate: scoreApiRefStub() + code example bonus (+5pts) + summary scoring rebalance
- Summaries: drop Documentation section (lives in guide), target 400-600B, max 5 vocab
- Config: SUMMARY_VALIDATION.maxSize 5KB→2KB
- Tests: path resolution integration tests (guide pointers, router refs, Related Skills)

* chore: regenerate skills with V2 improvements

- Feature guides now include language-agnostic SDK code examples
- API ref guides replaced with lightweight stubs (0.5-1.3KB)
- Summaries trimmed (no Documentation section, max 5 vocab)
- 62/64 passing quality gate (standalone-sso + cognito semantic persist)

* fix: strengthen feedback for cognito + standalone-sso, re-refine

- cognito: clarified hash limitation is Cognito-side, WorkOS CAN import
  hashes. Fixed WORKOS_COOKIE_PASSWORD scope (all server-side AuthKit SDKs,
  not just Next.js). Now passing semantic check (90 + 80).
- standalone-sso: promoted terminology rule to Corrections, clarified
  WORKOS_COOKIE_PASSWORD scope. Semantic check still strict (accepted).
- 63/64 passing quality gate.

* chore: formatting

* docs: update README, CLAUDE, and AGENTS for progressive disclosure + V2

- README: replace stale commands, add progressive disclosure and feedback
  system sections, remove defunct domain rules and batch refine references
- CLAUDE: add summary/guide/stub/feedback file types, update conventions
- AGENTS: add two-step loading pattern, update file layout and skill patterns

* chore: fixes

* chore: delete .cursorrules
2026-02-19 19:45:26 -06:00
Nick Nisi 8c8f4e7039 refactor: move hidden docs under skills/workos/ directory
Hidden docs now live alongside the router that references them:
  skills/workos/SKILL.md              (router)
  skills/workos/workos-sso.md         (hidden doc)
  skills/workos/workos-sso.rules.yml  (domain rules)

Top-level skills/ is now clean: 7 directories only (router + 6 AuthKit).
Pipeline, rules loader, and manifest builder updated for new paths.
2026-02-11 19:52:21 -06:00
Nick Nisi b44267182e refactor: flatten hidden skills to files, consolidate to 7 exposed plugins
- Hidden skills (32) now live as `skills/{name}.md` flat files instead
  of `skills/{name}/SKILL.md` directories. Only registered skills (router
  + 6 AuthKit) keep the directory/SKILL.md convention.
- marketplace.json reduced from 44 to 7 plugin entries
- Router generator bakes in loading protocol: AuthKit via Skill tool,
  everything else via Read `skills/{name}.md`
- Rules files moved to `skills/{name}.rules.yml` (flat)
- Pipeline updated: generator, refiner, quality gate, rules loader,
  manifest builder all handle new flat file structure
- Full regeneration + refinement: 33/33 passing quality gate
2026-02-11 19:04:10 -06:00
Nick Nisi 48e9ede514 refactor: rename workos-router to workos
The entry-point skill is now just `workos` — cleaner name for the
master dispatcher. Updated all references in generator, refiner,
refine-batch, tests, README, AGENTS.md, and .cursorrules.
2026-02-10 08:30:49 -06:00
Nick Nisi 74b026019c fix: address root causes for 5 low-scoring skills
Refiner prompt fixes (systemic, survive regeneration):
- SDK method names: trust scaffold examples from docs, only block
  invented methods. Prevents over-correction that stripped real methods.
- Migration accuracy: distinguish source system vs WorkOS limitations
  (fixes Cognito "can't import hashes" false claim)
- Thin APIs: acknowledge thin-by-design skills, don't pad with invented
  content — add usage context instead
- Generic guides: compensate with more decision trees

Per-skill rules:
- workos-migrate-aws-cognito: hard-gate blocking "WorkOS cannot import
  password hashes" (factually wrong)
- workos-migrate-descope: rule requiring SDK method preservation
- workos-migrate-other-services: rule requiring decision tree coverage

Re-refined all 5 skills with improved prompts:
- aws-cognito: password hash contradiction eliminated
- api-widgets: doubled from 134 to 270 lines
- other-services: grew to 428 lines with more decision trees
- descope: WebFetch-first approach (reliable over hallucinated methods)
2026-02-10 07:00:11 -06:00
Nick Nisi d192b72052 feat: systemic pipeline fixes for quality, accuracy, and stability
Pipeline improvements (survive regeneration):
- Inject valid skill names into refiner prompts (prevents phantom refs)
- "Never write 'check docs for exact method'" attribution instruction
- "Never invent SDK method names" — use WebFetch URL instead
- Global quality gate check: flag skills with 3+ "check docs" deferrals
- Skip 4 thin/deprecated sections: magic-link, pipes, domain-verification,
  feature-flags (excluded from manifests, kept on disk)

Skill fixes:
- workos-authkit-base: converted to router-only (strip Step 4 fallback)
- All 32 remaining skills re-refined with improved prompts
- Zero phantom skill references in shipped skills
- "Check docs" count: vault 6→1, mfa 5→0, email 4→0

Ship count: 39 skills (down from 43 — dropped FGA, magic-link, pipes,
domain-verification, feature-flags)
2026-02-09 15:59:31 -06:00
Nick Nisi 80016d817e fix: improve 5 not-ship-ready skills to pass quality bar
- workos-authkit-base: rewrite from reference doc to procedural skill
  with framework detection, decision tree routing, verification commands
- workos-integrations: expand generator template with SAML/SCIM/OAuth
  setup steps, troubleshooting decision tree, 14-row error recovery table
- workos-migrate-aws-cognito: re-refine with attribution, add .rules.yml
  blocking WORKOS_COOKIE_PASSWORD and excessive "check docs" patterns
- workos-migrate-the-standalone-sso-api: re-refine with clear framing,
  add .rules.yml requiring "standalone/legacy/old SSO" terminology
- Fix pre-existing rules.spec.ts test for promoted dsync rule
2026-02-09 15:07:32 -06:00
Nick Nisi 78eb52f7b6 feat: add domain rules system and source attribution to refiner
Phase 2 — Domain rules:
- Add per-skill .rules.yml with must_contain/must_not_contain regex checks
- Graduated enforcement (warn by default, promoted: true = hard gate)
- Quality gate evaluates rules and reports violations
- Rules injected into refiner prompts so LLM knows constraints
- First rule: workos-directory-sync webhooks are mandatory
- 14 new tests for rule loading, evaluation, and severity logic

Phase 3 — Source attribution:
- All three refiner prompts now instruct LLM to only claim what's in docs
- Cite doc URLs for non-obvious claims, never hallucinate SDK methods
2026-02-09 12:44:35 -06:00
Nick Nisi a852248285 feat: add content-addressed locking to skill generation pipeline
- Add hasher module (computeSourceHash, parseMarker, shouldRegenerate)
- Embed source hash in marker: <!-- generated:sha256:HASH -->
- Refiner preserves hash, upgrades to <!-- refined:sha256:HASH -->
- Generator skips files with matching hash (0 writes on second run)
- Add --force flag to bypass locking
- Quality gate recognizes new marker format
- 15 new hasher tests, updated generator tests
2026-02-09 12:33:09 -06:00
Nick Nisi 91740064f8 feat: add API ref refine prompt, skip FGA, increase refiner token limit
- Add buildApiRefRefinePrompt() for API reference skill refinement
- Remove workos-api-* exclusion from generate.ts SKIP_REFINE
- Add API ref skills to refine-batch.ts GENERATED_SKILLS list
- Skip FGA section in config.ts (deprecated, may return later)
- Exclude FGA from manifest builder (EXCLUDE_FROM_MANIFEST)
- Increase refiner MAX_TOKENS from 4096 to 8192 (fixes truncated skills)
- Remove FGA from router description in generator template
- Add error recovery and verification to integrations template
2026-02-09 11:03:38 -06:00
Nick Nisi 8ca4bcca8f style: format codebase with prettier 2026-02-06 17:08:56 -06:00
Nick Nisi 251bdd9aa1 feat: improve router skill with disambiguation, detection priority, and refinement support
- Better description for skill matching
- Add disambiguation rules (feature vs API ref, AuthKit vs named feature)
- Fix framework detection order (most-specific first)
- Add router-aware refinement prompt in refiner.ts
- Remove workos-router from refiner SKIP set
2026-02-06 17:05:07 -06:00
Nick Nisi 76e4d8059c fix: restructure plugin manifests to match skills.sh marketplace pattern
- Remove monolithic root plugin.json
- Update marketplace.json with 44 individual plugin entries (matching Clerk pattern)
- Add per-skill .claude-plugin/plugin.json with name, description, keywords, category
- Add build-plugin-manifests.ts script for regenerating manifests from SKILL.md frontmatter
2026-02-06 13:04:09 -05:00
Nick Nisi 0e5c9ecbd7 feat: add API reference skills, quality gate, and re-refine all skills (Phase 3)
- API reference splitter: parses llms.txt reference URLs by domain, generates
  10 API-focused skills (sso, authkit, directory-sync, audit-logs, organizations,
  events, vault, roles, widgets, admin-portal)
- Quality gate: automated rubric scoring (frontmatter, markers, doc refs,
  structure, size) — all 38 skills pass
- Router updated to include API reference skills in topic map
- All 36 generated skills re-refined via Anthropic API
- 56 tests pass, 44 total skills (6 hand-crafted + 38 generated)
2026-02-06 12:57:02 -05:00
Nick Nisi d0b3d1ceb2 feat: add splitter, generator, and AI refiner pipeline with 28 generated skills
Build the Phase 2 skill generation pipeline:
- Splitter: parses llms.txt URL index, applies per-section split strategies
- Generator: transforms SkillSpecs into SKILL.md scaffolds with frontmatter
- Skill template: renders doc fetch, prerequisites, implementation, verification
- Refiner: two-pass LLM refinement via Anthropic API transforms doc prose into
  procedural agent instructions (decision trees, verification commands, error recovery)
- Batch refiner: parallel execution with configurable concurrency

Generated 28 skills (16 feature + 10 migration + 2 routers), all graded A/A-/B+/B
by skill-reviewer agents against the AuthKit gold standard. Hand-crafted AuthKit
skills untouched.
2026-02-06 12:42:49 -05:00
Nick Nisi 718badf413 feat: scaffold @workos-inc/skills package with parser, fetcher, and 6 AuthKit skills
Phase 1 of the WorkOS skills generator. Sets up the repo as a publishable
npm package compatible with skills.sh, copies 6 hand-crafted AuthKit
framework skills from the CLI repo, and builds the foundation for skill
generation from llms-full.txt.

- npm package: @workos-inc/skills with skills/ in files array
- Fetcher: downloads llms.txt/llms-full.txt with retry + local cache
- Parser: extracts 24-section tree from ## Name {#anchor} boundaries
- Validator: format guards that fail loudly on doc structure changes
- 18 passing tests (bun test)
2026-02-06 11:36:11 -05:00