jotbook-ink — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited jotbook-ink (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
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.
This is the primary jotbook entry point. It has two shapes, both gated on initialization:
If the plugin hasn't been initialized in this project (no .claude/jotbook.local.md), either shape routes to jotbook-init first. After init completes, the user re-invokes whichever flow they actually wanted.
Read the invocation arguments and route as follows. Do this before reading the rest of the skill:
.claude/jotbook.local.md in the project) → invoke the jotbook-init skill. After init completes, stop. Do not auto-chain into curation or the per-slug procedure — let the user re-invoke once they're set up.jotbook-review, which owns the full decision loop: it inventories jots, takes the user's free-form decisions (drop / merge / tweak / ink / pencil / keep, the latter two accepting their respective slugs and any --html flag), applies structural changes in place, and dispatches into this skill's per-slug procedure (for ink) or jotbook-pencil (for pencil) directly. Do not duplicate that orchestration here — let the review skill drive end-to-end.When the per-slug procedure is re-entered from review and detects an existing pencil, let it handle the promote-vs-regenerate question.
If the jot backlog is empty when review starts, it reports and stops on its own — no further action needed here.
jotbook-pencil or the per-slug procedure without the user explicitly marking a jot as ready./jotbook-pencil-review.jotbook-init, defer entirely to it. Don't continue on a fresh just-initialized jotbook (there are no jots yet anyway).The remaining sections apply only to the targeted-ink path (one or more slugs supplied). You're turning a specific jot (or a small set of related jots) into a long-form entry. The jot file is a pointer; the actual content needs to be reconstructed from the referenced files, conversation history, and — if context is thin — direct questions to the user. The output is an inked entry in the jotbook.
If a pencil (provisional draft) already exists for the requested slug, you can promote it instead of regenerating — see the Pencil promotion branch in step 2 of Procedure.
Read .claude/jotbook.local.md if present. From the frontmatter, extract:
| field | default | meaning |
|---|---|---|
jots_dir | docs/jotbook/_jots/ | where staged jots live |
pencils_dir | docs/jotbook/_pencils/ | where pencils live (checked for promotion) |
entries_dir | docs/jotbook/ | where inked entries are written |
output_format | markdown | one of markdown, obsidian, html |
template_path | (none) | path to an HTML template used when output_format: html |
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.
If output_format: html is set but template_path is empty or points to a missing file, stop. Do not invent a template inside this flow. Instead, surface the situation clearly to the user — something along the lines of:
"I can't ink this entry —output_formatishtmlbuttemplate_pathisn't set (or points to a missing file). Two ways forward: (1) switchoutput_formattomarkdownin your settings and re-run, or (2) run/jotbook-template(or/jot template) to design the HTML template — a guided design workflow that builds the template, verifies it, and (on your sign-off) wirestemplate_pathfor you. Once the template exists, re-run."
Then stop — the template is a deliberate, named artifact, and /jotbook-template is where it gets built.
(One exception: if a pencil already exists in HTML format for the requested slug and the user opts to promote it, the template gate doesn't apply — the template work happened at pencil time. The pencil's HTML is the source of truth.)
Files: line.<pencils_dir>/<slug>.<ext>.<pencils_dir>/<slug>.md or <pencils_dir>/<slug>.html.jots_dir. If a slug matches neither a jot nor a pencil, list what's there and ask the user to clarify — do not guess.Files: line.If a pencil exists for any of the requested slugs, surface this and ask:
"A pencil for<slug>exists (drafted<date>). Promote it (skip regen — just transform frontmatter, cross-link, and clean up) or regenerate from scratch?"
For multi-slug invocations where some have pencils and some don't, ask per-slug or ask once how to handle the batch.
If no pencil exists, follow the Fresh render path with no branching.
(Skip this step if you're on the Fresh render path.)
<pencils_dir>/<slug>.<ext>..md pencils, or below the leading HTML comment block for .html pencils).md or html.<entries_dir>/<slug>.<ext>:output_format: markdown): no frontmatter; write the body, then append the trailing *Sources:* line listing the pencil's sources: field (or omit if empty).output_format: obsidian): write Obsidian frontmatter — tags (3–6 short topic tags inferred from content), aliases (only if natural alternates), created (today's date in YYYY-MM-DD), sources (carried over from the pencil's sources: field). Drop the trailing *Sources:* line — that info lives in the frontmatter for Obsidian.output_format: html, pencil was Markdown): render through the template at template_path using the pencil body as source material. Follow the HTML output conventions described in Fresh render: HTML output. This is the Markdown→HTML uplift — automatic, no question asked.output_format: html): keep the HTML body as-is. Apply any template tokens that should change at ink time (issue numbering finalization, masthead "draft" → "published" if present, etc.)."The pencil is HTML but youroutput_formatis<format>. Keep the entry as.html(default — preserves the SVG/layout work that made you choose HTML at draft time) or downcast to Markdown (lossy: diagrams become alt text, complex layouts flatten)?"
Default to keep as HTML if the user doesn't pick. If they pick downcast: extract the readable content from the HTML body, convert to Markdown (preserve semantic structure where possible — headings, lists, code blocks, links; flatten interactive/visual elements to descriptive text or alt text), and write to <entries_dir>/<slug>.md with frontmatter appropriate for the global format (Obsidian's frontmatter for obsidian, none for plain markdown). Mention the downcast in your final report so the user knows what happened.
Then continue with step 5 (add navigation) through step 8 (regenerate the index).
(Skip this step if you're on the Promotion path.)
Files:.(Skip this step if you're on the Promotion path.)
Before writing, decide and briefly share with the user:
entries_dir when topically related.Tell the user the planned section list before writing the file, so they can redirect early if the shape is off.
Then write to <entries_dir>/<slug>.<ext> where <ext> is md (for markdown or obsidian) or html (for html).
#### Fresh render: Markdown output (default)
Write a plain Markdown file:
# <Title>
<one or two sentence standfirst>
## <Section 1>
...
## <Section 2>
...
> **Note:** Use GitHub-flavored note/warning callouts where helpful.
---
*Sources: `path/to/file_one.ext`, `path/to/file_two.ext`*End with a small Sources: line listing the jot's Files: for traceability. No frontmatter unless the user's house-style notes specify one.
#### Fresh render: Obsidian output
Same body structure as Markdown, with these differences tuned for an Obsidian vault:
tags (3–6 short topic tags inferred from content), aliases (only if the title has natural alternate phrasings), created (today's date in YYYY-MM-DD), and sources (the jot's Files: list, one per line).entries_dir use [[wikilink]] syntax — the link target is the entry slug without the .md extension. Use standard markdown links only for external URLs.#topic/subtopic are fine where they read naturally — don't force them.Example frontmatter:
---
tags: [jotbook, cache]
aliases: [LRU eviction, cache policy]
created: 2026-05-22
sources:
- src/cache/lru.ts
- src/cache/metrics.ts
---#### Fresh render: HTML output
When output_format: html and template_path is set:
template_path.{{PLACEHOLDER}} tokens it contains using the planned title, standfirst, sections, etc. Match the template's conventions (numbering schemes, masthead fields, colophon) — do not invent your own.<link> reference.<!-- ... --> notes (section pattern, delete-if-unused hints, token explanations) are authoring scaffolding — a published entry should not carry them. Remove every guiding comment after filling the tokens.(Both paths execute this step, on the entry just written to entries_dir.)
Every inked entry gets a link back to the jotbook index, so the collection is navigable from any entry. Longer entries also get a Contents list of their own sections.
# Title. If the file opens with YAML frontmatter, the link goes below the closing `---`, never above it — frontmatter must stay at line 1 or the parser (Obsidian especially) won't recognize it.[← Index](index.md) as the first line (plain Markdown has no frontmatter), above the # Title.[[index|← Index]] immediately below the frontmatter block, above the # Title — not as line 1.{{NAV}} token with <a href="index.html">← Index</a>. The index lives in entries_dir alongside entries, so the relative href resolves. (HTML pencils are not indexed — jotbook-pencil leaves {{NAV}} empty.)**Contents** line followed by - [Section title](#section-anchor) items. GitHub derives the anchor from the ## heading text (lowercased, spaces → hyphens, punctuation dropped) — match that.- [[#Section title]] within-note heading links.{{TOC}} token with the anchor list and give each rendered <section> (or its <h2>) the matching id so the links resolve. Below the threshold, leave {{TOC}} empty.When promoting an already-rendered HTML pencil (step 3a), the template tokens are already substituted, so there are no {{NAV}}/{{TOC}} placeholders to fill — insert the back-to-index anchor (and, if ≥3 sections, the Contents list + section ids) directly into the masthead/body instead.
(Both paths execute this step.)
If this entry is topically related to an existing entry, cross-link them: add a link from the appropriate place in the related entry to this one (and, where it reads naturally, from this one back). Confirm with the user before editing a previously-inked entry.
This is the at-ink-time pass over obviously-related entries. To re-examine the whole collection for missing links later — including linking older entries to entries inked after them — run /jotbook-link (or /jot link), the dedicated cross-link sweep.
(Both paths execute this step.)
jots_dir. If multiple were consolidated, delete all of them.pencils_dir.(Both paths execute this step.)
The index is the jotbook's landing page and table of contents. Rebuild it from scratch on every ink so it never drifts from what's on disk — do not append incrementally.
entries_dir for entry files (*.md for markdown/obsidian, *.html for html). Exclude the index file itself (index.md/index.html) and anything under the _jots/_pencils/_assets/_templates subdirectories.# heading; date = file mtime (plain Markdown carries no date field).# heading; date = created: frontmatter; tags = tags: frontmatter.<title> or masthead <h1>; date = the rendered date if the template surfaces one.<entries_dir>/index.<ext>, listing entries reverse-chronological (newest first):index.md: a # Jotbook heading and a - [Title](slug.md) list.index.md: a # Jotbook MOC using - [[slug|Title]] wikilinks; group entries under ## <tag> headings when the tags form natural clusters, otherwise a flat list.index.html: a document that LINKS _assets/jotbook.css (the index sits in entries_dir alongside entries, so the href resolves), with the masthead and a styled <ul> of entries. Use the index/landing classes the template's stylesheet defines — never inline CSS.Format conversion at promotion is asymmetric: going up in fidelity (Markdown → HTML) is automatic; going down (HTML → Markdown) is opt-in. The principle is that picking HTML at draft time was a deliberate signal that the entry wanted the richer format — don't silently throw that away.
| pencil format | output_format | entry written as | how |
|---|---|---|---|
.md | markdown | .md (plain) | direct write |
.md | obsidian | .md (with Obsidian frontmatter) | direct write |
.md | html | .html (via template) | render pencil body through template_path — automatic, no prompt |
.html | markdown | .html (default) or .md (if user opts to downcast) | ask once during promotion |
.html | obsidian | .html (default) or .md (if user opts to downcast) | ask once during promotion |
.html | html | .html | direct write; finalize any ink-time template tokens |
When asking about HTML→Markdown downcast, default to keep as HTML and warn the user that downcast is lossy (diagrams flatten to alt text, complex layouts collapse to prose).
The fresh render path always uses output_format — this table only applies when promoting a pencil.
index.<ext> from the entries on disk (step 8) so the landing page never drifts. Exclude the index file and the _jots/_pencils/_assets/_templates subdirs from the listing.entries_dir; an HTML pencil sits one directory deeper and isn't indexed, so its {{NAV}} stays empty — never emit a depth-unsafe back-link from a pencil.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.