A bookmark-organization agent: ingest a browser bookmark export → prune → categorize → human approve → export an organized file. Works on any NETSCAPE-format export (Chrome, Firefox, DuckDuckGo).
The pipeline is five phases. Each phase runs only when the previous phase's sentinel file exists, and drops its own sentinel when it finishes. The filesystem is the state — there is no hidden in-memory orchestrator.
ingest → prune → categorize → approve → export
↓ ↓ ↓ ↓ ↓
parsed pruned proposed approved exported
JSON artifacts and the touch-file sentinels both live under work/ (sentinels
in work/.sentinels/), which is gitignored.
- Inspectable — read any phase's JSON to see exactly where things stand.
- Restartable — delete a sentinel and that phase, plus everything downstream, re-runs from clean inputs.
- Non-destructive — nothing is deleted. Pruned items are retained with a reason code and carried forward.
- Human-gated — the
approvedsentinel is dropped only by user action in the React approve UI. The agent cannot reach export on its own.
The full design lives in ARCHITECTURE.md. How to work in
the repo lives in CLAUDE.md. Each phase's kickoff prompt is
preserved in docs/prompts/ as the build log.
All five phases shipped. v1 single-model (generator only); the adversarial
critic is staged for later — the flag field is already reserved in the
proposal schema so it drops in without reshaping anything.
npm install
npm run ingest # → work/01.parsed.json + 'parsed' sentinel
npm run prune # → work/02.pruned.json + 'pruned'
npm run categorize -- --stub # → work/03.proposed.json + 'proposed'
# (omit --stub to use the live Claude generator
# when ANTHROPIC_API_KEY is set)
npm run approve # opens the React approve UI on http://localhost:5173
# clicking 'Approve' writes work/04.approved.json
# and drops the 'approved' sentinel
npm run export # → work/bookmarks.organized.html + 'exported'
npm test # 46 tests covering every phase + sentinel gatingDelete any sentinel under work/.sentinels/ and that phase plus everything
downstream re-runs cleanly. rm -rf work/ is a full reset.