jotbook-template — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited jotbook-template (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The html output mode needs a real template before it works. The two gates differ, and this skill is the deliberate, named artifact both point at:
jotbook-ink hard-stops when output_format: html is set but template_path is empty or points at a missing file.jotbook-pencil hard-stops when --html is passed but template_path is empty or missing — independent of output_format.This skill produces a stylesheet, a tokenized template, a populated preview, and token-conventions documentation tailored to this project, verifies them mechanically, and — only after you sign off — wires the settings so the HTML path is armed.
It offers two design paths, recommended from the project's visual richness (step 1) but always the user's choice:
The fork lives only in the design phase. Both paths build the same fixed sample, write the same four artifacts, run the same mechanical verification, and hit the same sign-off gate. Quick is not lower-rigor output — it just skips exploring a design space that may have no room to be explored.
User-triggered only. This skill mutates config and (on the full path) runs a heavy multi-agent design panel; never auto-invoke it. It runs only in response to an explicit /jotbook-template (or /jot template) invocation.
The full panel's shape is the whole point, so when you take it, preserve its intent, not just its steps:
Read .claude/jotbook.local.md if present. From the frontmatter, extract:
| field | default | meaning |
|---|---|---|
jots_dir | docs/jotbook/_jots/ | where staged jots live (mined for the fixed sample) |
pencils_dir | docs/jotbook/_pencils/ | where pencils live (also mined for the fixed sample) |
entries_dir | docs/jotbook/ | where inked entries are written; the assets/templates dirs and the template's relative CSS link are derived from this |
output_format | markdown | the field this skill flips to html on sign-off |
template_path | (none) | the field this skill points at the new template on sign-off |
The body of the settings file (everything after the closing ---) is optional house-style guidance — voice, tone, conventions, terminology. If present, treat it as authoritative for stylistic decisions, and feed it verbatim into the design context so every concept matches the project's voice.
Derive these from entries_dir/pencils_dir (do not hardcode):
<entries_dir>/_assets/ AND <pencils_dir>/_assets/ (where jotbook.css is written — see below for why both).<entries_dir>/_templates/ (where jotbook.html and jotbook-preview.html are written).jotbook-ink writes the finished entry into entries_dir (e.g. docs/jotbook/<slug>.html);jotbook-pencil --html renders the SAME template into pencils_dir (e.g. docs/jotbook/_pencils/<slug>.html) — one directory deeper by default.A single relative href cannot resolve from both depths, and a sheet written only under <entries_dir>/_assets/ leaves every HTML pencil unstyled (_assets/jotbook.css from _pencils/<slug>.html points at the nonexistent _pencils/_assets/jotbook.css). The fix keeps the link uniform — always _assets/jotbook.css, resolved from the rendered file's OWN location, NOT from the template file's deeper _templates/ location — and writes a copy of the (identical) sheet into each consumer's _assets/ dir so that href resolves from both. Worked example: entry at docs/jotbook/<slug>.html ⇒ docs/jotbook/_assets/jotbook.css; pencil at docs/jotbook/_pencils/<slug>.html ⇒ docs/jotbook/_pencils/_assets/jotbook.css; both reachable via the same _assets/jotbook.css href. (The field-manual doc system fell into exactly this trap — its CSS link did not resolve from the jotbook dir.)
jotbook-init writes it and how jotbook-ink/jotbook-pencil consume it), e.g. docs/jotbook/_templates/jotbook.html.There is a third consumer of the sheet: the jotbook index/landing page (index.html), which jotbook-ink generates into entries_dir on every ink. It sits in the same directory as inked entries, so it reaches the sheet via the same _assets/jotbook.css href with no extra copy. The stylesheet therefore needs the index/landing classes (the entry list, titles, dates) so the index renders styled — jotbook-ink only links the sheet, it never inlines CSS.
--quick or --full flag, or plain-language intent in the steer ("just something simple/blog-like" → quick; "make it expressive / give me options" → full). When present, intent overrides the richness recommendation in either direction.Before generating anything, run a fixed discovery sweep and assemble a CONTEXT block passed to every agent. The skill must NOT bake in any one project's palette/fonts — discover them.
*.css, *.html templates, and design-token files (tokens.json, theme.*, tailwind.config.*, :root{} blocks, SCSS $vars). If a doc/site system already exists, read it for palette, type stack, spacing rhythm, and motifs — but treat it as a harmony reference and sibling document class, never a thing to clone. Record any masthead/numbering conventions that do NOT transfer (e.g. a "System No."/"Issue" masthead the jotbook has no equivalent for), and whether its relative CSS link would resolve from entries_dir.README.md, CLAUDE.md, package.json (name/description), logo/favicon assets, and any BRAND*/STYLE*/DESIGN* docs. Extract the project domain, tone words, and any existing color/font vocabulary..claude/jotbook.local.md is authoritative for voice/tone/terminology — feed it verbatim to the agents.tokens.json, tailwind.config.*, a real :root{} palette, SCSS $vars);BRAND*/STYLE*/worldbuilding/design docs, or a populated house-style body in .claude/jotbook.local.md;Form a recommendation, not a verdict: greenfield fallback fired (no visual context at all) → recommend quick; ≥3 leans-full signals → recommend full; otherwise → no strong lean, surface what was found and let the user pick. Record the lean and the one-line evidence for step 3. This is only a recommendation — explicit path intent (step 3) overrides it in either direction.
Produce ONE content-complete sample, frozen as a string, passed identically to every design agent, into the judge context, and into the synthesis preview. Do not let agents invent different content.
Prefer reconstruct-from-real-jot. Scan jots_dir/pencils_dir for the richest existing jot or pencil — one whose Files: reference real code and whose description has structural beats (problem → mechanism → params → gotcha). Reconstruct a full entry from it: read the referenced files for a genuine short code block, real parameter names for the table, and a real sibling entry slug for the cross-link. This makes the preview immediately legible to the user as THEIR content.
Fallback generic-but-full (non-code, greenfield, or thin backlog). If no jot is rich enough, the jotbook is empty, the project is non-code, or jots reference no readable files, synthesize a domain-flavored but self-contained sample from the discovered project domain. The sample generator must NEVER require reading real files when none exist. For a non-code domain, adapt the domain-specific elements:
<another-slug>.html) — state in a comment that this href is intentionally dangling in the sample/preview and is fine, since no sibling entry exists yet.Either way the sample MUST stress every supported element so concepts compare fairly and nothing renders untested: title; a 1-2 sentence standfirst/lede; created date (YYYY-MM-DD); 3-6 topic tags (chips); slug; a back-to-index nav link; a Contents TOC listing the sections (the sample has ≥3, so it qualifies); a STATUS rendered in the INKED state (with an HTML comment describing how the PENCIL state differs); 3-6 body sections, at least one with an h3 sub-section; a NOTE callout and a WARN callout; one short code/monospace block (≤ ~20 lines, terminal/source styled); a small table (header + ~3 rows); one inline SVG diagram + a <p class="caption">; an inline <code> span; an inline cross-link to another entry (<slug>.html); and a trailing Sources footer.
Resolve which design path to run BEFORE generating anything. Order of precedence: explicit intent → richness recommendation → default toward quick.
--quick or --full flag, or plain-language intent ("just something simple/blog-like" → quick; "make it expressive / give me options" → full), honor it and skip the question. Intent overrides the step-1 recommendation in either direction (e.g. a rich game repo whose owner just wants a plain blog look → quick).If the chosen path is full, you MAY also take a direction steer here ("share an existing doc look / give the jotbook a distinct identity / let the panel explore freely"); if declined, let the panel explore the full default direction set. The quick path takes the same steer as a single hint. Never block on any of this.
Two paths produce the synthesis output that step 5 writes. Both consume the same CONTEXT (step 1) and the same fixed SAMPLE (step 2), and both hand off to the identical steps 5–8. Run the one chosen in step 3.
#### 4-QUICK. Quick path — one opinionated pass
Skip the panel entirely. Produce the four artifacts in a single design pass tailored to the discovered (or baseline) palette/type/motifs:
css, templateHtml, previewHtml, tokenConventions (the SYNTH_SCHEMA in the appendix). The CSS must carry the full structural class set and the .leaf.inked / .leaf.pencil pure-class-swap treatment exactly as the full path requires — the quick path simplifies the exploration, not the output contract.Then continue to step 5 (write), 6 (verify), 7 (sign-off), 8 (wire) unchanged. State in the final report that the quick path was taken and which look was used.
#### 4-FULL. Full panel — Design → Judge → Synthesize
The workflow is Design → Judge → Synthesize, described below as a procedure you execute in this conversation. There are two execution modes; pick based on a concrete capability check.
Detect the execution mode first. If a Task/subagent dispatch tool is available, take the parallel path. If it is not, take the sequential fallback. Either way you run the same three phases against the same fixed SAMPLE and CONTEXT — only the dispatch differs.
The schemas and exact prompts for each phase are spelled out in the Workflow script (reference appendix) at the end of this skill; read it to build the prompts. (It is illustrative pseudocode for a workflow harness — NOT a file this skill executes. If you happen to be running inside a real workflow-orchestration harness that provides parallel()/agent()/phase() primitives, it is also runnable as-is as an accelerator.)
PARALLEL PATH — dispatch subagents (when a Task/subagent tool exists).
conceptName, designRationale, selfContainedHtml). Each commits HARD to its DISTINCT direction. The default archetype set, tailored to the discovered palette/type/motifs:Each renders the SAME fixed sample in the INKED state as one self-contained HTML document (inline CSS), with an HTML comment near the status element describing how PENCIL differs. Fold the discovered palette/type/motifs into the chosen archetype so all four feel like the same project seen four ways. Collect each returned HTML.
prefers-color-scheme handling; clean CSS with :root tokens and reusable classes; obvious {{TOKEN}} seams; variable section/callout/table counts handled; renders without JS.Tally scores across the panel; the cross-panel leader seeds synthesis.
SEQUENTIAL FALLBACK — single-conversation emulation (when no subagent tool exists). This is the path most invocations take. Preserve the structure; manage context aggressively:
<templates dir>/_concepts/<key>.html rather than holding all four inline in the conversation. Cap each concept at a reasonable byte budget (a focused page, not a sprawl). If context is tight, you MAY drop from 4 directions to 3 — keep bound-notebook, catalog, and console; drop domain-journal first.State which path was taken in the final report.
Write the synthesis output to disk, all paths derived from settings:
<entries_dir>/_assets/jotbook.css — :root color/type tokens; structural classes for header/masthead, section + h3 sub-section, .note/.warn callouts, terminal-styled pre/code + inline <code>, tables, .caption, cross-link anchors, tag chips, the pencil-vs-inked status treatment, sources footer; a back-to-index nav link, a Contents-TOC block, and landing-page/index classes (the index page's entry list, entry titles, and dates — jotbook-ink generates index.html against these); a prefers-color-scheme dark variant; a responsive breakpoint; robust fallback font stacks. The pencil-vs-inked treatment MUST be a pure class swap on an outer wrapper (e.g. .leaf.inked vs .leaf.pencil) with ALL pencil behaviour (graphite ink, a pencil-glyph stamp, a faint DRAFT watermark) defined under the .pencil selector. Then write a byte-identical copy to `<pencils_dir>/_assets/jotbook.css` (skip if pencils_dir resolves to the same directory as entries_dir) so the template's _assets/jotbook.css href resolves from HTML pencils too — splice the same bytes, don't re-emit the sheet.<entries_dir>/_templates/jotbook.html — LINKS the external sheet via the derived relative <link rel="stylesheet" href="_assets/jotbook.css">, uses {{TOKENS}} for all variable content, ZERO inline CSS, with guiding HTML comments (repeatable section pattern, delete-if-unused callout/table/diagram blocks, exactly how pencil-vs-inked status is set via the outer class + label tokens). Include two navigation tokens: a {{NAV}} slot (masthead) that jotbook-ink fills with a back-to-index anchor and jotbook-pencil leaves empty (pencils aren't indexed), and a {{TOC}} slot for the within-entry Contents list (ink fills it on entries with ≥3 sections, leaves it empty otherwise). Give each repeatable <section> an id matching its TOC anchor so the Contents links resolve.Guiding comments must not nest comment markers. HTML comments do not nest: the first --> ends the block, so a <!-- delete if unused --> written inside a larger <!-- ... --> example terminates the outer comment early and leaks the rest of the example markup as visible content into every rendered entry. Write each guiding comment as a SINGLE self-contained <!-- ... --> block, and express delete-if-unused hints as plain text (e.g. (delete if unused)), never as inner <!-- --> markers. Show structural examples without angle-bracket comment delimiters inside the block.
<entries_dir>/_templates/jotbook-preview.html — build it by construction, not by retyping CSS. Take the populated sample HTML (the synthesis preview body, or the template with the fixed sample substituted and the <link> removed), then Read jotbook.css and splice its exact bytes into a single <style> block in the <head>. This guarantees the preview's inline styles are byte-identical to the sheet rather than depending on a model reproducing a long stylesheet twice.These artifacts are inert: nothing reads them until template_path points at the template, so writing-then-holding is safe.
Run these checks and report each result. They turn a subjective design into something pass/fail.
<style> block from the preview and assert it is byte-for-byte identical to jotbook.css. Because step 5 built the preview by splicing the css bytes, this passes by construction. If a divergence is ever detected, regenerate the preview from the css file (re-splice) rather than re-prompting synthesis — never ask the model to retype the sheet.<style> block and no style="..." attributes (the SVG diagram is the one allowed exception if it needs geometry attrs, but presentational CSS lives in the sheet), AND that it links the external sheet with the derived relative href. Then assert <entries_dir>/_assets/jotbook.css exists, and — unless pencils_dir is the same directory — that <pencils_dir>/_assets/jotbook.css also exists and is byte-identical, so the template's _assets/jotbook.css href resolves from an inked entry in entries_dir AND from an HTML pencil in pencils_dir. A missing pencil-dir copy means every HTML pencil renders unstyled.{{TOKENS}} covering title/standfirst/date/tags/slug/status/sections/sources plus the {{NAV}} and {{TOC}} navigation slots, that each repeatable <section> carries an id for its TOC anchor, and that the section, callout, table, and figure patterns are repeatable (delete-if-unused comment examples present) so variable counts work.<!--/--> inside a <!-- ... --> block); the cheap proof is to substitute every {{TOKEN}} with empty and confirm the result contains no stray example markup (no leftover -->, note/warn blocks, or sec-anchor/other-slug text) — anything visible there would leak into real entries.command -v with multiple names exits non-zero unless all resolve, so it can't be used to detect "any one present." Try, each with a short timeout: command -v google-chrome || command -v chromium || command -v chromium-browser || command -v chrome (Linux/PATH), the macOS path /Applications/Google Chrome.app/Contents/MacOS/Google Chrome, then command -v wkhtmltoimage. If one is found, render the preview to PNG with --headless=new --no-sandbox --virtual-time-budget=4000 (let any fade-in settle), a tall --window-size, then crop, under an overall render timeout (~20s). If nothing is found, or the render fails/times out, immediately skip and tell the user to open the self-contained preview HTML in their own browser. The render is purely confirmatory and never on the critical path.leaf inked → leaf pencil) plus the coordinated status-label tokens, and confirm the CSS already defines all .pencil behaviour so pencil is a pure class swap, not a separate template. Render it too if a browser is available.Present the preview to the user — the screenshot if rendered, the path to the self-contained preview HTML, the pencil-state proof, and the verification results — then HOLD. Do NOT touch .claude/jotbook.local.md until the user explicitly approves.
When you ask for approval, also surface the scope choice, because template_path and output_format arm different things: setting `template_path` alone makes the template available to /jot pencil <slug> --html (the pencil gate is independent of output_format); also setting `output_format: html` additionally makes every plain /jotbook-ink render through the template. Offer both — e.g. "Make HTML the default for all inked entries (output_format: html), or just enable the template for --html pencils and keep output_format as <current>?" Default to the narrower option (template only) if the user doesn't care, since it's non-destructive to their current ink format.
On approval, in .claude/jotbook.local.md:
template_path to the project-relative template path (e.g. docs/jotbook/_templates/jotbook.html) — always;output_format: html only if the user chose to make HTML the default for all inked entries (the scope choice above); if they opted for template-only, leave output_format untouched so their existing markdown/obsidian inks are unaffected and only --html pencils render through the template;## HTML template tokens, placed BELOW any existing house-style content and OUTSIDE (after) the starter HTML comment block that jotbook-init writes (the <!-- ... --> block whose first line reads House style (optional)., closed by -->). Do NOT write the conventions inside that comment (where ink/pencil would treat them as inert and never see them), and do NOT delete or overwrite existing body prose. If only the starter comment exists, add the live section after its closing -->.This is what arms the HTML path in jotbook-ink/jotbook-pencil. Until it's done, those flows correctly hard-stop (ink on output_format: html + empty template_path; pencil on --html + empty template_path). Report the wired settings; if output_format was set to html, remind the user that /jotbook-ink now renders through the template; if they kept the narrower scope, remind them that /jot pencil <slug> --html renders through the template while plain /jotbook-ink still uses their existing output_format.
output_format/template_path is the one action that arms the HTML gate for every future ink and pencil. Mirror jotbook-init's "don't auto-chain" discipline./jotbook-template (or /jot template)..leaf.inked/.leaf.pencil class swap), run the same step-6 verification, and hit the same step-7 sign-off gate. Quick simplifies exploration, never output rigor or safety.<!-- --> ends the outer block early and leaks example markup into every rendered entry. One self-contained <!-- ... --> per note; delete-if-unused hints as plain text, not inner markers.jotbook-ink's rule: "Don't paste CSS inline in HTML output when the template already links a stylesheet." The only presentational exception is geometry attributes on the SVG diagram.entries_dir/pencils_dir — never hardcode docs/jotbook/.... The CSS href resolves from each RENDERED FILE's own location (an inked entry in entries_dir, an HTML pencil in pencils_dir), not the template file's _templates/ location — which is why the sheet is written into both consumers' _assets/ dirs.<style> is byte-identical to the external CSS, or it doesn't represent production fidelity.The following JS is the Design → Judge → Synthesize workflow expressed for a workflow-orchestration harness. It is illustrative — a non-normative reference for the phase prompts and output schemas, NOT a file this skill executes. A bare in-session skill has no parallel()/agent()/phase() runtime; follow the procedure in step 4 instead, using this as the source of the exact prompts and schemas. (If you ARE running inside a harness that provides these primitives, the script is runnable as-is: the caller assembles globalThis.JOTBOOK_CONTEXT from discovery (step 1) and globalThis.JOTBOOK_SAMPLE from the fixed sample (step 2); it is project-agnostic and bakes in no palette, fonts, or domain.)
export const meta = {
name: 'jotbook-template-design',
description: 'Design a new HTML template + stylesheet for a jotbook by judging distinct concepts against a fixed sample, then synthesizing the winner with grafts. Project-agnostic: the caller passes in a discovered CONTEXT block and a fixed SAMPLE.',
phases: [
{ title: 'Design', detail: '4 distinct template concepts render the same fixed sample entry' },
{ title: 'Judge', detail: 'panel scores all concepts across 4 lenses' },
{ title: 'Synthesize', detail: 'merge winner + best grafts into final css/template/preview/token-doc' },
],
}
// INPUTS provided by the caller (NOT hardcoded): globalThis.JOTBOOK_CONTEXT
// (discovery block) and globalThis.JOTBOOK_SAMPLE (the fixed, content-complete
// sample, frozen as a string). Optional globalThis.JOTBOOK_DIRECTIONS overrides
// the default archetype set. The SAMPLE is held constant across every concept.
const CONTEXT = globalThis.JOTBOOK_CONTEXT
const SAMPLE = globalThis.JOTBOOK_SAMPLE
if (!CONTEXT || !SAMPLE) {
throw new Error('jotbook-template-design: JOTBOOK_CONTEXT and JOTBOOK_SAMPLE must be provided by the calling skill (discovery + fixed sample).')
}
const DEFAULT_DIRECTIONS = [
{ key: 'bound-notebook', brief: "DIRECTION — Engineer's bound notebook. A faint graph/grid-paper substrate, a stitched or taped binding margin down one side, monospace-forward metadata (a date stamp, tag labels set like margin annotations), a restrained serif body that reads as if written into a real ruled notebook. Tactile, calm, technical. The most domain-neutral, safe-default direction. Pencil-vs-inked could differ by graphite-grey vs ink-blue rendering." },
{ key: 'catalog-archive', brief: 'DIRECTION — Library/archive catalog card. The entry reads like a card pulled from a drawer: accession/catalog styling, prominent date and tag chips, ruled card lines, crisp archival typographic hierarchy, a quiet filing-code motif. Orderly, indexed, pleasingly clinical. Pencil-vs-inked could differ by a "PROVISIONAL" rubber-stamp vs a clean filed card.' },
{ key: 'domain-journal', brief: "DIRECTION — In-world / domain-voiced journal. The literary option, voiced from THIS project's domain as given in the context: a naturalist's field journal for a game world, a lab logbook for a science tool, an ops runbook for infra, a studio sketchbook for a creative app. A characterful display face, marginalia energy, captions written as dry observations. If the project domain is unknown, fall back to a generic 'working lab notebook' voice rather than inventing lore. Restrained, never costume." },
{ key: 'console-log', brief: 'DIRECTION — Console / log terminal. A darker console-styled header with a timestamped log line and a signal/mono motif, monospace headers, atmospheric. The body must remain HIGHLY readable (do not sacrifice legibility for theme). The most distinct-from-paper option; ties to any event-stream / CLI / telemetry flavour in the project. Pencil-vs-inked could differ by a "DRAFT / UNFILED" header state.' },
]
const ANGLES = (globalThis.JOTBOOK_DIRECTIONS && globalThis.JOTBOOK_DIRECTIONS.length)
? globalThis.JOTBOOK_DIRECTIONS
: DEFAULT_DIRECTIONS
const DESIGN_SCHEMA = {
type: 'object', additionalProperties: false,
required: ['conceptName', 'designRationale', 'selfContainedHtml'],
properties: {
conceptName: { type: 'string', description: 'Short evocative name for this concept' },
designRationale: { type: 'string', description: '2-4 sentences: the core design idea and how it serves a personal, re-readable dev notebook' },
selfContainedHtml: { type: 'string', description: 'Complete self-contained HTML5 document, all CSS inline in one <style> block, rendering the fixed sample entry in the INKED state, with an HTML comment near the status element describing how PENCIL differs' },
},
}
const JUDGE_SCHEMA = {
type: 'object', additionalProperties: false,
required: ['lens', 'scores', 'winner', 'graftSuggestions'],
properties: {
lens: { type: 'string' },
scores: {
type: 'array',
items: {
type: 'object', additionalProperties: false,
required: ['conceptName', 'score', 'notes'],
properties: {
conceptName: { type: 'string' },
score: { type: 'number', description: 'integer 1-10 on this lens' },
notes: { type: 'string', description: 'concise, specific rationale' },
},
},
},
winner: { type: 'string', description: 'conceptName that best serves this lens' },
graftSuggestions: { type: 'string', description: 'specific elements from non-winning concepts worth grafting into the final synthesis' },
},
}
const SYNTH_SCHEMA = {
type: 'object', additionalProperties: false,
required: ['chosenDirection', 'css', 'templateHtml', 'previewHtml', 'tokenConventions'],
properties: {
chosenDirection: { type: 'string', description: 'Which concept won, why, and what specifically was grafted from the others' },
css: { type: 'string', description: 'Final external stylesheet (jotbook.css) — :root tokens, header/masthead, section + h3 sub-section, .note/.warn callouts, terminal pre/code + inline <code>, tables, .caption, cross-link anchors, tag chips, the pencil-vs-inked status treatment, sources footer, a back-to-index nav link, a Contents-TOC block, landing-page/index classes (entry list/title/date for the generated index.html), prefers-color-scheme dark variant, responsive breakpoint, robust fallback font stacks' },
templateHtml: { type: 'string', description: 'Final tokenized template (jotbook.html): links the external sheet via a RELATIVE <link rel="stylesheet" href="_assets/jotbook.css">, uses {{TOKENS}} for all variable content (including a {{NAV}} back-to-index slot and a {{TOC}} Contents slot, both empty-able), gives each repeatable <section> an id matching its TOC anchor, ZERO inline CSS, with guiding HTML comments (repeatable section pattern, delete-if-unused callout/table/diagram blocks, exactly how pencil-vs-inked status is set via the outer class + label tokens)' },
previewHtml: { type: 'string', description: 'Self-contained preview (jotbook-preview.html): inline <style> BYTE-IDENTICAL to css, populated with the fixed sample entry in the INKED state, openable directly. NOTE: the calling skill rebuilds this by splicing the css bytes, so exact reproduction here is a best-effort starting point, not the source of truth.' },
tokenConventions: { type: 'string', description: 'Markdown documenting every {{TOKEN}} and exactly how jotbook-ink/pencil fills each (including the pencil-vs-inked status value, the {{NAV}} back-to-index anchor that ink fills and pencil leaves empty, and the {{TOC}} Contents list filled only on entries with >=3 sections), suitable to append to the house-style body of .claude/jotbook.local.md' },
},
}
// --- Design ----------------------------------------------------------------
phase('Design')
const concepts = (await parallel(ANGLES.map(a => () =>
agent(
CONTEXT +
'\n\n=== YOUR ASSIGNED DESIGN DIRECTION ===\n' + a.brief +
'\n\n=== TASK ===\nProduce ONE complete self-contained HTML document for your direction, all CSS inline in one <style> block, rendering the fixed sample entry above EXACTLY (same text, same structure — do not invent different content), in the INKED state. Exercise every content type the sample calls for (sections, the h3 sub-section, note + warn callouts, the code block, the table, the inline SVG + caption, the inline cross-link, the Sources footer, a back-to-index nav link, a Contents TOC of the sections) and surface all metadata (title, standfirst, date, tags, slug, status). In an HTML comment near the status element, describe how the PENCIL/draft state would differ visually. Fold the discovered project palette/type/motifs into your direction so it feels like THIS project, never a generic framework/AI default. Commit HARD to your direction — distinctive and production-grade beats a hedged blend. Return the full document in selfContainedHtml.',
{ label: 'design:' + a.key, phase: 'Design', schema: DESIGN_SCHEMA }
)
))).filter(Boolean)
log(concepts.length + ' concepts rendered: ' + concepts.map(c => c.conceptName).join(', '))
// --- Judge -----------------------------------------------------------------
phase('Judge')
const conceptsBlock = concepts.map((c, i) =>
'### Concept ' + (i + 1) + ': ' + c.conceptName + '\nRationale: ' + c.designRationale + '\n\nHTML:\n<<<HTML\n' + c.selfContainedHtml + '\nHTML'
).join('\n\n---\n\n')
const LENSES = [
{ key: 'genre-fit', name: 'Genre fitness for a personal dev notebook', brief: 'Does it serve working lab notes meant to be re-read weeks later? Surfaces metadata (date, tags, slug, sources) cleanly; clearly distinguishes pencil vs inked; scales gracefully from a short jot to a long entry; handles every content type without strain; reads calmly, not like marketing.' },
{ key: 'craft', name: 'Typographic & visual craft', brief: 'Quality of typography, hierarchy, spacing, rhythm, colour discipline, distinctiveness. Penalize generic framework/AI-default looks, weak hierarchy, cramped or noisy layouts, theme-over-legibility.' },
{ key: 'project-coherence', name: 'Project coherence', brief: "Does it feel like it belongs to THIS project's visual language as described in the context (harmonizing with any existing brand/docs) WITHOUT cloning a sibling document class? Tasteful and restrained, never kitsch or costume; clearly a distinct-but-related personal document class. If no house style exists, judge domain-appropriateness and internal consistency instead." },
{ key: 'technical', name: 'Technical soundness & tokenisability', brief: 'Valid semantic HTML; accessible contrast; responsive at 1280px and on mobile; prefers-color-scheme handling; clean, well-organized CSS with :root tokens and reusable structural classes; obvious where {{TOKENS}} would go; variable section/callout/table count handled cleanly; renders without JS; robust font fallback stacks so it holds offline.' },
]
const judgments = (await parallel(LENSES.map(l => () =>
agent(
'You are judging jotbook HTML template concepts on ONE lens. Be specific and critical — this is an adversarial quality gate, not encouragement.\n\nLENS: ' + l.name + '\n' + l.brief +
'\n\nScore EVERY concept 1-10 on this lens with concise specific notes, name the single best concept for this lens, and call out specific elements from the non-winners worth grafting into a final synthesis.\n\n' + CONTEXT + '\n\n=== CONCEPTS TO JUDGE ===\n' + conceptsBlock,
{ label: 'judge:' + l.key, phase: 'Judge', schema: JUDGE_SCHEMA }
)
))).filter(Boolean)
const tally = {}
for (const j of judgments) for (const s of j.scores) tally[s.conceptName] = (tally[s.conceptName] || 0) + s.score
log('Lens winners: ' + judgments.map(j => j.lens.split(' ')[0] + '->' + j.winner).join(' | '))
log('Score totals: ' + Object.entries(tally).map(e => e[0] + '=' + e[1]).join(', '))
// --- Synthesize ------------------------------------------------------------
phase('Synthesize')
const judgeBlock = judgments.map(j =>
'## Lens: ' + j.lens + '\nWinner: ' + j.winner + '\nScores: ' + j.scores.map(s => s.conceptName + '=' + s.score + ' (' + s.notes + ')').join('; ') + '\nGraft: ' + j.graftSuggestions
).join('\n\n')
const final = await agent(
'You are producing the FINAL jotbook template, synthesizing from a judged design panel.\n\n' + CONTEXT +
'\n\n=== ALL CONCEPTS ===\n' + conceptsBlock +
'\n\n=== JUDGE PANEL ===\n' + judgeBlock +
'\n\n=== SYNTHESIS TASK ===\nBase the final on the concept that scored best across the panel, grafting the specific strengths judges flagged from the others. Produce four artifacts:\n' +
'(1) css — a clean, well-organized external stylesheet (jotbook.css). Use :root colour/type tokens (with robust fallback font stacks) and clear structural classes for: header/masthead, section + sub-section (h3), .note and .warn callouts, pre/code (terminal-styled) and inline <code>, tables, .caption for diagrams, inline cross-link anchors, tag chips, a back-to-index nav link, a within-entry Contents-TOC block, landing-page/index classes (the entry list, title, and date for the generated index.html), the pencil-vs-inked status treatment, and the sources footer. Include a prefers-color-scheme dark variant and a responsive breakpoint. Comment the sheet lightly. The pencil-vs-inked treatment MUST be a pure class swap on an outer wrapper (e.g. .leaf.inked vs .leaf.pencil), so flipping ONE class plus a few coordinated label tokens produces the pencil state — define ALL pencil behaviour (graphite ink, a pencil-glyph stamp, a faint DRAFT watermark, etc.) under the .pencil selector.\n' +
'(2) templateHtml — the skeleton (jotbook.html). It MUST link the external sheet via a RELATIVE <link rel="stylesheet" href="_assets/jotbook.css"> (do NOT inline CSS here). Use {{TOKENS}} for every variable piece (title, standfirst, date, tags, slug, status, sections, sources), plus a {{NAV}} slot in the masthead for the back-to-index anchor (ink fills it; pencils leave it empty) and a {{TOC}} slot for the within-entry Contents list (filled only when an entry has >=3 sections). Give each repeatable <section> an id matching its TOC anchor so the Contents links resolve. Include guiding HTML comments showing the repeatable section pattern, how to add/remove callouts/tables/SVG diagrams (delete-if-unused), and exactly how the PENCIL vs INKED status is set (the outer class + the coordinated label tokens).\n' +
'(3) previewHtml — a fully self-contained document whose inline <style> is BYTE-IDENTICAL to the css artifact, populated with the fixed sample entry (INKED state), so the user can open it and see production fidelity. (The calling skill will rebuild this by splicing the css bytes; emit your best-effort copy regardless.)\n' +
'(4) tokenConventions — markdown listing every {{TOKEN}} and precisely how jotbook-ink/pencil should fill it (including the pencil-vs-inked status value and the outer-class swap), ready to APPEND to the house-style body of .claude/jotbook.local.md.\n' +
'Make the final cohesive and production-grade — not a mechanical merge.',
{ label: 'synthesize', phase: 'Synthesize', schema: SYNTH_SCHEMA }
)
return {
chosenDirection: final.chosenDirection,
css: final.css,
templateHtml: final.templateHtml,
previewHtml: final.previewHtml,
tokenConventions: final.tokenConventions,
conceptNames: concepts.map(c => c.conceptName),
tally,
}~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.