Files
obsidian-vault/personal/projects/personal-os/personal-os-self-modification.md
T
2026-05-29 20:00:17 +00:00

5.8 KiB
Executable File

namespace, tags, last_updated, confidence
namespace tags last_updated confidence
work
system
self-modification
eagle
meta
2026-04-28 1.0

Personal OS — Self-Modification Guide

How Eagle (and Alex via Claude Code) can safely evolve the system without breaking it.

Rule: Always show a diff/draft first, confirm, then apply. Commit the vault after.


What Eagle Can Change (no approval needed — show draft first)

1. Prompt files (~/Developer/personal-os/agent/prompts/*.md)

Eagle reads and writes its own prompts. When Alex says "add X to the morning brief" or "change how inbox triage handles Y":

  1. Read the current prompt: ~/Developer/personal-os/agent/prompts/<name>.md
  2. Draft the change, show the diff in Discord
  3. On confirmation: write the file
  4. Commit: cd ~/Developer/personal-os && git add agent/prompts/<name>.md && git commit -m "[YYYY-MM-DD] prompt: <description>"

Do not change executor-bug-fix.md without explicit confirmation — it controls autonomous code changes.

2. SOUL.md (~/.hermes/SOUL.md)

Eagle's identity, rules, and operating context. Eagle can propose changes to:

  • Allowed vault write paths
  • Focus gating rules
  • Channel routing

Same flow: draft → confirm → write → no vault commit needed (SOUL.md is outside vault).

3. ActivityWatch project rules (~/Developer/personal-os/aw-projects.json)

To classify a new project as work or personal:

  1. Read current aw-projects.json
  2. Add entry with project, namespace (omit for work, "personal" for pet projects), and rules
  3. Show draft, confirm, write
  4. Commit: cd ~/Developer/personal-os && git add aw-projects.json && git commit -m "[YYYY-MM-DD] aw: classify <project>"

The namespace: "personal" field excludes a project from work activity in status.md and activity_daily.

4. Vault knowledge pages (~/obsidian/wiki/, ~/obsidian/work/wiki/)

Eagle does not write to wiki/ — that's the wiki-ingest job (22:00 launchd). But Eagle can write to:

  • ~/obsidian/work/projects/SLUG.md — project notes
  • ~/obsidian/work/decisions/YYYY-MM-TOPIC.md — decisions
  • ~/obsidian/personal/ — personal notes
  • ~/obsidian/family/ — family docs

After writing: cd ~/obsidian && git add -A && git commit -m "[YYYY-MM-DD] <description>"

5. Correction logging (corrections_log table)

Eagle silently logs a row whenever Alex pushes back on a suggestion. No approval needed — this is continuous background instrumentation, not a visible change.

INSERT INTO corrections_log (date, week_number, source, original_plan, correction, deferred_gids, reason_tag)
VALUES (current_date, EXTRACT(WEEK FROM current_date)::int, 
        '<source>', '<original>', '<user_message>', 
        ARRAY[<gids>]::text[], '<reason_tag>');

What Requires Approval (always confirm explicitly)

Schema changes (PostgreSQL)

New tables, columns, or indexes require a SQL migration. Pattern:

  1. Draft the SQL in Discord, explain the purpose
  2. On "go": run via psql personal_os -c "..."
  3. Update ~/obsidian/wiki/personal-os-schema.md (this is auto-generated at 22:00, but a manual update is fine)

Current tables: tasks, stories, task_edges, sync_state, task_annotations, activity_daily, corrections_log, executor_runs.

New Hermes cron jobs

Add to ~/.hermes/config.yaml. Format:

crons:
  - id: my-new-job
    schedule: "30 9 * * 1-5"
    prompt: |
      Run: ~/Developer/personal-os/agent/prompts/my-prompt.md
    channel: "#channel-name"

Must confirm before writing — a broken cron syntax silently prevents Hermes from starting.

New launchd agents (~/Library/LaunchAgents/)

New plist files. Rarely needed — only if a job requires Mac filesystem access and can't run inside Hermes (e.g., wiki-ingest). Confirm before writing and before loading with launchctl.

Executor prompt (executor-bug-fix.md)

Controls autonomous code changes. Changes here need explicit approval because a mistake could cause the Executor to behave incorrectly on real PRs.

Hermes model or MCP configuration (~/.hermes/config.yaml)

Model upgrades, new MCP servers. Show the diff; confirm before writing.


How generate-status.js Gets Extended

When a new data signal should appear in status.md:

  1. Add a SQL query function (e.g., getNewSignal())
  2. Add a render function (e.g., renderNewSignal(data))
  3. Add both to main(): Promise.all for the query, the render call in parts
  4. Test: node ~/Developer/personal-os/generate-status.js and read ~/context/status.md
  5. Commit

Never edit generate-status.js to change how Asana sync works — that's sync.js territory.


Debugging the System

Symptom Check
status.md is stale (> 40 min old) stat -f "%Sm" ~/context/status.md — if old, run bash ~/scripts/run-pipeline.sh
Hermes cron didn't fire Check heartbeat: tail -20 ~/Developer/personal-os/logs/heartbeat.log
Eagle gave wrong Asana data The DB may be stale — run node ~/Developer/personal-os/sync.js manually
activity_daily missing today generate-status.js runs upsert — check select * from activity_daily where bucket_day = current_date
corrections_log empty Eagle only inserts on pushback — expected to be sparse
Executor in stuck state SELECT id, state, updated_at FROM executor_runs WHERE state NOT IN ('complete','abandoned');

Safe Operations Checklist

Before making any system change:

  • Read the current file/config before proposing a change
  • Show the diff, not just a description
  • Wait for explicit confirmation
  • Apply the change
  • Verify: run the component or check output
  • Commit if in a git repo (personal-os or obsidian)

See Also

  • personal-os-architecture.md — full system map
  • personal-os-agent-rules.md — Eagle's rules and channel routing
  • personal-os-purpose.md — why this system exists