Imported from benni-arnarsson/ormstunga (
dorian/AGENTS.md). Install upstream withnpx skills add benni-arnarsson/ormstunga --skill dorian. Copyright stays with the author.
dorian — literary-critique plugin
dorian is the literary-critique CLI plugin in the ormstunga plugin
family. It ingests manuscripts, critiques them against style profiles
and RAG-retrieved exemplars, tracks characters / plot / world, runs
editor-style issue detection, supports ideation, export, scheduler,
memory, and a few adjacent capabilities (similarity search, summary,
background generation).
Every user-facing capability is registered with the dispatch registry
and exposed to ahab over the CLI Transport Protocol
(docs/cli-transport-protocol.md).
Ahab is a peer package, not a dependency of dorian.
Layout
| Path | Purpose |
|---|---|
dorian/app/ |
DI container (app.App) — holds Config, DB, Queries, VectorStore, Adapter, Embedder, ProfileLoader |
dorian/ahab/ |
dorian-side CLI transport glue (wraps shared/cliplugin) |
dorian/background/ |
Writer background / rambling generation |
dorian/commands/ |
Kong command structs for every CLI command |
dorian/config/ |
TOML config loading |
dorian/core/ |
DORIAN.md parser, init flow, ProjectContext |
dorian/critique/ |
Critic agents + critique pipeline + sessions |
dorian/dispatch/ |
Capability handler registry (the CLI transport's server side) |
dorian/editor/ |
Issue detection on prose |
dorian/export/ |
Pandoc wrapper + book.toml generator |
dorian/ideation/ |
Conversational ideation sessions |
dorian/inspiration/ |
Inspiration prompts / "inspire" feature |
dorian/manifest/ |
CLI transport manifest generator |
dorian/model/ |
model.Adapter interface alias surface (the canonical types live in shared/llmadapter) |
dorian/profile/ |
ProfileLoader interface + bundled YAML profiles in assets/profiles/ |
dorian/rag/ |
Document parser, chunking, ingest, retriever |
dorian/scheduler/ |
Job queue + daemon |
dorian/similarity/ |
Similarity detection |
dorian/storage/ |
SQLite connection, migrations, sqlc-generated queries |
dorian/summarize/ |
Summarization pipeline |
dorian/teacher/ |
Teaching / self-profile |
dorian/tracking/ |
Character / plot / world tracking |
dorian/vectorstore/ |
Store / Embedder interfaces (chromem-go impl) |
See ARCHITECTURE_WALKTHROUGH.md for
deeper context.
Package invariants (canonical)
- Manual DI through
dorian/app.App. No service locator, no framework-level container. Every command handler is injected via Kong'sBind()with an*App. Tests constructAppwith mocks. model.Adapterremains the single LLM gate from dorian's perspective; it is a Go type alias toshared/llmadapter.Adapter, which is the cross-plugin canonical type. Plugins importshared/, never the reverse — putting the canonical interface inshared/is the only shape that satisfies the dependency-arrow rule. Every LLM call goes through that interface; no direct HTTP against Ollama, no new adapter frameworks. Prompt and schema live at the call site; the adapter only transports bytes. Traces to thecritique-profilesandintegrationarchived changes.core.ParseDorianMDparses project context. The Markdown front-matter + section grammar is a contract —DORIAN.mdin a manuscript directory holds style, characters, plot, world, notes. Returnsnilwith no error when absent. Never hard-code project context; always go through this parser.- RAG pipeline is deterministic. Chunk + embed + store is
idempotent on the same input. Re-ingesting the same file does not
duplicate chunks. Traces to
ollama-rag. - Every new dorian feature has a CLI command AND a dispatch
handler. Register in
dorian/dispatch/handlers.go; the handler is automatically exposed viadorian ahab exec <capability>. No separate MCP tool file. - No real LLM API calls in tests. All LLM calls must be mocked
via
model.Adapter. Tests are table-driven; mocks are manual. - Command daemon dependency. Every new dorian CLI command MUST be
registered in either
standaloneCommandsorrequiresDaemonCommandsincmd/dorian/main.go. Standalone commands run underdaemon_consent = "denied"; requires-daemon commands fail fast with the existing remediation message. The proposing OpenSpec change SHALL declare the new command's category. Drift is caught atmake testtime byTestStandaloneAndRequiresDaemonAreExhaustive. Seeopenspec/specs/dorian-command-daemon-dependency/spec.md.
Shared/-first
Before inventing a cross-plugin-sibling plumbing surface inside dorian, prefer the shared utility:
shared/cliplugin— manifest emission, Dispatcher interface, Kong subcommand tree, canonical JSON marshaler.dorian/ahab/anddorian/manifest/build on this; do not hand-roll manifest emission.shared/credentials— socket-speaking credentials client. Use for any secret dorian needs (Anthropic key, etc.); never read credentials from env directly in plugin code.shared/admin— admin registry +Servehelper. If dorian grows a plugin-admin protocol beyond what the CLI transport already covers, use this.
Examples of what belongs in shared/: anything a second plugin
might also need (manifest shape, credential retrieval, admin
registry). Examples of what stays in dorian/: critique-specific
grammar, manuscript parser, tracking schemas, profile format.
Agent dispatch
dorian-architect— plan-time review / proposal design / architecture alignment for dorian-local changes. Read-only.dorian-engineer— apply-time TDD / debug / verification for dorian tasks.- Escalate to
ahab-architectfor CLI-transport or plugin-admin questions (the dorian/ahab glue layer). Escalate to the globalarchitectfor multi-package sequencing.
Cross-package links
ahab— the orchestrator ahab discovers dorian via CLI transport.dorian/ahab/is the client side.feanor— sibling plugin; feanor hosts coding backends while dorian hosts critique. They do not import each other.anansi/mercury— sibling plugins for marketing and publishing. Cross-reference viashared/only.shared— the utilities above. Seeshared/AGENTS.md.
Verification
make fmt && make test for unit, make test-e2e for full CLI
end-to-end (requires Ollama + qwen3.5:9b + nomic-embed-text; the
e2e suite runs only on the designated mac-mini host per the root
AGENTS.md "E2E test execution policy" section), make test-e2e-playwright
for LibreChat UI (requires Docker, same host gate).
Package-scoped: go test ./dorian/.... Never claim done without a
fresh run.