Build plan: from the built system to the space and memory model
Plan v1.0 · approved (M-106) and built: stages 1l–1s live 2026-10-11 (M-109), 1t (M-111) v1.2 · next: the move to IT-Labs hardware (section 15); 1u set aside 2026-10-11
This plan looks at the whole picture once more. It covers what is built (stages 1a–1k), what the research asks for (Q-35 auto-mapping and automatic saving, Q-36 space and memory model v1.1), and the gap between them. It then says what we reuse, what we build new, and in what order. It replaces the old "stage 1l = live sync" line on the roadmap. Nothing is built until the user approves.
Summary
- Keep and extend; don't rebuild. The built system already does the hard parts: sign-in, tenant walls in the database, permissions, grants, approvals, promotion, connectors, audit, sync and search. The new model is a layer on top of it, not a replacement.
- What is missing comes down to four things: spaces (space IDs, aliases, links to places), the memory address on every item, automatic capture (helper, hooks and checkpoints), and a two-way loop (envelope, conversations and a change cursor). After those come collective memory, space knowledge and index cards.
- The two memories fit the existing scopes. Organizational memory = today's Org / Project / Team / Client memory. A person's "lane" = today's User memory (or a bot's own memory) plus a space ID. The work pool = User memory with no space yet. Collective memory = a view that counts lane items by space links. So the scopes, rules and tests we have stay valid.
- One new registry: spaces. It has company and client tenants, spaces, aliases and versioned links. Today's place mappings (
git_repo:,jira_project:) are moved into it, so place resolution keeps working. - One small client: the
cmcphelper. It fingerprints the folder, receives the space manifest, tags each stretch of a session, and uploads checkpoints in the background. The first tool is Claude Code; others follow through the same helper. - The server routes; the tool's model writes notes. The notes come from the tool's own model, already short and marked "about the person" or "about the work". cMCP routes them by rules (stretch tag first, then an explicit mention). The slow local model is never needed in the request path.
- Private first, review first. Automatic items land only in the person's own memory or work pool. Shared places get them through the approval and promotion paths that already exist. Real accounts start in "review first".
- Space knowledge reuses connectors and the memories table. Jira and the IMAP mailbox already store sources and approve facts. They gain layers (raw → cleaned → typed records), and typed records (decision, action, status) are memories with a kind and fields. No second store is needed.
- Seven stages, 1l–1r, each a thin, testable slice following the usual flow: threat model → build → tests → reviews → S-xx approval → commit. The first visible proof comes at the end of stage 1n: this server's own Claude saves into
owner-soloon its own, and every item answers the seven questions. - The real account
pilotjoins last, after the allowed-AI-apps list (1q) and company approval, because tools like Claude Code send the memory they read to their vendor's cloud model.
1. The complete picture
1.1 What is built (stages 1a–1k, live since go-live)
| Area | What exists today (verified in the code, HEAD e719914, migrations 0001–0054) |
|---|---|
| Identity | Keycloak (one-time code for people), web-admin login, bot keys cmcp_bot_…, AI apps as OAuth clients. principals types: human, delegated_agent, bot, service. client_apps = person + app (agent instance), with elevation. |
| Places and scopes | One org per account. Projects, teams, clients and memberships (several leads). Scopes: org, project, client, team, user, personal, agent. Client wall. Org read floor. |
| Rules | Forced RLS on every tenant table (41 tables; platform.audit is the approved exception). One permission service. Grants, powers, elevation, covers, feature switches, times and limits, access requests, the ADMIN role, audit in the same transaction. |
| Memory | memories with scope, owner, kind, audience, confidence, valid from / to, version, status (current / superseded / deleted / staged), created_via_app_id and created_via_model; memory_versions; memory_links (derived_from, promoted_from, contradicts, relates_to, supersedes); sources with raw text. |
| Flows | Memory requests, promotion User / Agent → Team (≥ 3 people, neutral rewrite, lead approves), lateral synthesis (off by default), approvals inbox and bulk decisions. |
| Sync | Scope versions, change_events (bigserial), per-app manifest {"scope:id": version}, delta packs with removed ids, must-apply notices, resource subscription on cmcp://context/{app_id}, memory_refresh. |
| Place resolution | context.resolve_place: explicit place → app default → mapping rule (git_repo:, jira_project:, chat_channel: in place_mappings, member only) → home team → org. URL spelling is cleaned; there is no fingerprint and no alias table. |
| Connectors | Jira Cloud, PostgreSQL views, IMAP. Each item version is a sources row (external_ref unique per connector). The extract job stages facts, and leads approve them. Raw mail / row text is emptied 30 days after the decision. OpenBao holds the secrets. |
| Worker and engine | Jobs: extract, index, unindex, promote, synthesize, import, housekeeping (and reembed, which has no handler). Local qwen3 4B for real accounts; Groq first for synthetic ones. Hindsight in chunks mode: one bank per account with strict scope tags, and separate banks for each Personal space and each client. |
| Interfaces | REST /v1 (reads X-CMCP-Place / Model / Purpose / Token-Budget / Format / App) and /mcp with 11 tools. /mcp reads no X-CMCP headers and no _meta. Web console with W-01…W-10 screens, the platform screens and the manual. |
| Tests | 399 backend tests at the end of 1k (282 test functions: e2e 118, isolation 90, unit 67, sync 7; some take parameters), about 13 browser tests, and retrieval and Jira extraction eval scripts. |
1.2 What the research asks for
A helper shared by all tools. Folder fingerprints and aliases. Private spaces. Ask-once links. Personal device keys. An allowed-AI-apps list per account. Identity from the sign-in only. An envelope (place, conversation, run, tool, model, idempotency key) on REST,
/mcp headers and _meta. A cursor change feed. Saving at checkpoints through hooks and a bot library, curated first, private first, review first for real accounts. Whole conversations only under M-105.Four kinds of actor. Space IDs from platform ids, never with the person in them. Owner side from hard facts. Links: same / declared / confirmed / suggested. A space manifest sent at session start. Session routing and a private work pool. A memory address on every item. Store once, count by links. Collective vs organizational memory. Space knowledge in four layers. Indexes per category, a link graph and index cards.
1.3 The gap, in one table
| Needed by the model | Today | Gap |
|---|---|---|
| Space ID, address, aliases, owner side | Spelling-cleaned mapping keys only | New registry (tenants, spaces, aliases) |
| Links space → place with kind, confidence, history | place_mappings (one kind, no history) | Versioned links; migrate the mappings |
| Memory address (space, app, run, conversation, confidence) | Scope, owner, app id, model | Add columns plus a frozen address stamp |
| Envelope on every call | REST headers only; /mcp reads tool arguments | One envelope reader for REST and /mcp |
| Conversations, runs, idempotency | None (only connector external_ref) | New tables |
| "What changed since" cursor | Scope-version manifest and push notice | /v1/changes?cursor= on change_events |
| Automatic capture | Explicit saves; session summary (staged ones are stuck: no confirm path) | Helper, hooks, checkpoint, "To review" list (bug fix) |
| Work pool, routing, ask-once | None | Routing service and pool view |
| Collective memory (aggregate, ≥ 3) | Promotion counts confirmations inside a team | Counts-toward view by space links; promotion reads it |
| Space knowledge layers and typed records | Raw source → staged facts | Cleaned layer, typed kinds, digests |
| Index cards and catalog indexes | Context pack (all scopes, within a budget) | Person and place cards; catalog search |
| Digital workers | Bots with a sponsor and keys | New principal kind with master / backup rules |
| Allowed AI apps, device keys | App registration; bot keys | Allow-list per account; personal device keys |
2. Reuse or rebuild: the verdict
- The model's "store once, count by links" matches how memory is already owned (owner + scope) and linked (
memory_links). - "Organizational memory needs approval" is exactly the promotion and approval flow built in 1d.
- "Derived data keeps its source's rules" already holds for connector facts (source link, strictest audience).
change_eventsis already a per-account sequence, so the cursor feed is a read over it.
- Space knowledge from a private channel needs per-source audiences. That is a new access rule, so it is deferred: the first sources are only spaces whose audience equals a place's members (stage 1p).
- Local paths are personal data. Path aliases are stored only for the person who owns them.
- Adding a principal kind (digital worker) touches every permission check, so it waits for its own stage (1r) and threat model.
3. Reuse map: every part, and what happens to it
REUSE as is · EXTEND small additions · NEW new part · RETIRE moved into a new part
| Existing part | Role in the new model | Change | |
|---|---|---|---|
| Keycloak, bot keys, OAuth clients | REUSE | Who: org, actor, app (principle P1) | Device keys added in 1q |
principals | EXTEND | Person, task bot (bot), agent (delegated_agent) | Kind worker plus a worker profile in 1r |
client_apps | EXTEND | "App" = tool + actor (+ device later) | Tool label, device, allowed-list state |
| Places, memberships, client wall | REUSE | Places of the model, unchanged | None |
| Org / Project / Team / Client memory | REUSE | Organizational memory | Evidence links from promotions |
| User memory, a bot's own memory, Agent scope | EXTEND | Lanes (with space_id) and the work pool (no space yet) | Address columns, routing state |
| Personal memory | REUSE | Stays per-app, never promoted, never routed | None |
place_mappings + resolve_place | RETIRE | Become space aliases + declared links; resolution goes envelope → space → link → place | Read-compatible for one stage, then dropped |
memory_links | REUSE | Evidence, "replaces", one item linked to several spaces | None |
sources | EXTEND | Session copy, and layers 1–2 of space knowledge | space_id, conversation_id, cleaned text, hash, thread key |
| Promotion, synthesis, requests, approvals inbox | REUSE | Collective → organizational, and lead approval of space knowledge | Promotion reads the counts-toward view |
change_events, scope versions, app manifest | EXTEND | Cursor feed and the space manifest | /v1/changes, manifest v2 |
| Context pack | EXTEND | Index cards plus details on demand | Cards first, pack kept as a fallback |
memory_save_session_summary (staged) | EXTEND | One kind of checkpoint | "To review" list and a confirm path (bug fix) |
| Connectors (Jira, IMAP, DB views), OpenBao | EXTEND | Company spaces and space knowledge | Spaces registered from connectors; layers and kinds |
| Worker jobs, Hindsight banks | EXTEND | Same jobs plus routing suggestions, ageing, digests | Tag space:{id} on documents |
| Feature switches, times and limits | EXTEND | Capture mode, allowed apps, the source defaults of Q-36 decision 17 | New keys, and the risk notices of M-105 |
| Audit, versioning, isolation test harness | REUSE | P10 "everything stamped" | New tables get the same harness |
| Envelope reader, conversations, idempotency, routing service, space registry, helper and hooks, cards, counts-toward view | NEW | The missing parts | Sections 6–8 |
4. How the model fits the existing scopes
This is the key design choice, because it decides whether everything built so far stays valid.
| Model term (Q-36) | Stored as | Who reads it (existing rules) |
|---|---|---|
| Lane "Alice · sp_ship_api" | memories with scope user = Alice, space_id = sp_ship_api, routing state placed | Alice and her apps (User memory rules) |
| Work pool | Same, with space_id empty and routing state pool | Alice only |
| Task bot lane | The bot's own memory with space_id | The bot and its sponsor (sponsor view) |
| Digital worker lane (1r) | The worker's own memory with space_id, marked AI | The worker and its master |
| Collective memory of Shipping | Nothing stored: a view counts_toward(item → place) through the item's space and that space's links | Members see aggregates only (≥ 3 distinct people, humans only); names only on items people shared |
| Organizational memory of Shipping | Project memory (unchanged), with promoted_from links to the evidence | Project members (unchanged) |
| Space knowledge from #shipping (company space, members = Shipping) | memories with scope project = Shipping, space_id = sp_ship_chan, kind decision / action / status …, status staged until the lead approves (as connector facts today) | Project members; restricted items as today |
| Session copy | sources kind session_copy, private to the person, emptied after 30 days (like connector text) | The person |
5. Target architecture
6. Data model changes (migrations 0055 onward)
Every new table follows the new-tenant-table skill: account_id, ENABLE + FORCE RLS, policies bound to cmcp_app / cmcp_worker, audit, and isolation tests in the two-account harness.
| Table / change | Main columns | Stage |
|---|---|---|
NEW tenants | platform (github, bitbucket, atlassian, microsoft, google, slack), tenant key, owner side (company / client), client_id, how it was verified | 1m |
NEW spaces | space ID (sp_ + short id), kind, address space:<kind>:<tenant>/<stable id> (unique per account), owner side and its basis, owner principal (person-owned only), client_id, status, created_by | 1m |
NEW space_aliases | space_id, alias kind (url, root_commits, jira_key, name, marker, path), normalised value; path aliases carry the owner principal and are visible only to that person | 1m |
NEW space_links | space_id → place (type, id), kind (same / declared / confirmed / suggested), confidence, evidence (jsonb), author, accepted_by, valid_from / valid_to, version | 1m |
NEW space_rules | Company mapping rules ("Bitbucket workspace pilot, project SHIP → project Shipping"); the existing place_mappings rows are migrated into aliases + declared links | 1m |
NEW conversations | client_app_id, principal, outside id (session_id, conversation_id, run id), tool and model labels, started / last seen, last cursor, last space; unique per (app, outside id) | 1l |
NEW stretches | conversation_id, sequence number, space_id (or none), from / to, match evidence, confidence | 1n |
NEW idempotency_keys | principal, key, request hash, stored response, created_at (kept 24 h) | 1l |
EXTEND memories | space_id, conversation_id, stretch_id, origin (explicit, checkpoint, memory_file, model_note, connector, promotion), routing_state (placed, pool, suggested), address jsonb (frozen stamp with a confidence per part, never rewritten), fields jsonb for typed kinds; new kinds: preference, decision, action_item, status_signal, procedure | 1l (columns), 1n, 1p |
EXTEND sources | space_id, conversation_id, kind session_copy, cleaned text, content hash, thread key | 1n, 1p |
NEW routing_decisions | memory_id, candidates, chosen space, evidence (tag / mention / similarity), confidence, decided by (rule / person) | 1n |
NEW view counts_toward | item → place through space links (current version at the item's time); aggregate functions only, minimum group 3, humans only | 1o |
NEW index_cards | subject (person / place / space), version, lines with references, audience, built_at, pinned lines | 1n (v0), 1o |
| EXTEND settings / switches | capture_mode (off / review_first / auto_with_undo), allowed_ai_apps, source defaults per space kind, risk-notice records (M-105) | 1n, 1q |
EXTEND principals + NEW worker_profiles | kind worker; master, backup, purpose, end date, spend / call limits, review date | 1r |
NEW device_keys | personal device keys (device flow), shown once, revocable, per device | 1q |
place_mappings move is copy-then-switch: 1m writes both, and 1n reads only spaces. The old table is dropped one stage later, after a count check.7. API and MCP changes
| Interface | Change | Stage |
|---|---|---|
| Envelope | One reader shared by REST and /mcp: headers X-CMCP-Place, X-CMCP-Space, X-CMCP-Conversation, X-CMCP-Run, X-CMCP-Cursor, Idempotency-Key, plus _meta["com.example.cmcp/envelope"]. If a header and _meta disagree, the call is refused. A declared org or user that differs from the sign-in is refused (Q-35 decision 16). | 1l |
POST /v1/conversations, …/{id}/checkpoint, …/{id}/end | Start returns the place, cards, manifest version and cursor. Checkpoint takes notes (each marked about=person / work, with an optional stretch tag) and the session copy, and returns where each note landed, the changes and a new cursor. Idempotent. | 1l (start / end), 1n (checkpoint routing) |
GET /v1/changes?cursor= | Built on change_events, filtered for the caller when it is read. Returns changed, removed and the new cursor. A cursor that is too old, or a permission change since the cursor (authz_epochs), returns 410: fetch the full context again. | 1l |
GET /v1/review, POST /v1/memories/{id}/confirm | discard | The "To review" list for staged and auto-saved items. This fixes the stuck session summaries. | 1l |
GET /v1/manifest | Manifest v2: the person's spaces with their recognisers and place paths, a version, and the person and place cards. Client spaces only when the person is assigned to that client. | 1n |
POST /v1/spaces/resolve | Fingerprint (remotes, root commits, marker, Jira key) → space ID and confidence. An unknown space returns "ask once" choices. | 1n |
/v1/spaces, /v1/spaces/{id}/links, /v1/space-rules, /v1/me/spaces, /v1/me/pool | Register, alias and link spaces (ADMIN / lead); the person's own spaces, confirmations and work pool | 1m, 1n |
| MCP tools | memory_get_context returns cards and the manifest version. New space_link (answer to an ask-once question) and memory_checkpoint (for tools without hooks). memory_save accepts a space and the about flag. Built with the mcp-tool-pair skill; mcp-tools.json → 1.5.0, openapi → 1.8.0. | 1l–1n |
| Webhooks (signed) | For bots: a "something changed" wake-up only; bots always pull from their cursor | 1q |
8. The cmcp helper and hooks
uv tool, Q-35 decision 8)cmcp login: reuses today's sign-in (the headersHelper pattern); device keys come in 1q.cmcp status | link | pool: shows where you are and lets you answer ask-once questions.cmcp hook <event>: one entry point for every tool's hooks.- Local cache in
~/.cmcp/: manifest, cursor, upload queue. Path aliases never leave the machine unless the person links them. - Fingerprint: remotes, root commits (
git rev-list --max-parents=0), the.cmcp-spacemarker, Jira keys in branch names. - Secret scan before any upload. Text that came from cMCP is marked, so it is never saved back (echo filter).
cmcp hook.
routing_decisions.9. Stages
Each stage keeps the usual flow: threat model (threat-modeler, once) → build → tests → reviews by the custom agents → docs and manual → S-xx in todo.md → commit and push only after "S-xx: approved". Sizes are relative to stages 1h–1k (M ≈ one of those). Every stage is tested in synthetic accounts (test, other, owner-solo) only.
1l · Two-way base: envelope, conversations, change feed, To review size M
- Envelope reader for REST and
/mcp(headers +_meta, conflict refusal, refusal of a declared org / user that differs from the sign-in). conversations,idempotency_keys; conversation start / end;Idempotency-Keyon every write./v1/changes?cursor=with 410 on an old cursor or a permission change; a cursor in every tool answer; its own small rate budget (decision 18).- "Memory changed" notice in every MCP tool answer (from the old 1l plan).
- "To review" list plus confirm / discard (fixes the stuck staged summaries); the tool and model shown on items.
- Address columns added to
memories(nullable, filled from now on: conversation, origin, app, model).
1m · Space registry: company side size M–L
tenants,spaces,space_aliases,space_links,space_rules; migrateplace_mappings(written to both for one stage).- Company tenants registered by the ADMIN: GitHub org (today IT-Labs-AJ) and the Bitbucket workspace when it exists, and the Atlassian site. Jira projects become spaces from the existing connector.
- Optional repo list import (GitHub / Bitbucket API, read-only): repo id, root commits, URL aliases. A spike first checks whether repo ids survive renames and transfers.
resolve_placebecomes envelope space / place → space → current link → place, and keeps the old fallbacks (app default, home team).- Hindsight documents get the tag
space:{id}. - Web: ADMIN "Spaces" screen (tenants, spaces, aliases, links with history); a "Spaces" tab on each place.
.git) and a mirror resolve to one space. A faked remote routes, but reads nothing without membership.
1n · People's side, first slice: manifest, helper, Claude Code capture, work pool size L
- Manifest v2 and
/v1/spaces/resolve; index cards v0 (person and current place) built from existing data: open items, must-apply items, recent decisions and places. cmcphelper plus a Claude Code plugin (hooks above, headersHelper, a/cmcpskill); stretches; background uploader; echo filter; secret scan.- Checkpoint routing (tag → mention → pool),
routing_decisions, the about-person rule, one item linked to several spaces throughmemory_links. - Person-owned spaces:
.cmcp-spacemarker and personal repos; ask-once links (confirmed); the person decides, and the lead accepts when others will see items. - Claude Code auto-memory files copied in as
memory_fileitems, replacing older versions instead of piling up. - Capture modes: review first (default for real accounts), automatic with undo (test accounts); quality gate; ageing (decision 19).
- Web: "My spaces", "Work pool", "To review", an "auto-saved by <tool>" label.
owner-solo works across two repos and a scratch folder. Items land in the right lanes and the work pool without anyone saving, and every item answers the seven questions. A second machine (or a second clone) gets the same space IDs. The ~24 outdated items from 2026-10-03 are replaced or marked by the imported memory files.
1o · Collective → organizational memory size M
counts_towardview; aggregate panels on place pages and place cards ("7 people noted …"; never below 3; humans only).- The promotion job reads candidates by space link across lanes instead of inside one team; it keeps the neutral rewrite and lead approval; evidence goes in
promoted_fromlinks. - Approved items flow back down through cards and the change feed to every app in a linked space.
- Matching ladder 0.4–0.8 as suggestions (worker similarity, branch-name Jira keys, same people active); a weekly work-pool digest.
- Replace with dates, duplicates as confirmations, ageing of unused automatic items.
1p · Space knowledge v1: Jira, shared mailbox, first channel size L
- Layers for existing connectors: raw (sources, as today) → cleaned (quotes, signatures and duplicates removed, no AI) → typed records (memories of kind decision / action_item / status_signal / fact, with fields, a quote, extractor version and confidence).
- Rules filter before the model (newsletters, bots, one-liners). Extraction runs when a thread goes quiet. Status signals from Jira transitions and Git merges are trusted without the model.
- Decision log, open actions, project status on place and person cards; nightly status, weekly digest.
- Only spaces whose audience equals a place's members (team channels, shared mailboxes, Jira projects linked to one place). Private channels and per-source audiences wait (see section 11).
- First chat platform per decision N3 (Teams through Microsoft Graph delta, or Slack). This is a new connector, so it needs a host check and the user's go-ahead first.
- "Who to ask" counts are built but switched off until the legal check (decision 19).
1q · Every surface: allowed apps, device keys, other tools, bot library size L
- Allowed-AI-apps list per account, enforced at sign-in and on keys, with M-105 risk notices when it is loosened. This is the gate for the real account.
- Personal device keys plus device flow (cloud sessions, cron, SSH without a browser).
cmcp hookadapters for Codex, Gemini CLI, Cursor and Copilot; copying of GEMINI.md / AGENTS.md style files; the bridge for tools without hooks.- Python bot library (start → checkpoint → changes), a Claude memory-tool handler, signed webhooks.
- claude.ai connector through Keycloak (only if the allow-list permits it).
1r · Digital workers size M
- Principal kind
workerandworker_profiles: created only by an ADMIN in person, master + backup, end date, limits, 90-day review. Paused when no master is named within 7 days. - Its mail threads and chats are spaces; its input is untrusted data; it is marked AI everywhere and never counts toward the three people needed for promotion.
- Every permission check reviewed by authz-architect; new isolation tests.
pilot. No stage switches it on. It joins only after 1q (allowed-apps list, review first) and after the company approves which AI apps may read company memory. Until then, the rule stays: tools that send text to a cloud model use synthetic accounts.10. Quality, speed and measures
- Per-prompt cursor check with nothing new: < 20 ms
- Session start (manifest + cards): < 150 ms
- Checkpoint accepted (routing by rules): < 300 ms; embedding and indexing in the background
- Space resolve: < 50 ms
- Existing targets unchanged: search < 100 ms, pack < 150 ms
- Share of new items with a full address (target: 100 % for hook-captured items)
- Items placed vs left in the work pool; pool items placed later
- Automatic saves per active person per day (today: zero)
- "To review" backlog and its age; share of items discarded (noise)
- Promotions from collective memory, and how often organizational items are used
- Stale items found and replaced
Reviews before any stage is called done: security, tenant isolation, db-schema, authz, audit-log, mcp-protocol, UI, licence and host-guard. retrieval-evaluator runs on 1n, 1o and 1p (routing and cards change what search returns).
11. Risks of this plan
| Risk | Control |
|---|---|
| Automatic capture brings noise (one public audit found 97.8 % junk in raw extraction) | Curated inputs only (memory files and model notes), quality gate, review first, ageing, a measured discard rate |
| Aggregates or cards reveal one person's private item | Minimum group 3, humans only, Personal memory and the pool excluded, dedicated isolation tests, cards built per audience |
| Wrong link (a fork or mirror) routes items to the wrong place | Automatic only at ≥ 0.95 (host id or root set); 0.8 asks first; links are versioned and items keep their address; routing never shares |
| Session copies and path aliases are personal data | Owner-only, 30 days, emptied like connector text; path aliases stay on the machine unless linked |
| Hooks differ per tool or don't run headless (not yet verified) | Short spike at the start of 1n and 1q; the MCP tool memory_checkpoint is the fallback |
| Local 4B model too weak for long mail threads | Rules first; per-message extraction with thread context; extractor version stored for re-extraction later |
| Scope grows again (as it did with Q-35) | Each stage has one exit test; anything else goes to "Later"; stay centred on the space-mapping problem |
| Shared production host load | Background jobs capped as today; host-change-check before any new container or connector |
12. Decisions
Most questions were already answered with suggestions on the two research pages. This plan proposes taking those suggestions as they are, and asks only for what is new.
| # | Question | Suggestion |
|---|---|---|
| N1 | Adopt this plan: extend, not rebuild, with stages 1l–1r in this order? | Yes (proposal S-43) |
| N2 | Accept the suggested answers on the Q-35 page (decisions 1–13, 15–22) and the Q-36 paper (decisions 3–24) as written? | Yes, in one approval, so stages don't wait on them one by one |
| N3 | First chat platform for space knowledge (1p): Microsoft Teams or Slack? | The one the company actually uses for project talk. If both, Teams (Graph delta queries are well documented) |
| N4 | Lanes and organizational memory stored in the existing scopes (section 4), not in new tables? | Yes |
| N5 | Typed space knowledge stored as memories with new kinds and a fields column, not as separate record tables? | Yes: search, versioning, audit and RLS come free; add tables only if the kinds outgrow it |
| N6 | Company repo spaces from GitHub (IT-Labs-AJ) now, Bitbucket aliases added when the workspace exists? | Yes: space IDs survive the move by design |
| N7 | When may pilot use any of this? | After 1q and company approval of the allowed apps; never before |
| N8 | Drop place_mappings after the copy-then-switch in 1m / 1n? | Yes, one stage after the switch, after a count check |
13. Next steps
- The user reviews this plan and answers N1–N8 (or writes "S-43: approved" to take every suggestion).
- Threat model for 1l (envelope, cursor feed, idempotency, review list) with threat-modeler.
- Build 1l in
repo/, with its PLAN.md underdocs/stage-1l/. The user applies the migrations from the copy file. - Short spikes due before 1m / 1n: whether GitHub repo ids stay stable after a rename; whether hooks run in Claude Code headless and cloud sessions; which MCP clients pass
_meta. - Update the whitepaper only minimally, once 1n proves the model works.
14. Stage 1u (set aside): first real use in pilot
Set aside 2026-10-11 · nothing built 2026-10-11
pilot) has a Jira connector and little else. One day of real use already found what tests didn't: a browser that never
reached the console, a sign-in code the helper hid, bot notes discarded by mistake with no way back, and a sign-in limit shared by the
whole company. The pitch promised value for one real team before Phase 2. The cheapest way to learn whether spaces and automatic
saving help is a few weeks of real use, measured, before packaging cMCP for other companies.1u · First real use in pilot size M
A. A real account that is ready
- A readiness report (one command and a section on the ADMIN's Account page): every loosened switch, allowed AI apps, device keys, bots and their sponsors, connectors, and settings that differ from the defaults, marked green / amber / red.
pilotstarts with the allowed-apps list on (Q-35 decision 7): Claude Code through device keys and the web console only; the ADMIN adds others.- Checked and locked for the pilot: review first, extraction on the local model only, whole-conversation copies off.
B. Real people can start on their own
- The invitation path tested end to end for a new colleague: account, first sign-in with the one-time code, device approval, and the helper and plugin on their laptop (Windows and macOS steps; the helper stays a Python package for now, Q-35 decision 8).
cmcp doctor: checks name lookup, certificates, the three public addresses, sign-in, the stored key, the clock and the Claude Code hooks, and says in plain words what is wrong (the "browser never reached the server" case took an hour).- A "first day" page in the manual.
C. Operations that matter once data is real (the open go-live items)
- A real reboot in a planned window, proving that everything starts on its own.
- Resource limits for the cMCP containers (risk R-10), and a firewall review.
- Off-server encrypted backups and a restore test with the offline key (moved to Phase 2 on 2026-10-02; decision U3).
D. Measures (a weekly report page, counts only, never memory text)
- Per person and space: notes saved automatically, kept, discarded and aged; notes used in context and search; promotion suggestions made and accepted; requests and how long decisions take.
- Answer quality on real data: 20–30 questions the user writes once, scored weekly with the existing retrieval harness (local model only).
- Speed: context load, search and checkpoint, median and 95th percentile.
E. Carried over from 1t
- A 24-hour wait after ADMIN changes before a high-risk loosening (closes the "demote the second ADMIN" gap).
- Test hygiene: browser tests reuse sign-ins everywhere; notice checks read the database.
pilot on at least ten
working days; the readiness report is green; a restore and a reboot succeeded; at least 60% of automatic notes are kept rather than
discarded or aged (otherwise tune what is saved); at least one promotion suggestion accepted per active place each week, or a clear
reason why not; no secret stored and no read across accounts or clients in the audit; answer quality on the real questions at least
the synthetic baseline (23 of 24 in the top five).
What 1u does not do
No new memory features, no cloud model for real data, no packaging for other companies (that is Phase 2, Q-34). Anything the pilot shows is missing becomes a short follow-up or a Phase 2 item.
Decisions for 1u
| # | Question | Suggestion |
|---|---|---|
| U1 | Next stage: first real use (1u), or start Phase 2 packaging (Q-34 option B) now? | 1u first: Phase 2 should follow real evidence |
| U2 | Who joins the pilot? | The user and one to three colleagues who use Claude Code daily (the user names them) |
| U3 | Off-server encrypted backups: pull into 1u, or keep in Phase 2? | Pull in: once the data is real, a server failure must not lose it |
| U4 | Connectors in pilot during the pilot? | Jira only, as today; Microsoft 365, Google Drive and GitHub stay Phase 2 (decided 2026-10-02) |
| U5 | Allowed AI apps in pilot at the start? | Claude Code (device keys) and the web console only |
| U6 | How long, and how is it reviewed? | Three weeks, with the weekly report reviewed each week |
To start: answer U1–U6, or write "S-45: approved" to take every suggestion. Then the threat model for 1u, the build, and the pilot.
15. Next: the move to IT-Labs hardware
Planned · on hold until the owner resumes it 2026-10-11
The web console (people, ADMINs and the web-admin) moves to IT-Labs' web server at cmcp.it-labs.in. The API, MCP endpoint, sign-in, database, search and the local AI model move to a new GPU server. Until that server is rented, the console uses the pilot server's API and sign-in addresses.
| Done (2026-10-11) | Result |
|---|---|
| Company data cleared from the pilot account | Connector with its stored secret, 568 imported texts, 5,344 notes with their history, the Jira space and 1,504 search entries removed; backup taken first; a reusable maintenance script that counts first and audits what it removes |
| IT-Labs web server checked and hardened | Every installed package verified against its distribution's checksums; no sign of compromise; integrity scanners re-baselined (0 warnings); host firewall with an allow-list (23 of 23 outside checks passed, monitoring and proxy ports closed); the unused desktop turned off; the saved boot firewall, which would have blocked everything, replaced |
| Documents moved | All cMCP documents now at it-labs.in/cmcp/docs, hidden from search engines; GPU estimate added to the LLM results page |
A · Restart the web server into its newer kernel on hold
- Before: boot firewall equals the running one; the live applications on that server are saved to start again; integrity baselines copied; the provider's remote console ready.
- After, checked from outside: the newer kernel and a healthy disk mirror; the 23 outside checks; the hosted applications answer; firewall and ban rules as before.
- Fallback: boot the older kernel from the boot menu; expected downtime 2–5 minutes, at a quiet hour the owner picks.
B · The console at cmcp.it-labs.in on hold
- A DNS record and a hosting-panel site with a certificate (owner's go-ahead for each).
- A service account of its own, a current Node in that account's folder (the system Node unchanged), the console as a system service on
127.0.0.1only, behind the web server. - Sign-in: the new address registered as a return address; the edge router's sign-in limit exempts the console's own token exchanges, as it did on the pilot server.
- A private link (WireGuard, one port, both ends locked) for the web-admin back end, which is never made public.
- Checks: the browser test suite against the new address; the web server's existing sites unchanged.
C · The stack on a GPU server (Hetzner GEX45) when rented
- A current operating system, the GPU driver and Docker; firewall and SSH keys first.
- The cMCP stack from the code repository, at new addresses (for example
cmcp-api.it-labs.in,cmcp-auth.it-labs.in). - The local model chosen by running the existing quality test on the GPU (estimates on the LLM results page: today's model about 5× faster; larger models such as Qwen 27B fit).
- Only the code and the test accounts move; old backups of the pilot server stay there.
- Encrypted off-server backups and a restore test; then the console points at the new addresses, the full test suites run, and the pilot server's stack is switched off.
Decisions for the move
| # | Question | Suggestion |
|---|---|---|
| V1 | When may the web server restart? | A quiet hour outside the hosted applications' busy times |
| V2 | Where does the web-admin live? | Its own address (for example admin.cmcp.it-labs.in), reachable only from the owner's addresses or the VPN |
| V3 | The DNS record and the hosting-panel site for cmcp.it-labs.in | Yes, at the start of B |
| V4 | When to rent the GPU server | When B is stable; no minimum term |
| V5 | Rotate the web server's passwords and keys from its earlier incident | Before other people use the console |
| V6 | The web server's operating system has reached end of life | Plan an upgrade or a new server; keep the console isolated until then |