docs(compose): aurelio-theia migration plans + proxmox new-server migration plan/spec

This commit is contained in:
fabiorafaelcoutada 2026-07-12 20:53:08 +01:00
parent 09bcd03cf3
commit 223cdc2fb9
5 changed files with 1195 additions and 0 deletions

View file

@ -0,0 +1,111 @@
# Aurelio → Theia: Live-Code Delta & Current State
**Supersedes the "baseline-only" caveat** in `2026-07-10-aurelio-theia-migration-feature-inventory.md` and `…-porting-checklist.md`. Both repos were cloned read-only from Forgejo on CT 203 (`code.portugalfuturista.org` → `ssh://git@192.168.0.9:2222/portugalfuturista/<repo>.git`) into `~/portugalfuturista/`.
| Repo | Path | HEAD | Date | Note |
|---|---|---|---|---|
| `aurelio-vscode` | `~/portugalfuturista/aurelio-vscode` | `b37e9d2` (`main`) | 2026-06-22 | version **0.12.2** — live source of truth |
| `aurelio-theia` | `~/portugalfuturista/aurelio-theia` | `f8bed07` (`main`) | 2026-07-10 | version **0.1.0** — skeleton only (2 commits) |
**Access path used (for re-runs):** this host has LAN reachability to the Proxmox host `root@192.168.0.38` (key auth). The Forgejo git daemon runs in CT 203 (`pf-iot-stack`, `192.168.0.9`), exposed on host port `2222→22`. Direct `ssh code.portugalfuturista.org` does NOT work from here (Cloudflare anycast, no inbound 22, no IPv6 route, no local `cloudflared`). The working clone is over the LAN: `git clone ssh://git@192.168.0.9:2222/portugalfuturista/aurelio-vscode.git` (authenticates as Forgejo user `triviabilidades` via `~/.ssh/id_ed25519`). The bare repos live in the docker volume `/var/lib/docker/volumes/pf-iot-stack_forgejo-data/_data/git/repositories/portugalfuturista/`.
---
## 1. aurelio-vscode `main` (0.12.2) — measured delta vs the 0.12.0 baseline
The previous inventory/checklist were built from a git-history reconstruction tagged 0.12.0. Live `main` is **0.12.2** and is broadly consistent but has moved in a few material ways:
| Metric | 0.12.0 (reconstructed) | 0.12.2 (`main`, live) | Δ |
|---|---:|---:|---|
| `package.json` version | 0.12.0 | **0.12.2** | +2 patch |
| `engines.vscode` | ^1.90.0 | ^1.90.0 | — |
| Declared commands | 64 | **66** | +2 (`/glm`/`/claude` era additions) |
| Registered unique commands | ~79 | **83** | +4 |
| Declared-not-registered | some | **none** | all declared commands are wired |
| Registered-not-declared (internal) | ~15 | **17** | +2 |
| Settings keys (`aurelio.*`/`quarkdown.*`) | 123 | **126** | +3 (kimi multi-mode) |
| Sidebar views | 6 | 6 | — |
| View containers | 1 | 1 | — |
| Webview panels (`createWebviewPanel`) | 24 | **25** | +1 |
| Custom editor | 1 (PDF/EPUB) | 1 (PDF/EPUB) | — |
| `src/*.ts` LOC | ~51k | **41,781** (151 files) | ~9k (Jules removal + cleanup) |
| Node-built-in importer files | 46 | **70** | +24 (more backend-coupling, not less) |
| `vscode.lm` consumers | 1 (`sessionMemory.ts`) | **2** (`sessionMemory.ts` + `magicDocs.ts`) | +1 — the Theia-incompatible surface grew |
| `*.portugalfuturista.org` hosts | 13 | 13 | — (but 206→208/125 migration done) |
| `src/_future/*` dormant files | 5 | 5 (still present, still 0 importers) | — |
**What changed (commit log):**
- `61fc483 feat(vscode): multi-mode Kimi provider (direct/code/hermes) + OpenRouter model picker` → new `src/models/kimiProvider.ts` (211 LOC); new settings `aurelio.kimi.mode` (`direct|code|hermes`), `aurelio.kimi.apiKey`, `aurelio.kimi.codeApiKey`, `aurelio.kimi.codeModel`. **No `zaiProvider.ts` in this snapshot** — the `glm`/`claude` ModelTypes documented in `nervura-electrica/docs/AURELIO_GLM_CLAUDE.md` are *not yet* in this checkout; `modelRouter.ts` `ModelType = 'local'|'vertex'|'openrouter'|'antigravity'|'kimi'|'hermes'` (no `glm`/`claude`/`jules`). Slash map still `/local /vertex /openrouter /antigravity /kimi` (+ others).
- `4141235 refactor: remove Google Jules integration and point MCP servers to CT 208``julesClient.ts` gone, no `jules`/`@google/jules` refs anywhere. Checklist row B9 (Jules) is **now moot — drop it**.
- `1a5f478 fix: bypass CT 206 for print/Kimi and fall back to central brain`, `31d4f48 fix: point Hermes endpoint to reachable NVIDIA API` → CT 206 retired; MCP/brain now target **CT 208 (`192.168.0.125`)**, consistent with `nervura-electrica/AGENTS.md`.
- `b37e9d2 docs(agents): document frontend split and key settings` → confirms the **frontend split**: the VS Code webview reuses the **Svelte build from the separate `aurelio-web` repo**; the public `portal.portugalfuturista.org` is a distinct React app. Two frontends, same backend ecosystem. This matters for Theia: the Svelte control-center is shared infrastructure, not private to the VS Code extension.
- New context modules not in the 0.12.0 baseline: `src/context/consolidationLock.ts` (173), `src/context/sessionMemoryCompact.ts` (211), `src/context/sessionSnapshot.ts` (241) — the auto-dream/compaction subsystem has grown and is now locked/snapshotted. Strengthens the "move memory/context to Theia backend" recommendation (D-group).
**Net effect on the migration plan:** the feature *shape* in the inventory is still accurate; the *numbers* and a few subsystem details are now superseded by the table above. The two structural risks are *larger* than the baseline suggested: node-coupling rose from 46→70 files, and `vscode.lm` (no Theia equivalent) is now used in two places (`sessionMemory.ts` + `magicDocs.ts`).
---
## 2. aurelio-theia `main` (0.1.0) — what actually exists today
**It is a day-0 skeleton (2 commits, 13 files, no `node_modules`, not yet built).** Commit `f8bed07 "feat: initial scaffolding — Theia product + Aurelio extension skeleton"`. Do not treat it as a port — it's a greenfield shell with Aurelio-shaped placeholders.
**Stack pinned:** Eclipse Theia **1.56.0** (all `@theia/*` deps), `lerna ^8` + yarn workspaces, `typescript ~5.3.3`, `@modelcontextprotocol/sdk ^1.29.0`, `axios ^1.15.2`, `express ^4.18.0` (backend only).
**Layout:**
```
aurelio-theia/
├── package.json # product: @theia/* 1.56.0; `start` = `theia start --plugins=local-dir:./AurelioTheia`
├── lerna.json # yarn workspaces: AurelioTheia, aurelio-backend
├── tsconfig.json # ES2020, strict, jsx react
├── README.md
├── AurelioTheia/ # the Theia extension (frontend+backend)
│ ├── package.json # theiaExtensions: frontend lib/browser, backend lib/node
│ └── src/
│ ├── browser/aurelio-frontend-module.ts # binds 2 classes, no contrib wiring beyond commands
│ ├── browser/aurelio-commands.ts # EMPTY placeholder class
│ ├── browser/aurelio-sidebar-contribution.ts # registers 5 commands → console.log only
│ └── node/aurelio-backend-module.ts # empty ContainerModule (commented TODO list)
└── aurelio-backend/ # standalone express backend (placeholder)
├── package.json
└── src/server.ts # console.logs port 3101; no routes
```
**What's wired vs. stubbed:**
- 5 commands declared and registered (`aurelio.syncPush`, `aurelio.syncPull`, `aurelio.startSession`, `aurelio.switchRealm`, `aurelio.manageHeteronimos`) — every handler is `() => console.log(...)`. **No views, no webviews, no MCP client, no model router, no brain/sync implementation, no settings schema.** `AurelioCommands` (the class) is an empty placeholder; the real command ids live in `aurelio-sidebar-contribution.ts` as a const object.
- Backend module is an empty `ContainerModule` with a TODO comment listing brain sync / MCP registry / session management / realm discovery.
- Standalone `aurelio-backend` (express on :3101) prints a banner and exits — no endpoints.
- README promises: brain sync to CT 208, MCP registry, session management, realm discovery, heterónimo system — none implemented yet.
**Crucial architecture signal for the port:** the `start` script uses `--plugins=local-dir:./AurelioTheia` — i.e. the team is loading the Aurelio code as a **Theia plugin/extension in the plugin host**, *and* there's a separate **standalone `aurelio-backend` express service**. This maps cleanly onto the checklist's "Path C (hybrid)": the heavy/fs/network/MCP work goes in `aurelio-backend` (a normal Node service, can spawn dirac/esptool/git, reach CT 208/125, bind :3101), and the Theia extension contributes UI + calls the backend over HTTP/WS. This is the right shape and de-risks the F-group (hardware) and H-group (dirac/evolution) BLOCK rows: those belong in `aurelio-backend`, not in the browser plugin host.
**Gaps the skeleton hasn't addressed yet (decisions still open from checklist §6):**
- No Theia **preferences schema** ported from the 126 `aurelio.*`/`quarkdown.*` settings.
- No **secret storage** wiring for the keys (and the 3 plaintext-default keys in aurelio-vscode must not be carried over).
- No **webview** host for the Svelte control-center (shared with aurelio-web) — Theia mini-browser is pinned (`@theia/mini-browser 1.56.0`) but unused.
- No **vscode.lm** replacement plan (needed by sessionMemory + magicDocs).
- No **custom editor** strategy for PDF/EPUB.
- No **OTA/update** channel (Theia plugins don't use `vsce`/VSIX; needs a Theia plugin registry or image-baked decision).
- **Theia 1.56.0** (released ~2024) is pinned — verify the VS Code-extension-compat (plugin host) coverage for the specific APIs aurelio uses (webview `asWebviewUri`, `CustomEditorProvider`, `vscode.lm`, `registerWebviewViewProvider`) before assuming Path A works for the C-group webviews.
---
## 3. Concrete edits to the two existing docs (apply on next revision)
- **Feature inventory §1 (headline numbers):** replace with the 0.12.2 column above (66/83/126/6/25/41,781/70/2). Note `engines.vscode ^1.90.0`, publisher `portugalfuturista`, name `aurelio`, displayName "Aurelio — Réplica Omnisciente".
- **Models (B-group):** drop **B9 Jules** (removed). Add `kimiProvider.ts` multi-mode (direct/code/hermes) + the 4 `aurelio.kimi.*` settings. Flag that the documented `glm`/`claude` `ModelType`s from `nervura-electrica` are **not** present in this checkout — confirm whether they land on a branch or were planned-but-reverted.
- **vscode.lm (B15/D12):** now **2 consumers** — add `src/context/magicDocs.ts` to the reroute list alongside `sessionMemory.ts`.
- **CT targets:** the migration from CT 206 → CT 208 (`192.168.0.125`) is done in code; the 13 pf hosts list is unchanged but `192.168.0.125` now leads (6 refs). Update brain/sync target references.
- **Frontend split:** add a note that the Svelte control-center is **shared with the `aurelio-web` repo** (separate from the React portal). The Theia cockpit must consume that shared Svelte build, not a private copy.
- **Context/memory (D-group):** add the three new modules (`consolidationLock`, `sessionMemoryCompact`, `sessionSnapshot`); reinforces backend placement.
- **§6 decision 1 (hosting side):** partially **answered by the skeleton** — team chose **Path C (hybrid)**: Theia plugin host for UI + a standalone `aurelio-backend` (express :3101) for fs/network/MCP/spawn. Update §7 sequencing to put `aurelio-backend` build-out in Wave 1.
- **New section needed (in either doc):** "State of the Theia fork" = §2 above (1.56.0, skeleton, 5 stub commands, empty backend, open gaps).
## 4. Repro commands (read-only)
```bash
# LAN clone (works from this host; direct ssh to code.* does not)
git clone ssh://git@192.168.0.9:2222/portugalfuturista/aurelio-vscode.git
git clone ssh://git@192.168.0.9:2222/portugalfuturista/aurelio-theia.git
# bare repos live in CT 203 docker volume:
# /var/lib/docker/volumes/pf-iot-stack_forgejo-data/_data/git/repositories/portugalfuturista/{aurelio-vscode,aurelio-theia}.git
```

View file

@ -0,0 +1,343 @@
# Aurelio → Eclipse Theia Migration: Feature Inventory
**Source analyzed:** `aurelio-vscode` **v0.12.2 (live `main`, HEAD `b37e9d2`, 2026-06-22)**, cloned read-only from Forgejo on CT 203 (`code.portugalfuturista.org` → `ssh://git@192.168.0.9:2222/portugalfuturista/aurelio-vscode.git`) into `~/portugalfuturista/aurelio-vscode`. The Theia fork is `aurelio-theia` **v0.1.0 (HEAD `f8bed07`, 2026-07-10)** at `~/portugalfuturista/aurelio-theia`. The extension is VS Code-extension-shaped: the entire feature set lives in `package.json` + `src/`. Numbers below are measured from the live clone. (First draft used a `548b2cc6^` v0.12.0 reconstruction — superseded; see `2026-07-10-aurelio-theia-live-delta.md`.)
**Target:** migrate `aurelio.portugalfuturista.org` from code-server + this VS Code extension to a fork of Eclipse Theia.
**Status:** baseline inventory complete. Confirm whether the live extension repo has advanced past v0.12.0 before freezing the porting scope.
---
## 0. The one-paragraph summary
Aurelio is a 51k-LOC VS Code extension that turns the editor into the "central brain" cockpit for the Portugal Futurista fleet: an AI-agent chat with 7 routed model backends, a 16-tab Svelte control center, MCP server orchestration, a Git+Markdown memory/wiki layer, background sync to Proxmox, an evolutionary code loop (MAP-Elites) driven by a bundled Rust binary (`dirac`), and a deep hardware-lab integration (ESP32 fleet, PPK2 power profiler, sigrok logic analyzer, KiCad, SPICE/PSIM, FMU). Almost all of it is implemented against VS Code-only APIs (`vscode.window`, webviews, TreeDataProvider, StatusBarItem, `vscode.commands`) and a 123-key `aurelio.*` settings namespace. Theia has a VS Code-extension compatibility layer, so the *cheapest* migration path is to run the VSIX inside Theia's plugin host and only fork where Theia's compatibility gaps bite (custom editors, webview CSP, native binary spawning, status-bar, and the code-server-specific endpoints). Full rehosting to native Theia extensions is the expensive path.
---
## 1. Surface area at a glance
| Metric | Value |
|---|---|
| Extension version | 0.12.0 |
| `engines.vscode` | `^1.90.0` |
| Activation | `onStartupFinished` (always-on) |
| TS source files | 150 |
| Svelte files | 47 |
| Total `src/` LOC | ~51,127 |
| Declared commands (`package.json`) | 64 |
| Registered commands (extension.ts + modules) | ~79 (64 declared + 15 hidden/internal) |
| Activity-bar views (sidebar) | 6 |
| Webview panels (full editors) | 24 |
| Svelte control-center tabs | 16 |
| Settings keys (`aurelio.*` + `quarkdown.*`) | 123 |
| Keybindings | 2 (Quarkdown only) |
| Custom editors | 1 (`aurelio.pdfViewer` for `*.pdf`/`*.epub`) |
| Contributed languages/grammars | `quarkdown` (`.qd`) |
| Native binary bundled | `dirac` (Rust, in `native/dirac/`) |
| External services (portugalfuturista.org) | 13 hosts |
### Top-level `src/` modules (by LOC)
| Module | LOC | Role |
|---|---:|---|
| `webview/` | 14,770 | 24 panel hosts + chat + control center |
| `context/` | 3,140 | compaction, auto-dream, away-summary, scouts, session memory, speculation |
| `evolution/` | 2,887 | MAP-Elites evolutionary loop (orchestrator, mutator, sandbox, convergence) |
| `models/` | 2,654 | model router, heterónimos, kimi/jules/vertex clients, idempotency |
| `hardware/` | 2,604 | ESP32, PPK2, sigrok, KiCad, FMI, PSIM bridges |
| `quarkdown/` | 1,939 | embedded `.qd` language server + live preview + PDF export |
| `brain/` | 1,292 | sessions, realms, chronicle, immich, continuity |
| `sync/` | 1,043 | Proxmox brain sync, wiki sync, immich, session export |
| `core/` | 1,036 | native engine (dirac bridge), remote WS server, dirac gRPC client, event bus, service registry |
| `coordinator/` | 1,008 | autonomous worker orchestration, task registry, agent summary |
| `mcp/` | 962 | MCP hub, server manager, registry sync, servers tree |
| `memory/` | 932 | memory index, scan, extraction, types |
| `config/` | 810 | 3-tier config resolver, settings service |
| `_future/` | 748 | **DORMANT** — semantic cache, tool policy, voice (0 importers) |
| `utils/` | 733 | approval gate, aurelio-read, prevent-sleep, toon |
| `test/` | 682 | mocha suite (evolution/* only) |
| `antigravity/` | 562 | antigravity LS bridge + service |
| `gyro/` | 554 | unified Antigravity control (IDE + LSP services) |
| `workflow/` | 526 | workflow manager |
| `electronics/` | 317 | remote EDA client |
| `skills/` | 265 | directory-based skill loader |
| `updater/` | 166 | OTA self-update from firmware store |
---
## 2. Contributes (package.json) — the VS Code contract the Theia fork must satisfy
### 2.1 Activity bar + sidebar views (1 container, 6 views)
Container: `aurelio-sidebar` (icon `resources/aurelio-icon.svg`).
| View id | Type | Backing class |
|---|---|---|
| `aurelio.chatView` | webview view | `ChatPanel` (`src/webview/chatPanel.ts`, 2620 LOC) |
| `aurelio.sessionsView` | tree | `SessionProvider` (`src/brain/sessionProvider.ts`) |
| `aurelio.realmsView` | tree | `RealmProvider` |
| `aurelio.heteronimosView` | tree | `HeteronimoProvider` |
| `aurelio.immichView` | tree | `ImmichProvider` (`src/brain/immichProvider.ts`) |
| `aurelio.chronicleView` | tree | `ChronicleProvider` (`src/brain/chronicleProvider.ts`) |
### 2.2 Commands (64 declared) — grouped by subsystem
**Sessions / sync / wiki**
`aurelio.startSession`, `aurelio.syncPush`, `aurelio.syncPull`, `aurelio.wikiSync`, `aurelio.wikiPush`, `aurelio.wikiPull`, `aurelio.wikiExportSession`, `aurelio.pushSession`, `aurelio.refreshSessions`, `aurelio.deleteSession`, `aurelio.viewSessionHistory`
**Realms / heterónimos**
`aurelio.switchRealm`, `aurelio.refreshRealms`, `aurelio.openHeteronimosMenu`, `aurelio.switchHeteronimo`, `aurelio.refreshHeteronimos`
**Coordinator (autonomous mode)**
`aurelio.coordinator.start`, `aurelio.coordinator.status`, `aurelio.coordinator.finalize`, `aurelio.task`
**Context / memory / speculation**
`aurelio.addContext`, `aurelio.optimizeAgent`, `aurelio.suggestPrompts`, `aurelio.showDiagnosticSummary`, `aurelio.showAgentSummary`, `aurelio.cleanup`, `aurelio.speculation.start`, `aurelio.speculation.accept`, `aurelio.speculation.abort`
**Chat / UI**
`aurelio.openChat`, `aurelio.selectContext`, `aurelio.openControlCenter`, `aurelio.openSettings`, `aurelio.previewArtifact`
**MCP**
`aurelio.syncMcpRegistry`, `aurelio.assignServerToRealm`
**Immich**
`aurelio.importImmichAsset`, `aurelio.openImmichBrowser`, `aurelio.refreshImmich`
**Chronicle**
`aurelio.addChronicleEntry`, `aurelio.refreshChronicle`, `aurelio.openChronicleEntry`
**Hardware / lab dashboards**
`aurelio.openHardwareDashboard`, `aurelio.openHilDashboard`, `aurelio.openPpk2Dashboard`, `aurelio.openEsp32Controller`, `aurelio.openLogicAnalyzer`, `aurelio.openEngineeringHub`
**Electronics / EDA viewers**
`aurelio.openSpiceViewer`, `aurelio.showSpiceResults`, `aurelio.openCoverageDashboard`, `aurelio.loadCoverageFromWorkspace`, `aurelio.openSchematicViewer`, `aurelio.openSourcingDashboard`, `aurelio.openPsimViewer`, `aurelio.openFmuViewer`
**Fleet / finance / portals**
`aurelio.openGuardaLivrosDashboard`, `aurelio.openBolsaDoMundial`, `aurelio.refreshBolsaDoMundial`, `aurelio.placeBolsaOrder`
**Quarkdown**
`quarkdown.startPreview`, `quarkdown.stopPreview`, `quarkdown.restartLanguageServer`, `quarkdown.exportPdf`
**Hidden/registered-but-undeclared (internal wiring, 15):** `aurelio.openPdfViewer`, `aurelio.runSchematicAnalysis`, `aurelio.sourcing.search`, `aurelio.sourcing.findAlternates`, `aurelio.sourcing.optimize`, `aurelio.refreshGuardaLivros`, `aurelio.xgecuDetect`, `aurelio.xgecuRead`, `aurelio.jtagFlash`, `aurelio.ppkStart`, `aurelio.hermesStatus`, `aurelio.openArtifactRaw`, `aurelio.addArtifactComment`, `aurelio.activateSession`, `aurelio.selectSession`.
> Porting note: 9 declared commands are registered by secondary register-functions called from `extension.ts` (`registerCoordinatorCommands`, `registerSpeculativeCommands`, `registerContextCommands`) — none are dead.
### 2.3 Menus
- `view/title` (10 entries): sessions (openChat / refresh / syncPull / syncPush / openControlCenter), realms (refresh), heterónimos (refresh), immich (refresh), chronicle (add / refresh).
- `view/item/context` (2): inline `deleteSession` / `pushSession` on conversation items.
- `editor/title` (2): quarkdown preview/export when `resourceExtname == .qd`.
- `commandPalette` (3): quarkdown gated to `.qd`.
### 2.4 Settings — 123 keys across these namespaces
`aurelio.agent` (17), `aurelio.antigravity` (11), `aurelio.browser` (6), `aurelio.agyIde` (4), `aurelio.agyLsp` (4), `aurelio.endpoints` (4), `aurelio.electronics` (4), `aurelio.jules` (6), `aurelio.hub` (6), `aurelio.hermes` (3), `aurelio.tab` (5), `aurelio.editor` (3), `aurelio.autoDream` (3), `aurelio.contextCompaction` (2), `aurelio.memoryExtraction` (2), `aurelio.notifications` (3), `aurelio.ota` (2), `aurelio.immich` (2), `aurelio.hardware` (1), `aurelio.autoSync` (1), `aurelio.defaultModel` (1), `aurelio.ollamaUrl` (1), `aurelio.openRouterApiKey` (1), `aurelio.activeHeteronimo` (1), `aurelio.activeModelType` (1), `aurelio.approvalGates` (1), `aurelio.controlCenter` (1, enabledPanels object for 16 tabs), `aurelio.customizations.skillPaths`, `aurelio.knowledgeSettings` (1 big object), `aurelio.models` (3), `quarkdown.*` (3).
**Defaults that encode infrastructure (the Theia deployment must preserve or relocate these):**
- `aurelio.endpoints.{eda,mcp,ci,code}``*.portugalfuturista.org`
- `aurelio.antigravity.host` / `agyIde.host``antigravity.portugalfuturista.org:8900`
- `aurelio.agyLsp.host``agy-lsp.portugalfuturista.org:8902`
- `aurelio.electronics.remoteSimUrl``https://eda.portugalfuturista.org`
- `aurelio.hub.{hilBaseUrl,guardaLivrosBaseUrl,bolsaDoMundialBaseUrl}``hil.` / `api.portugalfuturista.org`
- `aurelio.hermes.endpoint``http://192.168.0.105:8200` (AORUS PRO Hermes 3)
- `aurelio.ollamaUrl``http://127.0.0.1:11434`
- `aurelio.ota.endpoint``https://firmware.portugalfuturista.org/extensions/aurelio/version.json`
- `aurelio.hardware.esp32Devices` → SaveEarth-01/02 at `192.168.0.54/55`
- ⚠️ **Hard-coded secrets in defaults:** `aurelio.antigravity.apiKey`, `aurelio.agyIde.apiKey`, `aurelio.agyLsp.apiKey` all default to the same 64-hex token. These are baked into the extension manifest and must be rotated/moved to secret storage during the Theia port — do not carry them as plaintext defaults.
### 2.5 Custom editor + language
- `aurelio.pdfViewer` (`PdfCustomEditorProvider` + `PdfViewerPanel`) for `*.pdf`/`*.epub` — uses `pdfjs-dist`, Svelte viewer. This is the one `CustomEditorProvider`; Theia's VS Code-compat custom-editor support is historically incomplete → likely porting hotspot.
- Language `quarkdown` (`.qd`) + grammar (`syntaxes/`) + `language-configuration.json` + embedded LSP (`src/quarkdown/`).
---
## 3. Feature inventory by subsystem
### 3.1 Chat + model routing (`webview/chatPanel.ts` 2620 LOC, `models/`)
- **Chat webview** with streaming tokens, tool-call start/end events, pending-message queue, review-changes diff flow, slash-command palette, copy/insert code, attach context, model/heterónimo pickers.
- **Slash commands:** `/local /hermes /vertex /openrouter /antigravity /kimi /jules /run /workflow`.
- **ModelRouter** backends (`ModelType`): `local` (Ollama `/api/tags` + generate), `hermes` (Nous Hermes 3 at 192.168.0.105:8200), `vertex` (Gemini via `VertexAuthProvider` / google-auth-library), `openrouter`, `antigravity` (extension-to-extension delegation), `kimi` (Moonshot), `jules` (Google Jules SDK). Fallback chain: `local → hermes → vertex → openrouter → antigravity`. Streaming supported for local/openrouter/vertex/antigravity/hermes/jules; Kimi falls through to non-streaming.
- **Heterónimos** (`HeteronimoManager`): markdown-frontmatter personas with `capabilities[]`, `preferredModel`; per-persona memory; switchable active persona; auto-routes model from `preferredModel` (google→vertex, `/`→openrouter, kimi→kimi).
- **IdempotencyLayer** for safe retries.
- **ApprovalGate** (`utils/approvalGate.ts`): command/terminal approval with `alwaysAllow/alwaysDeny/alwaysAsk` lists, `agent.reviewPolicy`, `agent.terminalAutoExecution`, sandbox toggle. Surfaced into chat + control center as `approvalRequested`/`approvalResolved`.
### 3.2 Control Center (`webview/controlCenterPanel.ts` 3229 LOC, Svelte)
Single webview hosting 16 tabs (App.svelte), ~95 message `case` handlers in the host. Tabs (pt-PT labels):
| id | label | Backing |
|---|---|---|
| bussola | Bússola | dashboard/orchestration |
| conversa | Conversa | chat (ChatTab) |
| motores | Motores | MCP servers (McpTab) |
| antigravidade | Antigravidade | Antigravity remote IDE control |
| arquivo | Arquivo de Orpheu | knowledge (annas-archive/arxiv/libgen/obsidian/calibre/zotero) |
| oficina | Oficina Sensacionista | school / Socratic "grill-me" learning |
| paineis | Painéis | dashboards launcher |
| pericias | Perícias | skills |
| sessoes | Sessões | sessions |
| cronicas | Crónicas | chronicle |
| frota | Frota | fleet analytics |
| processos | Processos | workflows |
| electronica | Electrónica | EDA/sourcing/SPICE |
| laboratorio | Laboratório | hardware lab |
| impressoras | Impressoras | 3D printers |
| engrenagens | Engrenagens | settings (10 sections) |
Host message groups: MCP (reconnect/connectAll/ping/saveConfig/toggle/call/addRecommended/setServerRealms), knowledge (sync/open/extract/ingestObsidian/ingestData/query/syncGoogleKeep/optimizeVault), electronics (search/getDetail/alternates/optimizeBom/runSpice/runErc/extractBom/analyzePower/scanProjects/getDatasheet/validateReplacement/convertToSpice), fleet/finance/forecasting, escola (addSource/chat/action/newSession/list/cite/grill-me/study-guide/save/export/share), antigravity (connect/grpcConnect/disconnect/screenshot/screencast/sendPrompt/quickAction/toggleAutoAccept), agyIde (mirror set), agyLsp (connect/listTools/executeTool/quota/sendPrompt), vertex (health/listModels/infer), jules (status/dispatch/cancel/history/listSessions/resume), wiki (sync/push/pull/export/status), approval (resolve), workflows, settings save, brain sync-now.
**Settings UI** (`settings-svelte`, 10 sections): Agente, Conta, Editor, Modelos, Navegador, Notificações, Personalizações, Reinos, Separador, Wiki.
### 3.3 Brain / sessions / realms (`brain/`, `sync/`)
- **BrainManager**: reads sessions from the 3-tier brain dir + fallback dirs (`~/.gemini/antigravity/brain`, `~/.kimi/sessions`); lists/deletes conversations; per-session artifacts + comments.
- **SessionProvider/RealmProvider/HeteronimoProvider**: tree views with inline delete/push.
- **SessionContinuityService**: captures editor state on `onDidChangeActiveTextEditor`.
- **ChronicleManager/Provider**: dated chronicle entries.
- **ImmichProvider/ImmichClient**: photo browsing + import from an Immich instance (`photos.portugalfuturista.org`).
- **ProxmoxSync**: HTTP push/pull/list against `aurelio.syncEndpoint` (default `https://mcp.portugalfuturista.org`, paths `/api/brain/{push,pull,list}`); **background loop every `sync.interval_seconds` (default 300s)** pushes all brain dirs + fallbacks.
- **WikiSync**: Git-backed sync to the sibling `olivrododesassossego` repo (auto-discovered as workspace folder / sibling / common parent); push/pull/export-session/status.
- **SessionExporter**: JSONL/JSON session persistence.
### 3.4 Context / memory (`context/`, `memory/`)
- **Compactor**: token-aware auto-compaction (threshold 0.85, max 128k).
- **AutoDream**: background memory consolidation (minHours 24, minSessions 5).
- **AwaySummaryManager**: recap on `onDidChangeWindowState` return.
- **SessionMemoryService** (+ `sessionMemory/` prompts/utils/types): per-session memory extraction.
- **MagicDocsService**: auto-updating docs.
- **PromptSuggestionService** + **ContextScout/ExternalScout**: prompt suggestions, repo + web scouting.
- **LSPClientService** (`vscode-languageclient`).
- **SpeculativeEngine** (+ speculativeCommands/speculativeFileSystem): speculative edit apply/accept/abort.
- **memory/**: frontmatter-typed memory files, index, scan, search, throttled extraction.
### 3.5 Coordinator + workflows + skills + evolution
- **Coordinator** (`coordinator/`): autonomous worker orchestration ported from claude-code coordinatorMode; phases driven over ModelRouter; `taskRegistry`, `agentSummary`, `autonomousBrain`.
- **WorkflowManager** (`workflow/`): named workflows registered as commands.
- **SkillLoader** (`skills/`): directory-based skills across global→workspace→realm cascade, registers dynamic commands.
- **EvolutionOrchestrator** (`evolution/`): MAP-Elites population loop backed by the dirac Rust engine; mutate→evaluate→insert on a timer; convergence detector; sandbox; mutator; file snapshots. **Only subsystem with tests** (`test/suite/evolution/*`).
### 3.6 Native engine + remote server + dirac (`core/`)
- **NativeEngine**: spawns bundled `native/dirac/target/release/dirac` (Rust); JSON-lines over stdio; respawn budget; exposes scan/search/index/toon/tokenizer/evolve + eval gates. Pure-TS fallbacks exist (`memoryScan.ts`, `toon.ts`). The dirac crate vendors a large set of `exa.*.proto` (Antigravity-derived) definitions.
- **RemoteServer**: HTTP + WebSocket server on port 34567 (default) for external control, gated by ApprovalGate.
- **DiracClient**: gRPC/self-hosted LS client, OAuth token injection, auto-discovery.
- **EventBus**, **ServiceRegistry**, **ConfigManager**.
### 3.7 MCP (`mcp/`)
- **McpHub**: `@modelcontextprotocol/sdk` client; **SSE** (`SSEClientTransport` for `url/serverUrl/sseUrl`) and **stdio** (`StdioClientTransport`) transports; reconnect backoff; per-tool enable/disable.
- **McpServerManager**: lifecycle, health, realm assignment.
- **McpRegistrySync**: pulls a registry of recommended servers; "add recommended" flow.
- **mcpServersProvider**: tree.
> All MCP servers in this deployment are remote (`mcp-remote` to `*.portugalfuturista.org`) per the workspace AGENTS.md — SSE is the dominant transport.
### 3.8 Hardware / lab (`hardware/`, `electronics/`, webview panels)
- **Esp32Bridge**: spawns `python3 -m esptool`; scans `/dev/ttyUSB*`/`/dev/ttyACM*`; fleet of SaveEarth devices.
- **PPK2Bridge**: spawns python3 to drive Nordic PPK2 power profiler (battery lab).
- **SigrokBridge**: spawns `sigrok-cli` for logic-analyzer capture/decode → CSV.
- **KiCadBridge**: project/net/DRC parsing.
- **FmiBridge**: FMU co-simulation (Reference-FMUs), `execFile`-based.
- **PsimBridge**: spawns PSIM/ngspice/LTspice.
- **remoteEdaClient** (`electronics/`): offloads to `https://eda.portugalfuturista.org` (`/sim/{spice,erc,power-rails,parse,convert,bom,bom/optimize}`) — CT 203 → Docker `pf-eda-sim:8090`.
- Webview dashboards: hardware, HIL, PPK2, ESP32 controller, logic analyzer, schematic, sourcing, coverage, SPICE, PSIM, FMU, engineering hub, guarda-livros (accounting), bolsa-do-mundial (fantasy market), immich browser.
### 3.9 Antigravity / Gyro (`antigravity/`, `gyro/`)
Remote control of an Antigravity IDE instance (CT 212 `pf-antigravity`) via CDP bridge REST + gRPC + a self-hosted language server: connect, screenshots, screencast start/stop, send prompt, quick actions, auto-accept toggle, OAuth token injection, quota, LSP tool list/execute. Two near-duplicate stacks: `antigravity/` (older) and `gyro/` (unified AgyIdeService + AgyLspService) — both wired into the control center.
### 3.10 Quarkdown (`quarkdown/`)
Embedded language (`*.qd`) with its own LSP client, process manager, live-preview webview, HTTP poller, and PDF export. Based on github.com/iamgio/quarkdown (vendored as source, not submodule). Contributes the only keybindings (`shift+ctrl+v` preview, `ctrl+alt+p` export) and the only language/grammar.
### 3.11 OTA updater (`updater/otaUpdater.ts`)
Polls `aurelio.ota.endpoint` (`firmware.portugalfuturista.org/extensions/aurelio/version.json`) for new VSIX; self-update flow. CI (`.github/workflows/build.yml`) packages with `vsce` and SCPs VSIX + `version.json` to CT 205 (`192.168.0.15:/var/www/firmware/extensions/aurelio/`). **This update channel is VS Code-specific and must be redesigned for Theia** (Theia plugins are deployed into the plugin host, not via `vsce`/VSIX OTA in the same way).
### 3.12 Dormant / postponed (`src/_future/`)
`semanticCache.ts`, `toolPolicy.ts`, `voiceKeyterms.ts`, `voiceStreamSTT.ts`, `voice.ts`**zero importers anywhere in `src/`**. Per the user's standing convention, treat as intentionally-postponed (not dead): keep, label, and carry a resume note rather than deleting. They are Phase 9.1 semantic cache, L-4 tool-calling policy, and voice/STT.
---
## 4. External integration map (what the Theia fork must still reach)
13 `*.portugalfuturista.org` hosts referenced from `src/`:
`agy-lsp`, `antigravity`, `api`, `ci`, `code`, `eda`, `hil`, `lab-gw`, `mcp`, `photos`, `portal`, `ssh`, `firmware` (OTA, from settings), plus LAN `192.168.0.105` (Hermes), `192.168.0.54/55` (ESP32), CT 205 firmware store (`192.168.0.15`), CT 203 EDA, CT 212 antigravity, CT 208 Gabinete/brain, CT 206 lab gateway.
Local processes spawned: `dirac` (bundled Rust), `python3 -m esptool`, `python3` (PPK2), `sigrok-cli`, `ngspice`/`ltspice`/`psim`, `quarkdown` (LSP), `gcloud` (vertex auth), `git` (wiki), `ollama` (HTTP). Browser via CDP (`cdpPort` 9222).
**Implication for a Theia fork running in a browser:** anything that spawns a local process or touches `/dev/tty*` (ESP32/PPK2/sigrok/PSIM/quarkdown LSP/dirac) cannot run in the browser front-end; it must run in the Theia **back-end** (Node) or be proxied through the lab gateway (CT 206 / `lab-gw.portugalfuturista.org`) and the existing MCP/EDA services. The hardware bridges are already partly split (EDA is remote; serial devices are local) — the cleanest Theia design moves all device I/O behind the lab gateway and keeps the front-end pure.
---
## 5. Migration paths
### Path A — Run the VSIX as-is inside Theia's VS Code extension host (cheapest)
Theia ships a VS Code API compatibility layer (`@theia/plugin-ext`). Realistic effort: days-to-weeks. Likely gaps to verify against Theia's current compat surface:
- `CustomEditorProvider` (PDF viewer) — historically partial.
- Webview CSP / `asWebviewUri`, Svelte bundles, message passing — usually works but CSP strictness differs.
- `vscode.window.createStatusBarItem`, `registerWebviewViewProvider`, `TreeDataProvider` — supported.
- Spawning the bundled `dirac` binary and `python3`/`sigrok-cli` from the extension host — works only if the plugin runs back-end side; browser-hosted plugins cannot spawn.
- `vscode-languageclient` (Quarkdown LSP) — supported.
- OTA self-update via VSIX — does not map to Theia's plugin deployment; replace.
### Path B — Rehost as native Theia extensions/plugins (expensive, clean)
Rewrite the 24 webviews + 6 tree views + 64 commands against Theia's `theia` plugin API or as Theia extensions (`@theia/core`). Effort: weeks-to-months. Only worth it for the pieces where Path A breaks or where you want native Theia theming/layout.
### Path C — Hybrid (recommended)
1. Stand up the Theia fork, enable the VS Code plugin host, drop in `aurelio-0.12.0.vsix`, and smoke-test every view/command. Keep a gap list.
2. Move all local-process spawns (dirac, esptool, PPK2, sigrok, SPICE, quarkdown LSP) behind the back-end or lab gateway; front-end talks HTTP/WS/MCP only.
3. Replace the OTA/VSIX channel with Theia's plugin deployment (build into the image or Theia's plugin registry).
4. Rotate the three baked-in API keys out of `package.json` defaults into Theia secret storage / env.
5. Re-implement the PDF custom editor as a Theia widget if the compat layer can't host it.
6. Port only the hotspot panels to native Theia widgets as needed.
---
## 6. Verification done for this inventory
- Reconstructed full source tree (427 files) from git object `548b2cc6^` via `git archive`.
- Parsed `package.json` programmatically: commands/views/menus/config/keybindings/customEditors/languages.
- Cross-checked declared vs registered commands (64 declared, ~79 registered incl. 15 internal; the 9 "declared-not-in-extension.ts" are registered by secondary register-functions — confirmed live).
- Confirmed `_future/` has 0 importers (dormant).
- Read top-of-file doc comments for every major module to confirm purpose.
- Grep'd for all `*.portugalfuturista.org` hosts, LAN IPs, spawn/execFile sites, transports, and the OTA/CI deploy path.
**Not done (needs live repo / network):** confirm whether the extracted independent `aurelio-vscode` repo has advanced past v0.12.0 since 2026-06-21; confirm current Theia VS Code-compat coverage for `CustomEditorProvider` and webview CSP; confirm which hosts are reachable from the Theia back-end network namespace.
---
## 7. File list (reconstructed baseline, `/tmp/aurelio-vscode-0.12.0/`)
Key entry points and the largest files to port first:
- `src/extension.ts` (1626 LOC) — activation, registers everything, background sync loop, status bars.
- `src/webview/controlCenterPanel.ts` (3229) — 16-tab cockpit host (~95 message handlers).
- `src/webview/chatPanel.ts` (2620) — chat + slash commands + streaming + tool/approval flow.
- `src/models/modelRouter.ts` — 7-backend routing + fallback chain.
- `src/core/nativeEngine.ts` — dirac spawn + respawn + eval gates.
- `src/core/remoteServer.ts` — WS control server :34567.
- `src/mcp/mcpHub.ts`, `src/mcp/McpServerManager.ts`, `src/mcp/mcpRegistrySync.ts` — MCP SSE/stdio.
- `src/sync/proxmoxSync.ts`, `src/sync/wikiSync.ts` — brain + wiki sync.
- `src/hardware/*.ts` (6 bridges) + `src/electronics/remoteEdaClient.ts`.
- `src/evolution/*.ts` (7 files, only tested subsystem).
- `src/quarkdown/*` — embedded language + LSP + preview + PDF.
- `package.json` — 123 settings, 64 commands, 6 views, 1 custom editor, 1 language.
---
## 8. Open questions before freezing scope
1. Path to the live `aurelio-vscode` independent repo (post-extraction) — is v0.12.0 still current, or has it moved on?
2. Theia version target for the fork, and whether plugins run in the Node back-end or browser front-end (decides where dirac/serial/LSP can live).
3. Whether `aurelio.portugalfuturista.org` today is plain code-server serving this VSIX, and which of the 13 backends are reachable from the new Theia host's network.
4. Keep Quarkdown + the hardware-lab panels in scope for v1 of the Theia fork, or stage them?

View file

@ -0,0 +1,226 @@
# Aurelio → Theia: Per-Feature Porting Checklist
Companion to `2026-07-10-aurelio-theia-migration-feature-inventory.md`. Baseline: `aurelio-vscode` **v0.12.2 (live `main`, `b37e9d2`)** cloned to `~/portugalfuturista/aurelio-vscode`; Theia fork `aurelio-theia` **v0.1.0 (`f8bed07`)** at `~/portugalfuturista/aurelio-theia`. See `2026-07-10-aurelio-theia-live-delta.md` for the measured numbers and the skeleton's current state. Risk ratings below remain static-analysis estimates pending the Wave 0 spike.
**How to read this:** one row per feature, with the VS Code API it leans on, the Theia target, a risk rating, a recommended path (A = run VSIX in Theia's VS Code plugin host, B = native Theia rewrite, C = hybrid), a porting owner, and a definition-of-done. Risk = chance the VS Code-compat layer can't host it unchanged.
| Risk | Meaning |
|---|---|
| LOW | Theia's `@theia/plugin-ext` covers it; expect config-only changes. |
| MED | Covered but with known caveats (CSP, lifecycle, messaging); needs testing + minor shim. |
| HIGH | Incomplete/unsupported in compat layer, or depends on local process/serial; needs backend move or rewrite. |
| BLOCK | Cannot work in a browser-hosted plugin at all — must move to backend/gateway. |
**Global findings that color every row below**
- Extension uses ~55 distinct `vscode.*` surfaces; heaviest: `vscode.window` (418 hits), `vscode.commands` (133), `vscode.workspace` (132), `vscode.Uri` (116), webview `postMessage` (361 references across 25 webview sites).
- Node built-ins (`fs`/`child_process`/`http`/`os`/`crypto`/`ws`) are imported in **46 source files**. Anything in that set that runs in a browser-hosted Theia plugin breaks; it must run in the Theia **backend** or be proxied.
- Local-process spawns: `dirac` (bundled Rust), `python3 -m esptool`, `python3` (PPK2), `sigrok-cli`, `ngspice/ltspice/psim`, `quarkdown` LSP, `gcloud`, `git`, `ollama` (HTTP). Plus CDP browser on :9222.
- 3 API keys are plaintext defaults in `package.json` (antigravity / agyIde / agyLsp) — rotate to secret storage, do not port as-is.
- `src/_future/*` (semantic cache, tool policy, voice) = 0 importers → intentionally dormant; carry, label, do not port in v1.
---
## A. Shell, activation, settings, commands, views
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| A1 | Activation + lifecycle (`onStartupFinished`) | `extension.ts` (1626) | `ExtensionContext`, `subscriptions`, `setInterval` bg loop | `@theia/plugin-ext` activation events | LOW | A | Platform | Extension activates on Theia startup; background sync loop runs; dispose cleans timers |
| A2 | 3-tier config cascade (global→workspace→realm) | `config/configResolver.ts` (810), `settingsService.ts` | `vscode.workspace.getConfiguration`, `ConfigurationTarget`, `fs` reads of `~/.aurelio`, `.aurelio/`, `realms/*/.aurelio` | Theia preferences + `fs` (backend) | MED | C (A shim for prefs; B for cascade files) | Platform | All 123 keys resolve with correct precedence; realm overrides win |
| A3 | 123 settings keys (`aurelio.*`, `quarkdown.*`) | `package.json` | `contributes.configuration` | Theia preference schema | LOW | A (schema auto-mapped) | Platform | Settings UI shows all keys; defaults preserved except 3 rotated keys |
| A4 | 64 declared commands + palette | `extension.ts`, `coordinator/coordinator.ts`, `context/speculation/*`, `context/contextCommands.ts`, `quarkdown/extension.ts` | `vscode.commands.registerCommand`, `menus.commandPalette` | `@theia/plugin` CommandRegistry | LOW | A | Platform | Every command appears in palette and executes; `when` clauses honored |
| A5 | Activity-bar container + 6 sidebar views | `package.json`, `brain/sessionProvider.ts`, `brain/chronicleProvider.ts`, `brain/immichProvider.ts` | `viewsContainers`, `TreeDataProvider`, `registerWebviewViewProvider` | Theia view containers + tree + webview view | LOW | A | Frontend | All 6 views render; refresh/inline actions work |
| A6 | Status bar items (context + Hermes) | `extension.ts:323-334` | `createStatusBarItem`, `StatusBarAlignment` | Theia status bar | LOW | A | Frontend | Both items show, click commands fire |
| A7 | Keybindings (Quarkdown) | `package.json` | `contributes.keybindings` | Theia keybindings | LOW | A | Platform | `shift+ctrl+v` / `ctrl+alt+p` trigger on `.qd` |
| A8 | `when`-clause contexts | package.json menus | `setContext`, `viewItem ==` | Theia context keys | MED | A (verify parity) | Platform | Contextual menus show/hide correctly |
| A9 | Output channels / diagnostics / progress | several | `OutputChannel`, `ProgressLocation`, `DiagnosticSeverity` | Theia output + problems + progress | LOW | A | Frontend | Logs stream; progress notifications appear |
---
## B. Chat, model routing, agent policy
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| B1 | Chat webview (streaming, tool calls, queue) | `webview/chatPanel.ts` (2620) | `WebviewPanel`, `postMessage`/`onDidReceiveMessage`, CSP, `asWebviewUri` | Theia webview (compat) | MED | A (verify CSP) | Frontend | Streaming tokens render, tool-call UI pauses/resumes, pending queue drains |
| B2 | Slash-command palette | `chatPanel.ts:806-825` | webview DOM | same webview | LOW | A | Frontend | `/local /hermes /vertex /openrouter /antigravity /kimi /jules /run /workflow` route |
| B3 | ModelRouter (7 backends + fallback) | `models/modelRouter.ts` (470) | `fetch` (Ollama/OpenRouter/Hermes), `google-auth-library` (Vertex), SDKs (Kimi/Jules) | backend Node service (network) | MED | C | Models | Each backend returns a completion; fallback chain `local→hermes→vertex→openrouter→antigravity` works; streaming where supported |
| B4 | Ollama (local) | `modelRouter.ts:92-106` | `fetch http://127.0.0.1:11434` | backend fetch to host Ollama | LOW | A/C | Models | `/api/tags` + generate reachable from Theia backend |
| B5 | Hermes 3 (LAN 192.168.0.105:8200) | `modelRouter.ts` | `fetch` | backend fetch | MED | A/C | Models | Reachable from Theia backend net namespace; OpenAI-compatible stream OK |
| B6 | Vertex AI (Gemini) | `models/vertexAuth.ts` | `google-auth-library`, `gcloud` | backend + `gcloud` present | MED | C | Models | Auth via ADC/key; `gemini-2.5-pro` infer works |
| B7 | OpenRouter | `modelRouter.ts` | `fetch` + `aurelio.openRouterApiKey` | backend fetch, key from secret | LOW | A/C | Models | Key moved to secret storage; infer works |
| B8 | Kimi (Moonshot) | `models/kimiClient.ts` | `fetch`/SDK, `fs` | backend | MED | C | Models | Non-streaming infer works; `KIMI_API_KEY` from env/secret |
| B9 | Jules (Google) | `models/julesClient.ts` (SDK) | `@google/jules-sdk` | backend | MED | C | Models | dispatch/cancel/history/resume/list work; `JULES_API_KEY` from secret |
| B10 | Antigravity delegation | `modelRouter.ts` case + `antigravity/*`, `gyro/*` | `fetch` to `antigravity.portugalfuturista.org`, gRPC, CDP | backend + CT 212 | HIGH | C | Models/Infra | Remote IDE reachable; sendPrompt/screenshot/screencast work |
| B11 | Heterónimos (personas + per-persona memory) | `models/heteronimoManager.ts` (170) | `fs` frontmatter parse, `gray-matter` | backend `fs` | MED | C | Models | Personas load from cascade dirs; switch updates active model routing |
| B12 | ApprovalGate (allow/deny/ask, terminal sandbox) | `utils/approvalGate.ts` (733) | `EventEmitter`, `vscode.window` warnings | Theia dialogs + event bus | MED | C | Agent | Risky tool/terminal calls prompt; allow/deny/ask lists honored; `agent.reviewPolicy` enforced |
| B13 | Idempotency layer | `models/idempotencyLayer.ts` | none (pure) | same | LOW | A | Models | Retried requests dedupe |
| B14 | Review-changes diff flow | `chatPanel.ts` | `WorkspaceEdit`, `applyEdit` | Theia workspace edit | MED | A | Agent | Proposed edits preview + apply/undo |
| B15 | `vscode.lm` usage (sessionMemory) | `context/sessionMemory/sessionMemory.ts:253-280` | `vscode.lm.selectChatModels`, `LanguageModelChat.sendRequest` | **No direct Theia equivalent** | HIGH | B (reroute through ModelRouter) | Models | sessionMemory no longer calls `vscode.lm`; uses ModelRouter instead |
> B15 is the single concrete `vscode.lm` consumer — Theia's compat layer does not provide the Language Model API. Must reroute to the internal ModelRouter.
---
## C. Control Center + webviews
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| C1 | Control Center host (16 tabs, ~95 msg cases) | `webview/controlCenterPanel.ts` (3229) | `WebviewPanel`, `retainContextWhenHidden`, `localResourceRoots`, `postMessage` | Theia webview (compat) | MED | A (CSP verify) | Frontend | All 16 tabs mount; tab switch preserves state; message round-trips OK |
| C2 | Svelte bundles (control-center/settings/pdf) | `webview-ui/**` (47 files) | `asWebviewUri`, Vite build to `dist/webviews` | Theia webview static serving | MED | A (build path) | Frontend | Vite outputs served via Theia webview URI; CSP allows the bundled JS |
| C3 | Bússola / Orchestration tabs | `tabs/OrchestrationTab.svelte` | webview | same | LOW | A | Frontend | Dashboard renders; actions dispatch |
| C4 | Motores (MCP) tab | `tabs/McpTab.svelte` + `mcp/*` | webview ↔ MCP hub | same + backend MCP | MED | C | MCP | connect/reconnect/ping/toggle/call/setServerRealms work |
| C5 | Antigravidade tab | `tabs/AntigravityTab.svelte` + `gyro/*`, `antigravity/*` | webview + CDP/gRPC | backend to CT 212 | HIGH | C | Infra | See B10 + G-group |
| C6 | Arquivo de Orpheu (Knowledge) | `tabs/KnowledgeTab.svelte` | webview + annas/arxiv/libgen/obsidian/calibre/zotero | backend for indexers | MED | C | Knowledge | sync/open/extract/ingest/query work; vault paths configurable |
| C7 | Oficina Sensacionista (School) | `tabs/EscolaTab.svelte` + `tabs/escola/*` | webview | same | LOW | A | Frontend | grill-me / study-guide / cite / save / export / share work |
| C8 | Painéis / Dashboards launcher | `tabs/DashboardsTab.svelte` | webview | same | LOW | A | Frontend | Opens each dashboard panel |
| C9 | Perícias (Skills) | `tabs/SkillsTab.svelte` + `skills/skillLoader.ts` | webview + `fs` dir scan | backend dir scan | MED | C | Skills | Skills discovered from cascade dirs; dynamic commands register |
| C10 | Sessões / Crónicas / Frota / Processos | `tabs/{Sessions,Chronicles,Fleet,Workflows}Tab.svelte` | webview | same | LOW | A | Frontend | Lists render; fleet/finance/forecasting handlers return data |
| C11 | Electrónica / Laboratório / Impressoras | `tabs/{Electronics,Lab,Printers}Tab.svelte` | webview + EDA/hardware | backend/gateway | HIGH | C | Hardware | See E-group / F-group |
| C12 | Engrenagens (Settings) | `settings-svelte/*` (10 sections) | webview | same | LOW | A | Frontend | 10 sections edit the 123 keys; save persists to correct tier |
| C13 | Artifact preview / session history / immich browser / chronicle panel | `webview/{artifactPreview,sessionHistoryPanel,immichBrowserPanel,chroniclePanel}.ts` | webview | same | LOWMED | A | Frontend | Each opens + populates |
**Webview cross-cutting risks (apply to all C-rows):** CSP strictness in Theia differs from VS Code — verify `script-src`/`connect-src` for the Svelte bundles and the `*.portugalfuturista.org` fetches; `asWebviewUri` path mapping for `dist/webviews/assets` (pdf.worker); `retainContextWhenHidden` semantics.
---
## D. Brain, sessions, sync, wiki, memory, context
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| D1 | BrainManager (sessions + fallback dirs) | `brain/brainManager.ts` (250) | `fs` of `~/.gemini/antigravity/brain`, `~/.kimi/sessions` | backend `fs` | MED | C | Brain | Lists/deletes conversations across all 3 sources |
| D2 | Session continuity | `brain/sessionContinuity.ts` | `onDidChangeActiveTextEditor`, `fs` | Theia editor events + backend fs | MED | C | Brain | Editor state captured on switch; restored on return |
| D3 | Chronicle | `brain/chronicleManager.ts`, `chronicleProvider.ts` | `fs`, tree | backend `fs` | MED | C | Brain | Add/open/refresh entries persist |
| D4 | Immich | `sync/immichClient.ts`, `brain/immichProvider.ts`, `webview/immichBrowserPanel.ts` (755) | `fetch` to Immich, `fs` import | backend fetch | MED | C | Brain | Browse/import from `photos.portugalfuturista.org`; keys from secret |
| D5 | Proxmox brain sync (push/pull/list + 5-min loop) | `sync/proxmoxSync.ts` (200) | `fetch` to `mcp.portugalfuturista.org/api/brain/*`, `createFileSystemWatcher` | backend fetch + Theia watcher | MED | C | Brain | pushAll/pullAll/list work; background loop interval honored; watcher triggers |
| D6 | Wiki sync (Git-backed) | `sync/wikiSync.ts` (300) | `git` spawn, `fs`, watcher, sibling-repo discovery | backend `git` + `fs` | HIGH | C | Brain | Discovers `olivrododesassossego`; push/pull/export/status; needs `git` in backend image |
| D7 | Session export | `sync/sessionExporter.ts` | `fs` JSONL/JSON | backend `fs` | LOW | A/C | Brain | Sessions serialize to brain dir |
| D8 | Memory index/scan/search/extract | `memory/*` (932) | `fs`, `gray-matter` | backend `fs` | MED | C | Memory | Frontmatter-typed memories index; search works; throttled extraction runs |
| D9 | Compactor | `context/compactor.ts` (260) | tokenizer (dirac or TS fallback) | backend | MED | C | Memory | Auto-compact at 0.85 / 128k |
| D10 | AutoDream | `context/autoDream.ts` (290) | `setInterval`, `fs`, ModelRouter | backend | MED | C | Memory | Consolidation fires after minHours/minSessions |
| D11 | Away summary | `context/awaySummary.ts` | `onDidChangeWindowState` | Theia window-state event | MED | A | Memory | Recap shows on focus return |
| D12 | Session memory service | `context/sessionMemory/*` | `vscode.lm` (see B15), `fs` | backend + ModelRouter | HIGH | C | Memory | Rerouted off `vscode.lm`; per-session memory writes |
| D13 | MagicDocs | `context/magicDocs.ts` | `fs`, watcher | backend | MED | C | Memory | Docs auto-update |
| D14 | ContextScout / ExternalScout / PromptSuggestion | `context/{contextScout,externalScout,promptSuggestion}.ts` | `fs`, `fetch`, `executeWorkspaceSymbolProvider` | backend + Theia symbol providers | MED | C | Memory | Repo + web scouting; prompt suggestions populate |
| D15 | Speculative execution | `context/speculation/*` (engine/fs/commands) | `WorkspaceEdit`, `applyEdit`, speculative FS | Theia workspace edit | MED | C | Agent | start/accept/abort; edits apply+save; rollback clean |
| D16 | LSP client (generic) | `context/lspClient.ts` | `vscode-languageclient`, `WorkspaceEdit` | Theia LSP client | MED | A/C | Platform | Hover/refs/symbols/code-actions route through Theia |
---
## E. MCP
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| E1 | MCP hub (SSE + stdio) | `mcp/mcpHub.ts` (145) | `@modelcontextprotocol/sdk` `SSEClientTransport`/`StdioClientTransport` | backend Node (SSE dominant; stdio only if backend-local) | MED | C | MCP | Remote servers (`*.portugalfuturista.org`) connect via SSE; reconnect backoff works |
| E2 | Server manager + health + realm assignment | `mcp/McpServerManager.ts` (220) | `createFileSystemWatcher` of `mcp_config.json`, `fs` | backend | MED | C | MCP | Config watch reloads; per-realm assignment persists |
| E3 | Registry sync + "add recommended" | `mcp/mcpRegistrySync.ts` | `fetch` registry | backend fetch | LOW | A/C | MCP | Registry loads; recommended server installable |
| E4 | Tool enable/disable + call routing | `mcpHub.ts`, `controlCenterPanel.ts` | webview messages | same | LOW | A | MCP | `mcp:call` returns result/error; per-tool toggle persists |
---
## F. Hardware / lab / EDA
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| F1 | ESP32 fleet (esptool) | `hardware/esp32Bridge.ts` (spawns `python3 -m esptool`, scans `/dev/ttyUSB*`) | `child_process.spawn`, serial | **BLOCK in browser** → lab gateway (CT 206) / backend | BLOCK/HIGH | C (move behind `lab-gw`) | Hardware | Device scan/flash/read routed via gateway; no serial from front-end |
| F2 | PPK2 battery lab | `hardware/ppk2Bridge.ts` (python3) + `webview/ppk2Dashboard.ts` | spawn, serial `/dev/ttyACM0` | gateway/backend | BLOCK/HIGH | C | Hardware | Sampling streams via gateway; dashboard charts render |
| F3 | sigrok logic analyzer | `hardware/sigrokBridge.ts` (spawns `sigrok-cli`) + `webview/logicAnalyzerDashboard.ts` | spawn, `execSync` | gateway/backend | BLOCK/HIGH | C | Hardware | Capture/decode → CSV via gateway; viewer plots |
| F4 | KiCad | `hardware/kicadBridge.ts` + `webview/schematicViewer.ts` (604) | `fs`, `createFileSystemWatcher`, `execFile` | backend `fs` (+ `.kicad` CLI if used) | HIGH | C | Hardware | Project/net/DRC parse; schematic viewer renders; watcher works |
| F5 | FMU co-sim | `hardware/fmiBridge.ts` + `webview/fmuViewer.ts` (434) | `execFile` (Reference-FMUs) | backend | HIGH | C | Hardware | FMU loads + steps via backend; plots render |
| F6 | PSIM / SPICE (ngspice/ltspice) | `hardware/psimBridge.ts` + `webview/{psimViewer,spiceViewer}.ts` | spawn sims | backend/gateway (or remote EDA) | HIGH | C | Hardware | Sim runs server-side; waveforms stream/plot |
| F7 | Remote EDA offload | `electronics/remoteEdaClient.ts` (317) | `fetch https://eda.portugalfuturista.org` | backend fetch | LOW | A/C | Hardware | `/sim/{spice,erc,power-rails,parse,convert,bom,bom/optimize}` reachable; token from secret |
| F8 | Engineering hub + hardware + HIL dashboards | `webview/{engineeringHub,hardwareDashboard,hilDashboard}.ts` | webview + `hil.portugalfuturista.org` | webview + backend | MED | C | Hardware | HUB launches; HIL logs fetch via backend |
| F9 | Sourcing / coverage / guarda-livros / bolsa dashboards | `webview/{sourcingDashboard,coverageDashboard,guardaLivrosDashboard,bolsaDoMundial}.ts` | webview + `api.portugalfuturista.org` | webview + backend fetch | MED | C | Hardware/Portal | Search/alternates/optimize, coverage load, accounting sync, fantasy-market orders route via backend |
> F-group is the highest-risk cluster: serial/local-process bridges cannot run in a browser-hosted Theia plugin. Decision needed (section 6): full gateway proxy vs. backend-local vs. drop from v1.
---
## G. Antigravity / Gyro (remote IDE control)
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| G1 | AgyIde (CDP bridge REST) | `gyro/agyIdeService.ts` | `fetch` to `antigravity.portugalfuturista.org:8900` | backend → CT 212 | HIGH | C | Infra | connect/screenshot/screencast/sendPrompt/quickAction/autoAccept work |
| G2 | AgyLsp (self-hosted LS) | `gyro/agyLspService.ts`, `antigravity/antigravityLsBridge.ts` | `fetch` to `agy-lsp.portugalfuturista.org:8902`, `fs` | backend | HIGH | C | Infra | listTools/executeTool/quota/sendPrompt work |
| G3 | gRPC + OAuth injection | `core/diracClient.ts:135-150` | gRPC, `fetch` token inject | backend | HIGH | C | Infra | startSelfHosted + injectOAuthToken succeed; TLS toggle honored |
| G4 | Dedup legacy `antigravity/` vs `gyro/` | both dirs | — | consolidate to `gyro/` | MED | B | Models | Single Antigravity stack; control center uses one service |
> The two near-duplicate Antigravity stacks (`antigravity/` 562 LOC, `gyro/` 554 LOC) are both wired. Porting is the right moment to consolidate to one.
---
## H. Coordinator, workflows, skills, evolution, native engine
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| H1 | Coordinator (autonomous workers) | `coordinator/*` (1008) | `registerCommand`, ModelRouter, `fs` | backend | MED | C | Agent | start/status/finalize/task run; worker dispatch via ModelRouter |
| H2 | Workflows | `workflow/workflowManager.ts` (526) | `registerCommands`, `fs` | backend | LOW | A/C | Agent | Named workflows register + execute |
| H3 | Skills (dir-based, cascade) | `skills/skillLoader.ts` (265) | `fs` dir scan, dynamic `registerCommand` | backend `fs` + Theia commands | MED | C | Skills | Skills load from global→workspace→realm; dynamic commands register |
| H4 | Evolution loop (MAP-Elites) | `evolution/*` (2887) | dirac `NativeEngine`, `setInterval`, `fs` (sandbox/snapshots) | backend + dirac | HIGH | C | Evolution | mutate→evaluate→insert runs; convergence detected; **the only tested subsystem — keep its mocha suite green under Theia** |
| H5 | NativeEngine (dirac spawn + respawn) | `core/nativeEngine.ts` (520) | `child_process.spawn` of `native/dirac/target/release/dirac`, JSON-lines stdio, respawn budget | backend Node (binary must ship in Theia backend image) | HIGH/BLOCK | C | Evolution/Platform | dirac binary present for target arch; spawn + JSON-lines + respawn work; TS fallbacks engage if absent |
| H6 | Remote control WS server (:34567) | `core/remoteServer.ts` (100) | `http.createServer` + `ws` + ApprovalGate | backend HTTP/WS | HIGH | C | Platform | Server binds backend-side; external clients connect; ApprovalGate enforced |
| H7 | DiracClient gRPC | `core/diracClient.ts` (150) | gRPC self-hosted | backend | HIGH | C | Platform | compile_ast/evolve/ag.* requests route |
---
## I. Quarkdown (embedded language)
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| I1 | Language + grammar + config | `syntaxes/`, `language-configuration.json`, `package.json` | `contributes.languages/grammars` | Theia languages/textmate | LOW | A | Quarkdown | `.qd` files highlight + bracket config |
| I2 | LSP client (vscode-languageclient/node) | `quarkdown/client.ts` | `LanguageClient` (node), `documentSelector`, `fileEvents` watcher | Theia LSP client | MED | A/C | Quarkdown | Diagnostics/completion for `.qd` |
| I3 | LSP server process | `quarkdown/core/{quarkdownServer,processManager}.ts` | spawn `quarkdown` | backend spawn (needs `quarkdown` in image) | HIGH | C | Quarkdown | Server starts backend-side; restarts on command |
| I4 | Live preview webview | `quarkdown/{previewManager,previewWebview}.ts`, `core/httpPoller.ts` | webview + `http` poller | Theia webview + backend poll | MED | C | Quarkdown | `shift+ctrl+v` live preview updates |
| I5 | PDF export | `quarkdown/{pdfExport,core/pdfExportService}.ts` | spawn/export | backend | MED | C | Quarkdown | `ctrl+alt+p` exports PDF |
---
## J. PDF custom editor + OTA + infra glue
| # | Feature | Source (LOC) | VS Code API | Theia target | Risk | Path | Owner | Done when… |
|---|---|---|---|---|---|---|---|---|
| J1 | PDF/EPUB custom editor | `webview/pdfCustomEditorProvider.ts` (`CustomReadonlyEditorProvider`), `pdfViewerPanel.ts` (541), `pdf-viewer-svelte/*`, `pdfjs-dist` | `CustomEditorProvider`, webview, worker | **Theia compat: CustomEditor is historically weak** → native Theia widget | HIGH | B (likely) | Frontend | `*.pdf`/`*.epub` open in a Theia widget with pdf.js; pan/zoom/search work |
| J2 | OTA self-update (VSIX) | `updater/otaUpdater.ts` (166) + CI `.github/workflows/build.yml` | `fetch version.json`, `vsce package`, SCP to CT 205 | **Replace** with Theia plugin deployment (image-baked or Theia plugin registry) | HIGH | B | Platform | Update channel redesigned; no `vsce`/VSIX dependency; version check still works against a Theia-appropriate manifest |
| J3 | Prevent-sleep | `utils/preventSleep.ts` | `fs`/power | backend/no-op in browser | MED | C | Platform | Behavior defined for browser context (likely no-op or backend keepalive) |
| J4 | AurelioRead / Toon utils | `utils/aurelioRead.ts`, `utils/toon.ts` | `fs`, pure TS | backend / same | LOW | A | Platform | Read helper + toon encode/decode work |
---
## K. Secrets, network, packaging (cross-cutting)
| # | Concern | Where | Action | Risk | Owner |
|---|---|---|---|---|---|
| K1 | 3 plaintext API keys in `package.json` defaults (`antigravity.apiKey`, `agyIde.apiKey`, `agyLsp.apiKey`) | manifest | Move to Theia secret storage / env; rotate the shared 64-hex token | HIGH | Platform/Infra |
| K2 | `KIMI_API_KEY`, `JULES_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `aurelio.openRouterApiKey`, `aurelio.hub.apiToken`, `aurelio.electronics.remoteSimToken`, `aurelio.immich.apiKey`, `aurelio.hub.cfClientId/Secret` | settings / `.env` | Inject via backend env + Theia secret store; never ship in image | HIGH | Platform |
| K3 | Backend network reachability to 13 `*.portugalfuturista.org` hosts + LAN `192.168.0.105/.54/.55` | all `fetch`/spawn sites | Confirm Theia backend pod/host can route; document egress | MED | Infra |
| K4 | Native binaries in image (`dirac`, `git`, `python3`+esptool, `sigrok-cli`, `ngspice`/`ltspice`/`psim`, `quarkdown`, `gcloud`) | `native/`, spawns | Decide: bake into Theia backend image vs. proxy via lab gateway | HIGH | Infra |
| K5 | Build system (webpack extension + Vite webviews → `dist/`) | `package.json` scripts, `webpack.config.cjs`, `vite.config.ts` | Keep for Path A; repackage as Theia plugin for B/C | MED | Platform |
| K6 | `@aurelio/shared` (file:../../shared) protobuf dep | `package.json` | Ensure shared lib available to Theia plugin build | MED | Platform |
| K7 | Dormant `_future/` (semantic cache, tool policy, voice) | `src/_future/*` | Carry over labeled POSTPONED; do not port in v1 | LOW | Platform |
---
## 6. Key decision points (need answers before/early in the port)
1. **Plugin hosting side:** do Theia plugins run in the Node backend or the browser frontend on `aurelio.portugalfuturista.org`? This single decision resolves every BLOCK/HIGH row (F-group serial, H5 dirac, H6 WS server, I3 quarkdown LSP).
2. **Hardware scope for v1:** drop the serial/serial-spawn panels (F1F6) from v1, or commit to routing them through `lab-gw.portugalfuturista.org` (CT 206)? EDA (F7) is already remote and LOW-risk.
3. **Custom editor (J1):** accept Theia's CustomEditor compat if it works, or budget a native pdf.js widget now?
4. **OTA (J2):** image-baked plugin vs. Theia plugin registry — pick the deployment mechanism; remove `vsce`.
5. **Antigravity dedup (G4):** consolidate `antigravity/` + `gyro/` to one stack during the port.
6. **`vscode.lm` (B15/D12):** reroute sessionMemory through ModelRouter — confirm no other `vscode.lm` consumers appear in the live repo.
## 7. Suggested sequencing
- **Wave 0 (spike):** stand up Theia fork, enable plugin host, drop in `aurelio-0.12.0.vsix`, smoke-test A/C rows; produce the empirical gap list that upgrades these risk ratings from "estimated" to "measured."
- **Wave 1 (backend spine):** config cascade (A2), secrets (K1/K2), ModelRouter (B3B9), brain+sync+wiki+memory (D-group), MCP (E-group) — all backend, all testable headlessly.
- **Wave 2 (cockpit):** control center + chat webviews (B1/B2, C-group) behind the verified backend spine; fix CSP/`asWebviewUri`.
- **Wave 3 (specialized):** evolution+dirac (H4/H5), Quarkdown (I), PDF (J1), Antigravity (G), OTA redesign (J2).
- **Wave 4 (lab):** hardware/serial (F) behind gateway, per decision point 2.
## 8. Owners legend
Platform = shell/activation/settings/build/deploy · Frontend = webviews/views/widgets · Models = routing/personas/LM · Agent = coordinator/approval/speculation · Brain = sessions/sync/wiki · Memory = context/memory · MCP = MCP · Hardware = lab/EDA · Infra = network/secrets/CT routing · Evolution = dirac/MAP-Elites · Quarkdown · Skills · Knowledge · Portal
---
## 9. Verification status of this checklist
Risk ratings are **estimated from static analysis** of the v0.12.0 source (API grep, node-built-in import map, spawn sites, transports, doc-comments) — not from running against Theia. The Wave 0 spike is required to convert estimates into measured results. Counts (API hits, LOC, file lists) are measured from the reconstructed tree.

View file

@ -0,0 +1,445 @@
# Proxmox New Server Migration — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use compose:subagent (recommended) or compose:execute to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a new mid-range server to the Proxmox cluster and migrate CTs 208, 212, 213, 216 from ASUS to relieve the 55.5 GB overcommit on a 16 GB host.
**Architecture:** Join the new server as a 3rd node in the `portugalfuturi` cluster. Migrate CTs via vzdump backup + restore. Update Cloudflare tunnel routes, MCP registry, sync scripts, and proxy backends to new IPs.
**Tech Stack:** Proxmox VE, Corosync, Cloudflare Tunnel, Python sync scripts, Node.js proxy server
## Global Constraints
- ASUS host: 192.168.0.38 (current primary, must remain operational during migration)
- Gigabyte host: 192.168.0.104 (existing cluster node)
- New server IP: TBD (must be on 192.168.0.x subnet, outside DHCP range)
- All Cloudflare routes use hostnames — only origin IPs change
- Brain sync (`sync.py`) uses `pct push`/`pct pull` via SSH to ASUS — must verify this still works after migration
- CT 208 should be downsized from 8 GB to 2 GB (only uses 72 MB)
---
### Task 1: Pre-migration snapshot and backup
**Covers:** [S4]
**Files:**
- Modify: None (operational commands only)
**Verification:**
- Run: `ssh root@192.168.0.38 "pct list"` — all CTs listed
- Run: `ssh root@192.168.0.38 "vzdump 208 --storage local --compress zstd --dumpdir /tmp/vzdump/"` — backup created
- [ ] **Step 1: Verify current CT state on ASUS**
```bash
ssh root@192.168.0.38 "pct list"
```
Expected: CTs 207, 208, 209, 212, 213, 214, 215, 216, 220 listed as running.
- [ ] **Step 2: Create vzdump backups of CTs to migrate**
```bash
ssh root@192.168.0.38 "mkdir -p /tmp/vzdump && vzdump 208 --storage local --compress zstd --dumpdir /tmp/vzdump/"
ssh root@192.168.0.38 "vzdump 212 --storage local --compress zstd --dumpdir /tmp/vzdump/"
ssh root@192.168.0.38 "vzdump 213 --storage local --compress zstd --dumpdir /tmp/vzdump/"
ssh root@192.168.0.38 "vzdump 216 --storage local --compress zstd --dumpdir /tmp/vzdump/"
```
Expected: 4 `.tar.zst` files in `/tmp/vzdump/` on ASUS.
- [ ] **Step 3: Verify backups exist**
```bash
ssh root@192.168.0.38 "ls -la /tmp/vzdump/"
```
Expected: 4 backup files, each non-empty.
- [ ] **Step 4: Record current service state for rollback reference**
```bash
ssh root@192.168.0.38 "for ct in 208 212 213 216; do echo \"CT \$ct:\"; pct exec \$ct -- systemctl list-units --type=service --state=running --no-pager 2>/dev/null | head -10; echo; done"
```
Expected: List of running services per CT. Save this output for comparison after migration.
---
### Task 2: Install and join new server to cluster
**Covers:** [S3]
**Files:**
- Create: None (Proxmox installer + cluster join)
**Verification:**
- Run: `corosync-cfgtool -s` on any node — shows 3 members
- Run: `pct list` on new node — operational
- [ ] **Step 1: Install Proxmox VE on new server**
Follow standard Proxmox VE installer. Assign static IP (e.g., 192.168.0.40 — verify no conflict first).
```bash
# On ASUS, check for IP conflicts
ssh root@192.168.0.38 "arp-scan --localnet | grep 192.168.0.40"
```
Expected: No response (IP is free).
- [ ] **Step 2: Add new node to cluster**
On the new node, join the existing cluster:
```bash
# On ASUS (existing node), get join info
ssh root@192.168.0.38 "pveam key --master 1"
```
On the new node:
```bash
# Replace <JOIN-info> with output from step above
pvecm add 192.168.0.38 --key <JOIN-info>
```
- [ ] **Step 3: Verify cluster health**
```bash
# On any node
corosync-cfgtool -s
pvecm status
pvecm nodes
```
Expected: 3 nodes listed (ASUS, Gigabyte, new), quorum achieved.
- [ ] **Step 4: Verify new node is ready for CT restore**
```bash
ssh root@<NEW_IP> "pct list && pveam available | head -5"
```
Expected: Empty CT list, storage available.
---
### Task 3: Migrate CTs to new node
**Covers:** [S4]
**Files:**
- None (operational commands)
**Verification:**
- Run: `pct list` on new node — shows CTs 208, 212, 213, 216
- Run: Service health checks on each CT
- [ ] **Step 1: Transfer backups to new node**
```bash
NEW_IP="192.168.0.40" # Replace with actual IP
scp /tmp/vzdump/vzdump-lxc-208-*.tar.zst root@${NEW_IP}:/tmp/
scp /tmp/vzdump/vzdump-lxc-212-*.tar.zst root@${NEW_IP}:/tmp/
scp /tmp/vzdump/vzdump-lxc-213-*.tar.zst root@${NEW_IP}:/tmp/
scp /tmp/vzdump/vzdump-lxc-216-*.tar.zst root@${NEW_IP}:/tmp/
```
- [ ] **Step 2: Restore CT 208 (Gabinete) with downsized RAM**
```bash
ssh root@${NEW_IP} "pct restore 208 /tmp/vzdump-lxc-208-*.tar.zst --memory 2048 --hostname pf-gabinete-dos-heteronimos"
```
Expected: CT 208 created with 2 GB RAM.
- [ ] **Step 3: Restore CT 212 (Antigravity)**
```bash
ssh root@${NEW_IP} "pct restore 212 /tmp/vzdump-lxc-212-*.tar.zst --memory 8192 --hostname pf-antigravity"
```
- [ ] **Step 4: Restore CT 213 (Immich)**
```bash
ssh root@${NEW_IP} "pct restore 213 /tmp/vzdump-lxc-213-*.tar.zst --memory 4096 --hostname pf-immich"
```
- [ ] **Step 5: Restore CT 216 (Management) with downsized RAM**
```bash
ssh root@${NEW_IP} "pct restore 216 /tmp/vzdump-lxc-216-*.tar.zst --memory 4096 --hostname pf-management"
```
- [ ] **Step 6: Start all restored CTs**
```bash
ssh root@${NEW_IP} "pct start 208 && pct start 212 && pct start 213 && pct start 216"
```
- [ ] **Step 7: Verify services on each CT**
```bash
# CT 208 - Gabinete health
ssh root@${NEW_IP} "pct exec 208 -- curl -s http://localhost:18000/api/health"
# CT 216 - Authentik
ssh root@${NEW_IP} "pct exec 216 -- systemctl status authentik --no-pager | head -5"
# CT 212 - Antigravity
ssh root@${NEW_IP} "pct exec 212 -- curl -s http://localhost:8900/ 2>/dev/null | head -1 || echo 'CDP Bridge check needed'"
# CT 213 - Immich
ssh root@${NEW_IP} "pct exec 213 -- curl -s http://localhost:2283/api/server/about 2>/dev/null | head -1 || echo 'Immich check needed'"
```
Expected: CT 208 returns health OK, CT 216 shows authentik active, others respond or are verifiable.
- [ ] **Step 8: Stop migrated CTs on ASUS**
```bash
ssh root@192.168.0.38 "pct stop 208 && pct stop 212 && pct stop 213 && pct stop 216"
```
- [ ] **Step 9: Verify ASUS resource improvement**
```bash
ssh root@192.168.0.38 "free -h && uptime"
```
Expected: RAM usage drops significantly, load decreases.
---
### Task 4: Update Cloudflare tunnel routes
**Covers:** [S5]
**Files:**
- Modify: `nervura-electrica/infrastructure/proxmox/config.yml`
- Modify: `/etc/cloudflared/config.yml` on ASUS (deployed copy)
**Verification:**
- Run: `curl -s https://mcp.portugalfuturista.org/api/health` — returns OK
- Run: `curl -s https://auth.portugalfuturista.org` — returns Authentik page
- [ ] **Step 1: Get new IP assignments for migrated CTs**
```bash
ssh root@${NEW_IP} "pct exec 208 -- hostname -I"
ssh root@${NEW_IP} "pct exec 212 -- hostname -I"
ssh root@${NEW_IP} "pct exec 213 -- hostname -I"
ssh root@${NEW_IP} "pct exec 216 -- hostname -I"
```
Record the IPs. Update the variable below:
```
NEW_CT208_IP=<from step>
NEW_CT212_IP=<from step>
NEW_CT213_IP=<from step>
NEW_CT216_IP=<from step>
```
- [ ] **Step 2: Update config.yml origin IPs**
Edit `nervura-electrica/infrastructure/proxmox/config.yml`:
```yaml
# CT 208 → new node
- hostname: mcp.portugalfuturista.org
service: http://${NEW_CT208_IP}:18000
# CT 212 → new node
- hostname: antigravity.portugalfuturista.org
service: http://${NEW_CT212_IP}:8900
- hostname: antigravity-ws.portugalfuturista.org
service: http://${NEW_CT212_IP}:8901
# CT 213 → new node
- hostname: photos.portugalfuturista.org
service: http://${NEW_CT213_IP}:2283
# CT 216 → new node
- hostname: auth.portugalfuturista.org
service: http://${NEW_CT216_IP}:9000
- hostname: vault.portugalfuturista.org
service: http://${NEW_CT216_IP}:8088
- hostname: scrobbler.portugalfuturista.org
service: http://${NEW_CT216_IP}:9078
- hostname: maloja.portugalfuturista.org
service: http://${NEW_CT216_IP}:42010
```
- [ ] **Step 3: Deploy updated config to Cloudflare tunnel**
```bash
scp nervura-electrica/infrastructure/proxmox/config.yml root@192.168.0.38:/etc/cloudflared/config.yml
ssh root@192.168.0.38 "systemctl restart cloudflared"
```
- [ ] **Step 4: Verify tunnel is healthy**
```bash
ssh root@192.168.0.38 "systemctl status cloudflared --no-pager | head -5"
```
Expected: Active (running).
- [ ] **Step 5: Test critical routes**
```bash
curl -s -o /dev/null -w "%{http_code}" https://mcp.portugalfuturista.org/api/health
curl -s -o /dev/null -w "%{http_code}" https://auth.portugalfuturista.org
curl -s -o /dev/null -w "%{http_code}" https://vault.portugalfuturista.org
curl -s -o /dev/null -w "%{http_code}" https://photos.portugalfuturista.org
```
Expected: All return 200 or 302 (redirect to login).
---
### Task 5: Update MCP registry and sync scripts
**Covers:** [S5]
**Files:**
- Modify: `nervura-electrica/infrastructure/proxmox/services/gabinete/mcp_registry.json`
- Modify: `replica-omnisciente/.aurelio/sync.py` (if CT 208 target changes)
- Modify: `nervura-electrica/infrastructure/proxmox/services/gabinete/deploy_gabinete_208.sh`
**Verification:**
- Run: `curl http://<NEW_CT208_IP>:18000/api/services` — returns spoke list
- Run: `python3 .aurelio/sync.py --push` — completes successfully
- [ ] **Step 1: Update mcp_registry.json spoke URLs**
Edit `nervura-electrica/infrastructure/proxmox/services/gabinete/mcp_registry.json`:
Replace all `192.168.0.125` references with `${NEW_CT208_IP}` (the actual IP from Task 4).
Also update the `savearth-mcp` URL if CT 212 moved (it was on `192.168.0.212`).
- [ ] **Step 2: Update deploy_gabinete_208.sh**
The deploy script uses `pct exec 208` on the Proxmox host. After migration, CT 208 lives on the new node. The script needs to target the new node:
Edit `nervura-electrica/infrastructure/proxmox/services/gabinete/deploy_gabinete_208.sh`:
```bash
# Change PROXMOX_HOST to new node IP
PROXMOX_HOST="${NEW_NODE_IP}" # was 192.168.0.38
```
- [ ] **Step 3: Update sync.py if needed**
Check if `sync.py` hardcodes CT 208 target. If it uses `pct push 208` on ASUS, it needs to either:
- SSH to the new node instead, or
- Use the cluster-aware approach (Proxmox cluster allows `pct` commands on any node for any CT)
```bash
grep -n "208\|pct push\|pct exec" replica-omnisciente/.aurelio/sync.py
```
If `pct push 208` is hardcoded to ASUS, update the SSH target to the new node.
- [ ] **Step 4: Update aurelio-web server.cjs proxy backends**
Edit `nervura-electrica/infrastructure/proxmox/aurelio-web/server.cjs`:
```javascript
// Update GABINETE_URL if CT 208 IP changed
const GABINETE_URL = process.env.GABINETE_URL || 'http://${NEW_CT208_IP}:18000';
```
- [ ] **Step 5: Deploy updated aurelio-web**
```bash
cd nervura-electrica/infrastructure/proxmox
./deploy-aurelio-web.sh
```
- [ ] **Step 6: Test brain sync**
```bash
cd replica-omnisciente
python3 .aurelio/sync.py --push
```
Expected: Sync completes without errors.
---
### Task 6: Post-migration cleanup and documentation
**Covers:** [S6, S7]
**Files:**
- Modify: `nervura-electrica/AGENTS.md` (update CT table, IPs, resource allocation)
**Verification:**
- Run: `ssh root@192.168.0.38 "free -h"` — RAM usage < 4 GB
- Run: All Cloudflare endpoints return expected responses
- [ ] **Step 1: Clean up /tmp on ASUS**
```bash
ssh root@192.168.0.38 "rm -rf /tmp/vzdump/ /tmp/local_brain.tar.gz"
```
- [ ] **Step 2: Remove old CT configs from ASUS (optional, for cleanliness)**
```bash
# Only if CT configs are cluttering; the CTs are stopped, not deleted
ssh root@192.168.0.38 "pct destroy 208 --purge" # Only after verifying migration success
```
Note: Do NOT run this until Task 4 and Task 5 verification passes completely.
- [ ] **Step 3: Update AGENTS.md with new topology**
Edit `nervura-electrica/AGENTS.md`:
- Update CT table: CTs 208, 212, 213, 216 now on new node
- Update resource allocation: ASUS now ~4 GB used
- Add new server to physical infrastructure table
- Update Cloudflare tunnel documentation
- Update deployment commands (deploy scripts target new node)
- [ ] **Step 4: Final verification sweep**
```bash
# Cluster health
corosync-cfgtool -s
pvecm nodes
# ASUS resources
ssh root@192.168.0.38 "free -h && uptime && df -h /"
# All endpoints
for host in mcp auth vault photos antigravity; do
code=$(curl -s -o /dev/null -w "%{http_code}" https://${host}.portugalfuturista.org)
echo "${host}: ${code}"
done
# Brain sync
cd replica-omnisciente && python3 .aurelio/sync.py --push
```
Expected: Cluster healthy, ASUS light, all endpoints responsive, sync works.
- [ ] **Step 5: Commit documentation updates**
```bash
cd nervura-electrica
git add AGENTS.md infrastructure/proxmox/config.yml infrastructure/proxmox/services/gabinete/
git commit -m "ops: migrate CTs 208,212,213,216 to new cluster node
- CT 208 (Gabinete): downsized 8GB → 2GB, moved to new node
- CT 216 (Management): downsized 8GB → 4GB, removed duplicate *arr apps
- Updated Cloudflare tunnel routes to new IPs
- Updated MCP registry spoke URLs
- Updated deploy scripts for new node target"
```

View file

@ -0,0 +1,70 @@
# Spec: New Server Integration — Proxmox Cluster Migration
> Date: 2026-07-10 | Status: Approved | Scope: Proxmox datacenter expansion
## [S1] Problem
The ASUS host (192.168.0.38) is critically overcommitted: 55.5 GB RAM allocated across 14 CTs on 16 GB physical RAM, with swap exhausted and disk 93% full. Four CTs (208, 212, 213, 216) need to migrate to a new mid-range server (16-32 GB RAM) to relieve pressure and improve reliability.
## [S2] Solution overview
Add the new server as a 3rd node in the existing `portugalfuturi` Proxmox cluster. Migrate CTs 208, 212, 213, and 216 via vzdump backup + restore. Update all routing (Cloudflare tunnel, MCP registry, sync scripts, proxy backends) to point to new IPs.
## [S3] Cluster join
- Install Proxmox VE on new hardware
- Join cluster via `pct create` or cluster join command
- Assign static IP on 192.168.0.x subnet
- Corosync rebalances quorum automatically (2→3 nodes)
- Verify cluster health: `corosync-cfgtool -s`
## [S4] CT migration
| CT | Name | Current RAM | Target RAM | Services |
|----|------|-------------|------------|----------|
| 208 | Gabinete/MCP | 8 GB | 2 GB | FastAPI+FastMCP gateway, 14 MCP spokes, model router |
| 212 | Antigravity | 8 GB | 8 GB | Headless VS Code, CDP Bridge |
| 213 | Immich | 4 GB | 4 GB | Photo server (Docker-in-Docker) |
| 216 | Management | 8 GB | 4 GB | Authentik, Vaultwarden, Maloja, Multi-scrobbler |
Migration steps per CT:
1. `vzdump <CTID> --storage local --compress zstd` on ASUS
2. Transfer backup to new node
3. `pct restore <CTID> <backup> --hostname <name> --memory <target>` on new node
4. Start CT, verify services
5. Stop CT on ASUS
Total RAM freed on ASUS: ~24 GB (from 55.5 GB allocated to ~31.5 GB)
## [S5] Route updates
Files requiring IP changes:
| File | Current target | New target |
|------|---------------|------------|
| `nervura-electrica/infrastructure/proxmox/config.yml` | CT IPs on 192.168.0.x | New node IPs |
| `replica-omnisciente/.aurelio/mcp_config.json` | `*.portugalfuturista.org` URLs | Same hostnames, different origins |
| `nervura-electrica/infrastructure/proxmox/services/gabinete/mcp_registry.json` | 192.168.0.125 for CT 208 | New IP |
| `nervura-electrica/infrastructure/proxmox/aurelio-web/server.cjs` | Proxy backend IPs | New IPs |
| `replica-omnisciente/.aurelio/sync.py` | CT 208 target (192.168.0.38 → pct 208) | Verify still works via cluster |
| `nervura-electrica/infrastructure/proxmox/services/gabinete/deploy_gabinete_208.sh` | pct exec 208 on ASUS | May need to target new node |
Note: Cloudflare tunnel routes use hostnames, not IPs. The tunnel config (`config.yml`) maps hostnames to origin IPs — only the origin IPs need updating.
## [S6] ASUS post-migration
After migration, ASUS runs only:
- CT 207 (Aurelio web, 2 GB) — React portal + code-server
- CT 215 (Matrix, 1 GB) — Synapse homeserver
- System overhead (~1 GB)
Total: ~4 GB used of 16 GB — healthy headroom.
## [S7] Verification
1. Cluster health: `corosync-cfgtool -s` shows 3 nodes
2. All 4 CTs running on new node: `pct list` on new host
3. Cloudflare routes: curl each `*.portugalfuturista.org` endpoint
4. MCP health: `curl http://<new-ip>:18000/api/health`
5. Brain sync: `python3 .aurelio/sync.py --push` completes successfully
6. ASUS load: `uptime` shows load < 2.0