From a04506a08143683fe8c3514226387d74a817f4bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=CE=A7=CE=B3=CF=86=CF=84=20Kompanion?=
 <chigammaphitau@chelydra.at>
Date: Wed, 15 Oct 2025 22:35:19 +1300
Subject: [PATCH] Extend command line and add db init.

This also removes obsolete schema files for clarity
---
 CMakeLists.txt              |  15 +++++-
 db/core.sql                 |  59 --------------------
 db/db-init.sql              |   5 --
 db/schema.sql               | 105 ------------------------------------
 db/schema_pgvector.sql      |   5 --
 docs/configuration.md       |  13 +++++
 docs/memory-architecture.md |   1 +
 7 files changed, 27 insertions(+), 176 deletions(-)
 delete mode 100644 db/core.sql
 delete mode 100644 db/db-init.sql
 delete mode 100644 db/schema.sql
 delete mode 100644 db/schema_pgvector.sql

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a02469..c412bac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,8 @@ project(metal_kompanion_mcp LANGUAGES CXX)
 set(CMAKE_CXX_STANDARD 20)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
+include(GNUInstallDirs)
+
 option(KOM_ENABLE_PG "Enable Postgres-backed DAL support" ON)
 
 set(KOM_HAVE_PG OFF)
@@ -38,6 +40,9 @@ if (KOMPANION_KCONFIG_TARGET STREQUAL "")
   message(WARNING "KConfig (KF6/KF5) not found; defaulting to environment-based configuration.")
 endif()
 
+set(KOMPANION_DB_INIT_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/kompanion/db/init")
+install(DIRECTORY db/init/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/kompanion/db/init FILES_MATCHING PATTERN "*.sql")
+
 option(BUILD_KOMPANION_CLI "Build Kompanion Qt command-line client" ON)
 if (BUILD_KOMPANION_CLI)
   find_package(Qt6 COMPONENTS Core QUIET)
@@ -58,7 +63,10 @@ add_executable(kom_mcp
 )
 target_include_directories(kom_mcp PRIVATE src)
 target_link_libraries(kom_mcp PRIVATE kom_dal)
-target_compile_definitions(kom_mcp PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}")
+target_compile_definitions(kom_mcp PRIVATE
+  PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
+  KOMPANION_DB_INIT_INSTALL_DIR="${KOMPANION_DB_INIT_INSTALL_DIR}"
+)
 if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "")
   target_link_libraries(kom_mcp PRIVATE ${KOMPANION_KCONFIG_TARGET})
   target_compile_definitions(kom_mcp PRIVATE HAVE_KCONFIG)
@@ -74,7 +82,10 @@ if (BUILD_KOMPANION_CLI)
   )
   target_include_directories(kompanion PRIVATE src)
   target_link_libraries(kompanion PRIVATE Qt6::Core kom_dal)
-  target_compile_definitions(kompanion PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}")
+  target_compile_definitions(kompanion PRIVATE
+    PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}"
+    KOMPANION_DB_INIT_INSTALL_DIR="${KOMPANION_DB_INIT_INSTALL_DIR}"
+  )
   if (NOT KOMPANION_KCONFIG_TARGET STREQUAL "")
     target_link_libraries(kompanion PRIVATE ${KOMPANION_KCONFIG_TARGET})
     target_compile_definitions(kompanion PRIVATE HAVE_KCONFIG)
diff --git a/db/core.sql b/db/core.sql
deleted file mode 100644
index 6b7b0b6..0000000
--- a/db/core.sql
+++ /dev/null
@@ -1,59 +0,0 @@
--- metal-kompanion core schema (pgvector)
-CREATE EXTENSION IF NOT EXISTS vector;
-
-CREATE TABLE IF NOT EXISTS knowledge (
-  id          BIGSERIAL PRIMARY KEY,
-  source      TEXT,
-  path        TEXT,
-  sha256      TEXT,
-  lineno      INT,
-  text        TEXT NOT NULL,
-  tags        TEXT[],
-  created_at  TIMESTAMPTZ DEFAULT now()
-);
-
--- embeddings: 1024-dim space (extend with more tables if needed)
-CREATE TABLE IF NOT EXISTS embeddings_1024 (
-  id            BIGSERIAL PRIMARY KEY,
-  knowledge_id  BIGINT REFERENCES knowledge(id) ON DELETE CASCADE,
-  model         TEXT NOT NULL,
-  embedding     vector(1024) NOT NULL,
-  created_at    TIMESTAMPTZ DEFAULT now()
-);
-CREATE INDEX IF NOT EXISTS embeddings_1024_l2 ON embeddings_1024 USING ivfflat (embedding vector_l2_ops) WITH (lists=100);
-
--- memory branches (git-like)
-CREATE TABLE IF NOT EXISTS mem_branch (
-  id        BIGSERIAL PRIMARY KEY,
-  name      TEXT UNIQUE NOT NULL,
-  purpose   TEXT,
-  created_at TIMESTAMPTZ DEFAULT now()
-);
-
-CREATE TABLE IF NOT EXISTS mem_commit (
-  id         BIGSERIAL PRIMARY KEY,
-  branch_id  BIGINT REFERENCES mem_branch(id) ON DELETE CASCADE,
-  parent_id  BIGINT,
-  author_did TEXT,
-  message    TEXT,
-  created_at TIMESTAMPTZ DEFAULT now()
-);
-CREATE INDEX IF NOT EXISTS mem_commit_branch ON mem_commit(branch_id);
-
--- commit deltas referencing knowledge rows
-CREATE TABLE IF NOT EXISTS mem_delta (
-  id           BIGSERIAL PRIMARY KEY,
-  commit_id   BIGINT REFERENCES mem_commit(id) ON DELETE CASCADE,
-  knowledge_id BIGINT REFERENCES knowledge(id) ON DELETE CASCADE,
-  action      SMALLINT NOT NULL CHECK (action IN (0,1,2)) -- 0:add,1:update,2:delete
-);
-CREATE INDEX IF NOT EXISTS mem_delta_commit ON mem_delta(commit_id);
-
--- per-branch centroid for fast routing
-CREATE TABLE IF NOT EXISTS branch_embedding_1024 (
-  branch_id  BIGINT REFERENCES mem_branch(id) ON DELETE CASCADE,
-  model      TEXT NOT NULL,
-  embedding  vector(1024) NOT NULL,
-  updated_at TIMESTAMPTZ DEFAULT now(),
-  PRIMARY KEY(branch_id, model)
-);
diff --git a/db/db-init.sql b/db/db-init.sql
deleted file mode 100644
index 896bfe3..0000000
--- a/db/db-init.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO komp.space(name, model, dim) VALUES
-  ('dev_knowledge','mxbai-embed-large',1024),
-  ('pattern_exchange','mxbai-embed-large',1024),
-  ('runtime_memory','mxbai-embed-large',1024)
-ON CONFLICT (name) DO NOTHING;
diff --git a/db/schema.sql b/db/schema.sql
deleted file mode 100644
index ccdbe2f..0000000
--- a/db/schema.sql
+++ /dev/null
@@ -1,105 +0,0 @@
--- Requires: CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS ltree;
-
-CREATE SCHEMA IF NOT EXISTS komp;
-CREATE EXTENSION IF NOT EXISTS vector;
-CREATE EXTENSION IF NOT EXISTS ltree;
-
-CREATE TABLE IF NOT EXISTS komp.source (
-  id         BIGSERIAL PRIMARY KEY,
-  kind       TEXT NOT NULL,       -- filesystem|repo|url|note
-  uri        TEXT NOT NULL,       -- path or URL
-  repo       TEXT,
-  ref        TEXT,
-  meta       JSONB DEFAULT '{}'::jsonb,
-  created_at TIMESTAMPTZ DEFAULT now()
-);
-
-CREATE TABLE IF NOT EXISTS komp.chunk (
-  id         BIGSERIAL PRIMARY KEY,
-  source_id  BIGINT REFERENCES komp.source(id) ON DELETE CASCADE,
-  lineno     INT,
-  text       TEXT NOT NULL,
-  sha256     TEXT NOT NULL,
-  tokens     INT,
-  created_at TIMESTAMPTZ DEFAULT now()
-);
-CREATE INDEX IF NOT EXISTS idx_chunk_source ON komp.chunk(source_id);
-
--- A space is a distinct memory with its own model+dim & policy
-CREATE TABLE IF NOT EXISTS komp.space (
-  id     SERIAL PRIMARY KEY,
-  name   TEXT UNIQUE,   -- dev_knowledge | pattern_exchange | runtime_memory
-  model  TEXT NOT NULL,
-  dim    INT  NOT NULL,
-  metric TEXT NOT NULL DEFAULT 'cosine'
-);
-
--- Embedding tables per common dimension (add more as needed)
-CREATE TABLE IF NOT EXISTS komp.embedding_768 (
-  id           BIGSERIAL PRIMARY KEY,
-  chunk_id     BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
-  space_id     INT REFERENCES komp.space(id) ON DELETE CASCADE,
-  embedding    VECTOR(768) NOT NULL,
-  created_at   TIMESTAMPTZ DEFAULT now(),
-  UNIQUE(chunk_id, space_id)
-);
-CREATE INDEX IF NOT EXISTS idx_embed768_space ON komp.embedding_768(space_id);
-CREATE INDEX IF NOT EXISTS ivf_embed768 ON komp.embedding_768 USING ivfflat (embedding vector_cosine_ops) WITH (lists=100);
-
-CREATE TABLE IF NOT EXISTS komp.embedding_1024 (
-  id           BIGSERIAL PRIMARY KEY,
-  chunk_id     BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
-  space_id     INT REFERENCES komp.space(id) ON DELETE CASCADE,
-  embedding    VECTOR(1024) NOT NULL,
-  created_at   TIMESTAMPTZ DEFAULT now(),
-  UNIQUE(chunk_id, space_id)
-);
-CREATE INDEX IF NOT EXISTS idx_embed1024_space ON komp.embedding_1024(space_id);
-CREATE INDEX IF NOT EXISTS ivf_embed1024 ON komp.embedding_1024 USING ivfflat (embedding vector_cosine_ops) WITH (lists=100);
-
--- Branch hierarchy (Branch Embeddings): path encodes the cluster tree (e.g., physics.quantum.tunneling)
-CREATE TABLE IF NOT EXISTS komp.branch (
-  id       BIGSERIAL PRIMARY KEY,
-  space_id INT REFERENCES komp.space(id) ON DELETE CASCADE,
-  path     LTREE NOT NULL,
-  label    TEXT,
-  meta     JSONB DEFAULT '{}'::jsonb,
-  UNIQUE(space_id, path)
-);
-CREATE INDEX IF NOT EXISTS gist_branch_path ON komp.branch USING GIST (path);
-
--- Centroids per dimension (store only the dim matching the space)
-CREATE TABLE IF NOT EXISTS komp.branch_centroid_768 (
-  branch_id  BIGINT PRIMARY KEY REFERENCES komp.branch(id) ON DELETE CASCADE,
-  embedding  VECTOR(768) NOT NULL,
-  updated_at TIMESTAMPTZ DEFAULT now()
-);
-CREATE TABLE IF NOT EXISTS komp.branch_centroid_1024 (
-  branch_id  BIGINT PRIMARY KEY REFERENCES komp.branch(id) ON DELETE CASCADE,
-  embedding  VECTOR(1024) NOT NULL,
-  updated_at TIMESTAMPTZ DEFAULT now()
-);
-
--- Soft membership of chunks to branches
-CREATE TABLE IF NOT EXISTS komp.chunk_branch (
-  chunk_id  BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
-  branch_id BIGINT REFERENCES komp.branch(id) ON DELETE CASCADE,
-  weight    REAL NOT NULL CHECK (weight >= 0 AND weight <= 1),
-  PRIMARY KEY(chunk_id, branch_id)
-);
-
--- Relations between chunks (similarity / cites / derives / contradicts / …)
-CREATE TABLE IF NOT EXISTS komp.chunk_edge (
-  src_chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
-  dst_chunk_id BIGINT REFERENCES komp.chunk(id) ON DELETE CASCADE,
-  relation     TEXT NOT NULL,
-  weight       REAL,
-  meta         JSONB DEFAULT '{}'::jsonb,
-  PRIMARY KEY(src_chunk_id, dst_chunk_id, relation)
-);
-
-CREATE OR REPLACE VIEW komp.latest_sources AS
-  SELECT s.*, max(c.created_at) AS last_chunk_at
-  FROM komp.source s LEFT JOIN komp.chunk c ON c.source_id = s.id
-  GROUP BY s.id;
-
diff --git a/db/schema_pgvector.sql b/db/schema_pgvector.sql
deleted file mode 100644
index 5b1be28..0000000
--- a/db/schema_pgvector.sql
+++ /dev/null
@@ -1,5 +0,0 @@
--- pgvector knowledge schema (v0.2, branch embeddings)nCREATE EXTENSION IF NOT EXISTS vector;nn-- Documents tracked by content hash; multiple logical paths may point to same blobnCREATE TABLE IF NOT EXISTS doc_blob (n  blob_sha256  text PRIMARY KEY,n  bytes        bigint NOT NULL,n  created_at   timestamptz DEFAULT now()n);nn-- Logical document identity and branch/commit lineagenCREATE TABLE IF NOT EXISTS doc (n  id           bigserial PRIMARY KEY,n  origin       text,          -- e.g., filesystem, forgejo, exportn  root_path    text,          -- repo root or base dirn  rel_path     text,          -- path relative to rootn  blob_sha256  text REFERENCES doc_blob(blob_sha256)n);nCREATE TABLE IF NOT EXISTS branch (n  id           bigserial PRIMARY KEY,n  name         text UNIQUE,n  created_at   timestamptz DEFAULT now()n);nCREATE TABLE IF NOT EXISTS revision (n  id           bigserial PRIMARY KEY,n  branch_id    bigint REFERENCES branch(id) ON DELETE CASCADE,n  parent_id    bigint REFERENCES revision(id),n  commit_sha   text,          -- optional link to VCSn  message      text,n  created_at   timestamptz DEFAULT now()n);nn-- Chunked text with provenance; each revision can re-chunk same docnCREATE TABLE IF NOT EXISTS chunk (n  id           bigserial PRIMARY KEY,n  revision_id  bigint REFERENCES revision(id) ON DELETE CASCADE,n  doc_id       bigint REFERENCES doc(id) ON DELETE CASCADE,n  lineno       int,n  text         text NOT NULL,n  tags         text[],n  sha256       text,n  created_at   timestamptz DEFAULT now()n);nCREATE INDEX IF NOT EXISTS idx_chunk_doc ON chunk(doc_id);nCREATE INDEX IF NOT EXISTS idx_chunk_rev ON chunk(revision_id);nn-- Embedding models registrynCREATE TABLE IF NOT EXISTS embed_model (n  id           bigserial PRIMARY KEY,n  name         text UNIQUE NOT NULL,   -- e.g., mxbai-embed-largen  dims         int NOT NULL,n  tokenizer    text,n  notes        textn);nn-- Branch embeddings: per revision, per chunk, per model (dims parametrized by table)nCREATE TABLE IF NOT EXISTS embedding_1024 (n  id           bigserial PRIMARY KEY,n  chunk_id     bigint REFERENCES chunk(id) ON DELETE CASCADE,n  model_id     bigint REFERENCES embed_model(id),n  embedding    vector(1024) NOT NULL,n  created_at   timestamptz DEFAULT now()n);nCREATE INDEX IF NOT EXISTS idx_emb1024_chunk ON embedding_1024(chunk_id);nCREATE INDEX IF NOT EXISTS idx_emb1024_vec ON embedding_1024 USING ivfflat (embedding vector_l2_ops) WITH (lists=100);nn-- Views: latest chunks per branchnCREATE OR REPLACE VIEW v_latest_chunks AS
-SELECT c.* FROM chunk c
-JOIN (SELECT revision_id, max(id) over (partition by doc_id, branch_id) as maxid, doc_id
-      FROM revision r JOIN chunk c2 ON c2.revision_id=r.id) t
-  ON c.id=t.maxid;nn-- Ledger mirror (optional)nCREATE TABLE IF NOT EXISTS ledger_mirror (n  id          bigserial PRIMARY KEY,n  ts          timestamptz NOT NULL,n  actor       text,n  action      text,n  body        jsonbn);n
\ No newline at end of file
diff --git a/docs/configuration.md b/docs/configuration.md
index 7ac4f0f..275da19 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -9,6 +9,19 @@ Kompanion adheres to KDE’s KConfig conventions so deployments are kioskable an
 
 The CLI (`kompanion`) and MCP runner (`kom_mcp`) fall back to this entry when the `PG_DSN` environment variable is not set. If neither are present the in-memory DAL stub is used.
 
+## Initialization Wizard
+- Run `kompanion --init` to launch an interactive wizard.
+  - Autodetects reachable Postgres instances (tries `postgresql://kompanion:komup@localhost/kompanion_test`).
+  - Prompts for host, port, database, user, password, or Unix socket path with sensible defaults.
+  - Writes the resulting DSN to `kompanionrc` and exports `PG_DSN` for the current session.
+  - If the target database is empty, it applies the SQL migrations shipped under `share/kompanion/db/init/*.sql`.
+- The wizard is also triggered automatically the first time you run `kompanion` without a configured DSN.
+
+## CLI Modes
+- Standard invocation: `kompanion <tool> --request payload.json`
+- Interactive prompt: `kompanion -I <tool>` keeps a REPL open; enter JSON payloads or `!prompt text` to wrap plain text. Use `-V/--verbose` to echo request/response JSON streams.
+- Use `kompanion --list` to enumerate available tools, including `kom.meta.v1.project_snapshot` for quick project context dumps.
+
 ## Future HTTP Streaming
 While current tooling focuses on stdio dispatch (for editor and agent integration), the roadmap includes an HTTP/2 or WebSocket streaming surface so MCP clients can maintain persistent conversations without leaving CLI compatibility behind. The same configuration keys will apply for both transports.
 
diff --git a/docs/memory-architecture.md b/docs/memory-architecture.md
index 399897c..028e326 100644
--- a/docs/memory-architecture.md
+++ b/docs/memory-architecture.md
@@ -73,6 +73,7 @@
 - **Observability**: CLI should read the `jobs/semantic_sync` state block to display cursors, pending counts, and last error logs; dry-run mode estimates embeddings without committing.
 - **Activation parity**: Long term, mirror the KDE `akonadiclient`/`akonadi-console` pattern—Kompanion CLI doubles as an MCP surface today and later as a DBus-activated helper so tools can be socket-triggered into the memory service.
 - **KConfig defaults**: `kom_mcp` and `kompanion` load `Database/PgDsn` from `~/.config/kompanionrc` (see `docs/configuration.md`) when `PG_DSN` is unset, keeping deployments kioskable.
+- **CLI UX**: `kompanion --init` guides first-run setup (auto-detects databases, applies schemas); `-I/--interactive` keeps a JSON REPL open, and `-V/--verbose` echoes request/response streams for future HTTP transport parity.
 
 ## Next-Step Checklist
 - [x] Detect pqxx via CMake and plumb `HAVE_PG`.
