Digital Garden

Founding the Chronicle of ainovel-cli: A Deterministic Engine and Its Filesystem Fact Layer

2026-10-15 · ~9 min read · ainovel-cli · AI writing · Go · architecture survey · open source

While most “AI writes novels” projects are still prompt scripts, someone turned long-form creation into a piece of engineering machinery. On this day, voocel/ainovel-cli was surveyed in full — the conclusion: documentation, architecture, and tests agree to an unusual degree; this is not a README-hype project.

I. Architecture: iron that is deterministic, wind that is semantic

73,000 lines of Go code (plus 25,000 lines of tests, about 35%) raise one sentence — “deterministic fact layer, autonomous semantic layer”: deterministic code manages flow and state; the LLM only creates and makes a few semantic rulings. Taken apart, it is five pieces:

II. The key audit: the question before handing it your keys

The user was about to hand over an API key, so a full-chain security audit came with the scan. Conclusion: leak risk is low; key handling is precisely one of the areas where this project is most rigorous. On storage, keys live only in ~/.ainovel/config.json, written via temp file plus Chmod(0o600), with a dedicated test pinning the behavior; .gitignore explicitly excludes .ainovel/. On transit, all logs across the repo record only provider and model names — not one place records a key or request header; environment variables are not read for keys (no os.Getenv anywhere), eliminating the classic “error message dumps environment” surface; the only unusual network egress is a GitHub API update check, just a GET carrying no user data. On exposure, saved keys in the TUI show only masked head and tail, and /diag exports are designed to be pasted into GitHub issues — novel body text and thinking content are all replaced with hashes, and tool arguments keep only pure-ASCII structural identifiers within 32 characters. Three residual risks were honestly stated: log files are 0o644 (a hygiene issue on multi-user machines), keys inevitably go to the configured base_url (inherent to any LLM client), and the author’s self-built litellm adapter was only structurally audited, not line-by-line. One practical suggestion: even with the audit passing, use capped keys — rotating keys in this project costs one config change and a restart.

III. The binary and the mechanics: one book per folder

The v0.7.9 Windows x86_64 binary landed on the desktop (SHA256 matching official checksums, verified by running it to print the version), and several facts were confirmed along the way. It is a pure terminal program — the GUI-looking screenshot is a Bubble Tea TUI drawn on a terminal character grid; the 213×57 in the title bar is the terminal size; the “TUI + Headless dual entry” exists precisely because of this, so SSH, NAS, Docker, and CI can all run it unattended. One book binds to one folder — all output lands in {launch directory}/output/novel/: chapters/drafts/summaries/reviews plus premise.md, outline.json, characters.json, world_rules.json, timeline, and under meta: progress/checkpoints/foreshadow/state_changes/snapshots/compass/decisions.jsonl/style_rules.json — a book is wholesale portable; copy it to another machine, cd back and start, and it continues from the nearest checkpoint; the folder carries a flock, so two instances fighting over one book are blocked. Four agents run fine on one model — Arbiter cannot be configured separately (fixed to the default model), Architect/Writer/Editor fall back to the default when unset; per-role configuration is purely a cost/quality tradeoff (the expensive model only does Writer’s work), and the Engine is a single-goroutine serial loop with only one agent running at a time — no concurrency conflicts. Three entries to the context window and one locked line — TUI /config, per-model context_window, and the legacy top-level field; unset resolves as “model-specific value → legacy top-level → built-in registry → 200K fallback”; the compression threshold is locked at 85% (window × 0.85), leaving 15% headroom for the next prompt and tool results, making even 1M-window models compress proactively rather than fill up — that is the attention-decay zone. The neatest part is the factory pattern: Writer’s context manager is rebuilt per chapter by the current model, Architect/Editor per run — so /config window changes need no exit; the chapter currently being written finishes (a natural safety boundary), and the next chapter takes effect.

IV. Two honest demerits

The survey report did not only sing praises. License inconsistency — the README says MIT, but the repository’s LICENSE is actually Apache-2.0; commercial use needs clarification from the author. Releases lag development — no new commits on main after September 26, the latest release is v0.7.9 from September 4, more than five weeks behind main; the October 11/12 CI failures were on other branches — main itself is green across the dual matrix (ubuntu+windows gofmt/vet/test/race), not a misreport. Three structural traits were also on record: dependence on the author’s two self-built libraries (agentcore and litellm are both voocel’s own projects — an ecosystem single point), strong web-novel orientation (foreshadow ledgers, chapter-end hooks, de-AI-flavoring; English publication-facing work is not a fit), and the high Go 1.25.5 bar. One-line verdict: if the scenario is batch production of Chinese web-novel serials, this is one of the most complete open-source solutions on GitHub today; for occasional short stories, its heavy architecture advantages go unrealized.

Real coordinates

Comments

← Digital Garden