Skip to content

About

Per-Project Modular Book Writing Workflow for Coding Agents - Generating Human Grade Long Form Text Through Agentic AII

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Buchbinder — Professional Book Writing Workflow for OpenCode

Buchbinder is a professional-grade book writing workflow for OpenCode that guides authors from initial concept to completed, publishable manuscript. It supports fiction, non-fiction, mixed, and series projects through a structured phase system with fine-grained outlining, XML-structured drafting, 25 hard-block quality gates, 8 critique modes, three-pass editing, multi-pass revision, and pandoc-based publishing.

Named after the German Buchbinder — the bookbinder, the craftsperson who folds, sews, and binds printed sheets into a finished, durable book — Buchbinder is a tool for the writer's craft in the age of AI-assisted composition.


Quick Start

Run this in your book project directory — empty or not:

d=$(mktemp -d) && curl -fsSL https://github.com/Thomashighbaugh/buchbinder/archive/refs/heads/main.zip -o "$d/bb.zip" && unzip -q "$d/bb.zip" -d "$d" && node "$d"/buchbinder-main/bin/install.mjs; rm -rf "$d"

wget instead of curl works identically:

d=$(mktemp -d) && wget -qO "$d/bb.zip" https://github.com/Thomashighbaugh/buchbinder/archive/refs/heads/main.zip && unzip -q "$d/bb.zip" -d "$d" && node "$d"/buchbinder-main/bin/install.mjs; rm -rf "$d"

That one line downloads the repository's main branch as a ZIP (the same archive as GitHub's Code ▸ Download ZIP), runs the installer out of the extracted tree, and deletes the temporary download afterward. Everything the project needs is copied into .opencode/; nothing of the download is kept.

No clone, no git, no npm install, no published release — just curl/wget, unzip, and node. The installer carries its own runtime dependencies and bootstraps them on first run (into the extracted tree, never into your project or your global config), so there is nothing to set up before you invoke it.

Re-run the same one-liner any time: it offers Refresh (sync updates, keep your edits), Reinstall (overwrite everything), or Cancel — no flags.

The installer will:

  1. Ask which track you want (fiction / non-fiction / mixed)
  2. Create the project directory structure under book/
  3. Install commands, skills, templates, tools, and lib files into .opencode/
  4. Initialize track metadata

After installation, type /buchbinder in OpenCode to open the workflow menu, or type /buchbinder <subcommand> for direct dispatch.

Nothing is left behind. The install is per-project and self-contained: the workflow lives entirely in the project's own .opencode/ (assets as source, dependencies declared and installed there), and the temporary download is removed by the rm -rf "$d" above. Deleting .opencode/ later removes Buchbinder from the project completely.

Why a self-bootstrapping installer? Running it from a source checkout needs no prior npm install either — node bin/install.mjs self-bootstraps the same way. The installer installs things; requiring its own dependencies to be installed before it can install anything would be circular.


What It Is

Buchbinder is not a prompt pack and not one chat loop. It drives a deterministic, twelve-phase writing workflow on top of OpenCode — constitute → specify → clarify → research → outline → draft → critique → revise → edit → review → publish — where each phase has its own agents, context budget, and exit criteria, and every transition is checked against evidence-based, hard-block gates. Four tracks (fiction, non-fiction, mixed, series) recombine the same core for the project at hand.

It is engineered for output quality, not volume: a manuscript that is internally consistent, voice-stable, and structurally sound — and, for non-fiction, correctly cited. Exactly one artifact is left to a human, the book cover; everything else (outline, draft, critique, revision, three-pass edit, continuity audit, bibliography, multi-format export) is produced end to end.

Highlights:

  • Fine-grained outline with scene beats, setup/payoff chains, and continuity anchors — gated before drafting
  • XML-structured drafting with awareness maps; each chapter loads only its outline slice, pinned neighbours, and style sheets
  • 26 hard-block quality gates across 8 categories
  • 8 critique modes, including an adversarial two-agent dialectic and 3–5 persona readers
  • Three-pass editing (line-edit → copy-edit → proofread) and multi-pass revision (--depth full)
  • Per-character and per-narration voice fingerprinting; 5 modular style sheets
  • Fully local semantic retrieval (ONNX embedder + reranker + NLI classifier) over each project's canon
  • JSON checkpoints with content hashing for reproducible resume
  • Series lorebook with cross-book inheritance; external lorebook import (SillyTavern, JanitorAI, CharacterAI)
  • 8 human-in-the-loop features: phase preview, authorial-intent capture, diff-based approval, severity tiers, veto key, feedback memory, non-negotiables, provenance tracking
  • Pandoc export with fallback generators

For the design rationale — origin, per-project vs MCP, the agentic stack, and packaging — see Design Notes.


The Subcommand Workflow

All functionality is accessed through the /buchbinder hub command. /buchbinder with no arguments opens an interactive menu via state detection. /buchbinder <subcommand> routes directly to the specified phase.

Phase Subcommands

# Subcommand Purpose Key Features
1 constitute Establish creative/intellectual principles Thematic statement (required, hard block), series lorebook inheritance
2 specify Build story specification Premise stress-test (6 criteria, hard block) before specification
3 clarify Resolve specification ambiguities Consistency checker, forgotten elements scan
4 research Active research Sources, annotation, literature review, field notes, interviews
5 outline Fine-grained chapter structure Scene beats (min 2/chapter), setup/payoff chains, continuity anchors, quality gate + 3 revision cycles
6 task-manager Break outline into tracked tasks Per-chapter sub-status lifecycle
7 draft Write chapters Batch-first (up to 6), XML structure, awareness map, prose quality, echo detection, beat arc check
8 critique Structured critique 8 modes: alpha, beta, peer, sensitivity, cold-read, comprehensive, adversarial, personas
9 revise Apply revisions Batch revision, revision-verify gate, --depth full (structural→language→pacing)
10 edit Line-level editing Three-pass: line-edit → copy-edit → proofread + linguistic gates (subtext, purple-prose, cliché, rhythm)
11 review Broad project QA Continuity scan + 7 Phase 2 structural analyses + 2 visualization outputs
12 publish Export manuscript Pandoc integration + post-export verification

Utility Subcommands

Subcommand Purpose
guided Automatic state detection — recommends next phase
import Import existing work (manuscript, draft, outline, spec, research, or whole project) at the stage it belongs to, then hand off
track Unified tracking: character state, plot progress, timeline, sources
timeline Chronological consistency verification
meta Bibliographic metadata management
cite Citation lifecycle (non-fiction): add, format, validate, bibliography
drafter Loose draft jumpstart from raw ideas
verify On-demand quality gate runner — 25 gates available
resume JSON checkpoint resume with file diff
cycle Full draft→critique→revise→edit cycle for all chapters
pacing-audit Cross-chapter pacing analysis
hook-review Opening/closing hook audit + book-level opening/closing strength
read-through Full reader experience audit + immersion + trust accounting
series Series lorebook operations: init, sync, audit, register, status, import

Quality Gate System

Buchbinder uses hard-block quality gates — gates produce evidence-based pass/fail results that block progression on failure. No soft warnings: a gate either passes or stops the workflow with specific evidence.

26 Gates Across 8 Categories

Category Gates When Run
Outline outline Before drafting — checks scene beats (min 2/chapter), setup/payoff bidirectionality, continuity anchors, pacing distribution
Pre-Draft pre-draft Before each draft session — 13 context items must be loaded with evidence
Post-Draft post-draft, prose-quality, echo-detection, beat-arc After drafting — XML structure, metadata, scenes, tracking, voice, awareness map verification, prose metrics (filter words, adverbs, passive, info-dumps, tense/POV), echo/repetition, beat arc trajectory
Revision revision-verify After revision — critique items cross-referenced against revision log
Structural reverse-outline, character-arc, qa-accounting, promise-audit, escalation-curve, cognitive-load, knowledge-state, thread-matrix, dependency-graph During review — Phase 2 deep analyses
Linguistic subtext, purple-prose, cliche, rhythm During edit — on-the-nose dialogue, overwriting, clichés, sentence monotony
Experience immersion, trust, opening-closing, continuity, style During read-through/review — immersion breaks, trust violations, hook strength, cross-chapter contradictions, style sheet compliance
Non-negotiables non-negotiables During draft/revise/edit — checks content against author's declared creative constraints (plot, character, tone, content, structure, world)

Gate Severity Levels

Level Behavior
Hard block Workflow stops. Evidence cited. Must fix before proceeding.
Warning Flagged for review. Does not block progression.

Prose quality scorecard: 5 hard-block metrics (filter words, adverbs, passive voice, info-dumps, tense/POV drift) + 4 warning metrics (showing/telling, concrete ratio, crutch words, dialogue ratio).

Echo detection: 2 hard-block checks (word echo, crutch words) + 2 warning checks (structural echo, beat echo).

Run /buchbinder verify to run any gate on demand. Run /buchbinder verify --all to run all gates.


Track System

Track Phase Sequence Use Case
Fiction Constitute → Specify → Clarify → (Research) → Outline (gate) → Tasks → Draft → Critique → Revise → Edit (3-pass) → Review → Read-Through → Publish Novels, short stories, serials, creative non-fiction
Non-Fiction Constitute → Research → (Cite) → Outline → Tasks → Draft → Fact Check → Cite → Revise → Edit (3-pass) → Review → Publish Academic works, journalism, biography, technical books
Mixed Constitute → Specify + Research → Clarify → Outline → Tasks → Draft → Fact Check → Cite → Critique → Revise → Edit → Review → Read-Through → Publish Creative non-fiction, memoir with research, narrative journalism
Series Series Lorebook Init → Constitute (inherit) → Specify → Outline → [per-book cycle] → Series Audit → Sync Lorebook Multi-book series with shared world/characters

XML-Structured Drafting

Drafts use internal XML tags for verification. Tags are stripped on save to produce clean prose.

<chapter number="3" title="The Summons">
<metadata>
  <wordcount>3200</wordcount>
  <pov>Mira</pov>
  <timeline>Day 4, evening</timeline>
  <characters-present>Mira, Theron, Captain Voss</characters-present>
</metadata>

<awareness-map>
  <payoff-from>ch2:Theron's-suspicion, ch1:summons-arrival</payoff-from>
  <sets-up>ch5:betrayal-revelation</sets-up>
  <continuity-anchors>Mira's scar (ch1), Voss's loyalty (ch2)</continuity-anchors>
</awareness-map>

<scene number="1" goal="Mira confronts Theron about his disappearance">
<beatchange emotion="dread" intensity="3" reason="Theron's evasion suggests guilt"/>
...

<tracking>
  <open-threads>summons-origin, Theron's-absence, Voss's-secret</open-threads>
  <resolved-threads>none</resolved-threads>
</tracking>
</chapter>

The post-draft gate verifies:

  • XML structure completeness (metadata, scenes, tracking)
  • Awareness map honored (payoff-from items addressed, sets-up items planted, continuity anchors present)
  • Voice profile compliance (per-character + per-narration)
  • Style sheet compliance (5 modules)
  • Prose quality scorecard (9 metrics)
  • Echo detection (4 checks)
  • Beat arc trajectory (flat streak detection, cross-chapter arc)

Critique Modes

Mode Description
alpha Structural critique: pacing, plot logic, character arcs, scene necessity, causality
beta Experience critique: engagement, comprehension, emotional investment, clarity
peer Academic/peer review methodology (non-fiction)
sensitivity Sensitivity assessment: representation, stereotypes, harmful tropes
cold-read First-impression reader with no context — surfaces confusion points
comprehensive All dimensions in a single pass
adversarial Two-agent dialectic: defender agent + challenger agent + synthesis agent for blind-spot surfacing
personas 3-5 reader types: Genre Fan, Casual Reader, Literary Critic, Subject Expert, Skeptical Reviewer

Three-Pass Editing

Pass Focus What It Checks
line-edit Craft Sentence-level quality, word choice, rhythm, imagery, scene construction, dialogue tags, showing vs telling
copy-edit Mechanics Grammar, punctuation, spelling, consistency (tense, POV, names), formatting, style sheet compliance
proofread Typos Final pass — typos, missing words, doubled words, punctuation errors, formatting glitches

Linguistic analyses run during editing:

  • Subtext analysis: on-the-nose dialogue detection
  • Purple prose: modifier ratio, metaphor density, elevated vocabulary
  • Cliché detection: 5 phrase categories + 5 genre-trope overuse categories
  • Sentence rhythm: length distribution, monotony score, consecutive similar-length detection

Phase 2 Structural Analyses

Run during /buchbinder review — 14 dedicated analysis libraries:

Analysis What It Detects
Reverse outline Draft vs planned outline comparison — missing beats, added beats, drift
Character arc Per-character arc completeness (intro→escalation→crisis→transformation→resolution)
Q/A accounting Narrative question tracking — answered, unanswered, deliberately unresolved
Promise audit Genre/tone/thematic/structural/mystery/romantic promises kept by book end
Escalation curve Stakes escalation from act to act, plateau detection, descending stretches
Subtext analysis On-the-nose dialogue detection, surface vs subtext comparison
Sentence rhythm Length distribution, monotony score, consecutive similar-length detection
Purple prose Modifier ratio, metaphor density, elevated vocabulary, purple passages
Immersion audit Anachronisms, authorial intrusion, meta-references, tone shifts, logic breaks
Trust audit Coincidences, deus ex machina, stupid-for-plot, plot armor
Cognitive load Per-chapter named characters/active threads/open questions tracking
Knowledge state Character vs reader knowledge matrix, dramatic irony detection
Opening/closing First/last 500 words analysis, hook scoring, resonance scoring
Cliché detection Cliché phrases (5 categories), genre-trope overuse (5 genres)

Series Lorebook Infrastructure

For multi-book series, Buchbinder provides a shared knowledge base:

book/series/lorebook/
├── characters.md    # Cross-book character profiles
├── glossary.md       # Shared terminology
├── threads.md        # Active plot threads across books
├── timeline.json     # Master timeline (all books)
└── world.md          # World-building canon
  • /buchbinder series init — Initialize series lorebook
  • /buchbinder series sync — Sync book-level knowledge to lorebook
  • /buchbinder series audit — Audit lorebook for inconsistencies
  • /buchbinder series register — Register a new book in the series
  • /buchbinder series status — Show series status and per-book progress
  • /buchbinder series import — Import external lorebook (SillyTavern, JanitorAI, CharacterAI)

Semantic Lore Injection

When generating content (outline, draft, critique, revise, review), Buchbinder uses semantic lore retrieval to inject only the most relevant lore into the prompt — not the entire lorebook. This keeps the context window focused and reduces token usage.

The retrieval pipeline is two-stage and fully local, running ONNX models in-process via @huggingface/transformers:

  1. Embedding — Xenova/bge-base-en-v1.5 (ONNX, 768-d) — Chunks lore files by section (## headings) and embeds each chunk
  2. Vector search — Cosine similarity between the task query and lore chunks
  3. Reranking (optional, --rerank) — an in-process ONNX cross-encoder (Xenova/bge-reranker-base) re-scores the top candidates jointly. Because a cross-encoder sees the query and the passage together, it reorders candidates more accurately than distance alone.

Setup: nothing to pull by hand — the installer fetches the ONNX models (embedder + reranker + classifier, ≈0.5 GB) into a shared cache (~/.cache/buchbinder/models) during install. To fetch or re-fetch them later, from a Buchbinder checkout:

node bin/fetch-models.mjs

Everything runs locally — no data leaves your machine, and no provider API requests are made. The query script (lore-query.mjs) is installed as .opencode/lib/scripts/lore-query.mjs and called automatically by the phase workflows. The ONNX runtime (@huggingface/transformers) is added to the project's .opencode/package.json by the installer.

If a model or the ONNX runtime is unavailable, the system degrades gracefully — embedding falls back to distance-only retrieval, then to reading lore files directly. No functionality is lost, only the selective retrieval optimization.

External lorebook import supports:

  • SillyTavern character cards (PNG embedded JSON, JSON files)
  • JanitorAI character definitions
  • CharacterAI character exports
  • Heuristic classification of entries into characters, locations, items, concepts

On-disk Index (v3)

Lore retrieval is fast because Buchbinder maintains an on-disk embedding index at:

.opencode/cache/lore-index/index.json

The index is built once and reused on every phase invocation. Without the index, lore-query.mjs re-embeds every chunk on every call (slow for multi-book series). With the index, query time is O(chunks) cosine comparisons in memory + one local embedding of the query.

Index coverage — these source files are scanned:

Path Chunked by Notes
series/lorebook/* Markdown headings characters, world, glossary, timeline.json, threads
series/outline.md Markdown headings Cross-book condensed outline (series-level beats)
book/knowledge/* Markdown headings character-profiles, voice-profiles, locations, world-rules, character-voices
book/constitution.md Markdown headings Project canon — highest priority
book/specification.md Markdown headings Book specification
book/outline.md, book/outline/chapter_*.md Markdown headings / one-per-file Whole-book + per-chapter outline
book/drafts/chapter_*.xml XML chunker (see below) Drafted chapters

Build / refresh the index — from inside the project:

# Build or incrementally update the index
node .opencode/lib/scripts/lore-query.mjs --build

# Check status (chunk count, age, embedder version)
node .opencode/lib/scripts/lore-query.mjs --status

Or use the slash command: /buchbinder refresh-index.

The index build is incremental: re-running on an up-to-date index is a no-op. Only source files whose content has changed since the last build are re-chunked and re-embedded. A refresh (see below) rebuilds the index automatically when source files have changed.

Env overrides. Retrieval defaults, all overridable:

Var Default Purpose
ONNX_EMBED_MODEL Xenova/bge-base-en-v1.5 ONNX embedding model (768-d)
RERANK_MODEL Xenova/bge-reranker-base ONNX cross-encoder
RERANK_BACKEND onnx onnx | none
CLASSIFIER_MODEL Xenova/nli-deberta-v3-xsmall zero-shot / NLI classifier
ONNX_DTYPE q8 ONNX weight dtype
ONNX_CACHE_DIR ~/.cache/buchbinder/models shared ONNX model cache
ONNX_OFFLINE unset 1 — never download; use cache or fall back
RERANK_MAX_LENGTH 512 reranker tokenizer truncation length
RERANK_DISABLED unset 1 — force distance-only retrieval

Local ONNX model stack

Three small Transformers.js models power retrieval and quality evidence. They are fetched once into a shared, machine-wide cache and reused by every Buchbinder project:

Role Model ≈Size
Embeddings Xenova/bge-base-en-v1.5 110 MB
Reranking Xenova/bge-reranker-base 280 MB
Classification (NLI) Xenova/nli-deberta-v3-xsmall 70 MB

The classifier turns qualitative judgements into local, reproducible evidence — useful for the hard-block quality gates ("does this chapter entail its outline beat?"), the premise stress-test, and non-fiction claim↔source checks:

# Zero-shot ranking of labels for a passage
node .opencode/lib/classifier.mjs --labels "foreshadowing,pacing,continuity" "the passage text"
# NLI entailment between a premise and a hypothesis
node .opencode/lib/classifier.mjs --entail "Chapter 7 pays off the locket from Chapter 2" "the locket resurfaces"

Wired into the gates. The classifier runs as a step inside two quality gates, chosen because NLI is decisive when a delivered artifact must entail a claimed property: post-draft (does the prose entail the draft's own awareness-map claims) and revision-verify (does each revision entry entail the critique recommendation it claims to address). Gates whose relation is correspondence rather than entailment — such as the outline's setup↔payoff pairing — are deliberately left out, because NLI scores those unreliably and a noisy step erodes gate trust:

node .opencode/lib/nli-gates.mjs --gate post-draft . --chapter 3

Findings are deliberately surgical — lowest entailment first, capped — and persisted to .opencode/cache/nli-evidence/<gate>.{json,md} so the evidence is available exactly when the gate runs.

Pinned Adjacent Chapters

For draft, critique, and revise phases, the lore query can pin specific chapters to be included verbatim in the context, regardless of semantic score. This is critical for continuity — the agent drafting chapter N needs the exact last scene of N-1.

# /buchbinder draft Chapter 5 → include the entire prior chapter (4) verbatim
bun .opencode/lib/scripts/lore-query.mjs \
  --query "Draft context for chapter 5" \
  --pin-chapter 5 --pin-side previous --top 5 --rerank

# /buchbinder critique Chapter 5 → include both N-1 and N+1 verbatim
bun .opencode/lib/scripts/lore-query.mjs \
  --query "Critique context for chapter 5" \
  --pin-chapter 5 --pin-side both --top 5 --rerank
  • --pin-side previous → pin chapter N-1
  • --pin-side next → pin chapter N+1
  • --pin-side both → pin both N-1 and N+1

The pinned chapter is loaded from disk directly (bypassing the index). It's emitted in the context block as raw XML, clearly marked as PINNED — verbatim for continuity.

XML Draft Chunker

book/drafts/chapter_*.xml files use a separate chunker that understands the draft schema:

<chapter number="N" title="...">
  <metadata>...</metadata>              <!-- 1 chunk: who/where/when -->
  <awareness-map>
    <sets-up ref="ChM: ...">...</sets-up>
    <payoff-from ref="ChM: ...">...</payoff-from>
    <continuity-anchors>
      <anchor name="...">...</anchor>
    </continuity-anchors>
  </awareness-map>                     <!-- 1 chunk: cross-chapter refs -->
  <scene number="K" type="..." goal="..." conflict="...">
    <narration>...</narration>
    <interiority .../>
    <sensory-inject .../>
  </scene>                              <!-- 1 chunk per <scene> -->
  <scene continuation="true" ...>       <!-- continuation scenes get inferred numbers -->
</chapter>

Emits four chunk kinds per file: metadata, awareness, scene (one per <scene>), and whole-chapter (used only by the pinned path). Continuation scenes (<scene continuation="true"> with no number= attribute) get an inferred sequential number so a 7-scene chapter always produces 7 scene chunks.

The chunker is permissive: missing <metadata> or <awareness-map> blocks are skipped silently; unknown <scene> children are flattened to text. The markdown chunker handles the lore, outline, canon, and spec sources; the XML chunker handles only the drafts.

Lore as Canonical Truth (Doctrine)

The lorebook — series/lorebook/*, book/knowledge/*, book/constitution.md, book/specification.md, and the project series/outline.md / book/outline.md — is the absolute source of truth for a project. Between agents (outline, draft, critique, revise, review), the lorebook is taken as literal, beyond-reproach canon. Only the human user's explicit direction can alter lore; agents must work hard to make internally-consistent sense of canon before suggesting any change.

If you believe a lore entry is wrong, do NOT silently rewrite it. Flag it in the critique report (./book/critique/chapter_NN.md) and ask the user. If a draft would substantially contradict established lore, halt and ask the user before proceeding.

This doctrine is restated in each phase spec (outline, draft, critique, revise, review) so every agent invocation sees it.

Local Overrides via HTML Comments

Buchbinder ships a set of phase specs (src/tools/hubs/buchbinder/{outline,draft,critique,revise,review}.ts) that you may want to customize for your project. Because refresh preserves locally-modified files (see below), a common workflow is:

  1. Refresh once after install to set up the baseline.
  2. Edit a phase spec (e.g. .opencode/tools/hubs/buchbinder/outline.ts) to add a custom instruction wrapped in HTML comments for clarity.
  3. Subsequent refreshes leave your edit alone — the file appears in the locallyModified[] list in the refresh summary.

Example:

// .opencode/tools/hubs/buchbinder/draft.ts
// <!-- buchbinder:override -->
// Custom: always end chapters on a sensory beat, not a dialogue beat.
// <!-- /buchbinder:override -->

The override survives refreshes because refresh diffs your file against the source and skips the copy when the SHA differs. Choosing Reinstall (or node bin/refresh.mjs --force) overrides it, destructively.

Per-project Install Model

Buchbinder installs per-project, not globally. Each book project has its own .opencode/ directory containing its own copy of the plugin's skills, tools, templates, slash commands, and TUI sidebar plugin. This mirrors the Nix/dependency-isolation pattern: pinning per project means a project created today will build the same way a year from now on a different machine. This containment — and why it is preferable to an MCP-server approach — is covered in Why per-project, not an MCP server.

The install writes .opencode/opencode.jsonc, .opencode/tui.json, and .opencode/package.json to register the buchbinder-sidebar plugin as a project-local plugin. It does not touch your global opencode config, ~/.config/opencode, or your global node_modules. Plugin-owned subtrees are: skills/, tools/, templates/, commands/, plugins/, plus the three config files. Everything else under .opencode/ (and the project-root book/, memory/, output/, series/ directories) is project-owned and never touched by install or refresh.

The first time you install, the installer prints an acknowledgement screen explaining the per-project model and asks you to confirm before proceeding. The acknowledgement is not recorded — you re-acknowledge on every fresh install.

Refreshing an Existing Install

Once a project is installed, updating is a prompt, not a flag. Two equivalent ways:

  • In OpenCode: /buchbinder refresh.
  • In a shell, from the project: re-run the install one-liner and choose Refresh.

Both shell out to the installed .opencode/lib/scripts/refresh.mjs, which re-fetches the Buchbinder package (the installer does not keep it in the project), runs refresh from it, and removes the download. Either way it syncs changed/new files, rebuilds the index, and preserves your local edits.

From a Buchbinder checkout you can also run refresh directly; the arguments are all optional:

node bin/refresh.mjs                 # sync changed files, preserve local edits, rebuild index
node bin/refresh.mjs --prune         # also remove files that disappeared from source
node bin/refresh.mjs --force         # overwrite locally-modified files (destructive)
node bin/refresh.mjs --skip-index    # skip the lore index rebuild

buchbinder-refresh:

  • Always rebuilds the TypeScript-derived sidebar bundle (npm run build:sidebar in the package).
  • Always rebuilds the lore index (incrementally).
  • Preserves files you've locally modified (HTML-comment override workflow).
  • Never touches project-owned paths.

The postinstall script in package.json calls node bin/refresh.mjs --postinstall || true so npm install buchbinder from a consumer project also triggers a sync. This is idempotent — re-running on an up-to-date project is a no-op.

Exit codes:

  • 0 — success, no drift
  • 1 — success, but locally-modified files were preserved (drift detected; review the locallyModified[] list)
  • 2 — refresh failed

Voice & Style System

Voice Profiles

Per-character AND per-narration voice fingerprints:

{
  "narration": {
    "register": "literary",
    "sentenceLength": "varied",
    "figurativeDensity": "moderate",
    "sensoryPriority": ["tactile", "auditory", "visual"]
  },
  "characters": {
    "Mira": {
      "register": "blunt",
      "vocabulary": "sparse",
      "speechPattern": "short-declarative",
      "contractions": true
    }
  }
}

Modular Style Sheets

5 separate modules in book/style-sheet/:

Module What It Covers
prose.md Sentence structure, paragraph rhythm, figurative language density
dialogue.md Dialogue tags, speech patterns, attribution conventions
description.md Sensory emphasis, description density, exposition handling
pacing.md Scene length, chapter rhythm, tension/release cycles
pov.md POV type, head-hopping rules, narrator distance

Human-in-the-Loop Features

Buchbinder integrates 8 HITL features to keep the author in control of the AI-assisted process:

Phase Preview

Before any phase executes, the author sees a preview: which chapters will be affected, estimated duration, what context will be loaded, which gates will run. The author confirms before execution.

## Phase Preview: DRAFT
Chapters: 3, 4, 5, 6, 7, 8 (6 total)
Estimated duration: ~36 minutes (18000 words)
Gates to run: pre-draft, post-draft, prose-quality, echo-detection, beat-arc, non-negotiables
Confirm to proceed.

Authorial Intent

Before each phase (draft, revise, edit), the author states their intent in 1-2 sentences. If unsure, a generic intent is used: "Produce the best possible output consistent with the outline and constitution." After the phase, the AI verifies the output honors the stated intent.

Diff-Based Approval

After revise or edit passes, the author sees a structured diff (before/after). Approve line-by-line, reject specific hunks, or accept all. Rejected hunks preserve the original text.

Suggestion Severity Tiers

All AI suggestions are tiered:

Tier Behavior
must-fix Blocks progression (maps to gate failure)
should-consider Warning — flagged but not blocking
your-call Preference — author's choice
FYI Observation — no action needed

Author controls the filter level — only must-fix shown by default.

Veto System

The author types | to veto any suggestion:

  • | — silent veto (no explanation required)
  • | keeping this rhythm for effect — veto with reason

Vetoed suggestions are never re-suggested. Vetoes with reasons feed into feedback memory.

Feedback Memory

When the author rejects a suggestion with a reason, the reason is logged as an avoidance pattern. The AI checks preferences before making future suggestions and avoids patterns the author has consistently rejected.

Non-Negotiables (Creative Constraints)

At constitution, the author declares creative elements that must not be changed by any AI pass — the author's red lines:

Category Example
Plot "Mira must die in chapter 12"
Character "Theron never lies"
Tone "Always melancholic, never hopeful"
Content "No on-page violence against children"
Structure "Each chapter must end on a turn"
World "Magic always has a cost"

The non-negotiables gate checks all content against these constraints during draft, revise, and edit phases. Violations block progression.

Provenance Tracking

Every line of prose is tagged with its origin:

Origin Meaning
author Written by the author
ai-drafted Generated by AI in draft phase
ai-revised Revised by AI (approved as-is)
ai-edited Edited by AI (approved as-is)
ai-modified AI-suggested, modified by author before acceptance
author-revised Author revised AI output

Manuscript-level statistics show the author vs AI percentage, per chapter and aggregate.


Checkpoint System

JSON checkpoints save state after each phase, enabling resume:

{
  "phase": "draft",
  "chapter": 7,
  "batchSize": 6,
  "contentHash": "sha256:...",
  "gates": { "pre-draft": "pass", "post-draft": "pass" },
  "timestamp": "2026-07-07T..."
}

/buchbinder resume loads checkpoint, diffs files against content hash, and reports what changed since the checkpoint was saved.


Project Structure

project/
├── .opencode/               # Installed workflow
│   ├── commands/buchbinder-router.md  # Hub phase router (direct phase execution)
│   ├── skills/               # 34 SKILL.md files across 5 categories
│   │   ├── quality-assurance/
│   │   ├── critique/
│   │   ├── research/
│   │   ├── fiction/writing-techniques/
│   │   ├── fiction/genre-knowledge/
│   │   └── non-fiction/
│   ├── tools/
│   │   ├── hubs/buchbinder/    # 29 subcommand spec files
│   │   └── lib/             # 32 library files
│   └── templates/           # Track + series templates
├── book/                    # All book content
│   ├── track.json           # Track selection: fiction | non-fiction | mixed
│   ├── constitution.md      # Core rules + thematic statement
│   ├── specification.md     # Story spec (with premise stress-test)
│   ├── outline/             # Fine-grained chapter structure
│   ├── content/             # Clean prose (tags stripped)
│   ├── drafts/              # XML-structured drafts (with verification tags)
│   ├── critique/            # Critique artifacts (8 modes)
│   ├── revisions/           # Revision tracking + verify gate results
│   ├── knowledge/           # Character profiles, locations, glossary
│   ├── tracking/            # State tracking JSON
│   ├── style-sheet/         # 5 modular style sheets
│   ├── checkpoints/         # JSON checkpoint state
│   ├── research/            # Sources, bibliography, interviews
│   └── series/lorebook/     # Series lorebook (if series project)
├── memory/                  # Durable reference
└── output/                  # Published exports

Batch-First Defaults

All pipeline phases default to batch processing:

  • draft: All chapters or up to 6 at a time
  • critique: All chapters with shared context loaded once per batch
  • revise: All chapters or up to 6
  • edit: All chapters or up to 6
  • cycle: Full draft→critique→revise→edit for all chapters

Single-chapter is an explicit override: /buchbinder draft 5 or /buchbinder edit Chapter 3.

Shared context (constitution, specification, knowledge, tracking, style sheet) is loaded once per batch, not per chapter.


Design Notes

Origin

Buchbinder is a substantial expansion and re-architecture of novel-writer-english, itself a translation and platform-agnostic adaptation of novel-writer-skills. The author's earlier non-agentic Fiction Fabricator contributed concepts refined here for the agentic context; the move from Python scripts to an agentic workflow was inspired by Claude Code and made possible by OpenCode. See ATTRIBUTION.md for the full chain.

Why per-project, not an MCP server

Buchbinder is not a server a project connects to; it is a workflow a project contains, installed only into that project's own .opencode/. That buys granular per-project configuration, no global install or lingering registration, many private projects side by side, and a guided workflow rather than a bare tool surface. Deleting .opencode/ removes it completely.

A compound, agentic system

Buchbinder orchestrates LLM inference across a deterministic phase state machine, calls its own typed tools, retrieves from a local embedding index with reranking, evaluates every transition against hard-block gates, and returns control to the author at deliberate checkpoints.

Built on OpenCode's SDK and plugin surface

Buchbinder registers a project-local TUI plugin (SolidJS + OpenTUI) that renders a custom sidebar, defines keybinds, opens select dialogs, raises toasts, and injects prompts back into the agent. Because the plugin model is native and project-local, the interface ships with the project and cannot rot when a third party stops shipping updates.

Nix-flake-inspired packaging

Declarative per-project definition, dependency isolation with pinned versions, diff-based non-destructive sync, and override granularity down to individual phase specs.

On dependencies

Reimplementation is a rational trade when the functionality is small and self-contained, a correct implementation costs minutes to hours, and an LLM can produce it cheaply under review. Buchbinder still uses dependencies where they are genuinely better (fs-extra, fast-xml-parser, solid-js, @opentui/*).


Development

git clone <repo>
cd buchbinder
node bin/install.mjs --help    # Runs with no node_modules — it self-bootstraps
npm install                    # Only needed to typecheck/build, not to run the installer
npx tsc --noEmit               # Type check
node bin/install.mjs           # Install into the current directory

bin/install.mjs and bin/refresh.mjs are three-line launchers: they call ensureDeps() (bin/lib/bootstrap.mjs) and then dynamically import the real CLI body (bin/lib/install.mjs, bin/lib/refresh.mjs). That indirection is what lets the bin run from a bare clone — the third-party imports (chalk, fs-extra, @inquirer/prompts) are only resolved after the dependencies they need have been installed.

Source structure:

  • src/commands/buchbinder-router.md — Hub phase router (direct /buchbinder-router <phase>)
  • src/tools/hubs/buchbinder/ — 29 subcommand spec files
  • src/lib/ — 32 library files (gates, voice, checkpoints, analyses, etc.)
  • src/skills/ — 34 SKILL.md files across 5 categories
  • src/templates/ — Track templates (fiction, non-fiction, series)
  • bin/install.mjs, bin/refresh.mjs — self-bootstrapping launchers (call ensureDeps(), then load the CLI body)
  • bin/lib/bootstrap.mjs — resolves/installs the package's own runtime deps so the bins run from a bare clone
  • bin/lib/install.mjs, bin/lib/refresh.mjs — the installer / refresher bodies

Keywords

Agentic AI · LLM orchestration · multi-agent systems · compound AI systems · tool calling / function calling · retrieval-augmented generation (RAG) · semantic search · embeddings · reranking · vector retrieval · prompt engineering · context engineering · evaluation harness · quality gates · deterministic pipelines · workflow state machines · human-in-the-loop (HITL) · Model Context Protocol (MCP) · TypeScript · OpenCode SDK · OpenCode plugin API · SolidJS · OpenTUI · TUI design · per-project configuration · dependency isolation · Nix flakes · reproducible builds · supply-chain security · checkpointing · observability · provenance · structured output · XML structuring · long-form content generation · creative-writing automation · publishing pipeline · Pandoc.


License

MIT. See LICENSE.


Attribution

This project builds upon the work of multiple antecedent projects:

  • wordflowlab — novel-writer-skills (MIT) — original Chinese-language methodology and skill architecture
  • JeroTan — novel-writer-english (MIT) — English translation and eight-step fiction workflow
  • Thomas Highbaugh — Fiction Fabricator (MIT) — the author's earlier non-agentic AI novel generator; contributed multi-phase generation, XML state management, lorebook system, and export concepts that were refined for the agentic context
  • pulpgen-dev — pulpgen (MIT) — AI novel drafting agent that inspired Fiction Fabricator's multi-phase approach and patch-based state tracking
  • OpenCode team — OpenCode — the agentic coding platform whose hub-and-skill architecture, slash command system, and per-project configuration model are the foundation Buchbinder runs on
  • Anthropic — Claude Code — terminal-based agentic coding approach that inspired the shift from non-agentic Python scripts to an agentic workflow design

See ATTRIBUTION.md for the full attribution chain and a detailed accounting of what Buchbinder adds.

About

Per-Project Modular Book Writing Workflow for Coding Agents - Generating Human Grade Long Form Text Through Agentic AII

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages