Local Migration Control Center
This static local page explains the KW consolidation plus AIApp migration, shows the latest PM workspace status, and points at the local prompt and runbook needed to continue the migration on a stronger PC.
Generated at 2026-07-28T09:18:16.862Z from project /var/www/kw/Kara-und-Weiss-API and PM workspace /tmp/kw-migration-pm.
Companion docs: ./.cursor/docs/local-migration-pm-prompt.md and ./.cursor/docs/local-migration-runbook.md. The full prompt and setup brief are embedded below so your local PM agent can use this page as the single briefing surface.
What this migration is
- Unify the public CLI under
kw. - Make
Kara-und-Weiss-APIthe sole HTTP + CLI home. - Keep customer business data local-first with SQLite.
- Keep vendor Supabase thin for license/billing/heartbeat only.
- Drain remaining KW waves and AIApp desktop-to-mobile tickets through the existing PM loop.
Guardrails
- No customer business data on vendor Supabase.
- No cockpit LLM-to-shell product path.
- No dual-write as a normal operating mode.
- No secrets rendered into this site.
- No git commit unless a human explicitly asks.
Wave status
| Wave | Title | Status | Milestones | Summary |
|---|---|---|---|---|
| W0 | Governance & brain | done | M1✅ M2✅ | ADR+BRAIN+templates+agent rules |
| W1 | Root CLI `kw` | done (bridges live) | M1✅ M2✅ | `kw -h` goldens; `kw ai`; `kw api`; cockpit dropped |
| W2 | Absorb AICLI platform | done (tree+build; openapi merge plan) | M1✅ M2✅ | `platform/` builds in this repo |
| W3 | API owns all mutators | active | M1⬜ M2⬜ | CLI mutators → OpenAPI only |
| W4 | Customer SQLite thick | open | M1✅ M2✅ | B2B default `KW_STORAGE=sqlite` |
| W5 | Vendor Supabase thin | open | M1⬜ M2✅ | license+heartbeat; **no** biz tables |
| W6 | Backup → Google Drive | open | M1⬜ M2⬜ | backup/restore tests pass (Drive fake OK) |
| W7 | Extract app backends | open | M1⬜ M2✅ | Organizer routes proxy→KW-API |
| W8 | Clients retarget | open | M1⬜ M2⬜ | AIApp/Telegram use KW-API+`kw` |
| W9 | Cutover / docs / sales | open | M1⬜ M2⬜ | install playbook + SKU + checklist |
PM queue
| Ticket | Status | Repo | Summary |
|---|---|---|---|
| MIG-KW-W3-0002-openapi-gaps | done | /var/www/kw/Kara-und-Weiss-API | KW-W3-0002 done (TDD): OPENAPI-PORT maps all must_port leaves; added spawnAgentPack + spawnCapabilityTeam to shared/contracts/openapi.v1.yaml; donor kw ai setup/config/ticket deferred to follow-ups/KW-W3-F001; ADR 0060; PROGRAM/M1 checkboxes updated; gate tests green. |
| MIG-KW-W3-0003-generated-clients | done | /var/www/kw/Kara-und-Weiss-API | KW-W3-0003 done (TDD): make generate-client/ci + .github/workflows/openapi-client.yml emit shared/contracts/goclient from openapi.v1.yaml (oapi-codegen, ADR 0061). Gate tests green. Dart deferred. PROGRAM/MILESTONE checkboxes updated. |
| MIG-KW-W3-0004-cli-http-only | done | /var/www/kw/Kara-und-Weiss-API | KW-W3-0004 done (TDD): added cli/apiclient, wired cli/main.go doRequest through FromEnv().Do, CLI→API→store integration + feature gates green; ADR 0059; PROGRAM/M2/MILESTONES checkboxes updated; must_port FS leaves remain until OpenAPI port. |
| MIG-KW-W3-0005-no-shell-string-runs | done | /var/www/kw/Kara-und-Weiss-API | KW-W3-0005 done TDD: createRun rejects raw shell with 422 shell_string_rejected; allowlist ask|plan|debug|run|review|intent; OpenAPI enum+pin; ADR 0058; PROGRAM/MILESTONE checkboxes updated. |
| MIG-KW-W4-0001-store-port-sqlite | done | /var/www/kw/Kara-und-Weiss-API | KW-W4-0001 done TDD: storesUnderTest always includes sqlite; Memory↔SQLite org/project/ticket/customer parity; XOR no dual-write gates; ADR 0062; PROGRAM/M1 checkboxes updated. |
| MIG-KW-W4-0002-migrations-sqlite | done | /var/www/kw/Kara-und-Weiss-API | KW-W4-0002 done (TDD): SQLite-dialect logical migrations under platform/infrastructure/migrations/sqlite; MigrateSQLite+OpenSQLite.SchemaVersion; migrate fresh+reopen green; ADR 0063; PROGRAM/M1 checkboxes updated. |
| MIG-KW-W4-0003-default-b2b-sqlite | done | /var/www/kw/Kara-und-Weiss-API | KW-W4-0003 done (TDD): B2B default KW_STORAGE=sqlite — ResolveStorageSelection/platform-api boots without PLATFORM_SQLITE_PATH; Hono resolveKWStorage + GET /health storage; PROJECT/.env.example/OpenAPI HealthStatus; ADR 0062. Gates + vitest + store unit tests green. No dual-write. W4-M1 exit gate checked. |
| MIG-KW-W4-0004-artifacts-local | done | /var/www/kw/Kara-und-Weiss-API | KW-W4-0004 done (TDD): LocalRoot + POST/GET /api/v1/artifacts on disk (PLATFORM_ARTIFACTS_ROOT), OpenAPI uploadArtifact, ADR 0065, PROGRAM/M2 checkboxes updated. |
| MIG-KW-W4-0005-health-storage | done | /var/www/kw/Kara-und-Weiss-API | KW-W4-0005 done (TDD): GET /health (+ /health/ready) reports storage+schemaVersion; OpenAPI HealthStatus/HealthPayload; ADR 0067; platform+gate+vitest green; PROGRAM/M2 checkboxes updated. |
| MIG-KW-W5-0001-schema-thin | done | /var/www/kw/Kara-und-Weiss-API | KW-W5-0001 done TDD: supabase/migrations thin control plane (tenants/users/licenses/billing_status/install_heartbeats only); no biz tables; gate tests RED→GREEN; ADR 0063; PROGRAM W5 vendor schema live checked. |
| MIG-KW-W5-0002-license-api | done | /var/www/kw/Kara-und-Weiss-API | KW-W5-0002 done TDD: OpenAPI getLicenseStatus/activateLicense; Hono thin license store+routes; kw license activate|status via apiclient; ADR 0064; MUTATOR has_http; PROGRAM/M1 checkboxes; gate+vitest green. |
| MIG-KW-W5-0003-billing-status-mirror | done | /var/www/kw/Kara-und-Weiss-API | KW-W5-0003 done (TDD): GET /api/v1/billing/status + POST /api/v1/billing/webhook mirror status only; card payloads → card_data_rejected; OpenAPI/v1-types; ADR 0066; PROGRAM/M1 checkboxes; vitest+gate green. |
| MIG-KW-W5-0004-heartbeat | done | /var/www/kw/Kara-und-Weiss-API | KW-W5-0004 done (TDD): POST /api/v1/license/heartbeat + InstallHeartbeatRequest additionalProperties:false forbids biz fields; kw license heartbeat via apiclient; ADR 0069; vitest+gate green; PROGRAM/M2 checkboxes updated. |
| MIG-KW-W5-0005-grace-offline | done | /var/www/kw/Kara-und-Weiss-API | KW-W5-0005 done TDD: evaluateOfflineGrace (7d default) → grace/expired/localOpsAllowed; store+OpenAPI+heartbeat refresh; ADR 0068; PROGRAM checkbox checked; vitest+gate green. |
| MIG-KW-W6-0001-backup-local-bundle | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0001 done: CreateLocalBundle packs sqlite+artifacts+manifest (fake-fs unit tests); kw backup now wired (local_ok); ADR 0070; PROGRAM/M1 checkboxes updated; help golden updated. |
| MIG-KW-W6-0002-gdrive-oauth-local | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0002 done TDD: cli/kw/gdriveoauth Store (Memory/File/OpenLocalKeyring); kw backup auth set|status|clear local_ok; ADR 0066; MUTATOR rows; PROGRAM/M1 checkboxes; no tokens to vendor Supabase; gate+unit tests green. |
| MIG-KW-W6-0003-upload-drive | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0003 done (TDD): cli/kw/gdriveupload FakeDrive+UploadLocalBundle; kw backup upload --fake (backup_upload_cmd.go); ADR 0071; gate+unit tests green; PROGRAM/M1/PROJECT updated; local_ok in MUTATOR-MATRIX. |
| MIG-KW-W6-0004-schedule-retention | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0004 done (TDD): ScheduleConfig + ApplyRetention + kw backup schedule|retain (ADR 0073); unit+gate tests green; PROGRAM/M2 checkboxes updated. |
| MIG-KW-W6-0005-restore-local | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0005 done (TDD): backupbundle.RestoreLocalBundle round-trips CreateLocalBundle; kw backup restore-local --from wired (local_ok); ADR 0075; MUTATOR-MATRIX + PROGRAM/M2 checkboxes; unit+CLI+gate tests green. No vendor Supabase writes; prefer update over wipe. |
| MIG-KW-W6-0006-optional-encrypt | done | /var/www/kw/Kara-und-Weiss-API | KW-W6-0006 done (TDD): KWENC1 AES-256-GCM Encrypt/DecryptBackupPayload+Bundle; kw backup encrypt|decrypt; ADR 0074; PROGRAM/M2 gate checked; local_ok only. |
Active slots
| Slot | Ticket | PID | Started |
|---|
Recent PM events
| Kind | Ticket | Detail |
|---|---|---|
| ticket_done | MIG-AIAPP-crm-deal | CrmDealScreen /apps/crm/deals/:id live via HttpPlatformApi: crmDeal→GET /deals/{id}, closeCrmDeal→POST /deals/{id}/close (PlatformJson.crmDeal/crmClosure). TDD mig_aiapp_crm_deal_*.dart 8/8 green. Migrate state page crm-deal=done. ADR 0151. No commit. |
| ticket_done | MIG-AIAPP-social-post | Social compose /apps/social/compose: SocialComposeScreen + HttpPlatformApi.enqueueSocialPost → POST /tickets with social: prefix (no Hono/Seed). QA green: mig_aiapp_social_post_{static,test,widget}_test. Migrate state social-post=done. ADR 0147. |
| ticket_done | MIG-AIAPP-leadgen-detail | LeadgenDetailScreen /apps/leadgen/:id on PlatformApi; HttpPlatformApi GET /leads/{id} + POST /leads/{id}/score (no Fake Seed, no Hono). QA: static+http gates ALL GREEN; flutter test 7/7 passed. Migrate state leadgen-detail → done. No USB phone attached (skipped deploy). No git commit. |
| ticket_done | MIG-AIAPP-invoice-list | InvoiceListScreen /apps/invoice wired to PlatformApi.listInvoices; HttpPlatformApi maps GET /tickets [invoice|] titles (no Fake Seed, no Hono). QA mig_aiapp_invoice_list_* green; migrate state invoice-list=done (ADR 0149). |
| ticket_done | MIG-AIAPP-invoice-detail | Invoice detail /apps/invoice/:id live via PlatformApi.getInvoice (GET /invoices/{id}, ticket fallback) + updateInvoice (PATCH /invoices/{id}); InvoiceDetailScreen Mark sent/paid wired; migrate state invoice-detail=done; QA green (mig_aiapp_invoice_detail_* + invoice-list suite). |
| ticket_done | MIG-AIAPP-leadgen-detail | LeadgenDetailScreen /apps/leadgen/:id on PlatformApi; HttpPlatformApi GET /leads/{id} + POST /leads/{id}/score (no Fake Seed, no Hono). QA: static+http gates ALL GREEN; flutter test 7/7 passed. Migrate state leadgen-detail → done. No USB phone attached (skipped deploy). No git commit. |
| ticket_done | MIG-AIAPP-crm | CrmScreen /apps/crm live via PlatformApi: HttpPlatformApi listCrmDeals/createCrmDeal (+ existing fetchCrmStatus/crmDeal/closeCrmDeal) map OpenAPI /deals + /crm/status; PlatformJson mappers; QA mig_aiapp_crm_{static,test} 7/7 green; migrate state page crm=done. ADR 0149 + brain mig-aiapp-crm. |
| ticket_done | MIG-AIAPP-crm | CrmScreen /apps/crm live via PlatformApi: HttpPlatformApi listCrmDeals/createCrmDeal (+ existing fetchCrmStatus/crmDeal/closeCrmDeal) map OpenAPI /deals + /crm/status; PlatformJson mappers; QA mig_aiapp_crm_{static,test} 7/7 green; migrate state page crm=done. ADR 0149 + brain mig-aiapp-crm. |
| ticket_done | MIG-AIAPP-leadgen | Leadgen /apps/leadgen: HttpPlatformApi OpenAPI /leads + /crm/status (not Fake Seed, not Hono); LeadgenScreen focused-project gate; PlatformJson.crmLead; static+http gates ALL GREEN; migrate state leadgen=done. |
| ticket_done | MIG-AIAPP-leadgen | Leadgen /apps/leadgen: HttpPlatformApi OpenAPI /leads + /crm/status (not Fake Seed, not Hono); LeadgenScreen focused-project gate; PlatformJson.crmLead; static+http gates ALL GREEN; migrate state leadgen=done. |
| ticket_done | MIG-AIAPP-agent-store-mission | /agent-store/mission-control AgentStoreMissionScreen PlatformApi (runs/notifications/approvals/templates). HttpPlatformApi.notifications → GET /inbox (no Seed). tool/mig_aiapp_agent_store_mission_{static,http}_gate.dart ALL GREEN. state.json agent-store-mission → done; ADR 0144. flutter_test thrash under parallel slots — pure-Dart gates authoritative. No git commit. Hard rejects held. |
| ticket_done | MIG-AIAPP-agent-store-mission | /agent-store/mission-control AgentStoreMissionScreen already PlatformApi (runs/notifications/approvals/templates). HttpPlatformApi.notifications → GET /inbox + PlatformJson.inboxItem (no Seed). tool/mig_aiapp_agent_store_mission_{static,http}_gate.dart ALL GREEN (FINAL:0). state.json agent-store-mission → done; ADR 0144. flutter_test thrash under parallel PM slots — pure-Dart gates authoritative (sibling pattern). No git commit. Hard rejects held. |
Local commands
node script/migration-pm-loop.mjs --seed --interval=30 --max=4 --keepcat /tmp/kw-migration-pm/state.jsonls /tmp/kw-migration-pm/inbox /tmp/kw-migration-pm/slotstail -f /tmp/kw-migration-pm/logs/pm.log
Copy-paste PM prompt
Give your local agent this instruction: open this page first, then follow the embedded prompt and runbook.
--- title: Local migration PM prompt status: active product: kw --- # Local migration PM prompt Use this prompt on your stronger local PC when you want a PM agent to continue the migration and keep the local status site fresh. ## Prompt ```text You are the Migration PM for the Kara und Weiss consolidation and AIApp migration. Workspace root on this machine contains local clones for: - Kara-und-Weiss-API - AIApp - KWDEV Primary repo path: - <LOCAL_ROOT>/Kara-und-Weiss-API Related repo path: - <LOCAL_ROOT>/AIApp Read and follow these source-of-truth files first: 1. <LOCAL_ROOT>/Kara-und-Weiss-API/PROJECT.md 2. <LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/PROGRAM.md 3. <LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/MILESTONES.md 4. <LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/brain/migration-pm/BRAIN.md 5. <LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/brain/migration-pm/PROGRAM.md 6. <LOCAL_ROOT>/AIApp/PROJECT.md Mission: - Finish the remaining KW consolidation waves W3-W9 - Drain pending/in_progress AIApp desktop-to-mobile migration work - Use the existing migration PM flow, not a second orchestration system - Keep the local migration website updated after every meaningful PM tick and after each wave status change Non-negotiable rules: - TDD first - Prefer update over delete - No git commit unless the human explicitly asks - No customer business data on vendor Supabase - No cockpit LLM-to-shell product path - No dual-write as a normal mode - No new parallel migration state authority - Do not render secrets into HTML Execution model: - Use Kara-und-Weiss-API/script/migration-pm-loop.mjs as the PM runtime - Use Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/PROGRAM.md as the permanent wave authority - Use AIApp migration state as the page backlog authority - Refresh the local static site at .cursor/docs/local-migration-status.html after every tick What to do each cycle: 1. Read the current PM workspace state and queue 2. Read the permanent wave program and milestone gates 3. Spawn only the next bounded tickets that fit the current open/active waves 4. Require report-back from every spawned worker 5. Update the local status site 6. Stop and surface blockers clearly when credentials, missing repos, or failing gates prevent safe progress Output expectations: - Keep summaries concise - Record ticket-level progress in the PM workspace - Make the HTML site the simplest always-open operator view ``` ## Intended local runtime - PM runtime: `script/migration-pm-loop.mjs` - Local website: `.cursor/docs/local-migration-status.html` - Permanent wave SSOT: `.cursor/brain/kw-platform-consolidation/PROGRAM.md` - PM workspace: `/tmp/kw-migration-pm`
Local setup and runbook
Everything needed to clone, install, run the PM loop, and monitor the migration from a stronger local PC.
---
title: Local migration runbook
status: active
product: kw
---
# Local migration runbook
This runbook is for moving the migration work from the current server to a
stronger local PC while preserving the existing migration authority and safety
boundaries.
## Clone layout
Use one parent folder on your local machine, for example:
```text
<LOCAL_ROOT>/
Kara-und-Weiss-API/
AIApp/
KWDEV/
```
## Required repos
1. `Kara-und-Weiss-API`
- owns the `kw` CLI, `kw api`, migration PM loop, and consolidation program
2. `AIApp`
- owns the desktop-to-mobile migration backlog and Flutter client work
3. `KWDEV`
- needed because `Kara-und-Weiss-API/package.json` depends on local packages:
- `file:../KWDEV/packages/auth`
- `file:../KWDEV/packages/db`
## Source of truth order
Read in this order before you run anything:
1. `Kara-und-Weiss-API/PROJECT.md`
2. `Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/PROGRAM.md`
3. `Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/MILESTONES.md`
4. `Kara-und-Weiss-API/.cursor/brain/migration-pm/BRAIN.md`
5. `Kara-und-Weiss-API/.cursor/brain/migration-pm/PROGRAM.md`
6. `AIApp/PROJECT.md`
7. `Kara-und-Weiss-API/.cursor/docs/local-migration-pm-prompt.md`
## Local prerequisites
- Node.js capable of running the repo toolchain
- npm
- Go for the `kw` and `ai-api` CLI builds
- Cursor/agent tooling on PATH if you want the PM loop to spawn agents
- Optional:
- Telegram env if you want PM done/error notifications
- Redis if you need worker paths
## Install and bootstrap
### Kara-und-Weiss-API
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API
npm install
```
### Build the root CLI
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API/cli/kw
go test ./...
go build -o kw .
```
### Optional legacy API CLI
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API/cli
go build -o ai-api .
```
## Important local env assumptions
From `Kara-und-Weiss-API/PROJECT.md`:
- `KW_API_BASE` usually points at `http://127.0.0.1:4001`
- `KW_API_PAT` is used by `kw api` when not using cookie auth
- `KW_STORAGE=sqlite` is the intended local-first default
- `PLATFORM_SQLITE_PATH` points at the local platform SQLite path
- `TELEGRAM_BOT_TOKEN` is only needed if you want Telegram notifications
## Local PM runtime
### One-shot dry run
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API
node script/migration-pm-loop.mjs --seed --once --dry-run --keep
```
### Normal local PM run
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API
node script/migration-pm-loop.mjs --seed --interval=30 --max=4 --keep
```
### Custom local site output
```bash
cd <LOCAL_ROOT>/Kara-und-Weiss-API
node script/migration-pm-loop.mjs --seed --interval=30 --max=4 --keep --status-site="<LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/docs/local-migration-status.html"
```
## What gets updated
- PM ephemeral workspace: `/tmp/kw-migration-pm`
- Local static status site:
- `Kara-und-Weiss-API/.cursor/docs/local-migration-status.html`
- Hosted server copy on this host:
- `https://migration.karaweiss.org`
- served from `Kara-und-Weiss-API/migration-site/index.html`, which can point at the generated local status file
- Permanent wave authority:
- `Kara-und-Weiss-API/.cursor/brain/kw-platform-consolidation/PROGRAM.md`
- AIApp migration authority:
- AIApp migration state file used by the existing PM backlog collector
## Monitoring commands
```bash
cat /tmp/kw-migration-pm/state.json
cat /tmp/kw-migration-pm/queue.json
ls /tmp/kw-migration-pm/inbox /tmp/kw-migration-pm/slots
tail -f /tmp/kw-migration-pm/logs/pm.log
```
Open the local website directly in your browser:
```bash
xdg-open <LOCAL_ROOT>/Kara-und-Weiss-API/.cursor/docs/local-migration-status.html
```
## Hard boundaries
- No customer business data on vendor Supabase
- No cockpit product path
- No normal-mode dual write
- No hidden second state authority
- No secrets in the HTML status site
- No git commit unless you explicitly ask for one