@sema-agent/server 1.196.0 → 1.197.0

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.
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Validate a categorical chart palette against the computable data-viz checks.
3
+ *
4
+ * Design-system-agnostic: feed it ANY palette's hex values plus the mode and
5
+ * surface, and it computes — never eyeballs — the four checks that can be
6
+ * measured from color alone:
7
+ *
8
+ * 2. Lightness band — OKLCH L within the mode's band
9
+ * 3. Chroma floor — OKLCH C >= floor (below it a hue reads as gray)
10
+ * 4. CVD separation — Machado-2009 ΔE between slots (protan/deutan/tritan);
11
+ * adjacent pairs by default, pairs:"all" for scatter/bubble/maps
12
+ * 5. Contrast vs surface — WCAG ratio of each mark against the chart surface
13
+ *
14
+ * Checks 1 (fixed hue order) and 6 (values are from the documented palette) are
15
+ * structural rules the skill enforces, not measurable from hexes alone.
16
+ *
17
+ * Usage (node):
18
+ * node validate_palette.js "#2a78d6,#1baf7a,#eda100,#008300,#4a3aa7,#e34948,#e87ba4,#eb6834" --mode light
19
+ * node validate_palette.js "#256abf,#199e70,..." --mode dark --surface "#1a1a19"
20
+ * node validate_palette.js "#cde2fb,#9ec5f4,#6da7ec,#3987e5,#256abf" --ordinal
21
+ *
22
+ * Usage (browser — as a module script):
23
+ * <body data-palette="#2a78d6,#1baf7a,..." data-mode="light">
24
+ * <script type="module" src="validate_palette.js"></script>
25
+ * → logs a console.table of the report and console.warn on any FAIL.
26
+ *
27
+ * Exit code 0 unless a check hard-FAILs; 1 on any FAIL. WARN bands do not fail:
28
+ * adjacent CVD in the 8–12 floor band, and contrast in the sub-3:1 relief band,
29
+ * are reported as WARNs and still exit 0 (each is legal only with mandatory
30
+ * secondary encoding: direct labels, gaps, or texture).
31
+ */
32
+
33
+ // ── thresholds ────────────────────────────────────────────────────────────────
34
+ const BAND = { light: [0.43, 0.77], dark: [0.48, 0.67] }; // OKLCH L
35
+ const CHROMA_FLOOR = 0.10; // OKLCH C
36
+ const CVD_TARGET = 12.0, CVD_FLOOR = 8.0; // CIE76 ΔE on adjacent pairs
37
+ const CONTRAST_MIN = 3.0; // WCAG vs surface
38
+ const DEFAULT_SURFACE = { light: "#fcfcfb", dark: "#1a1a19" };
39
+ const ORDINAL_MIN_DL = 0.06; // min OKLCH ΔL between adjacent steps
40
+ const ORDINAL_LIGHT_FLOOR = 2.0; // lightest step: WCAG contrast vs surface
41
+
42
+ // Machado, Oliveira & Fernandes (2009) CVD transforms at severity 1.0 (linear RGB).
43
+ const MACHADO = {
44
+ protan: [[0.152286, 1.052583, -0.204868],
45
+ [0.114503, 0.786281, 0.099216],
46
+ [-0.003882, -0.048116, 1.051998]],
47
+ deutan: [[0.367322, 0.860646, -0.227968],
48
+ [0.280085, 0.672501, 0.047413],
49
+ [-0.011820, 0.042940, 0.968881]],
50
+ tritan: [[1.255528, -0.076749, -0.178779],
51
+ [-0.078411, 0.930809, 0.147602],
52
+ [0.004733, 0.691367, 0.303900]],
53
+ };
54
+
55
+ // ── color conversions ──────────────────────────────────────────────────────────
56
+ const hex2srgb = (h) => { h = h.trim().replace(/^#/, ""); return [0, 2, 4].map(i => parseInt(h.slice(i, i + 2), 16) / 255); };
57
+ const s2lin = (c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
58
+ const lin2s = (c) => { c = Math.max(0, Math.min(1, c)); return c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055; };
59
+ const lin = (h) => hex2srgb(h).map(s2lin);
60
+ const relLum = (h) => { const [r, g, b] = lin(h); return 0.2126 * r + 0.7152 * g + 0.0722 * b; };
61
+ export const contrast = (a, b) => { const [hi, lo] = [relLum(a), relLum(b)].sort((x, y) => y - x); return (hi + 0.05) / (lo + 0.05); };
62
+
63
+ function oklab(h) {
64
+ const [r, g, b] = lin(h);
65
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
66
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
67
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
68
+ return [
69
+ 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s, // L
70
+ 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s, // a
71
+ 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s, // b
72
+ ];
73
+ }
74
+ const oklch = (h) => { const [L, a, b] = oklab(h); return [L, Math.hypot(a, b)]; };
75
+ const okhue = (h) => { const [, a, b] = oklab(h); return ((Math.atan2(b, a) * 180 / Math.PI) % 360 + 360) % 360; };
76
+
77
+ // CIELAB (D65) for ΔE
78
+ function lin2lab(r, g, b) {
79
+ const X = 0.4124564 * r + 0.3575761 * g + 0.1804375 * b;
80
+ const Y = 0.2126729 * r + 0.7151522 * g + 0.0721750 * b;
81
+ const Z = 0.0193339 * r + 0.1191920 * g + 0.9503041 * b;
82
+ const f = (t) => t > 0.008856 ? Math.cbrt(t) : 7.787 * t + 16 / 116;
83
+ const [fx, fy, fz] = [f(X / 0.95047), f(Y / 1.0), f(Z / 1.08883)];
84
+ return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
85
+ }
86
+ function simulate(h, kind) {
87
+ const [r, g, b] = lin(h), M = MACHADO[kind];
88
+ const clamp = (c) => Math.max(0, Math.min(1, c));
89
+ return [
90
+ clamp(M[0][0] * r + M[0][1] * g + M[0][2] * b),
91
+ clamp(M[1][0] * r + M[1][1] * g + M[1][2] * b),
92
+ clamp(M[2][0] * r + M[2][1] * g + M[2][2] * b),
93
+ ];
94
+ }
95
+ function deltaE(h1, h2, kind) {
96
+ const a = lin2lab(...(kind ? simulate(h1, kind) : lin(h1)));
97
+ const b = lin2lab(...(kind ? simulate(h2, kind) : lin(h2)));
98
+ return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
99
+ }
100
+
101
+ // ── checks ─────────────────────────────────────────────────────────────────────
102
+ export function validate(palette, { mode = "light", surface, pairs = "adjacent" } = {}) {
103
+ surface ??= DEFAULT_SURFACE[mode];
104
+ const [lo, hi] = BAND[mode];
105
+ const report = [];
106
+ let ok = true;
107
+
108
+ // 2. lightness band
109
+ const offband = palette.filter(c => { const L = oklch(c)[0]; return L < lo || L > hi; })
110
+ .map(c => [c, +oklch(c)[0].toFixed(3)]);
111
+ if (offband.length) ok = false;
112
+ report.push(["Lightness band", !offband.length,
113
+ offband.length ? `outside band: ${JSON.stringify(offband)}` : `all ${palette.length} inside L ${lo}–${hi}`]);
114
+
115
+ // 3. chroma floor
116
+ const lowc = palette.filter(c => oklch(c)[1] < CHROMA_FLOOR).map(c => [c, +oklch(c)[1].toFixed(3)]);
117
+ if (lowc.length) ok = false;
118
+ report.push(["Chroma floor", !lowc.length,
119
+ lowc.length ? `below floor (reads gray): ${JSON.stringify(lowc)}` : `all ${palette.length} >= ${CHROMA_FLOOR}`]);
120
+
121
+ // 4. CVD separation — adjacent for stacks/bars/lines; ALL pairs for scatter/bubble/maps/small-multiples
122
+ const n = palette.length;
123
+ const pairlist = pairs === "all"
124
+ ? Array.from({ length: n }, (_, i) => Array.from({ length: n - i - 1 }, (_, k) => [i, i + 1 + k])).flat()
125
+ : Array.from({ length: n - 1 }, (_, i) => [i, i + 1]);
126
+ const label = pairs === "all" ? "all-pairs" : "adjacent";
127
+ let worst = null;
128
+ for (const kind of ["protan", "deutan"]) {
129
+ for (const [i, j] of pairlist) {
130
+ const d = deltaE(palette[i], palette[j], kind);
131
+ if (worst === null || d < worst[0]) worst = [d, kind, palette[i], palette[j]];
132
+ }
133
+ }
134
+ const tri = pairlist.length ? Math.min(...pairlist.map(([i, j]) => deltaE(palette[i], palette[j], "tritan"))) : 99;
135
+ const nor = pairlist.length ? Math.min(...pairlist.map(([i, j]) => deltaE(palette[i], palette[j]))) : 99;
136
+ const wd = worst ? worst[0] : 99;
137
+ const cvdState = wd >= CVD_TARGET ? "pass" : wd >= CVD_FLOOR ? "floor" : "fail";
138
+ if (cvdState === "fail") ok = false;
139
+ report.push(["CVD separation", cvdState,
140
+ worst ? `worst ${label} ${worst[3]}↔${worst[2]} ΔE ${wd.toFixed(1)} (${worst[1]}) · tritan ${tri.toFixed(1)} · normal ${nor.toFixed(1)}` : "n/a"]);
141
+
142
+ // 5. contrast vs surface — sub-3:1 is a documented conditional relax (visible labels / table view), not a hard fail
143
+ const low = palette.filter(c => contrast(c, surface) < CONTRAST_MIN).map(c => [c, +contrast(c, surface).toFixed(2)]);
144
+ report.push(["Contrast vs surface", low.length ? "relief" : "pass",
145
+ low.length ? `below ${CONTRAST_MIN}:1 — relief required (visible labels or table view): ${JSON.stringify(low)}`
146
+ : `all ${palette.length} >= ${CONTRAST_MIN}:1`]);
147
+
148
+ return { report, ok };
149
+ }
150
+
151
+ export function validateOrdinal(palette, { mode = "light", surface } = {}) {
152
+ /* Ordered categories (funnel stages, size tiers, time buckets rendered as
153
+ discrete marks) take a one-hue ramp, not categorical hues. The categorical
154
+ checks FAIL a correct ramp by design (it spans the lightness band; light
155
+ steps drop below the chroma floor). The ordinal checks instead verify the
156
+ ramp reads *as a ramp*: one hue, monotone lightness with visible gaps
157
+ between steps, and a lightest step that still clears the surface. */
158
+ surface ??= DEFAULT_SURFACE[mode];
159
+ const report = [];
160
+ let ok = true;
161
+ const Ls = palette.map(c => oklch(c)[0]);
162
+
163
+ // Monotone lightness — sorted by L must match input order (or its reverse).
164
+ const order = [...Ls.keys()].sort((a, b) => Ls[a] - Ls[b]);
165
+ const fwd = order.every((v, i) => v === i);
166
+ const rev = order.every((v, i) => v === Ls.length - 1 - i);
167
+ const mono = fwd || rev;
168
+ if (!mono) ok = false;
169
+ report.push(["Lightness monotone", mono,
170
+ mono ? "steps read light→dark" : `out of order — L values ${JSON.stringify(Ls.map(l => +l.toFixed(3)))}`]);
171
+
172
+ // Adjacent ΔL — each step must be visibly distinct from its neighbour.
173
+ const gaps = Ls.slice(1).map((l, i) => Math.abs(l - Ls[i]));
174
+ const thin = gaps.map((g, i) => [palette[i], palette[i + 1], +g.toFixed(3)]).filter(([, , g]) => g < ORDINAL_MIN_DL);
175
+ if (thin.length) ok = false;
176
+ report.push(["Adjacent ΔL", !thin.length,
177
+ thin.length ? `steps too close: ${JSON.stringify(thin)}` : `all gaps >= ${ORDINAL_MIN_DL}`]);
178
+
179
+ // Lightest step vs surface — the pale end must still read as a mark.
180
+ const byL = [...palette].sort((a, b) => oklch(a)[0] - oklch(b)[0]);
181
+ const lightest = mode === "light" ? byL[byL.length - 1] : byL[0];
182
+ const cr = contrast(lightest, surface);
183
+ if (cr < ORDINAL_LIGHT_FLOOR) ok = false;
184
+ report.push(["Light-end contrast", cr >= ORDINAL_LIGHT_FLOOR,
185
+ `${lightest} at ${cr.toFixed(2)}:1 vs surface` + (cr >= ORDINAL_LIGHT_FLOOR ? "" : ` — below ${ORDINAL_LIGHT_FLOOR}:1 floor`)]);
186
+
187
+ // Single hue — an ordinal ramp is one hue; a hue jump means it's categorical.
188
+ const hues = palette.map(okhue);
189
+ let spread = hues.length ? Math.max(...hues) - Math.min(...hues) : 0;
190
+ if (spread > 180) spread = 360 - spread;
191
+ const oneHue = spread <= 40;
192
+ if (!oneHue) ok = false;
193
+ report.push(["Single hue", oneHue,
194
+ `hue spread ${spread.toFixed(0)}°` + (oneHue ? "" : " — >40°, not a one-hue ramp")]);
195
+
196
+ return { report, ok };
197
+ }
198
+
199
+ // ── entrypoints ────────────────────────────────────────────────────────────────
200
+ const GLYPH = { true: "PASS", false: "FAIL", pass: "PASS", floor: "WARN", fail: "FAIL", relief: "WARN" };
201
+
202
+ function printReport({ report, ok }, { mode, surface, ordinal, n }) {
203
+ const kind = ordinal ? "ordinal ramp" : "categorical";
204
+ console.log(`\nPalette (${mode}, surface ${surface}, ${kind}): ${n} slots`);
205
+ for (const [name, state, detail] of report) {
206
+ console.log(` [${(GLYPH[state] ?? state).padEnd(4)}] ${name.padEnd(22)} ${detail}`);
207
+ }
208
+ if (ordinal) {
209
+ console.log(`\n → ${ok ? "ALL CHECKS PASS" : "FAILED — fix the marked checks"}`
210
+ + " (ordinal: one hue, monotone L, visible step gaps, light end clears surface)");
211
+ } else {
212
+ console.log(`\n → ${ok ? "ALL CHECKS PASS" : "FAILED — fix the marked checks"}`
213
+ + " (CVD in the 8–12 floor band is legal ONLY with secondary encoding: direct labels, gaps, or texture)");
214
+ console.log(" scope: categorical palettes only. For a lone status/text color check WCAG"
215
+ + " text contrast; for a sequential ramp, lightness monotonicity.\n");
216
+ }
217
+ }
218
+
219
+ // Node CLI
220
+ if (typeof process !== "undefined" && process.argv && process.argv[1] && process.argv[1].endsWith("validate_palette.js")) {
221
+ const args = process.argv.slice(2);
222
+ const VALUE_FLAGS = new Set(["--mode", "--surface", "--pairs"]);
223
+ const CHOICES = { mode: ["light", "dark"], pairs: ["adjacent", "all"] };
224
+ const opts = {}; let positional = null;
225
+ for (let i = 0; i < args.length; i++) {
226
+ let a = args[i], val;
227
+ const eq = a.indexOf("="); if (eq > 0) { val = a.slice(eq + 1); a = a.slice(0, eq); }
228
+ if (VALUE_FLAGS.has(a)) { opts[a.slice(2)] = val ?? args[++i]; }
229
+ else if (a === "--ordinal") { opts.ordinal = true; }
230
+ else if (a.startsWith("--")) { console.error(`unknown flag: ${a}`); process.exit(2); }
231
+ else if (positional === null) { positional = a; }
232
+ else { console.error(`unexpected extra positional: ${a}`); process.exit(2); }
233
+ }
234
+ for (const [k, allowed] of Object.entries(CHOICES)) {
235
+ if (opts[k] != null && !allowed.includes(opts[k])) {
236
+ console.error(`--${k} must be one of: ${allowed.join(", ")} (got ${JSON.stringify(opts[k])})`); process.exit(2);
237
+ }
238
+ }
239
+ const palette = (positional || "").split(",").map(s => s.trim()).filter(Boolean);
240
+ if (!palette.length) { console.error("usage: node validate_palette.js \"#hex,#hex,...\" [--mode light|dark] [--surface #hex] [--pairs adjacent|all] [--ordinal]"); process.exit(2); }
241
+ const mode = opts.mode || "light";
242
+ const surface = opts.surface || DEFAULT_SURFACE[mode];
243
+ const pairs = opts.pairs || "adjacent";
244
+ const result = opts.ordinal ? validateOrdinal(palette, { mode, surface }) : validate(palette, { mode, surface, pairs });
245
+ printReport(result, { mode, surface, ordinal: !!opts.ordinal, n: palette.length });
246
+ process.exit(result.ok ? 0 : 1);
247
+ }
248
+
249
+ // Browser auto-run (as a <script type="module">). Fires whenever the page has a
250
+ // data-palette attribute on <body>; omit it to import the module without auto-running.
251
+ if (typeof document !== "undefined") {
252
+ const b = document.body;
253
+ if (b?.dataset.palette) {
254
+ const palette = b.dataset.palette.split(",").map(s => s.trim()).filter(Boolean);
255
+ const mode = b.dataset.mode || "light";
256
+ const surface = b.dataset.surface || DEFAULT_SURFACE[mode];
257
+ const ordinal = "ordinal" in b.dataset;
258
+ const result = ordinal ? validateOrdinal(palette, { mode, surface }) : validate(palette, { mode, surface, pairs: b.dataset.pairs || "adjacent" });
259
+ console.table(result.report.map(([name, state, detail]) => ({ check: name, result: GLYPH[state] ?? state, detail })));
260
+ if (!result.ok) console.warn("validate_palette: FAILED — fix the marked checks");
261
+ }
262
+ }
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: find-skills
3
+ description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
4
+ ---
5
+
6
+ # Find Skills
7
+
8
+ This skill helps you discover and install skills from the open agent skills ecosystem.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use this skill when the user:
13
+
14
+ - Asks "how do I do X" where X might be a common task with an existing skill
15
+ - Says "find a skill for X" or "is there a skill for X"
16
+ - Asks "can you do X" where X is a specialized capability
17
+ - Expresses interest in extending agent capabilities
18
+ - Wants to search for tools, templates, or workflows
19
+ - Mentions they wish they had help with a specific domain (design, testing, deployment, etc.)
20
+
21
+ ## What is the Skills CLI?
22
+
23
+ The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools.
24
+
25
+ **Key commands:**
26
+
27
+ - `npx skills find [query]` - Search for skills interactively or by keyword
28
+ - `npx skills add <package>` - Install a skill from GitHub or other sources
29
+ - `npx skills check` - Check for skill updates
30
+ - `npx skills update` - Update all installed skills
31
+
32
+ **Browse skills at:** https://skills.sh/
33
+
34
+ ## How to Help Users Find Skills
35
+
36
+ ### Step 1: Understand What They Need
37
+
38
+ When a user asks for help with something, identify:
39
+
40
+ 1. The domain (e.g., React, testing, design, deployment)
41
+ 2. The specific task (e.g., writing tests, creating animations, reviewing PRs)
42
+ 3. Whether this is a common enough task that a skill likely exists
43
+
44
+ ### Step 2: Check the Leaderboard First
45
+
46
+ Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options.
47
+
48
+ For example, top skills for web development include:
49
+ - `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each)
50
+
51
+ ### Step 3: Search for Skills
52
+
53
+ If the leaderboard doesn't cover the user's need, run the find command:
54
+
55
+ ```bash
56
+ npx skills find [query]
57
+ ```
58
+
59
+ For example:
60
+
61
+ - User asks "how do I make my React app faster?" → `npx skills find react performance`
62
+ - User asks "can you help me with PR reviews?" → `npx skills find pr review`
63
+ - User asks "I need to create a changelog" → `npx skills find changelog`
64
+
65
+ ### Step 4: Verify Quality Before Recommending
66
+
67
+ **Do not recommend a skill based solely on search results.** Always verify:
68
+
69
+ 1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100.
70
+ 2. **Source reputation** — Official sources from well-known vendors (e.g. `vercel-labs`, `microsoft`) are more trustworthy than unknown authors.
71
+ 3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism.
72
+
73
+ ### Step 5: Present Options to the User
74
+
75
+ When you find relevant skills, present them to the user with:
76
+
77
+ 1. The skill name and what it does
78
+ 2. The install count and source
79
+ 3. The install command they can run
80
+ 4. A link to learn more at skills.sh
81
+
82
+ Example response:
83
+
84
+ ```
85
+ I found a skill that might help! The "react-best-practices" skill provides
86
+ React and Next.js performance optimization guidelines from Vercel Engineering.
87
+ (185K installs)
88
+
89
+ To install it:
90
+ npx skills add vercel-labs/agent-skills@react-best-practices
91
+
92
+ Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices
93
+ ```
94
+
95
+ ### Step 6: Offer to Install
96
+
97
+ If the user wants to proceed, you can install the skill for them:
98
+
99
+ ```bash
100
+ npx skills add <owner/repo@skill> -g -y
101
+ ```
102
+
103
+ The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts.
104
+
105
+ ## Common Skill Categories
106
+
107
+ When searching, consider these common categories:
108
+
109
+ | Category | Example Queries |
110
+ | --------------- | ---------------------------------------- |
111
+ | Web Development | react, nextjs, typescript, css, tailwind |
112
+ | Testing | testing, jest, playwright, e2e |
113
+ | DevOps | deploy, docker, kubernetes, ci-cd |
114
+ | Documentation | docs, readme, changelog, api-docs |
115
+ | Code Quality | review, lint, refactor, best-practices |
116
+ | Design | ui, ux, design-system, accessibility |
117
+ | Productivity | workflow, automation, git |
118
+
119
+ ## Tips for Effective Searches
120
+
121
+ 1. **Use specific keywords**: "react testing" is better than just "testing"
122
+ 2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd"
123
+ 3. **Check popular sources**: Many skills come from well-known vendor collections such as `vercel-labs/agent-skills`
124
+
125
+ ## When No Skills Are Found
126
+
127
+ If no relevant skills exist:
128
+
129
+ 1. Acknowledge that no existing skill was found
130
+ 2. Offer to help with the task directly using your general capabilities
131
+ 3. Suggest the user could create their own skill with `npx skills init`
132
+
133
+ Example:
134
+
135
+ ```
136
+ I searched for skills related to "xyz" but didn't find any matches.
137
+ I can still help you with this task directly! Would you like me to proceed?
138
+
139
+ If this is something you do often, you could create your own skill:
140
+ npx skills init my-xyz-skill
141
+ ```
142
+
143
+ <!--
144
+ TODO (blackboard [832], clay): add our own first-party skill sources here -
145
+ sema-registry / config-center - as a discovery+install lane alongside the open
146
+ skills.sh ecosystem. Not every deployment ships a config-center, so the section
147
+ must probe availability first and fall back to the public ecosystem cleanly.
148
+ -->
package/skills/init.md ADDED
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: init
3
+ description: Initialize the project's agent-instructions file with codebase documentation. Use when asked to init the repo, bootstrap agent instructions, or create/refresh the project instruction file that future agent sessions load when working in this repository.
4
+ ---
5
+
6
+ Please analyze this codebase and create the project's agent-instructions file, which will be given to future agent sessions operating in this repository.
7
+
8
+ **Filename:** the conventional name is `AGENT.md` at the repo root, but the exact filename is shell/deployment-configurable — if this deployment already loads a specific instructions file (check what the shell injects into sessions, or an existing instructions file at the repo root), write to that name instead of introducing a second one.
9
+
10
+ What to add:
11
+ 1. Commands that will be commonly used, such as how to build, lint, and run tests. Include the necessary commands to develop in this codebase, such as how to run a single test.
12
+ 2. High-level code architecture and structure so that future instances can be productive more quickly. Focus on the "big picture" architecture that requires reading multiple files to understand.
13
+
14
+ Usage notes:
15
+ - If there's already an agent-instructions file, suggest improvements to it.
16
+ - When you make the initial instructions file, do not repeat yourself and do not include obvious instructions like "Provide helpful error messages to users", "Write unit tests for all new utilities", "Never include sensitive information (API keys, tokens) in code or commits".
17
+ - Avoid listing every component or file structure that can be easily discovered.
18
+ - Don't include generic development practices.
19
+ - If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include the important parts.
20
+ - If there is a README.md, make sure to include the important parts.
21
+ - Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read.
22
+ - Be sure to prefix the file with the following text (substituting the actual filename you chose):
23
+
24
+ ```
25
+ # AGENT.md
26
+
27
+ This file provides guidance to coding agents when working with code in this repository.
28
+ ```