Milestones

The plan, and what is actually finished. Update the status here whenever milestone progress changes.

Status: βœ… done Β· 🚧 in progress Β· ⬜ not started


Milestone 1 β€” Runnable foundation βœ…

Goal: a clean, runnable, documented foundation. No product features.

Item Status
.gitignore protecting secrets and user data βœ…
Project memory (project-memory/) βœ…
Cross-agent instructions (AGENTS.md, per-tool pointers) βœ…
Documentation (README.md, docs/*.md) βœ…
LICENSE (PolyForm Noncommercial), LICENSING.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, CHANGELOG.md βœ…
project.json + scripts/set_identity.py for project identity βœ…
Session memory (SESSION_PROTOCOL.md, sessions/, scripts/session.py) βœ…
.env.example with safe placeholders βœ…
Backend: FastAPI, health + config endpoints, settings, event bus βœ…
Backend tests (pytest) βœ…
Frontend: React + TypeScript + Vite single-page workspace βœ…
Light mode default, dark mode toggle βœ…
Frontend tests (Vitest) βœ…
Docker + Docker Compose βœ…
GitHub Actions CI βœ…
GitHub Pages documentation foundation βœ…
Clean initial commit βœ…

Deliberately excluded: any importer, any archive browsing, any search, any cloud or sync code, authentication, multi-user support.


Milestone 2 β€” ChatGPT importer βœ…

Goal: import a ChatGPT export and store it as human-readable files.

Item Status
Importer protocol: detect(), validate(), parse() βœ…
Registry so core code never imports a provider module βœ…
ChatGPT parser, including the branching mapping tree βœ…
Normalisation into Conversation / Message βœ…
Markdown + JSON metadata on disk, one folder per conversation βœ…
Hostile-input handling: zip slip, zip bombs, size caps, path traversal βœ…
archive.imported and conversation.created events βœ…
Import UI: choose a file, see progress, plain-language result βœ…
Tests for malformed, truncated and hostile input βœ…

Deliberately excluded: browsing or reading imported conversations, search, the SQLite schema, attachments and images (recorded as placeholders in the Markdown), abandoned conversation branches.

Not generalised. The adapter interface stays shaped by one real importer. It gets generalised in Milestone 5 against a genuine second case.


Milestone 3 β€” Archive browser, Markdown and search βœ…

Item Status
Browse imported conversations βœ…
Render Markdown for reading βœ…
SQLite schema for metadata and indexing βœ…
Full-text search using SQLite FTS5 βœ…
The database is rebuildable from the files on disk βœ… enforced by a test
Rebuild on startup, and on demand βœ…

No Elasticsearch or external search infrastructure, as planned.

Deliberately excluded: editing or deleting conversations from the interface, tags, projects, and any per-message structure β€” the whole Markdown file is rendered rather than parsed back into messages.


Milestone 3.5 β€” Import ergonomics βœ…

Slotted in after Milestone 3 because getting an export out of ChatGPT turned out to be the real obstacle to using the product, not anything in the code. OpenAI’s own email says the export β€œmay take a few days” β€” see RESEARCH.md R-004.

Item Status
Watched inbox folder β€” drop an export in and it imports itself βœ…
Configurable to a folder you already keep exports in, files left in place βœ…
Honest re-import reporting: new, updated, already there βœ…
Unchanged conversations are not rewritten at all βœ…
Correct guidance: days to prepare, 24h link expiry, one request at a time βœ…
scripts/inspect_export.py β€” structure only, safe to share βœ…
scripts/make_fixture_export.py β€” large messy synthetic exports βœ…
scripts/browser/chatgpt-export.js β€” optional fast path, run by the user βœ…

Deliberately excluded: a filesystem watcher (scanning covers it), progress reporting during a long import, and anything that puts a session token inside Mind Archive (D-024).


Milestone 4 β€” Tags βœ…

Item Status
Tags stored in metadata.json, indexed in SQLite βœ…
An import never removes a tag βœ… enforced by a test
Add and remove tags on a conversation βœ…
Filter by tag, combined with search βœ…
Tag counts βœ…
conversation.tagged event βœ…

Deliberately excluded (D-026): Projects, and the Memory / Document / Attachment model types originally listed here. Tags plus full-text search already answer the question people actually have. A schema with no feature behind it is one nobody has tested against a real need.

Projects are in docs/BACKLOG.md, most likely as a reserved tag namespace rather than a parallel hierarchy.


Milestone 5 β€” A second provider, and getting everything back out βœ…

Item Status
A second real importer (Claude) βœ…
The Importer interface generalised against it βœ…
Shared JSON reading extracted once two callers wanted it βœ…
Export the whole archive as ordinary files βœ…
StorageProvider interface ⬜ deferred to Milestone 6 (D-028)

What the second provider revealed. ChatGPT and Claude both ship a file called conversations.json, and detection matched on the filename β€” so the ChatGPT importer would have claimed a Claude export and reported it empty. A latent bug from Milestone 2 that no amount of testing one importer could find. Detection now inspects shape (D-027).

Why StorageProvider waits. An interface with one implementation is a guess about the second, and this milestone is the evidence: the Importer interface only revealed its defect when a real second case arrived. Building StorageProvider now β€” with cloud still a milestone away β€” would repeat the mistake this milestone just corrected (D-028).


Milestone 6 β€” Optional cloud storage and synchronisation ⬜


Milestone 7 β€” Production hardening and public release ⬜