The planning package had grown to where a new agent could not tell what was authoritative. Phase 0 execution prompts sat beside the specification; four completed milestone reports sat beside the current one; and upstream AI-DnD's own `plan/` build log and `docs/` project site still described a hosted, scripted, multi-user product with accounts — every screenshot in it showed a Scripts tab and a Sign up button, none of which has existed since M2. `planning/archive/` now holds the history and says so in its own README: `phase0/` for the research that chose AI-DnD, `milestone-reports/` for M1 and M2, `decisions/` for ADR 008, the Phase-0-before-build gate Phase 0 satisfied. `planning/reports/` holds only the current milestone's report, because that is the one M4 planning has to read; it moves to the archive when M4's replaces it. Deleted rather than archived: the Phase 0B execution prompts and the handoff/status/summary documents, the Phase 0A discovery and triage reports, upstream's `plan/` and `docs/` trees, and `frontend/README.md`, which was Vite's template boilerplate. All of it is in Git history, and the two recommendation reports carry every conclusion the deleted research reached. Archived documents are kept verbatim. Paths written inside them point at where those files were when the document was written, which is the point: an evidence record that has been quietly edited is no longer evidence. Active documentation is corrected where it pointed at the removed trees or described removed capability as present. `DEVELOPMENT.md`'s "things M1 did not touch" list had gone stale at M2 and claimed QuickJS scripting was still tested; its test count was 604 against an actual 638. `README.md` loses the upstream CI badge, which reported upstream's pipeline rather than this fork's, and a reference to `backend/app/worldstate/engine.py`, a file that does not exist. `planning/README.md` is rewritten as the documentation index. New: `planning/PROJECT-SOURCES.md` and `planning/project-sources.txt`, the manifest of what belongs in the ChatGPT project's Sources. Source comments referring to the deleted trees are reworded; no behaviour changes. 638 backend tests pass, frontend lints and builds, and a reference scan over all 48 tracked Markdown files reports no unresolved path in active documentation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NCbwH7yLGKsj1rhXXzKSCu
2.9 KiB
ADR 002 — Ollama Is the v1 Model Backend
Status: Accepted; transport/TLS consequence added after M1
Decision
v1 will target Ollama inference running on user-controlled local infrastructure. The default endpoint is same-host loopback, but v1 must also support an explicitly configured Ollama instance on a trusted local-area network.
Context
The intended production deployment can eventually run the storyteller and Ollama on one machine, but development and testing may place Ollama on a separate machine on the user's LAN. The project prioritizes local control, privacy, predictable integration, and no dependency on Internet/cloud inference.
Alternatives Considered
- multiple cloud providers,
- LM Studio,
- llama.cpp direct integration,
- arbitrary OpenAI-compatible endpoints,
- Ollama.
Reason
Ollama is already available locally, provides a simple local API, supports both text-generation and embedding models, and avoids requiring external inference services.
Consequences
- candidate forks supporting multiple cloud providers should be simplified or hardened,
- candidate projects using another local API need an adapter,
- the storyteller must support both same-host Ollama and an explicitly configured trusted-LAN Ollama endpoint,
- LAN inference does not imply LAN exposure of the storyteller UI/API; the storyteller should still bind to loopback by default,
- arbitrary public Internet/cloud model endpoints remain outside normal v1 configuration,
- future backend abstraction may be added, but v1 should not be delayed to support it.
Transport for a Trusted-LAN Endpoint
Added after M1. Same-host Ollama speaks plain HTTP over loopback, and it was assumed a LAN endpoint would look the same. It does not have to.
A trusted-LAN Ollama may be served over HTTPS with a certificate issued by a
private or local CA rather than a public one — a self-hosted server that
terminates TLS for everything it exposes is the ordinary case, not an exotic
one, and it may offer no cleartext port at all. A v1 client that trusts only a
bundled public-CA list cannot talk to such a host, while curl and the user's
browser on the same machine can.
Therefore:
- production clients must verify against the operating system's trusted CA store in addition to any bundled certificate list, so a CA the user has installed on their own machine is honoured by this application too;
- certificate and hostname verification remain fully enabled;
- there must be no "ignore TLS errors" / "insecure" option, in the UI, in configuration, or as an environment variable. A LAN endpoint the machine does not trust is a configuration problem to fix at the OS level, not a check to switch off;
- the endpoint URL must therefore accept
https://on any port, not onlyhttp://…:11434.
M1 implemented this (backend/app/tlstrust.py); see
planning/archive/milestone-reports/M1-IMPLEMENTATION-REPORT.md §G.