Zion Boggan
repos/Zion Pm/README.md
zionboggan.com ↗
97 lines · markdown
History for this file →
1
# Zion PM v2
2
 
3
A single self-hosted Project Manager app for Zion's homelab. The PM brain is **GLM** (via the Z.ai Coding Plan subscription); it takes any task, decomposes it, delegates work to the worker fleet (Claude, Codex, local Ollama), supervises, and gates every outward action behind an approval outbox.
4
 
5
One surface, three panes:
6
- **Chat** - channels with a default model; `@mention` any model mid-conversation.
7
- **Board** - kanban tasks (todo / doing / done / blocked).
8
- **Fleet** - worker status, cap gauges, ping, and the approval outbox.
9
 
10
Built per `SEED.md` (the authoritative charter). Runs on **CT120 (REDACTED-IP)**, fronted at **https://REDACTED-HOST** behind Authentik SSO.
11
 
12
## Architecture
13
 
14
```
15
REDACTED-HOST  (Traefik + Authentik forwardAuth, CT244)
16
17
      ▼  http://REDACTED-IP:4100
18
Next.js app (App Router, port 4100)
19
      │  REST API routes
20
21
pmConductor  (Mastra Agent, GLM via Z.ai Anthropic-compat)
22
      │  tools: delegate / createTask / updateTask / draftApproval
23
24
Worker adapters ──► claude  (SSH root@CT215, claude -p)
25
                ──► codex   (SSH zion@CT241, codex exec)
26
                ──► ollama  (HTTP 3060 /api/chat)
27
shared memory ──► queryMemory (homelab-rag MCP :9876)
28
              ──► queryGraph  (cbm-homelab MCP :9877)
29
store ───────────► better-sqlite3 at data/zionpm.db
30
```
31
 
32
GLM is the **conductor**, not a worker. Worker tier = claude / codex / ollama, with strong→weak fallback (claude → codex → ollama) when a model is capped.
33
 
34
## Layout
35
 
36
| Path | Purpose |
37
|---|---|
38
| `lib/glm.ts` | GLM model via Z.ai Anthropic-compat (`@ai-sdk/anthropic`, custom baseURL) |
39
| `lib/mastra.ts` | `pmConductor` Mastra agent + tool registry + `runConductor()` |
40
| `lib/memory.ts` | `queryMemory` / `queryGraph` over the MCP SDK (SSE) |
41
| `lib/router.ts` | channel-default + `@mention` dispatch (§7) |
42
| `lib/db.ts` | SQLite schema + seed + accessors (§5) |
43
| `lib/workers/{delegate,claude,codex,ollama,ssh}.ts` | worker adapters + tier fallback (§6) |
44
| `app/api/**` | REST routes (channels, messages, tasks, outbox, fleet) |
45
| `app/page.tsx` | Chat / Board / Fleet UI |
46
 
47
## Configuration (`.env.local`, never committed)
48
 
49
| Var | Default | Notes |
50
|---|---|---|
51
| `ZAI_API_KEY` | - | Z.ai Coding Plan subscription key (from `.env.secrets`, CRLF-stripped) |
52
| `PM_BRAIN_MODEL` | `glm-4.6` | conductor model (also `glm-4.5`, `glm-5.2`) |
53
| `ZAI_BASE_URL` | `https://api.z.ai/api/anthropic/v1` | Anthropic-compatible endpoint |
54
| `ZPM_OLLAMA_URL` | `http://REDACTED-IP:11434` | 3060 Ollama (CT205 GPU node was offline at build) |
55
| `ZPM_CLAUDE_USER` | `root` | root@CT215 has the working claude login |
56
| `ZPM_SSH_KEY` | `/root/.ssh/id_ed25519` | CT120 key, authorized on CT215 + CT241 |
57
| `ZPM_RAG_SSE` / `ZPM_CBM_SSE` | `:9876` / `:9877` | MCP SSE endpoints |
58
 
59
Secrets live only in `.env.local` on CT120 and `/shared/projects/.env.secrets`. Never in code or git.
60
 
61
## Run / deploy
62
 
63
The canonical repo lives on the share at `/shared/projects/zion-pm` (committed + pushed from CT215; remote `github.com/zionboggan/zion-pm`, private). The app **runs from CT120 local fs** `/opt/zion-pm` (noexec CIFS rule - never execute from the share).
64
 
65
CT120 has no direct egress to github.com, so deploys are **CT215-mediated** (CT215 has GitHub access and syncs source to CT120 over SSH):
66
 
67
```bash
68
# on CT215: pull latest canonical, sync source to CT120, build + restart there
69
cd /shared/projects/zion-pm && git pull
70
tar czf - app lib public package.json pnpm-lock.yaml tsconfig.json next.config.ts \
71
  postcss.config.mjs | ssh root@REDACTED-IP 'tar xzf - -C /opt/zion-pm'
72
ssh root@REDACTED-IP 'cd /opt/zion-pm && pnpm install && pnpm build && systemctl restart zion-pm'
73
```
74
 
75
Service: `zion-pm.service` (systemd, onboot). Logs: `journalctl -u zion-pm -f`.
76
 
77
## Acceptance (SEED §10) - all 8 verified
78
 
79
1. Boot: CT120 clean, app on :4100, pm.lab behind Authentik login.
80
2. Channels `#pm`(glm) / `#claude` / `#codex` / `#ollama` seeded with model badges.
81
3. GLM conductor: 5-bullet cbm-homelab summary grounded via queryMemory/queryGraph.
82
4. `@ollama:mistral-nemo:12b` override → Ollama reply authored `ollama`.
83
5. `@claude` → SSH CT215 → `claude -p` creates a file; path returned.
84
6. Board: task created, drag todo→done persists.
85
7. Fleet: glm + claude + codex + ollama green; Ping returns latency for each.
86
8. Outbox: conductor/UI drafts an outward action → Approve/Reject; nothing auto-sends.
87
 
88
## Build notes / deviations from SEED
89
 
90
- **Node 22 LTS** (not 20): `create-mastra`/Mastra require Node ≥22.13.
91
- **Scaffold**: `create-next-app` + `@mastra/core` (the `--template nextjs` flag was not usable non-interactively). Honors the locked "Mastra/TypeScript" decision.
92
- **Ollama host**: CT205 / the pve-gpu node were **offline** at build time; the worker uses the documented overflow 3060 at `REDACTED-IP` (has `mistral-nemo:12b`).
93
- **Claude worker** runs as `root@CT215` with `IS_SANDBOX=1` (zion's claude login returned 401; root's is valid; root needs the sandbox flag for `--dangerously-skip-permissions`).
94
- **Live updates**: polling (MVP) rather than websockets (SEED permits).
95
- **Authentik**: a proxy provider + `zion-pm` application were added to the embedded outpost for `pm.lab` (mirrors the dashboard/notes apps).
96
 
97
See `OPS_RUNBOOK.md` for operations and `SEED.md` for the full charter.