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

cockpit-layout

Lays out your workspace so opening it shows your business, not technical clutter.
personal 2 files 2 recent evals

What it does for you

Lays out your workspace so opening it shows your business, not technical clutter.

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

eval modeshape
categorySystem
stages1

what's inside - the parts that make up a skill 3/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/cockpit-layout/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/cockpit-layout.ts present
code the skill can run
Reusable code this skill can call when it needs to.
Scripts
state/bin/cockpit-layout/ not present
helper scripts
Optional. Added when a skill has a few commands to run.
Loader
state/skills/cockpit-layout/AGENTS.md present
what the AI loads on the fly
Loaded automatically the moment this skill is needed. Kept short on purpose.

how it runs - the shared frame every skill uses 2/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
inferred
npx tsx state/lib/cockpit-layout.ts from a command
No worker named, so the first command in the skill is treated as the worker.
checks the work The reviewer
inferred
shape gate an automatic check
The check is an automatic pass or fail on the shape of the result, run separately from the work itself.
frame
learns Self-correction
not present

This skill doesn't fix its own gaps yet.

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 shape 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. The bundle layout command is npx tsx state/lib/cockpit-layout.ts. It creates operator folders/symlinks and _about.md files without moving canonical state/ data.
  2. Before claiming a snappy-shell page redesign is done, run npx tsx state/lint/codable-drift.ts from snappy-os and trace the page's actual dataClient method plus as: Type.self decode target. Fix the Codable the screen really uses, not just the first lint row.
  3. Pre-mount Swift screens can call only bootstrap endpoints: /healthz, /state, /bundle/status, /bundle/mount, /bundle/eject, /bundle-meta, and /events. Add a bootstrap endpoint server-side if richer data is needed before mount.
  4. Multi-rail snappy-os pages need an outer vertical ScrollView with a leading VStack; otherwise lower rails clip behind the pinned footer.
  5. For Swift investigation, use swiftlens first: swift_get_symbols_overview, symbol definition/references, diagnostics, validation. Read whole Swift files only after semantic tools point to a tight range.
  6. Parallel-agent workflow must use explicit pathspecs. Never git add -A, git add ., git commit -a, or broad git stash -u. For commits, prefer git commit -m "..." -- <paths>.
  7. +4 more in AGENTS.md →

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- step by step

1 stage
npx
npx tsx state/lib/cockpit-layout.ts

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

cockpit-layout - make the bundle look like the OS

When you open a snappy-os bundle in Finder, what you see should BE the sidebar. Not the engine room. The sidebar items collapse into 6 natural families per state/log/agents-md-feedback.log cockpit-recon-2026-04-26:

  • catalog/ - what the bundle CAN do (skills, apis, clients, agents, loaders)
  • ledger/ - what HAS happened (one evals.ndjson, six lenses)
  • memory/ - what's REMEMBERED (journal, daily, observations, asks)
  • inbox/ - incoming signals + queued work (observations, feedback, regen, meetings)
  • activity/ - what's HAPPENING (dispatches, commands, chain)
  • artifacts/ - what was PRODUCED (drafts, gallery)
  • meta/ - bundle ABOUT itself (env-vars, gateway, architecture, home)

This skill is idempotent - it can run repeatedly. Existing canonical files under state/ are left untouched; the operator surface is built from symlinks and one tiny generated _about.md per folder explaining what that folder is for.

Steps

npx tsx state/lib/cockpit-layout.ts

That command:

  1. Walks the canonical state/ tree
  2. Creates the 7 top-level operator folders
  3. For each folder, drops symlinks pointing at the canonical files/dirs
  4. Writes a small _about.md at the top of each folder describing what

it contains and which sidebar items it powers

  1. Logs an eval row with mode: shape because the auditor walks the

resulting tree and asserts every sidebar item has a path

Eval

shape. Auditor reads Route.swift-equivalent list (hardcoded in the lib), checks each section has either a folder or a symlink at the bundle root. Score 1.0 when every section resolves; partial credit per unresolved.

Why this is the bundle thesis

The thesis: a snappy-os bundle is the unit of distribution. The Swift shell renders whatever the bundle contains. Today the bundle's filesystem looks like a Node project; the operator sees node_modules/, package-lock.json, scattered markdown. After this skill runs, the bundle LOOKS like the OS in Finder. Same data, different surface.

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

cockpit-layout - loader

Full reference: state/skills/cockpit-layout/SKILL.md. The skill makes a bundle look like the OS in Finder; this loader also carries the cockpit layout guardrails that have caused regressions.

Critical Rules

  • The bundle layout command is npx tsx state/lib/cockpit-layout.ts. It creates operator folders/symlinks and _about.md files without moving canonical state/ data.
  • Before claiming a snappy-shell page redesign is done, run npx tsx state/lint/codable-drift.ts from snappy-os and trace the page's actual dataClient method plus as: Type.self decode target. Fix the Codable the screen really uses, not just the first lint row.
  • Pre-mount Swift screens can call only bootstrap endpoints: /healthz, /state, /bundle/status, /bundle/mount, /bundle/eject, /bundle-meta, and /events. Add a bootstrap endpoint server-side if richer data is needed before mount.
  • Multi-rail snappy-os pages need an outer vertical ScrollView with a leading VStack; otherwise lower rails clip behind the pinned footer.
  • For Swift investigation, use swiftlens first: swift_get_symbols_overview, symbol definition/references, diagnostics, validation. Read whole Swift files only after semantic tools point to a tight range.
  • Parallel-agent workflow must use explicit pathspecs. Never git add -A, git add ., git commit -a, or broad git stash -u. For commits, prefer git commit -m "..." -- <paths>.
  • After a pull/rebase in a shared worktree, re-read or diff your files before editing/committing; stash-pop and rebase can silently restore older content.
  • New Swift files require xcodegen after the file is written and before xcodebuild.
  • Concurrent xcodebuild runs need unique -derivedDataPath /tmp/snappy-shell-build-<name>.
  • Regen-drain/headless consumers must never run git write operations and must append a writeback line even when no edit is needed. Consumer timeout failures are harness/budget issues, not a reason to add loader prose.

Commands

actioncommand
build operator layoutnpx tsx state/lib/cockpit-layout.ts
Codable drift gatenpx tsx state/lint/codable-drift.ts
shell deploycd /Users/robertboulos/projects/snappy-shell && bash scripts/deploy.sh
Swift build truthxcodebuild -derivedDataPath /tmp/snappy-shell-build-<name> ...
safe commit shapegit commit -m "message" -- <paths>
eval logstate/log/evals.ndjson (skill: cockpit-layout)

Self-Test

An agent reading this should:

  1. [ ] Know the layout skill is state/lib/cockpit-layout.ts.
  2. [ ] Run Codable drift and trace actual screen decode paths before page claims.
  3. [ ] Respect the pre-mount endpoint allowlist.
  4. [ ] Add ScrollView for multi-rail shell pages.
  5. [ ] Use swiftlens for Swift navigation.
  6. [ ] Use pathspec-only git operations in shared worktrees.
  7. [ ] Keep regen consumers out of git writes and require writeback proof.

Found a gap? Edit this file. <!-- footer-injection-point -->

api.ts- the code it can call

#!/usr/bin/env npx tsx
/**
 * cockpit-layout.ts — build the operator-facing top-level folder layout
 * for a snappy-os bundle.
 *
 * Reads `state/cockpit-routes.json` (canonical sidebar manifest) and
 * creates 7 top-level folders (catalog/, ledger/, memory/, inbox/,
 * activity/, artifacts/, meta/). Inside each folder, drops a symlink
 * pointing at the canonical state/-rooted source for every route
 * declared in that family. Writes a small `_about.md` per folder.
 *
 * Idempotent: existing symlinks are replaced with the current target;
 * existing _about.md files are overwritten with the freshly-generated
 * version.
 *
 * Phase 1 (today): symlinks only — original state/ tree untouched.
 * Phase 3 (later): when state/ moves to _engine/state/, this file gets
 * a one-line update and re-runs to point at the new root.
 *
 * Run:
 *   npx tsx state/lib/cockpit-layout.ts
 */

import { readFileSync, writeFileSync, mkdirSync, symlinkSync, existsSync, lstatSync, unlinkSync, statSync, readdirSync } from "fs";
import { join, dirname, relative, resolve, basename } from "path";
import { fileURLToPath } from "url";
import { appendNdjsonQueued } from "./log.ts";

const HERE = dirname(fileURLToPath(import.meta.url));
const BUNDLE = resolve(HERE, "..", ".."); // state/lib → bundle root

type Route = {
  id: string;
  label: string;
  source: string;
  kind: "file" | "dir" | "glob" | "view";
  filter?: string;
  view?: string;
  alias_of?: string;
  phase2?: string;
};
type Family = {
  id: string;
  title: string;
  routes: Route[];
};
type Manifest = {
  version: number;
  description: string;
  families: Family[];
  engine_room_paths: string[];
};

const manifest: Manifest = JSON.parse(
  readFileSync(join(BUNDLE, "state/cockpit-routes.json"), "utf-8")
);

/** Replace existing symlink/file at path with a symlink pointing at target. */
function relink(linkPath: string, target: string): void {
  if (existsSync(linkPath) || isBrokenLink(linkPath)) {
    unlinkSync(linkPath);
  }
  symlinkSync(target, linkPath);
}

function isBrokenLink(p: string): boolean {
  try { return lstatSync(p).isSymbolicLink(); }
  catch { return false; }
}

const reportLines: string[] = [];
let routesResolved = 0;
let routesMissing = 0;
let symlinksCreated = 0;
let viewsGenerated = 0;

for (const family of manifest.families) {
  const familyDir = join(BUNDLE, family.id);
  mkdirSync(familyDir, { recursive: true });

  // _about.md — what is this folder, what sidebar items it powers.
  const aboutPath = join(familyDir, "_about.md");
  const aboutBody = generateAbout(family);
  writeFileSync(aboutPath, aboutBody);

  for (const route of family.routes) {
    const srcAbs = join(BUNDLE, route.source);

    // For "view" kind routes, write a small _<id>.md explainer
    // pointing at the source data file. The real rendering lives in
    // the Swift app or downstream readers; this is for filesystem
    // browsing.
    if (route.kind === "view") {
      const viewPath = join(familyDir, `${route.id}.md`);
      writeFileSync(viewPath, generateViewExplainer(route));
      viewsGenerated++;
      if (existsSync(srcAbs)) {
        routesResolved++;
        reportLines.push(`✓ ${family.id}/${route.id}.md → view of ${route.source}`);
      } else {
        routesMissing++;
        reportLines.push(`✗ ${family.id}/${route.id}.md → MISSING ${route.source}`);
      }
      continue;
    }

    // alias_of — skip linking, just record
    if (route.alias_of) {
      reportLines.push(`↩ ${family.id}/${route.id} alias of ${route.alias_of}`);
      continue;
    }

    // file/dir/glob — drop a symlink (or directory of symlinks for glob)
    const linkPath = join(familyDir, route.id);

    if (route.kind === "glob" && route.filter) {
      // Build a directory full of links to matching files/dirs under source.
      mkdirSync(linkPath, { recursive: true });
      const matches = expandGlob(srcAbs, route.filter);
      for (const m of matches) {
        const entry = join(linkPath, basename(m));
        const rel = relative(linkPath, m);
        relink(entry, rel);
        symlinksCreated++;
      }
      if (matches.length > 0) {
        routesResolved++;
        reportLines.push(`✓ ${family.id}/${route.id}/ ← ${matches.length} matches of ${route.source}/${route.filter}`);
      } else {
        routesMissing++;
        reportLines.push(`✗ ${family.id}/${route.id}/ ← 0 matches of ${route.source}/${route.filter}`);
      }
      continue;
    }

    // file or dir — single symlink
    if (!existsSync(srcAbs)) {
      // Phase-2 routes (krisp) may not exist yet; mark as pending.
      const tag = route.phase2 ? `pending (phase 2: ${route.phase2})` : "MISSING";
      routesMissing++;
      reportLines.push(`✗ ${family.id}/${route.id} → ${tag}: ${route.source}`);
      continue;
    }
    const rel = relative(familyDir, srcAbs);
    relink(linkPath, rel);
    symlinksCreated++;
    routesResolved++;
    reportLines.push(`✓ ${family.id}/${route.id} → ${route.source}`);
  }
}

// Top-level _about.md — explains the layout itself
const layoutAbout = `# snappy-os bundle layout

This bundle's filesystem mirrors the snappy-shell sidebar. Open any of
these folders to see the operator surface; the engine room lives under
\`state/\` (and will move to \`_engine/state/\` in a future restructure).

${manifest.families.map(f => `- **${f.id}/** — ${f.title}`).join("\n")}

The canonical source for sidebar items is \`state/cockpit-routes.json\`.
Re-run \`npx tsx state/lib/cockpit-layout.ts\` after editing the manifest
to rebuild the symlinks.

Last built: ${new Date().toISOString()}
Routes resolved: ${routesResolved}, missing: ${routesMissing}, symlinks: ${symlinksCreated}, views: ${viewsGenerated}
`;
writeFileSync(join(BUNDLE, "BUNDLE.md"), layoutAbout);

// Eval log — shape audit
const evalRow = {
  ts: new Date().toISOString(),
  skill: "cockpit-layout",
  verb: "build",
  ok: routesMissing === 0,
  score: routesMissing === 0 ? 1.0 : Math.max(0, 1 - routesMissing / (routesResolved + routesMissing)),
  routes_resolved: routesResolved,
  routes_missing: routesMissing,
  symlinks_created: symlinksCreated,
  views_generated: viewsGenerated,
  writer_id: "state/lib/cockpit-layout.ts",
  actor_session_id: process.env.CLAUDE_SESSION_ID ?? `cockpit-layout-${Date.now()}`,
  auditor_session_id: `cockpit-layout-shape-${Date.now()}`,
};
const evalsPath = join(BUNDLE, "state/log/evals.ndjson");
// P0 #2 (2026-05-11): per-path queue. Top-level await is OK here — this
// file is a CLI script with await elsewhere.
await appendNdjsonQueued(evalsPath, evalRow);

console.log(reportLines.join("\n"));
console.log(`\nlayout: ${routesResolved} routes resolved, ${routesMissing} missing, ${symlinksCreated} symlinks, ${viewsGenerated} views`);
console.log(`eval row appended → state/log/evals.ndjson (score=${evalRow.score.toFixed(2)})`);
process.exit(routesMissing === 0 ? 0 : 1);

// =============================================================
function generateAbout(family: Family): string {
  const lines: string[] = [];
  lines.push(`# ${family.id}/ — ${family.title}`);
  lines.push("");
  lines.push(`This folder is part of the snappy-os bundle's operator surface — the`);
  lines.push(`top-level layout that mirrors the snappy-shell sidebar. Routes here:`);
  lines.push("");
  for (const r of family.routes) {
    const target = r.kind === "view" ? `view of ${r.source}` : r.source;
    lines.push(`- **${r.id}** — ${r.label} → \`${target}\`${r.alias_of ? ` (alias of ${r.alias_of})` : ""}`);
  }
  lines.push("");
  lines.push(`Generated by \`state/lib/cockpit-layout.ts\` from`);
  lines.push(`\`state/cockpit-routes.json\`. Edit the manifest, re-run, refresh.`);
  lines.push("");
  lines.push(`Last built: ${new Date().toISOString()}`);
  return lines.join("\n");
}

function generateViewExplainer(route: Route): string {
  return [
    `# ${route.label} — view`,
    "",
    `This route is a **derived view** of \`${route.source}\`.`,
    `The view shape is \`${route.view ?? "unknown"}\`.`,
    "",
    `Open \`${route.source}\` to see the underlying data.`,
    `The snappy-shell screen for this route renders the view; the file`,
    `you're reading is a filesystem-side breadcrumb so the bundle's`,
    `layout reflects the sidebar.`,
    "",
    `Generated by \`state/lib/cockpit-layout.ts\`.`,
  ].join("\n");
}

function expandGlob(srcDir: string, pattern: string): string[] {
  // Two patterns supported by cockpit-routes.json today:
  //   "client-*"      → files/dirs in srcDir whose name starts with client-
  //   "*/AGENTS.md"   → AGENTS.md inside each subdir of srcDir
  if (!existsSync(srcDir)) return [];
  if (pattern.startsWith("*/")) {
    const tail = pattern.slice(2);
    const out: string[] = [];
    for (const e of readdirSync(srcDir, { withFileTypes: true })) {
      if (!e.isDirectory()) continue;
      const candidate = join(srcDir, e.name, tail);
      if (existsSync(candidate)) out.push(candidate);
    }
    return out;
  }
  if (pattern.endsWith("*")) {
    const prefix = pattern.slice(0, -1);
    return readdirSync(srcDir)
      .filter(n => n.startsWith(prefix))
      .map(n => join(srcDir, n));
  }
  if (pattern.startsWith("*")) {
    const suffix = pattern.slice(1);
    return readdirSync(srcDir)
      .filter(n => n.endsWith(suffix))
      .map(n => join(srcDir, n));
  }
  return [];
}

scripts- helper scripts it can run

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

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

rubric shape schema-shape check (no inline rubric)
recent mean 0.78 · 2 runs actor/auditor: unverifiable
deps none declared
timestamp verb score primary_issue artifact
2026-06-30 14:24Z - 1.00 - -
2026-06-30 08:35Z - 0.55 - -