Skip to content
Back to skills

Intentions

ASecurity

The intention graph carries the personal reading curriculum as nine `tactic-reading-chunk-*` nodes with `attributes.curriculum = {priority, passages: [{work, range}]}` (recorded 2026-07-06; see `strategy-philosophical-grounding`'s clarifications and `tactic-tradition-reading-program`'s index). The author owns DRM-free epubs on a network "print share" and reads on a USB-mounted e-reader. This tactic builds `/sync-reader`: a skill (SKILL.md + TypeScript scripts run via `npx tsx`) that scans the gr

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 3, 2026
ai-agentstypescriptgoshellnodegit

Works with

  • cli

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 21 files and shows the line behind each finding

Scanned September 3, 2026

npx -y skills add natb1/commons.systems --skill intentions --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Intentions?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Intentions
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/natb1-intentions-65e825c4/badge)](https://www.skillsdirectory.com/skills/natb1-intentions-65e825c4)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
id: tactic-sync-reader-skill
kind: tactic
statement: "Draft: /sync-reader skill — sync curriculum reading excerpts from
  the print share to the USB reader, priority-named, retiring resolved chunks"
owner: ai
status: codified
parent: null
rationale: "Retained from the 2026-07-06 /align-strategy interview
  (retain-not-refine): the author's requirement for reading-delivery tooling
  serving the tradition-reading recovery loop. The graph is the curriculum
  source (tactic-reading-chunk-* nodes), the print share is the text source, the
  chunk-node lifecycle is the retirement trigger. Full requirement and interview
  design decisions in the node body."
reading: null
serves:
  - strategy-philosophical-grounding
recovers: []
clarifications: []
tooling_goals: []
success_signal: null
attention:
  boosts:
    "1": 0.01
  rationale: >-
    Author-directed 2026-07-08 (refined): curriculum-maintenance/execution
    tooling (this skill, sibling tactic-sync-reader-skill) ranks below tactics
    that directly edit the /align-strategy and /align-tactics SKILL.md files
    (authored 8) and above the rest of strategy-graph-native-dispatch's subtree
    (inherited 5, unboosted) — boost 7. Supersedes the prior boost-4 rationale
    (dated 2026-07-08), which only cleared strategy-attention-surface (boost 3)
    and did not yet clear the rest of strategy-graph-native-dispatch. Scoped to
    curriculum-execution tactics only, not the reading-chunk tactics under
    strategy-philosophical-grounding, which remain unboosted.


    NAMESPACING STOPGAP 2026-08-11: magnitude compressed from 7 to 0.01 so this
    boost can no longer lift the node out of its parent strategy's band. The
    bound - a tactic boost is namespaced to its strategy's rank and must never
    cause the tactic to outrank a tactic of a higher-ranked strategy - is
    recorded doctrine on strategy-recursive-self-improvement but is NOT yet
    enforced by the resolver; tactic-attention-namespaced-rank makes it
    structural. Until then the flat additive sum defeats it, so the magnitudes
    are compressed by hand onto a 0.01-per-level ladder that preserves the
    original ordering WITHIN the band. Original magnitude preserved at
    attributes.pre_namespacing_boost for restoration.
phase: implement
execution:
  branch: tactic-sync-reader-skill
  pr: 2798
  attempts: {}
  markers: []
  strategy_fingerprint:
    strategy-graph-native-dispatch:
      hash: 033459bda2f251219b345224c2bf3aa36005e00e3dacf7140d2095b313c1b264
      sha: 1b787ada81dc185b333108392af40779d3aea496
  fix:
    since: 2026-07-22
    attempt: 1
    pushed_sha: null
  conflict: null
  completion: null
  lane_pass: null
validates: []
blocked_by: []
superseded_by: []
supersession_expiry: null
office_hours: null
pace_exempt: false
rounds: null
attributes:
  pre_namespacing_boost: 7
---
# /sync-reader skill — sync curriculum reading excerpts from the print share to the USB reader, priority-named, retiring resolved chunks

## Context

The intention graph carries the personal reading curriculum as nine
`tactic-reading-chunk-*` nodes with
`attributes.curriculum = {priority, passages: [{work, range}]}` (recorded
2026-07-06; see `strategy-philosophical-grounding`'s clarifications and
`tactic-tradition-reading-program`'s index). The author owns DRM-free epubs
on a network "print share" and reads on a USB-mounted e-reader. This tactic
builds `/sync-reader`: a skill (SKILL.md + TypeScript scripts run via
`npx tsx`) that scans the graph for active chunks (node file exists,
`phase !== "done"`), matches each cited work against share epubs by OPF
metadata, extracts the cited range at TOC-section granularity into one
excerpt epub per chunk, and mirrors the active-chunk set into a managed
`<reader>/commons-curriculum/` subdirectory with zero-padded
priority-prefixed filenames — deleting retired chunks' files, never touching
anything outside the managed dir, and printing an author-facing report for
anything missing/ambiguous/unmappable instead of falling back to whole-book
copies (clear errors over defensive fallbacks). The outcome is a
re-runnable, idempotent sync with core logic in a new tested workspace
package `packages/sync-reader` and a thin CLI under
`.claude/skills/sync-reader/scripts/`.

Note for the implementing session: committing `.claude/skills/**` from an
auto-mode dispatch session can be denied by the permission classifier
(agent-behavior config); if the commit is blocked, surface it rather than
retrying — the human grants and the session retries.

## Units of work

### Unit 1 — Package scaffold, config loader, curriculum reader

**Scope.** Files created:

- `packages/sync-reader/package.json` — `{"name": "@commons-systems/sync-reader", "private": true, "type": "module"}`
  with exports mapping to `.ts` sources (copy the style of
  `packages/intentionsutil/package.json`, which exports `./src/index.ts`
  directly so `npx tsx` consumers need no build). Direct dependencies:
  `unzipit@^1.4.3` (already a direct dep of print at
  `print/package.json:36` — zero new lockfile versions; Node-compatible zip
  READER), `jszip@^3.10.1` (zip WRITER for excerpt epubs — already in the
  tree transitively via epubjs per `package-lock.json:9858`, so this
  promotes an existing package rather than adding a new one; needed because
  `unzipit` cannot write and no other writer exists in the tree),
  `@xmldom/xmldom@^0.8.13` (Node `DOMParser` substitute for the browser-only
  `DOMParser` the print epub pattern uses at
  `print/src/local-metadata.ts:25`; the root `package.json:36` already
  forces `@xmldom/xmldom@^0.8.13` tree-wide via `overrides`, so this adds no
  new version), plus `@commons-systems/intentionsutil` (`"*"`, workspace).
  `yaml` is NOT needed (intentionsutil wraps it).
- `packages/sync-reader/tsconfig.json` and
  `packages/sync-reader/vite.config.ts` — copy
  `packages/intentionsutil/vite.config.ts` verbatim
  (`import { createLibConfig } from "@commons-systems/config/vite"; export default createLibConfig();`).
- `packages/sync-reader/src/config.ts` — self-contained loader for
  `dispatch.config/sync-reader.json`. Protocol mirrors
  `.claude/skills/dispatch-propagate/scripts/dispatch-config-load` WITHOUT
  editing it: resolve the shared project root as
  `dirname($(git rev-parse --path-format=absolute --git-common-dir))` (same
  rule as `resolve_project_root` at
  `.claude/skills/dispatch-propagate/scripts/lib.sh:1707-1711`, correct
  across worktrees), honor a `SYNC_READER_CONFIG_DIR` env override for tests
  (analogous to `DISPATCH_CONFIG_DIR`), return a discriminated union:
  `{kind:"config", reader_dir, share_dir}` when the file parses and both
  fields are non-empty strings; `{kind:"no-config"}` when absent; throw a
  clear error (message names the file and the bad field) when
  present-but-invalid.
- `packages/sync-reader/src/curriculum.ts` —
  `readActiveChunks(intentionsDir): ActiveChunk[]`. Uses `listNodes` from
  `@commons-systems/intentionsutil` (`packages/intentionsutil/src/store.ts:88`);
  filters to `id.startsWith("tactic-reading-chunk-")` AND
  `attributes.curriculum` present AND `phase !== "done"` (a chunk whose node
  file no longer exists is naturally absent from `listNodes` output — that
  is the retirement signal). Validates the curriculum shape (`priority`
  finite number, `passages` non-empty array of `{work: string, range: string}`)
  and throws a clear per-node error on a malformed shape — no skipping.
- `packages/sync-reader/test/config.test.ts` and `test/curriculum.test.ts` —
  temp-dir fixtures (write node files with `writeNode` from intentionsutil,
  write config JSON under a `SYNC_READER_CONFIG_DIR` temp dir); cover:
  config absent → no-config, invalid → throw, valid → normalized; chunk
  filtering by prefix/phase/missing-attribute, malformed curriculum → throw.

Files changed: root `package.json` — one-line addition of
`"packages/sync-reader"` to the `workspaces` array. This is the vitest
hook: the root `vitest.config.ts:8-20` derives its test projects directly
from `pkg.workspaces` (there is no `vitest.workspace.*` file), so the
workspace entry automatically creates a vitest project named
`packages/sync-reader`. Run `npm install` afterward to link the workspace.

Out of scope: any epub reading/writing, CLI, SKILL.md.

**Recommended model**: sonnet

### Unit 2 — Epub reading, work→epub matching, citation→section mapping

**Scope.** Files created (all under `packages/sync-reader/`):

- `src/epub-read.ts` — `openEpub(path): Promise<EpubSource>`. Read the file
  with `node:fs` `readFileSync`, pass the bytes to `unzip()` from `unzipit`
  (Node needs bytes, not a URL). Port the container→OPF pattern from
  `print/src/local-metadata.ts:25-42,108-115` replacing browser `DOMParser`
  with `new DOMParser()` from `@xmldom/xmldom`. Expose: `dcTitle`,
  `dcCreators` (all `dc:creator` elements, namespaced and unprefixed), the
  manifest (id → href/media-type), the spine (ordered idrefs), and the TOC
  parsed from the EPUB3 nav doc (`properties="nav"` manifest item) with
  EPUB2 NCX fallback (`spine@toc` → `.ncx`), each TOC entry as
  `{label, href, spineIndex}` (href resolved against the OPF directory and
  matched to a spine item; fragment stripped for spine resolution but
  retained).
- `src/matching.ts` — `matchWork(work: string, candidates: EpubMeta[])` →
  `{kind:"match", index} | {kind:"missing"} | {kind:"ambiguous", indices}`.
  Normalization: lowercase, Unicode NFD + strip combining marks
  (diacritics), strip punctuation, collapse whitespace, tokenize. The `work`
  string is `"Author, Title"`-shaped (e.g.
  `"Kant, Groundwork of the Metaphysics of Morals"`): split on the first
  comma into author part and title part; a candidate matches when all
  author tokens appear in the normalized `dc:creator` set AND all
  significant title tokens (drop stopwords: the/of/a/an/and) appear in the
  normalized `dc:title`. Exactly one candidate → match; zero → missing;
  two-plus → ambiguous (never guess).
- `src/citation.ts` — `mapRangeToSections(range, toc, spineLength)` →
  `{kind:"sections", spineIndices: number[]} | {kind:"unmapped", reason: string}`.
  Section-granularity resolution: parse the range into structured tokens
  covering the citation families in the curriculum — Stephanus
  (`"VII 514a-521b"`: roman-numeral book + page-letter span),
  Bekker/Academy (`"4:429"`, `"6:434-437"`, `"II.5-6"`: volume:page or
  book.chapter spans), and plain chapter/book references (`"ch. 2"`,
  `"IV"`). Matching strategy: score TOC entries by normalized-label token
  overlap with the parsed book/part designator (roman or arabic, e.g.
  "Book VII" / "VII" / "7"); the selected sections are the matched entry
  through (exclusive) the next same-depth entry, mapped to a contiguous
  spine-index range; a page-level span within one book still selects the
  whole containing section(s) — never sub-section slicing. Any parse or
  match failure returns `unmapped` with a human-readable reason quoting the
  range and the nearest TOC labels considered (feeds the Unit 4 report; no
  fallback).
- `test/fixture-epub.ts` — helper that builds a small in-memory EPUB
  (jszip) with a known OPF (title/creator), 4-6 XHTML spine items, one CSS +
  one image resource, and both a nav doc and an NCX with labels like
  "Book VII", "Book VIII"; used by Units 2-3 tests so no binary fixture is
  committed. Provide two prebuilt variants ("Plato, Republic"-like and
  "Kant, Groundwork"-like with a `4:429`-mappable section).
- `test/epub-read.test.ts`, `test/matching.test.ts`,
  `test/citation.test.ts` — parse round-trip through `openEpub`; matching
  normalization (diacritics, punctuation, subtitle noise), missing and
  ambiguous outcomes; citation mapping happy paths (Stephanus book range →
  section span, `4:429` → containing section) and unmapped outcomes with
  reason text.

Out of scope: excerpt writing, mirroring, CLI.

**Recommended model**: opus

**Dependencies**: Unit 1

### Unit 3 — Excerpt epub builder

**Scope.** Files created (under `packages/sync-reader/`):

- `src/excerpt.ts` — `buildExcerpt(source, spineIndices, opts: {title})` →
  `Promise<Uint8Array>`. Produces a minimal valid EPUB via jszip: first
  entry `mimetype` with `compression: "STORE"` (insertion-order-first,
  uncompressed, per the EPUB OCF requirement), `META-INF/container.xml`, a
  freshly generated OPF (unique identifier derived deterministically from
  source identifier + chunk selection; `dc:title` = `opts.title`, i.e.
  `"<work> — <range> (chunk <priority>)"`; `dc:creator` copied from
  source), the selected content documents in spine order, plus transitively
  required resources: parse each selected XHTML with `@xmldom/xmldom` and
  collect `link[href]`, `img[src]`, `image[xlink:href]`, and CSS `url(...)`
  references, resolving relative to the doc, copying those manifest
  resources (and CSS-referenced fonts/images one level deep). Include both
  an EPUB3 nav doc and an EPUB2 NCX for device compatibility, listing the
  selected sections. Set fixed zip file dates (e.g. an epoch constant) so
  identical inputs produce byte-identical output — this is what makes
  Unit 4's changed-file detection and idempotent re-runs work by simple
  byte comparison.
- `test/excerpt.test.ts` — build an excerpt from the Unit 2 fixture epub
  selecting a 2-section span; re-open the bytes with `openEpub` and assert:
  `mimetype` first and stored, title set, spine contains exactly the
  selected docs in order, CSS + image resources present, unselected docs
  absent; build twice → identical bytes.

Out of scope: file naming, reader I/O, report.

**Recommended model**: opus

**Dependencies**: Unit 2

### Unit 4 — Mirror sync, report, CLI, skill files

**Scope.** Files created:

- `packages/sync-reader/src/mirror.ts` — pure planning + execution split.
  `planMirror(desired: Map<filename, Uint8Array>, managedDir)` →
  `{writes, deletes, keeps}`: desired filenames are
  `` `${String(priority).padStart(2, "0")}-${chunkId}.epub` `` with the
  `tactic-` prefix dropped from the id for brevity (e.g.
  `04-reading-chunk-3-kant-humanity-servility.epub`) — document the exact
  rule in SKILL.md and keep it consistent. A file is a `write` if absent or
  bytes differ, a `delete` if it is a `*.epub` directly inside the managed
  dir and not in the desired set, a `keep` otherwise. `applyMirror` creates
  `<reader_dir>/commons-curriculum/` if absent and executes the plan; it
  refuses (throws) to delete anything outside the managed dir or any
  non-`.epub` entry, and never touches `reader_dir` outside the managed
  subdir.
- `packages/sync-reader/src/report.ts` — assemble and render the
  author-facing report: per-chunk outcome lines grouped as SYNCED
  (written/kept filename), MISSING WORK (work string; author action:
  acquire a DRM-free epub), AMBIGUOUS (work string + the 2+ candidate
  titles/paths; author action: disambiguate share filenames/metadata),
  UNMAPPED RANGE (work + range + the reason from `citation.ts`), plus
  DELETED (retired files). Plain text to stdout.
- `packages/sync-reader/src/index.ts` — re-export the public surface for
  the CLI.
- `.claude/skills/sync-reader/scripts/sync-reader.ts` — thin CLI. Resolve
  repo root from the script file's own location, never cwd (idiom:
  `packages/intentionsutil/scripts/frontier-view.ts:25-27`), `intentions/`
  under it; main-guard per `frontier-view.ts:35`. Args: 0 positional →
  config via `src/config.ts` (on `no-config`, exit 1 with instructions
  naming `dispatch.config/sync-reader.json` and the example file); 2
  positional → use them; 1 or 3+ → usage error, exit 1. Mount checks before
  any work, in the spirit of
  `.claude/skills/budget/scripts/ingest-downloads.sh:22-26`: each of
  reader_dir/share_dir must exist, be a directory, and be readable, else
  exit 1 with a message telling the user to verify the mount. Flow: read
  active chunks → enumerate `*.epub` under share_dir (recursive) → read
  metadata for each → match/map/build per chunk → plan + apply mirror →
  print report. Exit 0 when the run completes (missing/ambiguous/unmapped
  items are report content, not process failure); exit 1 only for
  environment/config/graph-shape errors. Import core logic as
  `@commons-systems/sync-reader` (resolves through the root `node_modules`
  workspace symlink; tsx follows the `.ts` exports like the existing
  intentionsutil scripts do).
- `.claude/skills/sync-reader/SKILL.md` — short, logic-in-scripts:
  frontmatter description with trigger `/sync-reader [reader_dir share_dir]`;
  body says to run
  `npx tsx .claude/skills/sync-reader/scripts/sync-reader.ts [args]` with
  `dangerouslyDisableSandbox` (USB/share mounts are outside the sandbox
  allowlist), relay the printed report to the user verbatim, and — for
  first-time setup — copy `sync-reader.example.json` to
  `<project-root>/dispatch.config/sync-reader.json` and fill in the two
  paths. Invocation style precedent: `.claude/skills/align-init/SKILL.md:141`.
- `.claude/skills/sync-reader/sync-reader.example.json` — committed
  template: `{"reader_dir": "/media/<user>/<device>", "share_dir": "/mnt/print-share"}`
  (precedent: `.claude/skills/dispatch-propagate/scripts/auto-merge.example.json`).
- `packages/sync-reader/test/mirror.test.ts` — temp-dir reader: fresh sync
  creates managed dir + files; re-run is a no-op (byte-identical excerpts →
  all keeps); retired chunk's file deleted; changed bytes rewritten; a
  stray non-epub file inside the managed dir and any file outside
  `commons-curriculum/` are untouched; delete-outside attempt throws.
- `packages/sync-reader/test/report.test.ts` — report rendering covers all
  five groups.

Out of scope: any change to dispatch-propagate scripts; device-specific
formatting beyond valid EPUB.

**Recommended model**: sonnet

**Dependencies**: Units 1, 2, 3

## Reuse

- `listNodes(dir)` / `readNode(dir, id)` — validated frontmatter-only graph
  reads: `packages/intentionsutil/src/store.ts:88` / `:74`.
- Script-file-relative repo-root resolution + main-guard idiom:
  `packages/intentionsutil/scripts/frontier-view.ts:25-32,35`.
- Epub open pattern (container.xml → OPF rootfile, dc:title extraction) to
  port from browser `DOMParser` to `@xmldom/xmldom`:
  `print/src/local-metadata.ts:25-42,108-115`.
- `unzipit` zip reading (already a direct dep at `print/package.json:36`).
- Config loader protocol (normalized JSON / `no-config` / env-var test
  override) and project-root rule `dirname(git --git-common-dir)`:
  `.claude/skills/dispatch-propagate/scripts/dispatch-config-load` and
  `lib.sh:1707-1711` (protocol copied, files untouched).
- Mount-validation + usage-error precedent:
  `.claude/skills/budget/scripts/ingest-downloads.sh:4,9-26`.
- Vitest project auto-registration from root workspaces:
  `vitest.config.ts:8-20`; lib test config factory `createLibConfig()` from
  `@commons-systems/config/vite` as used by
  `packages/intentionsutil/vite.config.ts`.
- Committed example-config precedent:
  `.claude/skills/dispatch-propagate/scripts/auto-merge.example.json`.

## Verification

```verify
npx vitest run --project packages/sync-reader --root .
```

```verify
npx tsc --noEmit -p packages/sync-reader/tsconfig.json
```

The no-config CLI path (exit 1 + setup instructions naming
`dispatch.config/sync-reader.json`) is covered by `test/config.test.ts`
rather than a shell check — a piped exit-code probe tests the wrong process.

Manual checks (prose): create a scratch pair
`mkdir -p $TMPDIR/reader $TMPDIR/share`, drop one known DRM-free epub cited
by an active chunk into `$TMPDIR/share`, run
`npx tsx .claude/skills/sync-reader/scripts/sync-reader.ts $TMPDIR/reader $TMPDIR/share`,
and confirm: `commons-curriculum/` appears with priority-prefixed excerpt
epubs for mappable chunks, the report lists every other chunk under
MISSING/AMBIGUOUS/UNMAPPED, a second run reports all keeps (no writes),
deleting a chunk node file (in a scratch worktree, not committed) and
re-running removes exactly that excerpt, and a decoy file placed at
`$TMPDIR/reader/keep-me.epub` survives every run. Open one generated
excerpt in an epub reader (e.g. the print app or Calibre) to confirm
device-grade validity. Note for Claude sessions: runs against the real USB
reader and network share, and writing `dispatch.config/sync-reader.json`,
need `dangerouslyDisableSandbox` (paths are outside the sandbox allowlist);
plain `npx vitest run` does not.

## QA items skipped by author (2026-07-22)

QA (PR #2798) escalated two manual-verification acceptance items to
office-hours; the author reviewed and explicitly waived both rather than
running the manual checks — clearing the park:

- Golden-path sync against real content (extraction correctness, priority
  naming, mirroring, retirement, report clarity, idempotency) — skipped.
- Device-grade epub validity on a real e-reader — skipped.

All script-verifiable acceptance items (test suite 54/54, typecheck, CLI
arg/config error paths, delete-outside-managed-dir safety guard) already
passed autonomously.

## Deliberate stale stamp (2026-09-01)

NOT re-stamped against the 2026-09-01 strategy edits, deliberately. The
2026-09-01 adversarial review found the earlier same-day mechanical
re-stamp was the weaker of the two freshness assertions: this node plans
a strategy-content reader skill, and three large new doctrine
clarifications plus the errata amendments are plausibly material to what
it reads. The stamp is left stale so the soft-freeze routes this node
through an /align-tactics re-plan before any further execution.

Files in this skill

  • README.md708 B
  • delegation-anthropic-claude.md14.4 KB
  • delegation-app-signin-identity.md3.1 KB
  • delegation-attention-services.md2.4 KB
  • delegation-banking.md2.4 KB
  • delegation-client-income.md2.1 KB
  • delegation-cloud-backup.md2.9 KB
  • delegation-communications.md2.6 KB
  • delegation-connectivity.md2 KB
  • delegation-finance-saas.md2.8 KB
  • delegation-firebase.md5.3 KB
  • delegation-food-supply.md2.6 KB
  • delegation-github.md2.2 KB
  • delegation-health-records.md1.9 KB
  • delegation-hosted-publishing.md2.2 KB
  • delegation-identity-root.md2.4 KB
  • delegation-knowledge-notes.md2 KB
  • delegation-media-libraries.md1.8 KB
  • delegation-mobile-platform.md2.5 KB
  • delegation-os-hardware.md2.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.