OpenMind v2 Phase 1: core extraction and tool-first foundation#6
Merged
Conversation
Turn OpenMind from a UI-centric application into a headless engineering
knowledge runtime that the CLI, the MCP server, the FastAPI app and the tests
all drive through one shared bootstrap. This is an architectural foundation; it
implements none of the later v2 enterprise knowledge features.
Runtime and services
Add openmind/runtime.py as the composition root: an idempotent, ordered
bootstrap (ensure dirs -> open database -> migrate to head -> build services)
that every adapter shares. Previously three call sites initialized the process
differently, and jobs.start_worker() ran only under FastAPI, so a job enqueued
from any other process stayed queued forever. Worker startup is opt-in per
surface, so doctor, status and export never spawn a background thread.
Add openmind/services/ (workspace, ingest, job, export, health, container),
openmind/domain/ (typed errors and boundary types) and openmind/ports/ (three
narrow protocols with real test seams: the workspace repository, the job
reader/engine, and a clock that makes bounded waits testable in milliseconds).
Services never import FastAPI and return plain dicts or dataclasses.
Database migrations
Replace the untracked CREATE TABLE IF NOT EXISTS block with a checksummed,
transactional migration runner and a schema_migrations ledger. A legacy
database is baselined, never recreated. Editing an already-applied migration
fails loudly. DDL is transactional via explicit BEGIN/COMMIT, since sqlite3
would otherwise run it in autocommit and survive a rollback.
CLI
Add openmind/cli.py: doctor, init, add, ingest, status, export, mcp serve and
serve. Under --json exactly one object goes to stdout with diagnostics on
stderr, and exit codes 0-5 are stable and documented. serve stays loopback-only
unless --allow-non-loopback is passed explicitly.
Adapters
Route the project, path, template, ingest, job, lifecycle and health
operations in main.py through the services. Add
mcp_server.create_mcp_server(runtime) and remove the import-time db.init_db()
side effect; the nine MCP tools keep their names and contracts.
Compatibility
Verified by probing the refactored routes on main and on this branch through a
git worktree and diffing the transcripts: across 29 probes there are zero
status-code differences and zero keys removed. The 14 differences are purely
additive - /api/health gains version and schema_version, and error bodies gain
an "error" key alongside the unchanged "detail".
One deliberate fix: DELETE /projects/{id}/paths returned None from a handler
annotated -> Dict[str, Any] for an unknown project, which FastAPI's response
validation turned into a 500 ResponseValidationError. It now returns 404 like
every sibling route.
Version
Add openmind/version.py (1.1.0-dev), reported by --version, doctor, the
FastAPI app and the artifact generator. Deliberately not 2.0.0: none of the v2
enterprise features exist yet. The artifact schema stays frozen at 1.1.0.
Tests and CI
Add verify_migrations, verify_runtime, verify_services, verify_cli and
verify_adapters (374 new checks), plus scripts/run_acceptance.py - an isolated,
offline runner in which a skipped core script counts as a failure and every
tests/verify_*.py must be registered, so a new test cannot silently go unrun.
Expand CI into a dependency-free artifact-contract job, an Ubuntu full gate, a
three-OS smoke matrix, and an optional pinned-ref skill-verification job.
All 24 acceptance scripts pass; no test invokes a paid or public model API.
Docs
Add docs/v2/phase-1-core-foundation.md, docs/cli.md and
docs/database-migrations.md, and give the README a tool-first quick start.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns OpenMind from a UI-centric application into a headless engineering knowledge runtime that the CLI, the MCP server, the FastAPI app and the tests all drive through one shared bootstrap.
This is an architectural foundation. It deliberately implements none of the later v2 enterprise knowledge features — see Deferred.
Design note:
docs/v2/phase-1-core-foundation.md.What changed
Runtime and services. New
openmind/runtime.pycomposition root with an idempotent, ordered bootstrap. Newservices/(workspace, ingest, job, export, health, container),domain/(typed errors + boundary types), andports/— three narrow protocols, each with a real test seam: the workspace repository, the job reader/engine, and a clock that makes bounded waits testable in milliseconds. Services never import FastAPI.The most consequential fix:
jobs.start_worker()previously ran only under the FastAPI lifespan, so a job enqueued from any other process satqueuedforever. Worker startup is now an explicit, opt-in runtime call — which is what makesingest --waitwork at all, while keepingdoctor/status/exportthread-free.Database migrations. Replaces the untracked
CREATE TABLE IF NOT EXISTSblock with a checksummed, transactional runner and aschema_migrationsledger. A legacy database is baselined, never recreated. Editing an already-applied migration fails loudly. DDL is transactional via explicitBEGIN/COMMIT—sqlite3would otherwise run it in autocommit, where it survives a rollback. No Alembic; the rationale is indocs/database-migrations.md.CLI.
python -m openmind.cli:doctor,init,add,ingest,status,export,mcp serve,serve. Under--json, exactly one object on stdout with diagnostics on stderr. Exit codes 0–5 stable and documented (docs/cli.md).servestays loopback-only unless--allow-non-loopbackis passed explicitly.Adapters. Project, path, template, ingest, job, lifecycle and health operations in
main.pynow go through the services.mcp_server.create_mcp_server(runtime)makes MCP startup testable, and importing the module no longer opens a database.Compatibility
mainvia a git worktree — zero status-code differences, zero keys removed. 14 differences, all additive.python -m openmind.mcp_serverunchanged.Two intentional changes:
/api/healthgainsversionandschema_version. The fulldoctorreport sits behind?diagnostics=1— including it unconditionally measured 0.8 ms → 2291 ms per call, which is wrong for a liveness endpoint.DELETE /projects/{id}/pathsnow returns 404 for an unknown project. That route was demonstrably broken: run againstmainit raisesResponseValidationError(a 500), because the handler returnedNonefrom a-> Dict[str, Any]signature.Verification
Baseline before any change: 18/18 verify scripts green, artifact contract 31/31.
Final:
python scripts/run_acceptance.py --all→ 24 passed, 0 failed, 0 skipped. New suites add 374 checks (migrations 49, runtime 31, services 97, CLI 112, adapters 85). Every acceptance-criteria command exits 0 from a clean data dir;python -m openmind.artifactsandpython -m openmind.skill_bridgestill work.The new acceptance runner isolates
OPENMIND_DATA_DIRper script and forces offline embeddings with no egress. Two integrity properties: a skipped core script counts as a failure, and everytests/verify_*.pymust be registered in the manifest, so a new test cannot silently go unrun while the suite reports green.Defects found and fixed during the work — each caught by a test rather than assumed away:
openmind --quiet doctorsilently not quiet: argparseparents=sharesActionobjects, so a subparser default clobbered the global flag. A first fix usingset_defaults()failed for the same reason.--waittimeout path, andinit --ingestreportedok:trueafter a failed ingest.services/__init__.pyeager imports pulledvectorstore→ numpy/chromadb intoexport, which would have broken the dependency-free CI job. Now lazy, and asserted by simulating the absent dependencies.get_runtime()andreset_runtime(); the acceptance runner reporting a stderr warning instead of the test verdict; two unused imports.Reviewer notes
main.pyis still ~950 lines. Ask, glossary-enrichment,/sourceand graph routes deliberately still call their modules directly: they are thin and adding a service layer there would be indirection without a seam.jobs.enqueue_*, and tests reaching intojobs._deleting/_shutdown/_recover_on_restart.verify_delete_responsiveis excluded from the CI gate — it asserts sub-2-second API latency while a delete drains, which is flaky on a shared runner. The reason is recorded in the manifest and it runs under--all.workflow_dispatch-only and does nothing unlessAGENT_SKILL_VERIFICATION_REFis set to a pinnedowner/repo@ref; it reports "not configured" rather than passing silently.Deferred
Enterprise Asset/Revision/Claim/Relation models, the Knowledge Graph, PDF/DOCX/XLSX, COBOL/JCL, cloud providers, requirement-to-code traceability, conflict detection, branch overlays, webhooks, Titan Mind, new graph/chat UI, autonomous code modification, TypeScript rewrite, monorepo conversion, Neo4j, Bundle 2.0, typed worker pool. Extension points exist (migration runner,
ports/,ServiceContainer, CLI subcommand table); no placeholder code pretends otherwise.Version is
1.1.0-dev, not2.0.0— labelling this build 2.0.0 would be a false claim.