@skill-graph/cli 0.5.7 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -3
- package/README.md +40 -14
- package/SKILL_GRAPH.md +2 -2
- package/bin/skill-graph.js +118 -2
- package/docs/ADOPTION.md +1 -1
- package/docs/PRIMER.md +6 -5
- package/docs/QUICKSTART-30MIN.md +2 -2
- package/docs/SKILL_AUDIT_CHECKLIST.md +1 -1
- package/docs/SKILL_METADATA_PROTOCOL.md +2 -2
- package/docs/_archived/marketplace-publication-priority-2026-05-18.md +1 -1
- package/docs/_drafts/0.5.8-release-prep.md +164 -0
- package/docs/field-reference.generated.md +1 -1
- package/docs/field-reference.md +2 -2
- package/docs/manifest-field-mapping.md +3 -3
- package/docs/marketplace-publication-queue.generated.md +2 -2
- package/docs/plans/scripts-roadmap.md +2 -2
- package/docs/positioning.md +88 -0
- package/docs/research/skill-comprehension-eval-research.md +5 -5
- package/docs/research/skill-demand-gap-roadmap-2026-05-16.md +215 -0
- package/docs/status.generated.md +48 -0
- package/examples/audits/context-graph/findings.md +59 -0
- package/examples/audits/context-graph/scorecard.md +22 -0
- package/examples/audits/context-graph/verdict.md +33 -0
- package/examples/evals/a11y.json +45 -13
- package/examples/evals/api-design.json +18 -5
- package/examples/evals/code-review.json +18 -5
- package/examples/evals/data-modeling.json +18 -5
- package/examples/evals/database-migration.json +18 -5
- package/examples/evals/debugging.json +37 -11
- package/examples/evals/dependency-architecture.json +18 -5
- package/examples/evals/design-system-architecture.json +18 -5
- package/examples/evals/error-tracking.json +18 -5
- package/examples/evals/event-contract-design.json +18 -5
- package/examples/evals/form-ux-architecture.json +18 -5
- package/examples/evals/framework-fit-analysis.json +18 -5
- package/examples/evals/graph-audit.json +55 -13
- package/examples/evals/information-architecture.json +18 -5
- package/examples/evals/interaction-feedback.json +18 -5
- package/examples/evals/interaction-patterns.json +18 -5
- package/examples/evals/layout-composition.json +18 -5
- package/examples/evals/lint-overlay.json +38 -11
- package/examples/evals/microcopy.json +18 -5
- package/examples/evals/observability-modeling.json +18 -5
- package/examples/evals/pattern-recognition.json +32 -9
- package/examples/evals/performance-engineering.json +18 -5
- package/examples/evals/refactor.json +41 -12
- package/examples/evals/semiotics.json +18 -5
- package/examples/evals/skill-infrastructure.json +32 -9
- package/examples/evals/skill-router.json +42 -13
- package/examples/evals/system-interface-contracts.json +18 -5
- package/examples/evals/task-analysis.json +18 -5
- package/examples/evals/testing-strategy.json +36 -11
- package/examples/evals/type-safety.json +251 -66
- package/examples/evals/visual-design-foundations.json +18 -5
- package/examples/evals/webhook-integration.json +18 -5
- package/examples/fixture-skills/README.md +47 -0
- package/examples/fixture-skills/comprehension-full/SKILL.md +79 -0
- package/examples/fixture-skills/minimal-capability/SKILL.md +51 -0
- package/examples/fixture-skills/with-grounding/SKILL.md +78 -0
- package/examples/fixture-skills/with-relations/SKILL.md +87 -0
- package/examples/skills.manifest.sample.json +1722 -446
- package/marketplace/README.md +1 -1
- package/marketplace/skills/a11y/SKILL.md +1 -1
- package/marketplace/skills/best-practice/SKILL.md +211 -0
- package/marketplace/skills/context-graph/SKILL.md +1 -1
- package/marketplace/skills/debugging/SKILL.md +1 -1
- package/marketplace/skills/graph-audit/SKILL.md +3 -1
- package/marketplace/skills/postgres-rls/SKILL.md +284 -0
- package/marketplace/skills/refactor/SKILL.md +1 -1
- package/marketplace/skills/skill-infrastructure/SKILL.md +2 -0
- package/marketplace/skills/skill-router/SKILL.md +3 -1
- package/marketplace/skills/testing-strategy/SKILL.md +1 -1
- package/package.json +3 -1
- package/scripts/__tests__/test-marketplace-export.js +6 -2
- package/scripts/__tests__/test-v3-1-alias-contract.js +3 -3
- package/scripts/build-status-doc.js +177 -0
- package/scripts/check-doc-drift.js +224 -0
- package/scripts/check-markdown-links.js +34 -4
- package/scripts/check-mirror-freeze.js +270 -0
- package/scripts/export-marketplace-skills.js +35 -6
- package/scripts/lib/audit-prompt-builder.js +3 -3
- package/scripts/lib/parse-frontmatter.js +2 -2
- package/scripts/skill-audit.js +7 -9
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: postgres-rls
|
|
3
|
+
description: "Guides agents implementing or auditing PostgreSQL Row Level Security in a multi-tenant SaaS codebase. Covers ENABLE+FORCE pairing, USING+WITH CHECK policies, view bypass via security_invoker, SET LOCAL for connection pool safety, superuser/owner bypass detection, and materialized view risks. Do NOT use for application-level authorization logic (use nextauth-patterns), non-PostgreSQL databases, or application query tier questions (use multi-tenancy-rls for orgQuery() usage)."
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: "Targets PostgreSQL 15+ with Neon serverless driver. The security_invoker view pattern requires PG15+. The SET LOCAL / set_config(key, val, true) pattern applies to any connection-pooled PostgreSQL setup. Core ENABLE+FORCE+USING+WITH CHECK rules are PG version-independent."
|
|
6
|
+
allowed-tools: Read Grep Glob Bash
|
|
7
|
+
metadata:
|
|
8
|
+
grounding: "{\"domain_object\":\"PostgreSQL Row Level Security implementation in Sales Hub\",\"grounding_mode\":\"repo_specific\",\"truth_sources\":[\"../sales-hub/apps/web/src/lib/db.ts\",\"../sales-hub/db/migrations/20260218_rls_hardening.sql\",\"../sales-hub/db/migrations/20260314_rls_expansion.sql\",\"../sales-hub/db/migrations/20260314_rls_with_check_and_security_invoker.sql\",\"../sales-hub/db/migrations/20260315_enable_rls_all.sql\"],\"failure_modes\":[\"security_leak\",\"incorrect_isolation\",\"missing_force_rls\",\"missing_with_check\",\"superuser_bypass\",\"connection_pool_context_leakage\",\"view_security_invoker_missing\"],\"evidence_priority\":\"repo_code_first\"}"
|
|
9
|
+
drift_check: "{\"last_verified\":\"2026-05-18\",\"truth_source_hashes\":{\"../sales-hub/apps/web/src/lib/db.ts\":\"d1d9988d1da4545c58f76b5f44dbd12d5323409b777920d31d5f496db31ad7cb\",\"../sales-hub/db/migrations/20260218_rls_hardening.sql\":\"b5fb6dc74e78a3fb7e77c669af4e4b4303a4e995eaf4993cb6bdcbe7bdca424f\",\"../sales-hub/db/migrations/20260314_rls_expansion.sql\":\"406e2c419b09a6866f10c508e4ff6dc1f7a1ee82b788c5e2515186561c30ffb5\",\"../sales-hub/db/migrations/20260314_rls_with_check_and_security_invoker.sql\":\"2edcb51debd4ab4e7306eb6f8908c7a725217b19962e1429728e911fc57e88fb\",\"../sales-hub/db/migrations/20260315_enable_rls_all.sql\":\"c8de6823684f84b54376284a3a51bb6b52e38acd4f5c29664be26e89e5d39570\"}}"
|
|
10
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.1.0\",\"type\":\"capability\",\"category\":\"engineering\",\"domain\":\"engineering/database-security\",\"scope\":\"codebase\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-05-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-05-18\\\\\\\",\\\\\\\"truth_source_hashes\\\\\\\":{\\\\\\\"sales-hub/apps/web/src/lib/db.ts\\\\\\\":\\\\\\\"d1d9988d1da4545c58f76b5f44dbd12d5323409b777920d31d5f496db31ad7cb\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260218_rls_hardening.sql\\\\\\\":\\\\\\\"b5fb6dc74e78a3fb7e77c669af4e4b4303a4e995eaf4993cb6bdcbe7bdca424f\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260314_rls_expansion.sql\\\\\\\":\\\\\\\"406e2c419b09a6866f10c508e4ff6dc1f7a1ee82b788c5e2515186561c30ffb5\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260314_rls_with_check_and_security_invoker.sql\\\\\\\":\\\\\\\"2edcb51debd4ab4e7306eb6f8908c7a725217b19962e1429728e911fc57e88fb\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260315_enable_rls_all.sql\\\\\\\":\\\\\\\"c8de6823684f84b54376284a3a51bb6b52e38acd4f5c29664be26e89e5d39570\\\\\\\"}}\",\"eval_artifacts\":\"none\",\"eval_state\":\"unverified\",\"routing_eval\":\"absent\",\"stability\":\"stable\",\"keywords\":\"[\\\\\\\"rls\\\\\\\",\\\\\\\"row-level-security\\\\\\\",\\\\\\\"postgres\\\\\\\",\\\\\\\"tenant-isolation\\\\\\\",\\\\\\\"org-id\\\\\\\",\\\\\\\"security-policy\\\\\\\",\\\\\\\"set-local\\\\\\\",\\\\\\\"view-bypass\\\\\\\",\\\\\\\"migration\\\\\\\",\\\\\\\"multi-tenant\\\\\\\",\\\\\\\"ENABLE ROW LEVEL SECURITY\\\\\\\",\\\\\\\"FORCE ROW LEVEL SECURITY\\\\\\\",\\\\\\\"security_invoker\\\\\\\",\\\\\\\"USING clause\\\\\\\",\\\\\\\"WITH CHECK\\\\\\\",\\\\\\\"superuser bypass\\\\\\\",\\\\\\\"orgQuery\\\\\\\",\\\\\\\"app.organization_id\\\\\\\",\\\\\\\"connection pool safety\\\\\\\",\\\\\\\"materialized view RLS\\\\\\\"]\",\"examples\":\"[\\\\\\\"adding RLS to a new table — what statements are required and in what order?\\\\\\\",\\\\\\\"auditing our existing RLS migrations for missing FORCE or WITH CHECK\\\\\\\",\\\\\\\"implementing a view on an RLS-protected table in PostgreSQL 15+\\\\\\\",\\\\\\\"debugging a cross-tenant data leak in a multi-tenant SaaS system\\\\\\\",\\\\\\\"ensuring connection pool context (SET LOCAL) does not leak tenant state between requests\\\\\\\",\\\\\\\"reviewing a migration that enables RLS to check for superuser and owner bypass risks\\\\\\\",\\\\\\\"verifying that materialized views over RLS tables are documented as security-sensitive\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"implementing application-level auth guards (requireAuth, requireOrgAuth) — use nextauth-patterns\\\\\\\",\\\\\\\"choosing when to use orgQuery() vs query() in application code — use multi-tenancy-rls\\\\\\\",\\\\\\\"implementing CSRF protection or webhook HMAC verification — use security-scanning\\\\\\\",\\\\\\\"designing the overall multi-tenant data architecture — use data-architect\\\\\\\",\\\\\\\"designing row-level access control in non-PostgreSQL databases\\\\\\\"]\",\"relations\":\"{\\\\\\\"adjacent\\\\\\\":[\\\\\\\"database-migration\\\\\\\",\\\\\\\"security-scanning\\\\\\\",\\\\\\\"data-architect\\\\\\\",\\\\\\\"guardrails\\\\\\\"],\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"nextauth-patterns\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"nextauth-patterns owns application-level authorization (requireAuth, requireOrgAuth, withOrgAuth); postgres-rls owns database-level isolation via PostgreSQL RLS policies\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"multi-tenancy-rls\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"multi-tenancy-rls owns the application query tier (orgQuery, query, withAppSession usage patterns); postgres-rls owns the PostgreSQL server-side RLS policy implementation\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"security-scanning\\\\\\\",\\\\\\\"database-migration\\\\\\\"]}\",\"grounding\":\"{\\\\\\\"domain_object\\\\\\\":\\\\\\\"PostgreSQL Row Level Security implementation in Sales Hub\\\\\\\",\\\\\\\"grounding_mode\\\\\\\":\\\\\\\"repo_specific\\\\\\\",\\\\\\\"truth_sources\\\\\\\":[\\\\\\\"sales-hub/apps/web/src/lib/db.ts\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260218_rls_hardening.sql\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260314_rls_expansion.sql\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260314_rls_with_check_and_security_invoker.sql\\\\\\\",\\\\\\\"sales-hub/db/migrations/20260315_enable_rls_all.sql\\\\\\\"],\\\\\\\"failure_modes\\\\\\\":[\\\\\\\"security_leak\\\\\\\",\\\\\\\"incorrect_isolation\\\\\\\",\\\\\\\"missing_force_rls\\\\\\\",\\\\\\\"missing_with_check\\\\\\\",\\\\\\\"superuser_bypass\\\\\\\",\\\\\\\"connection_pool_context_leakage\\\\\\\",\\\\\\\"view_security_invoker_missing\\\\\\\"],\\\\\\\"evidence_priority\\\\\\\":\\\\\\\"repo_code_first\\\\\\\"}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"declared\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"lifecycle\":\"{\\\\\\\"stale_after_days\\\\\\\":90,\\\\\\\"review_cadence\\\\\\\":\\\\\\\"quarterly\\\\\\\"}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v6\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/postgres-rls/SKILL.md\"}"
|
|
11
|
+
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
12
|
+
skill_graph_protocol: Skill Metadata Protocol v4
|
|
13
|
+
skill_graph_project: Skill Graph
|
|
14
|
+
skill_graph_canonical_skill: skills/postgres-rls/SKILL.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# PostgreSQL Row Level Security
|
|
18
|
+
|
|
19
|
+
## Domain Context
|
|
20
|
+
|
|
21
|
+
**What is postgres-rls?** Guides agents implementing or auditing PostgreSQL Row Level Security in Sales Hub. Covers ENABLE+FORCE pairing, USING+WITH CHECK policies, view bypass via security_invoker, SET LOCAL for connection pool safety, superuser/owner bypass detection, and materialized view risks.
|
|
22
|
+
|
|
23
|
+
## Key Files
|
|
24
|
+
|
|
25
|
+
| File | Purpose |
|
|
26
|
+
|------|------|
|
|
27
|
+
| `apps/web/src/lib/db.ts` | orgQuery(), query(), withReportingCurrency(), withAppSession() wrapper pattern (lines 1-895) |
|
|
28
|
+
| `db/migrations/20260218_rls_hardening.sql` | RLS hardening migration — ENABLE+FORCE patterns |
|
|
29
|
+
| `db/migrations/20260314_rls_expansion.sql` | RLS expansion to additional tables |
|
|
30
|
+
| `db/migrations/20260314_rls_with_check_and_security_invoker.sql` | WITH CHECK and security_invoker additions |
|
|
31
|
+
| `db/migrations/20260315_enable_rls_all.sql` | Full RLS enablement across all tables |
|
|
32
|
+
|
|
33
|
+
## Project-Specific Rules
|
|
34
|
+
|
|
35
|
+
This skill captures project-local rules and constraints that narrow or refine a broader pattern. Treat the repo-specific guidance and key files below as authoritative for this project.
|
|
36
|
+
|
|
37
|
+
Sales Hub uses `org_id` (not `tenant_id`) as the tenant column. Session variable is `app.organization_id`. All application queries go through `orgQuery()` (auto-sets session variable) or `query()` (system-only, bypasses RLS). The `db.ts` module manages a connection pool via `pg.Pool`; RLS context is set per-transaction using `set_config('app.organization_id', orgId, true)` (the third parameter `true` makes it transaction-local, equivalent to `SET LOCAL`).
|
|
38
|
+
|
|
39
|
+
## Coverage
|
|
40
|
+
|
|
41
|
+
This skill covers PostgreSQL Row Level Security implementation and auditing in Sales Hub: ENABLE+FORCE pairing, USING+WITH CHECK policies, view bypass via security_invoker, SET LOCAL for connection pool safety, superuser/owner bypass detection, materialized view risks, the `orgQuery()` wrapper pattern, and the `app.organization_id` session variable convention.
|
|
42
|
+
|
|
43
|
+
## Philosophy
|
|
44
|
+
|
|
45
|
+
RLS is the last line of defense against cross-tenant data leaks. When agents implement it incorrectly (missing FORCE, missing WITH CHECK, using SET instead of SET LOCAL), the system appears to work in testing but silently leaks data in production. This skill captures the exact footguns that have caused or nearly caused data breaches in multi-tenant SaaS systems.
|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
|
|
49
|
+
Row Level Security (RLS) provides defense-in-depth for data isolation. When implemented correctly, it prevents data leaks even if application code misses a filter. When implemented incorrectly, it creates false security confidence while data bleeds between tenants.
|
|
50
|
+
|
|
51
|
+
**Core principle:** RLS is your last line of defense, not your only one. Get it wrong and you have a data breach.
|
|
52
|
+
|
|
53
|
+
**Announce at start:** "I'm applying postgres-rls to verify Row Level Security implementation."
|
|
54
|
+
|
|
55
|
+
## When This Skill Applies
|
|
56
|
+
|
|
57
|
+
This skill is MANDATORY when ANY of these patterns are touched:
|
|
58
|
+
|
|
59
|
+
| Pattern | Examples |
|
|
60
|
+
|---------|----------|
|
|
61
|
+
| `**/migrations/**/*tenant*` | migrations/001_add_tenant_id.sql |
|
|
62
|
+
| `**/migrations/**/*rls*` | migrations/005_enable_rls.sql |
|
|
63
|
+
| `**/migrations/**/*policy*` | migrations/010_create_policies.sql |
|
|
64
|
+
| `**/*policy*.sql` | db/policies.sql |
|
|
65
|
+
| `**/auth/**` | src/auth/context.ts |
|
|
66
|
+
| `**/*tenant*` | lib/tenant.ts, services/tenantService.ts |
|
|
67
|
+
| `**/*multi-tenant*` | docs/multi-tenant-architecture.md |
|
|
68
|
+
|
|
69
|
+
Check with:
|
|
70
|
+
```bash
|
|
71
|
+
git diff --name-only HEAD~1 | grep -iE '(tenant|rls|policy|auth.*sql|multi.?tenant)'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Sales Hub Specifics
|
|
75
|
+
|
|
76
|
+
Sales Hub uses `org_id` (not `tenant_id`) as the tenant column. Session variable is `app.organization_id`.
|
|
77
|
+
|
|
78
|
+
**Current state (2026-03-14):** 22 tables with RLS. Policies use:
|
|
79
|
+
```sql
|
|
80
|
+
CREATE POLICY {table}_org_isolation ON {table}
|
|
81
|
+
FOR ALL
|
|
82
|
+
USING (org_id IS NOT NULL AND org_id = (current_setting('app.organization_id', true))::uuid)
|
|
83
|
+
WITH CHECK (org_id IS NOT NULL AND org_id = (current_setting('app.organization_id', true))::uuid);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Query wrappers (in `apps/web/src/lib/db.ts` — orgQuery, query, withAppSession):**
|
|
87
|
+
- `orgQuery(orgId, sql, params)` — auto-sets session variable + validates (preferred)
|
|
88
|
+
- `query(sql, params)` — raw query without validation (system operations only)
|
|
89
|
+
- `withAppSession(settings, fn)` — manual session variable injection
|
|
90
|
+
|
|
91
|
+
**Views:** All views use `ALTER VIEW ... SET (security_invoker = true)` (PG15+).
|
|
92
|
+
|
|
93
|
+
## The Critical Vulnerabilities
|
|
94
|
+
|
|
95
|
+
### 1. Superuser Bypass (CRITICAL)
|
|
96
|
+
|
|
97
|
+
Superusers and roles with `BYPASSRLS` ignore ALL policies.
|
|
98
|
+
|
|
99
|
+
```sql
|
|
100
|
+
-- DANGEROUS: Testing as superuser shows RLS "working" when it's bypassed
|
|
101
|
+
SET ROLE postgres;
|
|
102
|
+
SELECT * FROM orders; -- Returns ALL rows, RLS ignored
|
|
103
|
+
|
|
104
|
+
-- CORRECT: Test as application role
|
|
105
|
+
SET ROLE app_user;
|
|
106
|
+
SELECT * FROM orders; -- Returns only permitted rows
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Checklist:**
|
|
110
|
+
- [ ] Application connects as non-superuser role
|
|
111
|
+
- [ ] No roles have `BYPASSRLS` attribute
|
|
112
|
+
- [ ] Tests run as application role, NOT superuser
|
|
113
|
+
|
|
114
|
+
### 2. Table Owner Bypass (CRITICAL)
|
|
115
|
+
|
|
116
|
+
Table owners bypass RLS unless `FORCE ROW LEVEL SECURITY` is set.
|
|
117
|
+
|
|
118
|
+
```sql
|
|
119
|
+
-- INCOMPLETE: Owners bypass this
|
|
120
|
+
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
|
121
|
+
|
|
122
|
+
-- COMPLETE: Everyone including owners must obey policies
|
|
123
|
+
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
|
124
|
+
ALTER TABLE orders FORCE ROW LEVEL SECURITY;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Checklist:**
|
|
128
|
+
- [ ] All RLS tables have both ENABLE and FORCE
|
|
129
|
+
- [ ] Migration includes both statements
|
|
130
|
+
|
|
131
|
+
### 3. View Bypass (CRITICAL)
|
|
132
|
+
|
|
133
|
+
Views run with creator's privileges by default. Views owned by superusers bypass RLS entirely.
|
|
134
|
+
|
|
135
|
+
```sql
|
|
136
|
+
-- DANGEROUS: View owned by superuser bypasses RLS
|
|
137
|
+
CREATE VIEW all_orders AS SELECT * FROM orders;
|
|
138
|
+
|
|
139
|
+
-- SAFE (PostgreSQL 15+): Security invoker respects caller's RLS
|
|
140
|
+
CREATE VIEW user_orders
|
|
141
|
+
WITH (security_invoker = true)
|
|
142
|
+
AS SELECT * FROM orders;
|
|
143
|
+
|
|
144
|
+
-- Or retrofit existing views:
|
|
145
|
+
ALTER VIEW user_orders SET (security_invoker = true);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Checklist:**
|
|
149
|
+
- [ ] All views on RLS tables use `security_invoker = true` (PG15+)
|
|
150
|
+
- [ ] Views not owned by superuser roles
|
|
151
|
+
- [ ] Materialized views documented as bypassing RLS
|
|
152
|
+
|
|
153
|
+
### 4. USING vs WITH CHECK Mismatch (HIGH)
|
|
154
|
+
|
|
155
|
+
`USING` filters reads; `WITH CHECK` validates writes. Missing `WITH CHECK` allows inserting data you can't see.
|
|
156
|
+
|
|
157
|
+
```sql
|
|
158
|
+
-- INCOMPLETE: User can INSERT rows they can't SELECT
|
|
159
|
+
CREATE POLICY tenant_isolation ON orders
|
|
160
|
+
USING (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
161
|
+
|
|
162
|
+
-- COMPLETE: Both read and write protected
|
|
163
|
+
CREATE POLICY tenant_isolation ON orders
|
|
164
|
+
USING (tenant_id = current_setting('app.tenant_id')::uuid)
|
|
165
|
+
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Checklist:**
|
|
169
|
+
- [ ] All policies have both USING and WITH CHECK
|
|
170
|
+
- [ ] WITH CHECK logic matches security intent
|
|
171
|
+
|
|
172
|
+
### 5. Thread-Local Context Leakage (HIGH)
|
|
173
|
+
|
|
174
|
+
Connection pooling can leak tenant context between requests.
|
|
175
|
+
|
|
176
|
+
```sql
|
|
177
|
+
-- DANGEROUS: Context persists across pooled connections
|
|
178
|
+
SET app.tenant_id = 'tenant-123';
|
|
179
|
+
|
|
180
|
+
-- SAFE: Use SET LOCAL inside transaction (auto-resets)
|
|
181
|
+
BEGIN;
|
|
182
|
+
SET LOCAL app.tenant_id = 'tenant-123';
|
|
183
|
+
-- ... queries ...
|
|
184
|
+
COMMIT; -- Context automatically cleared
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Application pattern:**
|
|
188
|
+
```typescript
|
|
189
|
+
// DANGEROUS: Leaks between requests
|
|
190
|
+
await db.query(`SET app.tenant_id = '${tenantId}'`);
|
|
191
|
+
|
|
192
|
+
// SAFE: Transaction-scoped context (Sales Hub pattern)
|
|
193
|
+
await client.query("SELECT set_config('app.organization_id', $1, true)", [orgId]);
|
|
194
|
+
// The `true` parameter = transaction-local, equivalent to SET LOCAL
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Checklist:**
|
|
198
|
+
- [ ] Always use `SET LOCAL` or `set_config(key, val, true)`
|
|
199
|
+
- [ ] Context set inside transactions
|
|
200
|
+
- [ ] Post-request handler resets context (defense in depth)
|
|
201
|
+
|
|
202
|
+
### 6. SQL Injection in Policy Functions (HIGH)
|
|
203
|
+
|
|
204
|
+
Functions used in policies can be injection vectors.
|
|
205
|
+
|
|
206
|
+
```sql
|
|
207
|
+
-- The function must be injection-safe:
|
|
208
|
+
CREATE OR REPLACE FUNCTION current_tenant()
|
|
209
|
+
RETURNS uuid AS $$
|
|
210
|
+
BEGIN
|
|
211
|
+
-- SAFE: Casts to UUID, not string concatenation
|
|
212
|
+
RETURN current_setting('app.tenant_id')::uuid;
|
|
213
|
+
END;
|
|
214
|
+
$$ LANGUAGE plpgsql STABLE;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 7. Materialized Views and Data Export (MEDIUM)
|
|
218
|
+
|
|
219
|
+
Materialized views don't respect source table RLS. Data exports may bypass policies.
|
|
220
|
+
|
|
221
|
+
**Checklist:**
|
|
222
|
+
- [ ] Materialized views documented as security-sensitive
|
|
223
|
+
- [ ] Export jobs run as application role
|
|
224
|
+
- [ ] Audit log for bulk data access
|
|
225
|
+
|
|
226
|
+
## Migration Pattern
|
|
227
|
+
|
|
228
|
+
### Safe RLS Migration
|
|
229
|
+
|
|
230
|
+
```sql
|
|
231
|
+
-- Step 1: Add column (if needed)
|
|
232
|
+
ALTER TABLE orders ADD COLUMN IF NOT EXISTS org_id uuid REFERENCES organizations(id);
|
|
233
|
+
|
|
234
|
+
-- Step 2: Backfill data (batched for large tables)
|
|
235
|
+
UPDATE orders SET org_id = (...) WHERE org_id IS NULL;
|
|
236
|
+
|
|
237
|
+
-- Step 3: Create index
|
|
238
|
+
CREATE INDEX IF NOT EXISTS idx_orders_org_id ON orders(org_id);
|
|
239
|
+
|
|
240
|
+
-- Step 4: Enable RLS (both statements!)
|
|
241
|
+
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
|
|
242
|
+
ALTER TABLE orders FORCE ROW LEVEL SECURITY;
|
|
243
|
+
|
|
244
|
+
-- Step 5: Create policies with USING and WITH CHECK
|
|
245
|
+
DROP POLICY IF EXISTS orders_org_isolation ON orders;
|
|
246
|
+
CREATE POLICY orders_org_isolation ON orders
|
|
247
|
+
FOR ALL
|
|
248
|
+
USING (org_id IS NOT NULL AND org_id = (current_setting('app.organization_id', true))::uuid)
|
|
249
|
+
WITH CHECK (org_id IS NOT NULL AND org_id = (current_setting('app.organization_id', true))::uuid);
|
|
250
|
+
|
|
251
|
+
-- Step 6: Verify
|
|
252
|
+
DO $$ BEGIN
|
|
253
|
+
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename = 'orders' AND policyname = 'orders_org_isolation') THEN
|
|
254
|
+
RAISE EXCEPTION 'ASSERTION FAILED: RLS policy not found on orders';
|
|
255
|
+
END IF;
|
|
256
|
+
END; $$;
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Verification
|
|
260
|
+
|
|
261
|
+
Before completing RLS implementation:
|
|
262
|
+
|
|
263
|
+
- [ ] All tables have ENABLE and FORCE ROW LEVEL SECURITY
|
|
264
|
+
- [ ] All policies have both USING and WITH CHECK
|
|
265
|
+
- [ ] Application connects as non-superuser, non-BYPASSRLS role
|
|
266
|
+
- [ ] Context set with SET LOCAL / set_config(key, val, true) inside transactions
|
|
267
|
+
- [ ] Views use security_invoker = true (PG15+)
|
|
268
|
+
- [ ] Policy columns indexed
|
|
269
|
+
- [ ] Cross-tenant isolation tests passing
|
|
270
|
+
|
|
271
|
+
## References
|
|
272
|
+
|
|
273
|
+
- [PostgreSQL RLS Documentation](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
|
|
274
|
+
- [Common RLS Footguns](https://www.bytebase.com/blog/postgres-row-level-security-footguns/)
|
|
275
|
+
- [RLS Performance Optimization](https://scottpierce.dev/posts/optimizing-postgres-rls/)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
## Do NOT Use When
|
|
279
|
+
|
|
280
|
+
| Instead of this skill | Use | Why |
|
|
281
|
+
|---|---|---|
|
|
282
|
+
| Application-level auth logic | `nextauth-patterns` | RLS is DB-level; app auth is a separate layer |
|
|
283
|
+
| Non-PostgreSQL databases | General security patterns | RLS is PostgreSQL-specific |
|
|
284
|
+
| orgQuery() wrapper usage questions | `multi-tenancy-rls` | That skill owns the application query tier |
|
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: "Markdown, Git, any codebase"
|
|
6
6
|
allowed-tools: Read Grep Bash
|
|
7
7
|
metadata:
|
|
8
|
-
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"workflow\",\"category\":\"engineering\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-04-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-04-18\\\\\\\"}\",\"eval_artifacts\":\"present\",\"eval_state\":\"passing\",\"routing_eval\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"refactor\\\\\\\",\\\\\\\"cleanup\\\\\\\",\\\\\\\"simplify\\\\\\\",\\\\\\\"extract function\\\\\\\",\\\\\\\"reduce duplication\\\\\\\",\\\\\\\"clean this up\\\\\\\",\\\\\\\"simplify this\\\\\\\",\\\\\\\"rename this\\\\\\\",\\\\\\\"split this file\\\\\\\",\\\\\\\"too long function\\\\\\\",\\\\\\\"duplicated logic\\\\\\\",\\\\\\\"decompose function\\\\\\\",\\\\\\\"decompose code\\\\\\\",\\\\\\\"decompose long\\\\\\\",\\\\\\\"split by responsibility\\\\\\\",\\\\\\\"behavior preserving\\\\\\\",\\\\\\\"rename module\\\\\\\",\\\\\\\"rename utils\\\\\\\",\\\\\\\"messy code\\\\\\\",\\\\\\\"messy suite\\\\\\\",\\\\\\\"extract helper\\\\\\\",\\\\\\\"extract duplicated\\\\\\\",\\\\\\\"consolidate logic\\\\\\\",\\\\\\\"tighten structure\\\\\\\",\\\\\\\"large component refactor\\\\\\\",\\\\\\\"make sure refactor preserves behavior\\\\\\\"]\",\"triggers\":\"[\\\\\\\"refactor-skill\\\\\\\"]\",\"examples\":\"[\\\\\\\"this 600-line function is hard to reason about — decompose it while keeping tests green\\\\\\\",\\\\\\\"extract the duplicated validation logic from these three handlers into a helper\\\\\\\",\\\\\\\"rename this module from `utils` to something that describes what it actually does\\\\\\\",\\\\\\\"split this file by responsibility; no behavior changes, tests must still pass\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"the test is failing after my edit — what did I break?\\\\\\\",\\\\\\\"write an architecture note explaining this pattern for new team members\\\\\\\",\\\\\\\"reproduce why this function retries three times on transient network errors\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"debugging\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"debugging chases an observed failure; refactor runs only with a green test suite and preserves behavior\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"tool-call-flow\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"tool-call-flow owns the protocol-level cycle of model→runtime tool invocation including retry encoding inside the cycle; refactor only restructures the surrounding code while preserving behavior. The anti_example about a function retrying three times is a tool-call/runtime concern, not a refactor concern.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"generative-ui\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"generative-ui owns the model-emits-typed-UI-spec pattern; refactor only restructures existing code while preserving behavior. The retries anti_example has token overlap with the model-output/runtime cycle vocabulary generative-ui discusses, so naming it here keeps the boundary explicit.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"testing-strategy\\\\\\\"],\\\\\\\"depends_on\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"testing-strategy\\\\\\\",\\\\\\\"min_version\\\\\\\":\\\\\\\"^1.0.0\\\\\\\"}]}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/refactor/SKILL.md\"}"
|
|
8
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"workflow\",\"category\":\"engineering\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-04-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-04-18\\\\\\\"}\",\"eval_artifacts\":\"present\",\"eval_state\":\"passing\",\"routing_eval\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"refactor\\\\\\\",\\\\\\\"cleanup\\\\\\\",\\\\\\\"simplify\\\\\\\",\\\\\\\"extract function\\\\\\\",\\\\\\\"reduce duplication\\\\\\\",\\\\\\\"clean this up\\\\\\\",\\\\\\\"simplify this\\\\\\\",\\\\\\\"rename this\\\\\\\",\\\\\\\"split this file\\\\\\\",\\\\\\\"too long function\\\\\\\",\\\\\\\"duplicated logic\\\\\\\",\\\\\\\"decompose function\\\\\\\",\\\\\\\"decompose code\\\\\\\",\\\\\\\"decompose long\\\\\\\",\\\\\\\"split by responsibility\\\\\\\",\\\\\\\"behavior preserving\\\\\\\",\\\\\\\"rename module\\\\\\\",\\\\\\\"rename utils\\\\\\\",\\\\\\\"messy code\\\\\\\",\\\\\\\"messy suite\\\\\\\",\\\\\\\"extract helper\\\\\\\",\\\\\\\"extract duplicated\\\\\\\",\\\\\\\"consolidate logic\\\\\\\",\\\\\\\"tighten structure\\\\\\\",\\\\\\\"large component refactor\\\\\\\",\\\\\\\"make sure refactor preserves behavior\\\\\\\"]\",\"triggers\":\"[\\\\\\\"refactor-skill\\\\\\\"]\",\"examples\":\"[\\\\\\\"this 600-line function is hard to reason about — decompose it while keeping tests green\\\\\\\",\\\\\\\"extract the duplicated validation logic from these three handlers into a helper\\\\\\\",\\\\\\\"rename this module from `utils` to something that describes what it actually does\\\\\\\",\\\\\\\"split this file by responsibility; no behavior changes, tests must still pass\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"the test is failing after my edit — what did I break?\\\\\\\",\\\\\\\"write an architecture note explaining this pattern for new team members\\\\\\\",\\\\\\\"reproduce why this function retries three times on transient network errors\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"debugging\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"debugging chases an observed failure; refactor runs only with a green test suite and preserves behavior\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"tool-call-flow\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"tool-call-flow owns the protocol-level cycle of model→runtime tool invocation including retry encoding inside the cycle; refactor only restructures the surrounding code while preserving behavior. The anti_example about a function retrying three times is a tool-call/runtime concern, not a refactor concern.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"generative-ui\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"generative-ui owns the model-emits-typed-UI-spec pattern; refactor only restructures existing code while preserving behavior. The retries anti_example has token overlap with the model-output/runtime cycle vocabulary generative-ui discusses, so naming it here keeps the boundary explicit.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"context-graph\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"context-graph owns the design and documentation of AI workspace graph architecture; refactor owns behavior-preserving code restructuring. Writing an architecture note for team members is documentation work, not a code refactor.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"error-boundary\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"error-boundary owns React error boundary design and the mechanics of retry-on-error patterns; refactor owns behavior-preserving code restructuring. Reproducing or explaining retry behavior is a runtime/error-handling concern, not a refactor concern.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"testing-strategy\\\\\\\"],\\\\\\\"depends_on\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"testing-strategy\\\\\\\",\\\\\\\"min_version\\\\\\\":\\\\\\\"^1.0.0\\\\\\\"}]}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/refactor/SKILL.md\"}"
|
|
9
9
|
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
10
10
|
skill_graph_protocol: Skill Metadata Protocol v4
|
|
11
11
|
skill_graph_project: Skill Graph
|
|
@@ -5,6 +5,8 @@ license: MIT
|
|
|
5
5
|
compatibility: "Library- and harness-agnostic. Patterns apply to any skill-style library (Skill Graph, Claude skills, Cursor rules, custom in-house skill systems). Specific tool names in this skill (skill-lint, generate-manifest, routing-eval, drift-sentinel) are concrete examples from the Skill Graph reference implementation -- substitute your library's equivalents."
|
|
6
6
|
allowed-tools: Read Grep Bash Edit Write
|
|
7
7
|
metadata:
|
|
8
|
+
grounding: "{\"domain_object\":\"Deterministic health tooling for Skill Graph libraries\",\"grounding_mode\":\"hybrid\",\"truth_sources\":[\"package.json\",\"bin/skill-graph.js\",\"scripts/skill-lint.js\",\"scripts/lib/roots.js\",\"scripts/check-protocol-consistency.js\",\"scripts/generate-manifest.js\",\"scripts/skill-graph-drift.js\",\"scripts/skill-overlap.js\",\"scripts/skill-graph-routing-eval.js\",\"docs/manifest-field-mapping.md\"],\"failure_modes\":[\"health_tooling_categories_missing_from_ci\",\"protocol_mapping_drift\",\"eval_thresholds_become_self_attested\",\"overlap_or_drift_checks_not_run_after_batch_changes\"],\"evidence_priority\":\"repo_code_first\"}"
|
|
9
|
+
drift_check: "{\"last_verified\":\"2026-05-18\",\"truth_source_hashes\":{\"package.json\":\"2f480e50b8eecaa022caf065b5bb98db5db407f4e3ff8553a092a3f70750edba\",\"bin/skill-graph.js\":\"3048b6e2d9e648a25efa38152578217eaf230716c1dabc921e8f8d944164ec8b\",\"scripts/skill-lint.js\":\"e5de8a822b88172079263c8316b173e688b71498c9ed6a8a54dd0fba6aa9fd66\",\"scripts/lib/roots.js\":\"49085fc54b2c6ff0ad23a2dffe25b5ab2b3d1e8d14a8d5b1e1eefb53a30f20de\",\"scripts/check-protocol-consistency.js\":\"22f1f747b6b578e83ae371ac3f9af4b6906d94529f383d1785ed3303b4c5a008\",\"scripts/generate-manifest.js\":\"ec4ad89e21e44c272676846377679f59a272c193f0b0d448a7b6d881b0b9effc\",\"scripts/skill-graph-drift.js\":\"350f624a6e82bb488cd9abd3be4d832ca7892ce1c7f27d39efd97326e1f04db6\",\"scripts/skill-overlap.js\":\"ed642cbc677cc76ec1321300b37d6752337b6b5541c7a9f558fd315d6f934e4b\",\"scripts/skill-graph-routing-eval.js\":\"fffac2858863662bde6bc54c56bb77a219ae93f626e0c8d5886566f998181deb\",\"docs/manifest-field-mapping.md\":\"8de06aa16e23c219da1f5f2ec38b5b29aa912ad577377c8422e2300cdd77ee90\"}}"
|
|
8
10
|
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"capability\",\"category\":\"agent\",\"domain\":\"agent/skill-system\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-05-13\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-05-13\\\\\\\",\\\\\\\"truth_source_hashes\\\\\\\":{\\\\\\\"package.json\\\\\\\":\\\\\\\"7a3410a004aea78a2065092e289c0f3cf3c082298804dda6c5829eff22c14b62\\\\\\\",\\\\\\\"bin/skill-graph.js\\\\\\\":\\\\\\\"113a1e01ac7276ac1b5d77a1c32e35a73113da93fc33cfd0caf6db842d2d679f\\\\\\\",\\\\\\\"scripts/skill-lint.js\\\\\\\":\\\\\\\"3a78f75f8921542b91dc619cd41bde29bf379de3c16bdcf3653c854ecbe9fa29\\\\\\\",\\\\\\\"scripts/lib/roots.js\\\\\\\":\\\\\\\"e742efa57b6c33ff1c87034b16a689d1499f6d53c1e6b740f3e9783db7fd557f\\\\\\\",\\\\\\\"scripts/check-protocol-consistency.js\\\\\\\":\\\\\\\"0ff39406d36e7a9e51c176f657f4f426d8bd5a3fe6411d28b9e9a93dc7d89f29\\\\\\\",\\\\\\\"scripts/generate-manifest.js\\\\\\\":\\\\\\\"9d7bbbdae440fdb1763d61ffa7bda10c9efae92359d1c2139d0e971582d59e0e\\\\\\\",\\\\\\\"scripts/skill-graph-drift.js\\\\\\\":\\\\\\\"6b69c25b59c16b477a377e5ab40adb6ff30f72d5a12947772053a6cd16b1f409\\\\\\\",\\\\\\\"scripts/skill-overlap.js\\\\\\\":\\\\\\\"ed642cbc677cc76ec1321300b37d6752337b6b5541c7a9f558fd315d6f934e4b\\\\\\\",\\\\\\\"scripts/skill-graph-routing-eval.js\\\\\\\":\\\\\\\"fffac2858863662bde6bc54c56bb77a219ae93f626e0c8d5886566f998181deb\\\\\\\",\\\\\\\"docs/manifest-field-mapping.md\\\\\\\":\\\\\\\"aca0b7f2d4631be24a3e7daed1a1d207b488f253164a7d514b9db7af21c6177f\\\\\\\"}}\",\"eval_artifacts\":\"planned\",\"eval_state\":\"unverified\",\"routing_eval\":\"absent\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"skill library health\\\\\\\",\\\\\\\"skill system tooling\\\\\\\",\\\\\\\"skill library decay\\\\\\\",\\\\\\\"skill library maintenance\\\\\\\",\\\\\\\"skill census\\\\\\\",\\\\\\\"skill inventory\\\\\\\",\\\\\\\"frontmatter validation\\\\\\\",\\\\\\\"imperative conflict\\\\\\\",\\\\\\\"skill overlap detection\\\\\\\",\\\\\\\"skill conflict\\\\\\\",\\\\\\\"routing gap\\\\\\\",\\\\\\\"routing miss\\\\\\\",\\\\\\\"routing health\\\\\\\",\\\\\\\"eval threshold\\\\\\\",\\\\\\\"eval minimum\\\\\\\",\\\\\\\"contradiction check\\\\\\\",\\\\\\\"negative expectation\\\\\\\",\\\\\\\"drift sentinel\\\\\\\",\\\\\\\"truth source hash\\\\\\\",\\\\\\\"mirror parity\\\\\\\",\\\\\\\"skill graph health\\\\\\\",\\\\\\\"production skill library\\\\\\\",\\\\\\\"skill linter\\\\\\\",\\\\\\\"skill quality gate\\\\\\\",\\\\\\\"phantom ref\\\\\\\"]\",\"examples\":\"[\\\\\\\"our skill library is growing and we're getting silent decay — eval counts dropping, conflicts emerging — what tooling should we add?\\\\\\\",\\\\\\\"two of our skills give opposite instructions for the same function — how do we detect this automatically?\\\\\\\",\\\\\\\"we keep getting skill-router misses on real user queries — how do we surface and close routing gaps?\\\\\\\",\\\\\\\"design a health-check pipeline for a 200-skill library that runs in CI\\\\\\\",\\\\\\\"what's a reasonable minimum eval count per skill, and how do we enforce it?\\\\\\\",\\\\\\\"our skill mirror in `.claude/skills` keeps drifting from the source — what's the parity check?\\\\\\\",\\\\\\\"we want to add a contradiction-check eval pattern — what does it look like and when do we use it?\\\\\\\",\\\\\\\"skill-overlap-detector flagged 12 imperative conflicts — how do we triage which to fix vs suppress?\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"scaffold a new SKILL.md for our team's deploy procedure\\\\\\\",\\\\\\\"audit this Skill Graph repo for schema conformance and dangling relation targets\\\\\\\",\\\\\\\"the manifest sample drifted from the generator — find the mismatch\\\\\\\",\\\\\\\"improve this prompt's wording to get better outputs\\\\\\\",\\\\\\\"review this AI-generated PR for correctness\\\\\\\",\\\\\\\"set up ESLint for our TypeScript repo\\\\\\\",\\\\\\\"draft an architecture note explaining why we chose Postgres\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"skill-scaffold\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"skill-scaffold owns authoring methodology for one new SKILL.md; skill-infrastructure owns the deterministic health-tooling layer that watches the entire library after authoring\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"graph-audit\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"graph-audit is the operational audit of one specific library (Skill Graph), scope: codebase; skill-infrastructure is the portable discipline of designing health tooling for any skill library\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"lint-overlay\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"lint-overlay covers lint-rule selection and gate placement for general codebases; skill-infrastructure covers the skill-system-specific tooling category that includes lint but extends to overlap, routing-gap, drift, and mirror-parity\\\\\\\"}],\\\\\\\"related\\\\\\\":[\\\\\\\"skill-scaffold\\\\\\\",\\\\\\\"graph-audit\\\\\\\",\\\\\\\"testing-strategy\\\\\\\"],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"testing-strategy\\\\\\\",\\\\\\\"code-review\\\\\\\"]}\",\"grounding\":\"{\\\\\\\"domain_object\\\\\\\":\\\\\\\"Deterministic health tooling for Skill Graph libraries\\\\\\\",\\\\\\\"grounding_mode\\\\\\\":\\\\\\\"hybrid\\\\\\\",\\\\\\\"truth_sources\\\\\\\":[\\\\\\\"package.json\\\\\\\",\\\\\\\"bin/skill-graph.js\\\\\\\",\\\\\\\"scripts/skill-lint.js\\\\\\\",\\\\\\\"scripts/lib/roots.js\\\\\\\",\\\\\\\"scripts/check-protocol-consistency.js\\\\\\\",\\\\\\\"scripts/generate-manifest.js\\\\\\\",\\\\\\\"scripts/skill-graph-drift.js\\\\\\\",\\\\\\\"scripts/skill-overlap.js\\\\\\\",\\\\\\\"scripts/skill-graph-routing-eval.js\\\\\\\",\\\\\\\"docs/manifest-field-mapping.md\\\\\\\"],\\\\\\\"failure_modes\\\\\\\":[\\\\\\\"health_tooling_categories_missing_from_ci\\\\\\\",\\\\\\\"protocol_mapping_drift\\\\\\\",\\\\\\\"eval_thresholds_become_self_attested\\\\\\\",\\\\\\\"overlap_or_drift_checks_not_run_after_batch_changes\\\\\\\"],\\\\\\\"evidence_priority\\\\\\\":\\\\\\\"repo_code_first\\\\\\\"}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"lifecycle\":\"{\\\\\\\"stale_after_days\\\\\\\":90,\\\\\\\"review_cadence\\\\\\\":\\\\\\\"quarterly\\\\\\\"}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/skill-infrastructure/SKILL.md\"}"
|
|
9
11
|
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
10
12
|
skill_graph_protocol: Skill Metadata Protocol v4
|
|
@@ -5,7 +5,9 @@ license: MIT
|
|
|
5
5
|
compatibility: "Markdown, YAML, any agent runtime"
|
|
6
6
|
allowed-tools: Read Grep
|
|
7
7
|
metadata:
|
|
8
|
-
|
|
8
|
+
grounding: "{\"domain_object\":\"Skill Graph reference routing behavior\",\"grounding_mode\":\"repo_specific\",\"truth_sources\":[\"scripts/skill-graph-route.js\",\"scripts/skill-graph-routing-eval.js\",\"examples/evals/skill-router.json\",\"examples/evals/skill-router.routing.json\"],\"failure_modes\":[\"negation_paths_score_as_positive_matches\",\"routing_eval_claim_without_harness_pass\",\"boundary_exclusion_removes_stronger_match\",\"coverage_gap_silently_falls_back\"],\"evidence_priority\":\"repo_code_first\"}"
|
|
9
|
+
drift_check: "{\"last_verified\":\"2026-05-18\",\"truth_source_hashes\":{\"scripts/skill-graph-route.js\":\"7c29b1bc2420887f32809b8f52f5bd448c1234542672e669a68247942dd77df4\",\"scripts/skill-graph-routing-eval.js\":\"fffac2858863662bde6bc54c56bb77a219ae93f626e0c8d5886566f998181deb\",\"examples/evals/skill-router.json\":\"fccabcbc5f9d8057536f397fb0fc71a567371f75fb9a21afda343b197af30293\",\"examples/evals/skill-router.routing.json\":\"c4dc88db1e746bea78a7cf96b50c6c84532a07eda42da2e35d790c8928d4da8c\"}}"
|
|
10
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"router\",\"category\":\"agent\",\"domain\":\"agent/skill-system\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-04-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-05-13\\\\\\\",\\\\\\\"truth_source_hashes\\\\\\\":{\\\\\\\"scripts/skill-graph-route.js\\\\\\\":\\\\\\\"b9a7b51d0e8b845b11473f479c4593754768c3775508049db7339892b2f08cc2\\\\\\\",\\\\\\\"scripts/skill-graph-routing-eval.js\\\\\\\":\\\\\\\"fffac2858863662bde6bc54c56bb77a219ae93f626e0c8d5886566f998181deb\\\\\\\",\\\\\\\"examples/evals/skill-router.json\\\\\\\":\\\\\\\"fccabcbc5f9d8057536f397fb0fc71a567371f75fb9a21afda343b197af30293\\\\\\\",\\\\\\\"examples/evals/skill-router.routing.json\\\\\\\":\\\\\\\"c4dc88db1e746bea78a7cf96b50c6c84532a07eda42da2e35d790c8928d4da8c\\\\\\\"}}\",\"eval_artifacts\":\"present\",\"eval_state\":\"passing\",\"routing_eval\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"skill routing\\\\\\\",\\\\\\\"skill dispatch\\\\\\\",\\\\\\\"keyword routing\\\\\\\",\\\\\\\"route skill\\\\\\\",\\\\\\\"which skill to use\\\\\\\",\\\\\\\"skill selector\\\\\\\",\\\\\\\"routing table\\\\\\\",\\\\\\\"coverage gap\\\\\\\",\\\\\\\"ambiguous skill activation\\\\\\\",\\\\\\\"skill activate\\\\\\\",\\\\\\\"skill activates\\\\\\\",\\\\\\\"activate skill\\\\\\\",\\\\\\\"skill should activate\\\\\\\",\\\\\\\"which skill activates\\\\\\\",\\\\\\\"why did skill activate\\\\\\\",\\\\\\\"why skill activated\\\\\\\",\\\\\\\"routing decision\\\\\\\",\\\\\\\"dispatch request\\\\\\\",\\\\\\\"dispatch agent request\\\\\\\",\\\\\\\"agent request routing\\\\\\\",\\\\\\\"route this request\\\\\\\",\\\\\\\"route the request\\\\\\\",\\\\\\\"find the right skill\\\\\\\",\\\\\\\"choose the right skill\\\\\\\",\\\\\\\"which skill handles\\\\\\\"]\",\"triggers\":\"[\\\\\\\"skill-router\\\\\\\"]\",\"examples\":\"[\\\\\\\"activate the right skill for this agent request: 'my tests are failing in CI'\\\\\\\",\\\\\\\"build a routing table that covers every agent request type we see\\\\\\\",\\\\\\\"why did the documentation skill activate when the user asked about a11y?\\\\\\\",\\\\\\\"find the coverage gaps — which agent requests match no skill at all?\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"audit the graph-audit skill for schema conformance\\\\\\\",\\\\\\\"write a guide explaining how our routing works\\\\\\\",\\\\\\\"reproduce this routing mis-dispatch from production logs\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"graph-audit\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"graph-audit verifies ONE skill's metadata; skill-router chooses BETWEEN skills at request time\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"debugging\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"debugging reproduces a specific routing mis-dispatch from evidence; skill-router designs the routing table itself\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"skill-infrastructure\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"skill-infrastructure analyses routing-miss patterns across the whole library to find systemic gaps; skill-router authors the routing logic for one library at a time\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"middleware-patterns\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"middleware-patterns owns the design of Next.js middleware (request/response transforms, edge runtime, matchers); skill-router owns agent skill dispatch. Writing a guide explaining 'how our routing works' is documentation about Next.js middleware patterns, not an agent skill routing exercise.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"graph-audit\\\\\\\"]}\",\"grounding\":\"{\\\\\\\"domain_object\\\\\\\":\\\\\\\"Skill Graph reference routing behavior\\\\\\\",\\\\\\\"grounding_mode\\\\\\\":\\\\\\\"repo_specific\\\\\\\",\\\\\\\"truth_sources\\\\\\\":[\\\\\\\"scripts/skill-graph-route.js\\\\\\\",\\\\\\\"scripts/skill-graph-routing-eval.js\\\\\\\",\\\\\\\"examples/evals/skill-router.json\\\\\\\",\\\\\\\"examples/evals/skill-router.routing.json\\\\\\\"],\\\\\\\"failure_modes\\\\\\\":[\\\\\\\"negation_paths_score_as_positive_matches\\\\\\\",\\\\\\\"routing_eval_claim_without_harness_pass\\\\\\\",\\\\\\\"boundary_exclusion_removes_stronger_match\\\\\\\",\\\\\\\"coverage_gap_silently_falls_back\\\\\\\"],\\\\\\\"evidence_priority\\\\\\\":\\\\\\\"repo_code_first\\\\\\\"}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/skill-router/SKILL.md\"}"
|
|
9
11
|
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
10
12
|
skill_graph_protocol: Skill Metadata Protocol v4
|
|
11
13
|
skill_graph_project: Skill Graph
|
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
compatibility: "Markdown, Git, any codebase"
|
|
6
6
|
allowed-tools: Read Grep Bash
|
|
7
7
|
metadata:
|
|
8
|
-
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"capability\",\"category\":\"quality\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-04-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-04-18\\\\\\\"}\",\"eval_artifacts\":\"present\",\"eval_state\":\"passing\",\"routing_eval\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"testing strategy\\\\\\\",\\\\\\\"what to test\\\\\\\",\\\\\\\"what not to test\\\\\\\",\\\\\\\"which test level\\\\\\\",\\\\\\\"test scope\\\\\\\",\\\\\\\"effort vs risk\\\\\\\",\\\\\\\"regression target\\\\\\\",\\\\\\\"failure case coverage\\\\\\\",\\\\\\\"test plan\\\\\\\",\\\\\\\"do I need a test\\\\\\\",\\\\\\\"should I test this\\\\\\\",\\\\\\\"unit or integration\\\\\\\",\\\\\\\"test coverage\\\\\\\",\\\\\\\"pin this behavior\\\\\\\",\\\\\\\"plan test coverage\\\\\\\",\\\\\\\"plan coverage\\\\\\\",\\\\\\\"needs an automated test\\\\\\\",\\\\\\\"automated test\\\\\\\",\\\\\\\"manual QA coverage\\\\\\\",\\\\\\\"passes manual QA\\\\\\\",\\\\\\\"test level decision\\\\\\\"]\",\"triggers\":\"[\\\\\\\"testing-skill\\\\\\\"]\",\"routing_bundles\":\"[\\\\\\\"quality\\\\\\\"]\",\"examples\":\"[\\\\\\\"do I need a unit test for this pure formatter or is integration enough?\\\\\\\",\\\\\\\"what's the right test level for a webhook handler that talks to Stripe?\\\\\\\",\\\\\\\"the feature passes manual QA — does it need an automated test?\\\\\\\",\\\\\\\"pin this regression so the same bug can't slip through again\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"my existing test is failing — why?\\\\\\\",\\\\\\\"write a testing-patterns guide for the contributor docs\\\\\\\",\\\\\\\"clean up this duplicated test setup across three files\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"debugging\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"debugging chases a specific observed failure; testing-strategy decides what to test BEFORE a failure exists\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"refactor\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"refactor reshapes code (including test setup) while preserving behavior; testing-strategy decides what coverage to author in the first place\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"integration-test-design\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"integration-test-design owns the design of integration-level tests including their setup and data lifecycle; the 'duplicated test setup across three files' anti_example has token overlap with integration-test setup discipline. testing-strategy decides what level a test should be; integration-test-design owns how to design integration tests once chosen.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"debugging\\\\\\\"]}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/testing-strategy/SKILL.md\"}"
|
|
8
|
+
metadata: "{\"schema_version\":6,\"version\":\"1.0.0\",\"type\":\"capability\",\"category\":\"quality\",\"scope\":\"portable\",\"owner\":\"skill-graph-maintainer\",\"freshness\":\"2026-04-18\",\"drift_check\":\"{\\\\\\\"last_verified\\\\\\\":\\\\\\\"2026-04-18\\\\\\\"}\",\"eval_artifacts\":\"present\",\"eval_state\":\"passing\",\"routing_eval\":\"present\",\"stability\":\"experimental\",\"keywords\":\"[\\\\\\\"testing strategy\\\\\\\",\\\\\\\"what to test\\\\\\\",\\\\\\\"what not to test\\\\\\\",\\\\\\\"which test level\\\\\\\",\\\\\\\"test scope\\\\\\\",\\\\\\\"effort vs risk\\\\\\\",\\\\\\\"regression target\\\\\\\",\\\\\\\"failure case coverage\\\\\\\",\\\\\\\"test plan\\\\\\\",\\\\\\\"do I need a test\\\\\\\",\\\\\\\"should I test this\\\\\\\",\\\\\\\"unit or integration\\\\\\\",\\\\\\\"test coverage\\\\\\\",\\\\\\\"pin this behavior\\\\\\\",\\\\\\\"plan test coverage\\\\\\\",\\\\\\\"plan coverage\\\\\\\",\\\\\\\"needs an automated test\\\\\\\",\\\\\\\"automated test\\\\\\\",\\\\\\\"manual QA coverage\\\\\\\",\\\\\\\"passes manual QA\\\\\\\",\\\\\\\"test level decision\\\\\\\",\\\\\\\"right test level\\\\\\\",\\\\\\\"correct test level\\\\\\\",\\\\\\\"test level for webhook\\\\\\\",\\\\\\\"test level for handler\\\\\\\"]\",\"triggers\":\"[\\\\\\\"testing-skill\\\\\\\"]\",\"routing_bundles\":\"[\\\\\\\"quality\\\\\\\"]\",\"examples\":\"[\\\\\\\"do I need a unit test for this pure formatter or is integration enough?\\\\\\\",\\\\\\\"what's the right test level for a webhook handler that talks to Stripe?\\\\\\\",\\\\\\\"the feature passes manual QA — does it need an automated test?\\\\\\\",\\\\\\\"pin this regression so the same bug can't slip through again\\\\\\\"]\",\"anti_examples\":\"[\\\\\\\"my existing test is failing — why?\\\\\\\",\\\\\\\"write a testing-patterns guide for the contributor docs\\\\\\\",\\\\\\\"clean up this duplicated test setup across three files\\\\\\\"]\",\"relations\":\"{\\\\\\\"boundary\\\\\\\":[{\\\\\\\"skill\\\\\\\":\\\\\\\"debugging\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"debugging chases a specific observed failure; testing-strategy decides what to test BEFORE a failure exists\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"refactor\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"refactor reshapes code (including test setup) while preserving behavior; testing-strategy decides what coverage to author in the first place\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"integration-test-design\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"integration-test-design owns the design of integration-level tests including their setup and data lifecycle; the 'duplicated test setup across three files' anti_example has token overlap with integration-test setup discipline. testing-strategy decides what level a test should be; integration-test-design owns how to design integration tests once chosen.\\\\\\\"},{\\\\\\\"skill\\\\\\\":\\\\\\\"microcopy\\\\\\\",\\\\\\\"reason\\\\\\\":\\\\\\\"microcopy owns functional UI text and contributor-facing writing; testing-strategy decides what and how to test. Writing a testing-patterns guide for contributor docs is a documentation/writing task owned by microcopy, not a test-scope decision.\\\\\\\"}],\\\\\\\"verify_with\\\\\\\":[\\\\\\\"debugging\\\\\\\"]}\",\"portability\":\"{\\\\\\\"readiness\\\\\\\":\\\\\\\"scripted\\\\\\\",\\\\\\\"targets\\\\\\\":[\\\\\\\"skill-md\\\\\\\"]}\",\"skill_graph_source_repo\":\"https://github.com/jacob-balslev/skill-graph\",\"skill_graph_protocol\":\"Skill Metadata Protocol v5\",\"skill_graph_project\":\"Skill Graph\",\"skill_graph_canonical_skill\":\"skills/testing-strategy/SKILL.md\"}"
|
|
9
9
|
skill_graph_source_repo: "https://github.com/jacob-balslev/skill-graph"
|
|
10
10
|
skill_graph_protocol: Skill Metadata Protocol v4
|
|
11
11
|
skill_graph_project: Skill Graph
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skill-graph/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
4
|
"description": "Skill Graph — library-level tooling for SKILL.md libraries: lint, manifest compiler, router, drift sentinel, and export pipeline.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -59,6 +59,8 @@
|
|
|
59
59
|
"marketplace:verify": "node scripts/export-marketplace-skills.js --check && node scripts/verify-skill-md-export.js --plain marketplace/skills",
|
|
60
60
|
"overlap": "node scripts/skill-overlap.js",
|
|
61
61
|
"drift": "node scripts/skill-graph-drift.js",
|
|
62
|
+
"status": "node scripts/build-status-doc.js",
|
|
63
|
+
"status:check": "node scripts/build-status-doc.js --check",
|
|
62
64
|
"test:unit": "node scripts/__tests__/test-v3-1-skos-runtime.js && node scripts/__tests__/test-router-paths.js && node scripts/__tests__/test-v3-1-alias-contract.js && node scripts/__tests__/test-export-parser-drift.js && node scripts/__tests__/test-marketplace-export.js && node scripts/__tests__/test-stability-promotion.js && node bin/skill-graph.js --help",
|
|
63
65
|
"test:migrate": "node scripts/__tests__/migrate-skill-v3-to-v4.test.js && node scripts/__tests__/migrate-skill-v2-to-v3.test.js",
|
|
64
66
|
"test": "npm run test:unit && npm run test:migrate",
|
|
@@ -82,9 +82,13 @@ const exportedA11yFm = parseFrontmatter(exportedA11y);
|
|
|
82
82
|
assert(exportedA11yFm, 'marketplace export should have frontmatter');
|
|
83
83
|
const shape = validateExportedFrontmatter(exportedA11yFm);
|
|
84
84
|
assert(shape.errors.length === 0, `marketplace export should be plain SKILL.md shape: ${shape.errors.join('; ')}`);
|
|
85
|
+
// After the M1 category restructure, a11y lives at skills/quality/a11y/SKILL.md
|
|
86
|
+
// in the sibling skills repo. Derive the expected path from the resolved source
|
|
87
|
+
// rather than hardcoding it, so the assertion stays correct if the skill moves again.
|
|
88
|
+
const _expectedCanonicalSkill = a11y.canonicalSkillPath;
|
|
85
89
|
assert(
|
|
86
|
-
exportedA11yFm.metadata.skill_graph_canonical_skill ===
|
|
87
|
-
|
|
90
|
+
exportedA11yFm.metadata.skill_graph_canonical_skill === _expectedCanonicalSkill,
|
|
91
|
+
`marketplace export should preserve canonical source path (expected: ${_expectedCanonicalSkill})`
|
|
88
92
|
);
|
|
89
93
|
assert(
|
|
90
94
|
exportedA11yFm.metadata.skill_graph_protocol === SKILL_GRAPH_PROTOCOL &&
|
|
@@ -56,8 +56,8 @@ const fm = {
|
|
|
56
56
|
'allowed-tools': 'Read Grep',
|
|
57
57
|
allowed_tools: 'Read Grep',
|
|
58
58
|
compatibility: {
|
|
59
|
-
runtimes: ['
|
|
60
|
-
agent_runtimes: ['
|
|
59
|
+
runtimes: ['agent-runtime>=2.0'],
|
|
60
|
+
agent_runtimes: ['agent-runtime>=2.0'],
|
|
61
61
|
node: '>=20',
|
|
62
62
|
node_version: '>=20',
|
|
63
63
|
},
|
|
@@ -87,7 +87,7 @@ assert(entry.domain === fm.domain, 'domain should pass through');
|
|
|
87
87
|
assert(entry.allowed_tools === fm.allowed_tools, 'allowed_tools alias should pass through');
|
|
88
88
|
assert(entry.health.reviewed_at === fm.reviewed_at, 'reviewed_at alias should project to health.reviewed_at');
|
|
89
89
|
assert(entry.health.eval && entry.health.eval.content_state === 'unverified', 'nested eval alias should project to health.eval');
|
|
90
|
-
assert(entry.compatibility.agent_runtimes[0] === '
|
|
90
|
+
assert(entry.compatibility.agent_runtimes[0] === 'agent-runtime>=2.0', 'compatibility.agent_runtimes should pass through');
|
|
91
91
|
assert(entry.compatibility.node_version === '>=20', 'compatibility.node_version should pass through');
|
|
92
92
|
assert(entry.grounding.subject === 'Alias contract', 'grounding.subject should pass through');
|
|
93
93
|
assert(entry.grounding.claim_scope === 'repo_specific', 'grounding.claim_scope should pass through');
|