Files
obsidian-vault/wiki/personal-os-architecture.md
T

186 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
namespace: work
tags: [system, architecture]
last_updated: 2026-05-18
confidence: 1.0
---
# Personal OS — Architecture
## Why It Exists
See: [[personal-os-purpose]] and [[personal-os-agent-rules]] for goals and behavioral constraints.
## Agents
### Стратег (Strategist) — data pipeline, no conversation
- `~/scripts/run-pipeline.sh` → sync.js + generate-status.js every 30 min (workdays via Hermes cron)
- Writes `~/context/status.md` and `~/Developer/personal-os/asana_context.md`
- Writes daily AW activity summaries to `activity_daily` table with quadrant classification
- No Zulip output — pure data layer
### Орёл / Eagle (Tactician + reactive layer) — Hermes Zulip agent
- Reads `~/context/status.md`, daily/weekly briefs, vault via obsidian MCP
- Zulip streams: `daily-brief` `inbox` `focus` `executor` `projects` `journal` `retrospector`
- Cron jobs: morning-brief (08:30 MTWRF), eod-summary (18:00 MTWRF), inbox-check (30 min 0919 MTWRF), weekly-plan (Mon 08:00), weekly-review (Fri 17:00), retrospector (Fri 17:30), commit-vault (23:00 daily), wiki-curation (02:00 daily)
- Logs corrections to `corrections_log` table (SQL INSERT, silently on pushback)
- **Never accesses Asana API directly** — only reads pre-rendered markdown and DB
- **Zulip plugin**: `~/.hermes/plugins/zulip-topic-routing/` — intercepts `(no topic)` messages; routes to most recent related thread or renames to descriptive topic. Status: ✅ done (2026-05-14)
> ⚠️ **Mattermost migration in-progress (2026-05-14):** Work Eagle agent (briefs, inbox, executor) moving from Zulip → corporate Mattermost. Personal/family/journal remain on Zulip/Discord. Blocked on IT Ops creating MM bot accounts (eagle-bot, executor-bot, brief-bot). See `work/plans/mattermost-migration.md`.
### Ретроспектор (Retrospector) — Friday pattern analysis
- Runs as separate Hermes cron at 17:30 Friday → `#retrospector`
- Sources: corrections_log table, status.md subtask counts, obsidian git log, activity_daily quadrants, stories visibility metric
- Prompt: `~/Developer/personal-os/agent/prompts/retrospector.md`
### Исполнитель (Executor) — two modes
**Manual mode**: triggered by "fix bug [GID]" in #executor
- Single STOP gate after analysis; then autonomous: fix → build → test → draft PR → CI loop
- Prompt: `~/Developer/personal-os/agent/prompts/executor-bug-fix.md`
**Autonomous mode**: hourly cron (0918 workdays) → #executor
> ⚠️ Stale as of 2026-05-11: Original LLM-orchestrated autonomous cron **paused**. Replaced by v2 bash daemons:
**Autonomous mode (v2 — bash daemons, active 2026-05-11+):**
- `executor-runner.sh` — cron `*/5`; processes queued/in_progress/pr states; max 2 concurrent workers; spawns focused worker prompt per state; exits when no actionable tasks remain
- `executor-analyzer.sh` — cron `*/5`; picks one unanalyzed task, runs `claude -p` analysis prompt, sets `for_review`/`awaiting_go`/`skip`, exits; restarts for next task
- Worker prompts in `~/Developer/personal-os/agent/prompts/executor-worker-*.md`
- Queue state in `executor_queue` table; live plan: `~/Developer/personal-os/briefs/executor-queue.md`
**Orchestrator Pattern (Planning — 2026-05-14):**
> Research phase complete. Executor will become a separate Hermes profile with its own Zulip bot identity ("Исполнитель"), spawned by Eagle as orchestrator. Eagle monitors `#executor` via 2-min cron, auto-approves safe actions (`[REQUEST:create_worktree]`, `[REQUEST:run_tests]`, etc.), escalates ambiguous/risky ones to Alex. See `personal/projects/personal-os/executor-spawning-research.md` for full protocol and auto-approval rules.
>
> Key mechanism: **Hermes Profiles** — `~/.hermes/profiles/executor/` with its own SOUL.md, Zulip bot token, and gateway. `hermes profile create executor --clone`.
**Shared**:
- Worktree at `~/DuckDuckGo/apple-browsers.git/.claude/worktrees/executor-{gid}-{slug}/`
- Always `git fetch origin main` + branch from `origin/main`
- State machine in `executor_runs` table
- For UI tests: spins VM via ddg-vm MCP (virfield), cleans up on PR close/merge
**Eagle commands in #executor**:
| Command | Effect |
|---------|--------|
| `fix bug {gid}` | Spawn manual executor (separate agent) |
| `go {gid}` | Approve autonomous task → starts next tick |
| `skip {gid}` | Skip task in queue |
| `stop` | Pause current autonomous task |
| `next` | Pause current, analyze next |
| `resume {gid}` | Re-queue paused task |
| `queue` | Show current executor-queue.md |
## Data Flow
```
Asana API
→ sync.js (30 min, Hermes cron, silent)
→ PostgreSQL: tasks, stories, task_edges, sync_state, task_annotations
ActivityWatch (local daemon)
→ generate-status.js (reads AW HTTP API)
→ activity_daily (upserts daily project/quadrant summaries)
generate-status.js
→ ~/context/status.md ← Eagle reads this
→ ~/Developer/personal-os/asana_context.md ← inbox-check reads this
Eagle corrections in Zulip
→ corrections_log table (INSERT on pushback, no announcement)
→ Retrospector reads weekly
Executor runs
→ executor_runs table (state machine)
→ ~/DuckDuckGo/apple-browsers.git/.claude/worktrees/
→ GitHub draft PRs (--draft, --assignee @me, no reviewers)
```
## Key File Locations
| File / Path | Purpose |
|-------------|---------|
| `~/context/status.md` | Live Asana + AW snapshot. Written by generate-status.js. Eagle reads this. |
| `~/Developer/personal-os/asana_context.md` | Raw Asana context for inbox-check |
| `~/Developer/personal-os/agent/prompts/` | All agent prompts (Hermes cron + on-demand) |
| `~/.hermes/SOUL.md` | Eagle's identity, rules, vault write permissions |
| `~/Developer/personal-os/config.json` | Asana workspace/user GIDs, section GIDs |
| `~/Developer/personal-os/aw-projects.json` | ActivityWatch project classification rules |
| `~/.hermes/config.yaml` | Hermes config: model, MCP servers, cron settings |
| `~/obsidian/` | Vault — git repo, NAS remote, obsidian-mcp for search |
| `~/Developer/personal-os/logs/` | heartbeat.log, wiki-ingest-YYYY-MM-DD.md |
| `~/Developer/personal-os/briefs/` | daily/, weekly/, inbox/ — agent-written brief files |
| `~/DuckDuckGo/apple-browsers.git/` | Browser repo (bare), worktrees as sibling dirs |
| `~/DuckDuckGo/apple-browsers.git/.claude/worktrees/` | Executor worktrees |
## Database Tables
| Table | Written by | Read by |
|-------|-----------|---------|
| tasks | sync.js | generate-status.js, executor, status queries |
| stories | sync.js | generate-status.js, executor, retrospector |
| task_edges | sync.js | subtask traversal |
| sync_state | sync.js | generate-status.js header |
| task_annotations | manual / Eagle | generate-status.js irrelevant filter |
| activity_daily | generate-status.js | retrospector quadrant drift |
| corrections_log | Eagle on pushback | retrospector pattern analysis |
| executor_runs | executor (manual + autonomous) | generate-status.js active runs, executor state machine |
| executor_queue | executor-autonomous | generate-status.js queue display, autonomous tick state |
## MCP Servers
**Eagle (Mac M4) — Hermes agent:**
| Name | Command | Used for |
|------|---------|---------||
| obsidian | `node ~/scripts/obsidian-mcp-wrapper.js` (wraps `/opt/homebrew/bin/obsidian-mcp`) | Vault search, read, write. Wrapper handles ZodError/race condition — see [[obsidian-mcp-wrapper]] |
**Taiga (TrueNAS) — Hermes agent (`hermes-taiga` container):**
| Name | Command | Used for |
|------|---------|---------||
| obsidian | `/opt/data/.local/bin/mcpvault /vault` | Vault access (sparse: personal/ + family/). Tavily search enabled. |
**Kraken (RPi5) — Hermes agent (`hermes-kraken` container):**
|| Name | Command | Used for |
||------|---------|---------||
|| obsidian | `/opt/data/.local/bin/mcpvault /vault` | Vault access (sparse: personal/ + family/). Tavily search enabled. |
Skills on Kraken: `~/.hermes/skills/` (host) — **not** visible to the container at `/opt/data/skills/`. Copy skills there if needed.
Media stack on Kraken: full *arr stack (Prowlarr/Radarr/Sonarr) + Transmission + Jellyfin + media-pipeline. See [[concepts/kraken-media-stack]].
> ⚠️ **Kraken image routing (open issue, 2026-05-14):** Gemini API credits depleted → fallback to OpenRouter models (gpt-oss-120b, minimax-m2) → these lack vision → image inbox messages fail. Desired fix: add `save_to_fs` mode to Hermes `image_routing` (save image locally, pass path to agent instead of bytes). Workaround: top up Gemini API credits on Kraken. Tracked in `personal/projects/personal-os/kraken-obsidian-write-bug.md`.
> All three nodes run Hermes with obsidian/mcpvault MCP. Eagle uses obsidian-mcp-wrapper.js (fixes ZodError+race); Taiga and Kraken use mcpvault directly.
**Claude Code / `claude -p` sessions (Eagle only):**
| Name | Command | Used for |
|------|---------|---------||
| ddg-vm | `npx tsx ~/Developer/virfield/server/mcp-server.ts` | VM lifecycle for UI tests |
| obsidian | `node ~/scripts/obsidian-mcp-wrapper.js` | Vault access |
## launchd Agents
| Label | Schedule | Purpose |
|-------|----------|---------|
| personal.os.heartbeat | :05 every hour | Runs run-pipeline.sh directly (no Claude auth needed); also triggers missed Hermes jobs after wake |
| personal.os.wiki-ingest | 22:00 daily | `claude -p` wiki synthesis (needs filesystem access) |
## Vault Structure
```
~/obsidian/
├── wiki/ ← LLM-generated + hand-written (confidence: 1.0 = never overwrite)
│ ├── personal-os-architecture.md (this file)
│ ├── personal-os-purpose.md
│ ├── personal-os-agent-rules.md
│ ├── personal-os-self-modification.md
│ ├── personal-os-sync-pipeline.md
│ ├── personal-os-schema.md (auto-generated)
│ ├── ddg-asana-workflow.md
│ └── vault-filling-guide.md
├── raw/ ← symlinks to external source files (schema.sql, etc.)
├── work/
│ └── wiki/
│ └── apple-browsers/ ← .cursor/rules copies (.md) + vm-ui-testing.md
└── personal/ family/
```