OR Key
drop another .md file to compare - side-by-side diff against bootstrap

bootstrap

Teaches your assistant a brand-new skill without you writing anything.
description: "Triggers on prompt mention of 'bootstrap'."
personal 2 files 10 recent evals

What it does for you

Teaches your assistant a brand-new skill without you writing anything.

What it produces

A recent result, so you can see the kind of work it returns.

loading…

How to get it

These run inside the Snappy workspace. Want this working in your business? I set skills like this up with you, in one focused week.

Work with me
For developers how this skill is built, graded, and how it runs

at a glance- the short version

actorAgent running this skill (human or subagent).
auditorState/lint/check.ts + state/lint/audit.ts + the lib
eval modeauto
categorySystem
stages7
dependsskill

what's inside - the parts that make up a skill 2/4 present

A skill is just a few plain-text files. Only the main one is required. The rest are optional, added as the work needs them. This is what the skill is made of; how it runs is just below.

The skill
state/skills/bootstrap/SKILL.md present
the skill itself, in plain text
The main file. It says what the skill is and lays out the steps in plain English.
Code
state/lib/bootstrap.ts not present
code the skill can run
Optional. Many skills are just words and need no code at all.
Scripts
state/bin/bootstrap/ not present
helper scripts
Optional. Added when a skill has a few commands to run.
Loader
state/skills/bootstrap/AGENTS.md present
what the AI loads on the fly
Loaded automatically the moment this skill is needed. Kept short on purpose.

how it's graded - what counts as a good run 4 criteria · 3 deterministic · 1 judge

Each row is one thing a good run has to get right. deterministic means a quick check decides, pass or fail. judge means the AI reads the result and rates it. Grading each piece on its own (instead of one overall score) shows exactly where a run fell short, so the fix is obvious.

name
kind
check
lib_port_correctness
deterministic
The ported library file at 'state/lib/<short_name>.ts' must exactly match the source kernel 'api.ts' with only the specified (and logged) rewrites applied, as verified by a diff tool ignoring the defined substitutions and CLI guard alterations.
skill_page_completeness
judge
The generated skill page at 'state/skills/$skill_name.md' must have all required fields ('name', 'description', 'inputs', 'requires', 'steps', 'eval', 'gotchas') populated accurately and completely based on the kernel skill's metadata and the porting process, reflecting the intended purpose and usage of the new skill.
state_index_updated
deterministic
The 'state/index.md' file must correctly reflect the addition of the new library and skill, including an incremented 'Verbs (N total)' count, within the same transaction as the porting.
verification_steps_pass
deterministic
All three verification commands in Step 6 must execute successfully, with the first printing the correct number of function exports, the second exiting with code 0, and the third exiting with code 0 or reporting strictly fewer phantoms than prior to the bootstrap execution.

how it runs - the shared frame every skill uses 5/5 present

Every skill runs the same way. One part does the work, a separate part checks it, and a short loader hands the AI exactly what it needs for the job. Anything this skill doesn't use shows a one-line note saying why, on purpose, not by accident.

makes the work The worker
present
Agent running this skill (human or subagent). the worker
Does the actual work. Whatever it produces is what gets checked next.
checks the work The reviewer
present
State/lint/check.ts + state/lint/audit.ts + the lib the checker
A separate checker grades the work, so the part that made it can't approve its own work.
frame
learns Self-correction
present
fixes itself learns from gaps
When a run hits a gap, the skill gets edited on the spot [FIXED] or queued for a bigger rewrite [LOGGED], so it keeps getting better.
tidies up Background fixes
present
queued for rewrite runs in the background
Bigger fixes that can't be made on the spot get queued and rewritten in the background later.
remembers Run history
present
state/log/evals.ndjson unknown runs
Every run is written down here, so the next time this skill is used it already knows how the last runs went.
Critical rules the things this skill must not get wrong
  1. NEVER port a leaf skill before its kernel-sibling imports are in state/lib/ — depth-first, not breadth-first. Recursive ports are the norm (Gotchas §Recursive depth)
  2. NEVER refactor kernel code during port — only the three mechanical rewrites are allowed (settings/load path, sibling api.ts paths, CLI-guard realpathSync wrapped in try/catch). Anything else gets logged to state/log/port-notes.ndjson and surfaced in the skill page Gotchas
  3. NEVER skip the "update state/index.md FIRST" step — check.ts will fail with index-skill-count-drift and force interleaving anyway
  4. ALWAYS use the strong import probe (Object.keys(m).filter(k => typeof m[k] === "function")) — weak Object.keys(m).length is satisfied by tsx's module wrapper even when nothing exported
  5. ALWAYS roll back on lib_loads == false OR lint_passes == false. Audit regressions are 0.5, not 0.0

what it has learned - fixes written back in over time sample

When a run hits something this skill didn't handle, the fix gets written back into the skill so it doesn't happen again. FIXED means it was corrected on the spot. LOGGED means it's queued for a bigger rewrite. Either way, the skill gets a little better and never makes the same mistake twice.

  1. Loading feedback rows…

how the work flows- who makes it, who checks it

inputs skill
actor Agent running this skill (human or subagent).
1 generator
invoke
actor = Agent running this skill (human or subagent).
read program.md + state/index.md + audit.ts output, then follow `state/skills/bootstrap/SKILL.md` §Steps 1-7
auditor State/lint/check.ts + state/lint/audit.ts + the lib
2 auditor
inspect
auditor = State/lint/check.ts + state/lint/audit.ts + the lib
in order — `npx tsx -e 'import(...).then(m => Object.keys(m).filter(k => typeof m[k] === "function"))'` then `npx tsx state/lint/check.ts` then `npx tsx state/lint/audit.ts
5 data
Log + eval
```typescript

SKILL.md- the skill, written out in plain English

<!-- kernel-ok: this skill IS the kernel→os port runbook; references to ../snappy-* paths are intentional migration-table examples. -->

bootstrap

This is the self-hosting test. If a fresh agent can execute this skill reading only program.md + state/ and no conversation context, the system is self-extending. If not, fix what's missing in program.md or this page and try again.

Preconditions

  1. program.md has been read in full this session.
  2. state/index.md has been read in full this session.
  3. state/lint/audit.ts has been run this session and its output is the

source of truth for what gap to close.

  1. $kernel_skill exists at ~/projects/snappy-kernel/skills/$kernel_skill/.

Steps

1. Scope (no writes)

  • Read ~/projects/snappy-kernel/skills/$kernel_skill/api.ts.
  • List every import ... from that is not a Node builtin. For each,

classify: (a) already in state/lib/ (rewire to ./), (b) kernel sibling that needs recursive porting, or (c) external package (npm - leave alone).

  • If any (b) imports exist, recursively bootstrap them first - depth

first, not breadth. Do not port the leaf until its dependencies are in state/lib/.

  • Read state/skills/_template.md once. This is the starting point for

the new skill page.

2. Gate

Throw if any of these are true:

  • kernel_skill directory does not exist.
  • A file at state/lib/<kernel_skill-without-prefix>.ts already exists

(would clobber - require --force or a different name).

  • A skill page at state/skills/<skill_name>.md already exists.
  • state/lint/check.ts currently reports errors (bootstrap never runs on

a broken tree - fix first).

3. Port the lib

cp ~/projects/snappy-kernel/skills/$kernel_skill/api.ts \
   ~/projects/snappy-os/state/lib/<short_name>.ts

Rewrite rule - apply these three substitutions in order, then stop:

Kernel patternMini replacement
from "../snappy-settings/load.ts"from "./env.ts"
from "../snappy-<name>/api.ts"from "./<name>.ts" (only if the sibling is already in state/lib/)
await import("../snappy-<name>/api.ts")await import("./<name>.ts") (same condition)

Do not refactor anything else. The kernel code is assumed to work; the port is a reshuffle, not a rewrite. If a rewrite is actually needed, log a note to state/log/port-notes.ndjson and flag it in the skill page's ## Gotchas section.

CLI-guard carve-out. Kernel api.ts files often end with a if (import.meta.url === \file://\${realpathSync(process.argv[1])}\) { ... } CLI-entry guard. realpathSync(process.argv[1]) crashes under await import() (the verify probe in §5), so this one pattern IS allowed to be patched: wrap the realpathSync call in a try { ... } catch { return; } or delete the guard block entirely. Any other rewrite still violates the rule. Log the carve-out as a row in state/log/port-notes.ndjson with {kind: "cli-guard-patch", file} so the next agent knows why the diff exists.

4. Write the skill page

cp state/skills/_template.md state/skills/$skill_name.md

Then fill in:

  • name: - $skill_name
  • description: - one sentence derived from the kernel skill's SKILL.md
  • inputs: / requires: - derived from the exported functions' signatures
  • ## Steps - one bullet per exported function, pointing at the new lib
  • ## Eval - name the actor and the auditor explicitly. If you

cannot, mark eval: manual AND add a ## Gotchas note explaining which auditor would graduate it to auto.

  • ## Gotchas - copy any loud warnings from the kernel SKILL.md skillatim

5. Update state/index.md FIRST

Catalog update is a prerequisite for verify, not a follow-up. Add one row to the Libraries table and one row to the appropriate Verbs section, and bump the ## Verbs (N total · R% auto-eval) header count. If you skip this, check.ts will immediately fail with index-skill-count-drift and you'll have to interleave anyway. Do it here.

6. Verify

Run these three commands in order. Any failure rolls back.

npx tsx -e 'import("/Users/robertboulos/projects/snappy-os/state/lib/<short_name>.ts").then(m => { const ns = m.default || m; const fns = Object.keys(ns).filter(k => typeof ns[k] === "function"); console.log(fns.length + " function exports: " + fns.join(",")); })'
npx tsx state/lint/check.ts
npx tsx state/lint/audit.ts
  • Step 1 must print a function-export count that matches the number of

export function / export async function declarations in the kernel source. A weak check like Object.keys(m).length lets tsx's module wrapper satisfy "non-zero" even when nothing actually exported - filter to typeof m[k] === "function" so the probe is real.

  • Step 2 must exit 0 (structural lint passes).
  • Step 3 must exit 0 OR show strictly fewer phantoms than before the run

(new gaps are OK if they're nested ports; regressions are not). A phantom count that is unchanged counts as pass - baseline phantoms (external-deps, false-positive fn citations) are documented, not bugs.

7. Log + eval

append("chain", { run_id, skill: "bootstrap",
                  action: "ported",
                  kernel_skill, skill_name, lib_path, skill_path });
append("port", { wave: "incremental", via: "bootstrap",
                 kernel_skill, skill_name, exports, phantoms_before, phantoms_after });
score("bootstrap", run_id, {
  score:
    lib_loads && lint_passes && phantoms_not_worse ? 1.0 :
    lib_loads && lint_passes ? 0.5 :
    0.0,
  exports_count, phantoms_delta,
  primary_issue:
    !lib_loads ? "lib-import-fail" :
    !lint_passes ? "lint-errors" :
    "phantoms-regressed",
});

Eval

Actor: the agent running this skill (human or subagent). Auditor: state/lint/check.ts + state/lint/audit.ts + the lib import probe. All three are deterministic scripts, none of them wrote the port.

Score convention:

OutcomeScore
Lib loads, lint passes, audit delta ≤ 01.0
Lib loads + lint passes but audit regressed0.5
Lib fails to load OR lint errors0.0 - roll back

Thesis check: bootstrap is only graduated when an agent with no conversation context beyond program.md + state/ can execute it end-to-end. If you find yourself editing this page to close a gap the agent hit, that gap is real - fix this page before running again.

Gotchas

  • Recursive depth. If the kernel skill imports two other kernel

skills, you will be three ports deep before the leaf compiles. Budget for it. Log each nested port as its own port.ndjson row.

  • JSDoc examples trip greps. The kernel api.ts files often have

@example blocks with literal import ... from "../snappy-..." strings. The lint's regex strips block comments before scanning, but if you extend the lint, preserve that behavior.

  • Don't port *.md files. SKILL.md and AGENTS.md belong to the kernel

shape, not mini's. Extract the one or two load-bearing facts into the skill page's ## Gotchas section and leave the rest.

  • Don't port scripts unless the skill needs them. Mini's bin/ is for

graduated skills only. A new prose skill points at state/lib/<name>.ts and nothing else.

Rubric

criteria:
  - name: lib_port_correctness
    kind: deterministic
    check: "The ported library file at 'state/lib/<short_name>.ts' must exactly match the source kernel 'api.ts' with only the specified (and logged) rewrites applied, as verified by a diff tool ignoring the defined substitutions and CLI guard alterations."
  - name: skill_page_completeness
    kind: judge
    check: "The generated skill page at 'state/skills/$skill_name.md' must have all required fields ('name', 'description', 'inputs', 'requires', 'steps', 'eval', 'gotchas') populated accurately and completely based on the kernel skill's metadata and the porting process, reflecting the intended purpose and usage of the new skill."
  - name: state_index_updated
    kind: deterministic
    check: "The 'state/index.md' file must correctly reflect the addition of the new library and skill, including an incremented 'Verbs (N total)' count, within the same transaction as the porting."
  - name: verification_steps_pass
    kind: deterministic
    check: "All three verification commands in Step 6 must execute successfully, with the first printing the correct number of function exports, the second exiting with code 0, and the third exiting with code 0 or reporting strictly fewer phantoms than prior to the bootstrap execution."

AGENTS.md- what the AI loads when this skill comes up

bootstrap - loader

Per-turn rules for the bootstrap skill. Full reference: state/skills/bootstrap/SKILL.md. Do not skip these.

Critical Rules

  • NEVER port a leaf skill before its kernel-sibling imports are in state/lib/ - depth-first, not breadth-first. Recursive ports are the norm (Gotchas §Recursive depth)
  • NEVER refactor kernel code during port - only the three mechanical rewrites are allowed (settings/load path, sibling api.ts paths, CLI-guard realpathSync wrapped in try/catch). Anything else gets logged to state/log/port-notes.ndjson and surfaced in the skill page Gotchas
  • NEVER skip the "update state/index.md FIRST" step - check.ts will fail with index-skill-count-drift and force interleaving anyway
  • ALWAYS use the strong import probe (Object.keys(m).filter(k => typeof m[k] === "function")) - weak Object.keys(m).length is satisfied by tsx's module wrapper even when nothing exported
  • ALWAYS roll back on lib_loads == false OR lint_passes == false. Audit regressions are 0.5, not 0.0

Commands

| ui dashboard | state/skills/bootstrap/resources/ui.openui | |invoke: read program.md + state/index.md + audit.ts output, then follow state/skills/bootstrap/SKILL.md §Steps 1-7 |verify: in order - npx tsx -e 'import(...).then(m => Object.keys(m).filter(k => typeof m[k] === "function"))' then npx tsx state/lint/check.ts then npx tsx state/lint/audit.ts |eval log: state/log/evals.ndjson (skill: "bootstrap"); also state/log/port.ndjson for each nested port

OpenUI Resource

  • Skill-owned OpenUI Lang resource: state/skills/bootstrap/resources/ui.openui. Read it before rendering or editing this skill's generated component surface.
  • Treat this resource as a first-class artifact of the skill, not a generic chat response. Improve it when the skill's user-facing output needs to become richer.
  • System resources compose OpenUI primitives and inherit SnappyChat tokens. Use ui_contract: branded in SKILL.md only for deliberate platform or client visuals.

Known Pitfalls

  • JSDoc @example blocks trip greps. Kernel api.ts files have literal import ... from "../snappy-..." strings inside /** */. The lint strips block comments before scanning - preserve that behavior if you extend it.
  • Don't port *.md files. SKILL.md / AGENTS.md belong to kernel shape. Extract one or two load-bearing facts into the new skill's ## Gotchas section.
  • Don't port scripts unless the new skill is graduating. Mini's bin/ is for graduated skills only.
  • Phantom audit count unchanged ≠ regression. Baseline phantoms (external-deps, false-positive fn citations) are documented; only strict regressions fail.
  • CLI-guard carve-out logging. When you wrap realpathSync(process.argv[1]), log a {kind: "cli-guard-patch", file} row to state/log/port-notes.ndjson so the next agent knows why the diff exists.

Self-Test

An agent reading this should correctly:

  1. [ ] Recursively port a kernel-sibling import before touching the leaf
  2. [ ] Bump the ## Verbs (N total · R% auto-eval) count when adding a row to index.md
  3. [ ] Use the strong typeof-function probe in step 6 verify
  4. [ ] Score 0.5 (not 0.0) when audit phantoms grow but lib loads + lint passes

Self-report

If this loader fell short, append a line:

echo "[$(date -u +%FT%TZ)] bootstrap: <what was missing>" >> state/log/loader-feedback.log

<!-- kernel-ok: historical attribution for the PID-loader pattern. -->

Self-correcting loader (PID feedback)

This is the rule that makes loaders learn. Ported from snappy-kernel, where it demonstrably worked: the snappy-dom-cartographer skill mapped Skool admin UI once, every later ship-agent inherited the full map for free.

Before you finish, do two things:

1. Fix gaps (P - proportional). MANDATORY. If this loader didn't cover your case - if you had to read another file, run an undocumented command, work around a wrong selector, or discover a quirk - you MUST attempt an Edit to this AGENTS.md before you log.

  • Default action: edit this file. Surgical. Add the missing line, table

row, or code example where it belongs. No restructuring.

  • Only LOGGED is allowed when: the fix needs >10 lines, spans multiple

files, or requires a structural rewrite. In that case the state/regen/drain.sh queue picks it up asynchronously.

  • "I didn't have time" / "it's minor" / "the next agent will figure it out"

are NOT valid reasons. Minor gaps compound - that's the whole point of this loop.

  • Concrete example of a valid P-fix: discover agent-browser screenshot

takes path positionally not as --output <path>. One line in a table. Edit it in. Do not just log it.

  • The goal: the next agent never has to leave the loader.

2. Log the result.

echo "[$(date -u +%FT%TZ)] bootstrap: <what was missing or fixed> [FIXED|LOGGED]" >> state/log/loader-feedback.log
  • FIXED = you patched this loader inline (P-fix).
  • LOGGED = too large for inline; the PostToolUse enqueue + Stop-hook drain

will rewrite the loader from scratch on next session-end.

Do not skip this. Every agent run must leave the system better than it found it. The loader is the setpoint; you are the sensor; the gap is the error signal; closing the gap is the correction.

api.ts- the code it can call

⚠ no api.ts - this skill has no typed action surface

scripts- helper scripts it can run

prose-only skill - 5 inline code blocks live in SKILL.md above (no state/bin/ sidecar yet).

how we check it- the checks, plus the last 10 runs

rubric auto no rubric declared
recent mean 1.00 · 10 runs actor/auditor: unverifiable
deps skill
timestamp verb score primary_issue artifact
2026-04-25 04:11Z - 1.00 - -
2026-04-21 15:58Z - 1.00 - -
2026-04-21 15:56Z - 1.00 - -
2026-04-21 03:53Z - 1.00 - -
2026-04-20 17:35Z - 1.00 - -
2026-04-16 01:11Z - 1.00 - -
2026-04-16 01:11Z - 1.00 - -
2026-04-16 01:01Z - 1.00 - -
2026-04-16 00:04Z - 1.00 - -
2026-04-25 04:11Z - 1.00 - -