Integration Plan — Migrating to the Unified Agent OS
1. **Additive, not destructive** — New system reads legacy files; legacy systems continue unchanged until verified. 2. **Dual-write, then cutover** — During migration, both old and new storage are written to. Reads shift to new system first, writes follow. 3. **Each phase has a rollback** — If something breaks, revert by pointing back to legacy files. 4. **Test with real data** — Each phase runs against actual `[home-path]`, `[home-path]`, and `[home-path]`.
Full Public Reader
Integration Plan — Migrating to the Unified Agent OS
> Step-by-step migration from separate systems to UAOS.
> Each phase is independently deployable. No big-bang cutover.
---
Migration Philosophy
1. Additive, not destructive — New system reads legacy files; legacy systems continue unchanged until verified.
2. Dual-write, then cutover — During migration, both old and new storage are written to. Reads shift to new system first, writes follow.
3. Each phase has a rollback — If something breaks, revert by pointing back to legacy files.
4. Test with real data — Each phase runs against actual `[home-path]`, `[home-path]`, and `[home-path]`.
---
Phase 0: Foundation (Day 1)
Goal: Create the UAOS directory structure and state database without touching existing systems.
Steps
1. Create UAOS directory
mkdir -p [home-path] [home-path]2. Initialize SQLite database
# Create state.db with full schema from SHARED_STATE_SCHEMA.md
sqlite3 [home-path] < schema.sql3. Write config.yaml
- Copy template from SHARED_STATE_SCHEMA.md
- Adjust paths for this machine
- Set `dual_max.enabled: true`
4. Create the `uaos` Python package
[home-path]
├── uaos/
│ ├── __init__.py
│ ├── db.py # SQLite wrapper
│ ├── events.py # EventBus
│ ├── config.py # Config loader
│ ├── context.py # SharedContext + ContextBuilder
│ └── adapters/
│ ├── __init__.py
│ ├── pulse.py # PulseSessionAdapter
│ ├── dream.py # DreamAdapter
│ └── heartbeat.py # HeartbeatAdapter
└── schema.sql5. Verify
python3 -c "import sqlite3; db = sqlite3.connect('[home-path]); print(db.execute('SELECT name FROM sqlite_master WHERE type=\"table\"').fetchall())"
# Should list: entities, events, handoffs, tags, sessions, iterations, ...### Rollback
Delete `[home-path]`. No other systems affected.
### Definition of Done
- [ ] `[home-path]` exists with all tables
- [ ] `[home-path]` is valid
- [ ] `uaos` package is importable
- [ ] No existing system is modified
---
Phase 1: Import Historical State (Day 2-3)
Goal: Populate the state DB with all existing data from Pulse sessions, Dream Weaver dreams, and Heartbeat state. Read-only — no existing files modified.
Steps
1. Import Pulse sessions
# scripts/import_pulse.py
from pathlib import Path
from uaos.adapters.pulse import PulseSessionAdapter
from uaos.db import StateDB
db = StateDB()
sessions_dir = Path.home() / ".pulse" / "sessions"
for session_file in sessions_dir.glob("*.json"):
rows = PulseSessionAdapter.from_legacy(session_file)
db.upsert_entity(rows['entity'])
db.upsert_session(rows['session'])
print(f" Imported: {rows['session']['project_name']}")
print(f"Total sessions imported: {db.count('sessions')}")2. Import Noosphere dreams
# scripts/import_dreams.py
from uaos.adapters.dream import DreamAdapter
from uaos.db import StateDB
import json
db = StateDB()
dreams_file = Path.home() / ".claude" / "noosphere" / "dreams.json"
if dreams_file.exists():
data = json.loads(dreams_file.read_text())
for dream in data.get('dreams', []):
rows = DreamAdapter.from_noosphere(dream)
db.upsert_entity(rows['entity'])
db.upsert_dream(rows['dream'])
for tag in rows['tags']:
db.upsert_tag(tag)
print(f" Imported dream: {dream['seed_idea'][:50]}")
# Also import completed dreams from daemon
dreams_dir = Path.home() / ".claude" / "dream-weaver" / "dreams"
for dream_file in dreams_dir.glob("dream_*.json"):
# ... similar import logic3. Import Heartbeat state
# scripts/import_heartbeat.py
from uaos.adapters.heartbeat import HeartbeatAdapter
from uaos.db import StateDB
import json
db = StateDB()
state_file = Path.home() / "memory" / "heartbeat-state.json"
if state_file.exists():
state = json.loads(state_file.read_text())
domains = HeartbeatAdapter.from_legacy(state)
for domain in domains:
db.upsert_check_domain(domain)4. Import Connection Graph
# Copy noosphere graph to UAOS location
cp [home-path] [home-path] 2>/dev/null || true5. Verify imports
SELECT type, COUNT(*) FROM entities GROUP BY type;
-- Should show sessions, dreams, checks
SELECT COUNT(*) FROM tags;
-- Should show keywords from dreams
SELECT domain, last_checked_at FROM check_domains;
-- Should show heartbeat domains### Rollback
Drop and recreate tables in state.db. No legacy files touched.
### Definition of Done
- [ ] All Pulse sessions from `[home-path]` are in state.db
- [ ] All Noosphere dreams are in state.db
- [ ] Heartbeat domains are configured in state.db
- [ ] Connection graph copied to `[home-path]`
- [ ] `uaos.context.build()` returns a populated SharedContext
- [ ] Legacy files are untouched
---
Phase 2: Event Bus + Listeners (Day 4-5)
Goal: Implement the event bus and wire up cross-system listeners. Events are published but systems still use legacy state for reads.
Steps
1. Implement EventBus class
# uaos/events.py
class EventBus:
def __init__(self, db: StateDB):
self.db = db
self._subscribers = defaultdict(list)
def publish(self, topic, source, payload, entity_id=None, trace_id=None):
event = {...}
self.db.insert_event(event)
self._dispatch(topic, event)
def subscribe(self, pattern, handler):
self._subscribers[pattern].append(handler)
def _dispatch(self, topic, event):
for pattern, handlers in self._subscribers.items():
if self._matches(pattern, topic):
for handler in handlers:
try:
handler(event)
except Exception as e:
log(f"Handler error for {topic}: {e}")2. Wire up cross-system listeners
# uaos/listeners.py
def setup_listeners(bus: EventBus, db: StateDB):
"""Register all cross-system event handlers."""
# Dream emergence → Heartbeat alert
@bus.subscribe('dream.emerged')
def on_dream_emerged(event):
db.insert_check_result({
'domain': 'dreamWeaver',
'status': 'ok',
'alert_level': 8,
'details': json.dumps({
'type': 'dream_emerged',
'dream_id': event['entity_id'],
'message': f"Dream emerged: {event['payload'].get('seed_idea', '')[:50]}"
})
})
# Dream metamorphosis ready → Log for Cadence review
@bus.subscribe('dream.metamorphosis.ready')
def on_metamorphosis_ready(event):
db.insert_handoff({
'id': generate_id('ho'),
'from_system': 'dream_weaver',
'to_system': 'pulse',
'from_entity_id': event['entity_id'],
'handoff_type': 'metamorphosis',
'payload': event['payload'],
'status': 'pending',
'priority': 7,
})
# Pulse iteration complete → Feed to Mycelium
@bus.subscribe('pulse.iteration.completed')
def on_iteration_completed(event):
summary = event['payload'].get('summary', '')
keywords = extract_keywords(summary)
for kw in keywords:
db.update_sensing_pattern(kw, {
'source': 'pulse',
'timestamp': event['timestamp'],
'snippet': summary[:200]
})
# Heartbeat alert (critical) → Cadence escalation
@bus.subscribe('heartbeat.alert')
def on_critical_alert(event):
level = event['payload'].get('alert_level', 0)
if level >= 9:
db.insert_agent_message({
'id': generate_id('msg'),
'agent_id': 'higher_level',
'direction': 'inbox',
'msg_type': 'REQUEST',
'subject': f"Critical alert: {event['payload'].get('domain', 'unknown')}",
'body': json.dumps(event['payload']),
'priority': 'High',
'status': 'PENDING',
})3. Add event publishing to import scripts
- When importing historical data, also create retroactive events so the event log has history
4. Test event flow
# Test: publish a dream.emerged event and verify heartbeat alert is created
bus.publish('dream.emerged', 'dream_weaver', {
'seed_idea': 'test dream',
'connection_strength': 0.75
}, entity_id='dream_test_123')
alerts = db.query_check_results(domain='dreamWeaver', limit=1)
assert alerts[0]['alert_level'] == 8### Rollback
Remove listener registrations. Event bus is passive — removing it changes nothing.
### Definition of Done
- [ ] EventBus publishes and persists events
- [ ] 4 cross-system listeners are wired up
- [ ] Events table has data
- [ ] Test suite passes for each listener
---
Phase 3: Dual-Write Adapters (Day 6-8)
Goal: Modify existing systems to dual-write — continue writing legacy files AND publish events / write to state.db.
Steps
1. Patch `dual_runner.py` to publish events
# At the top of dual_runner.py, add:
try:
from uaos.events import EventBus
from uaos.db import StateDB
uaos_db = StateDB()
uaos_bus = EventBus(uaos_db)
UAOS_ENABLED = True
except ImportError:
UAOS_ENABLED = False
# In run_iteration(), after updating session:
if UAOS_ENABLED:
uaos_bus.publish('pulse.iteration.completed', 'pulse', {
'session_id': session.id,
'iteration': session.current_iteration,
'signal': signal,
'summary': output[:500]
}, entity_id=session.id)2. Patch Dream Weaver `daemon.py` to publish events
# In daemon.py main loop, after each iteration:
if UAOS_ENABLED:
uaos_bus.publish('dream.evolved', 'dream_weaver', {
'dream_id': incubation_id,
'iteration': result.get('current_iteration'),
'status': result.get('status')
}, entity_id=incubation_id)
if status == 'complete':
uaos_bus.publish('dream.emerged', 'dream_weaver', {
'dream_id': incubation_id,
'seed_idea': result.get('idea', '')
}, entity_id=incubation_id)3. Patch Heartbeat check to publish events
# In the main agent's heartbeat handler, after each check:
if UAOS_ENABLED:
uaos_bus.publish('heartbeat.check.completed', 'heartbeat', {
'domain': domain,
'status': check_status,
'alert_level': alert_level
})4. Add state.db writes alongside legacy file writes
- `save_session()` in `dual_runner.py` → also writes to `sessions` table
- Dream Weaver incubation save → also writes to `dreams` table
- Heartbeat state save → also writes to `check_results` table
5. Verify dual-write consistency
# scripts/verify_sync.py
# Compare every legacy file against state.db rows
# Report any discrepancies### Rollback
Remove the UAOS import blocks. Existing systems fall back to legacy-only writes.
### Definition of Done
- [ ] `dual_runner.py` publishes Pulse events to UAOS
- [ ] Dream Weaver daemon publishes evolution events
- [ ] Heartbeat publishes check results
- [ ] `verify_sync.py` shows zero discrepancies
- [ ] Legacy files continue to be written (backward compat)
---
Phase 4: Unified Daemon (Day 9-12)
Goal: Replace the Dream Weaver daemon with a unified UAOS daemon that runs all subsystem loops.
Steps
1. Create `[home-path]`
#!/usr/bin/env python3
"""
Unified Agent OS Daemon
Replaces:
- Dream Weaver daemon.py (evolution loop)
- Noosphere bridge sync
- Heartbeat state management
Adds:
- Event processing loop
- Handoff monitoring
- Account usage tracking
"""
import asyncio
import signal
from uaos.db import StateDB
from uaos.events import EventBus
from uaos.config import load_config
from uaos.loops import (
dream_evolution_loop,
heartbeat_check_loop,
event_processing_loop,
handoff_monitor_loop,
account_reset_loop,
)
async def main():
config = load_config()
db = StateDB(config.database.path)
bus = EventBus(db)
setup_listeners(bus, db)
# Start all loops
tasks = [
asyncio.create_task(dream_evolution_loop(db, bus, config)),
asyncio.create_task(heartbeat_check_loop(db, bus, config)),
asyncio.create_task(event_processing_loop(db, bus, config)),
asyncio.create_task(handoff_monitor_loop(db, bus, config)),
asyncio.create_task(account_reset_loop(db, config)),
]
bus.publish('system.startup', 'uaos', {'loops': len(tasks)})
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())2. Port Dream Weaver daemon logic to `uaos/loops/dream_evolution.py`
- Keep exact same incubation logic from `incubator.py`
- Replace file I/O with state.db reads/writes
- Publish events instead of writing to daemon.log
3. Port Heartbeat logic to `uaos/loops/heartbeat_check.py`
- Parse HEARTBEAT.md for check definitions
- Run checks against check_domains table
- Write results to check_results table
- Publish events for alerts
4. Create handoff monitor `uaos/loops/handoff_monitor.py`
- Check for pending handoffs every 5 minutes
- Auto-accept metamorphosis handoffs if configured
- Expire handoffs older than 24h
5. Stop old Dream Weaver daemon, start UAOS daemon
# Stop old daemon
python3 [home-path] stop
# Start unified daemon
python3 [home-path] start6. Verify daemon health
# Check PID
cat [home-path]
# Check logs
tail -20 [home-path]
# Check events
sqlite3 [home-path] "SELECT topic, COUNT(*) FROM events GROUP BY topic ORDER BY COUNT(*) DESC"### Rollback
Stop UAOS daemon, restart Dream Weaver daemon. Event bus stops but no data is lost.
### Definition of Done
- [ ] UAOS daemon runs with all 5 loops
- [ ] Dream evolution continues at same cadence
- [ ] Heartbeat checks run on schedule
- [ ] Handoff monitor catches pending handoffs
- [ ] Old daemon is stopped
- [ ] `uaos.context.build()` returns live data
---
Phase 5: Unified MCP Server (Day 13-15)
Goal: Create a single MCP server that exposes all subsystem tools under the `uaos.*` namespace.
Steps
1. Create `[home-path]`
- Import tool handlers from each subsystem
- Wrap in unified namespace: `uaos.pulse.start`, `uaos.dream.incubate`, etc.
- Add new cross-system tools: `uaos.context`, `uaos.handoff`, `uaos.events.query`, `uaos.lineage`
2. Register with Claude Desktop
// In claude_desktop_config.json
{
"mcpServers": {
"uaos": {
"command": "python3",
"args": ["[home-path]
"env": {}
}
}
}3. Deprecate old MCP servers (but don't remove yet)
- Keep `dream-weaver` and `pulse` MCP servers as fallbacks
- Add deprecation notice in their responses
4. Verify all tools work
# Test each tool category:
uaos.pulse.start → creates session in state.db
uaos.pulse.status → reads from state.db
uaos.dream.incubate → creates dream in state.db
uaos.dream.evolve → advances dream, publishes event
uaos.context → returns SharedContext
uaos.handoff.create → creates handoff record
uaos.events.query → queries event log### Rollback
Remove `uaos` from MCP config, re-enable old servers.
### Definition of Done
- [ ] Single MCP server serves all tools
- [ ] `uaos.context` returns live cross-system state
- [ ] `uaos.handoff.create` enables formal dream→pulse metamorphosis
- [ ] `uaos.lineage` traces entity history across systems
- [ ] Old MCP servers still work as fallback
---
Phase 6: Remove Legacy Paths (Day 16-20)
Goal: Stop dual-writing. State.db becomes the single source of truth. Legacy paths become read-only symlinks.
Steps
1. Create compatibility symlinks
# Pulse sessions: generate JSON files from state.db on read
# (implement a FUSE mount or a simpler file-watcher approach)2. Remove dual-write from `dual_runner.py`
- Pulse reads/writes exclusively from state.db
- Legacy `sessions/*.json` files are generated on-demand for backward compat
3. Remove `noosphere_bridge.py`
- The bridge is no longer needed — noosphere dreams live in state.db
- Connection graph still lives in `graph.json` (too graph-specific for SQL)
4. Remove legacy heartbeat-state.json writes
- Heartbeat reads check schedules from state.db
- `HEARTBEAT.md` remains as the human-readable config
5. Archive old files
mkdir -p [home-path]
cp -r [home-path] [home-path]
cp [home-path] [home-path]
cp [home-path] [home-path]6. Remove old Dream Weaver daemon files
# daemon.py, daemon.pid, daemon.log from [home-path]
# These are superseded by [home-path]### Rollback
Restore files from `[home-path]` and re-enable dual-write.
### Definition of Done
- [ ] State.db is the single source of truth
- [ ] No more dual-writing
- [ ] Legacy files archived
- [ ] All subsystems read from state.db
- [ ] `noosphere_bridge.py` is removed
- [ ] System runs stable for 48h
---
Phase 7: Enriched Spawn Integration (Day 21-23)
Goal: Update `enriched_spawn.py` to include cross-system context from UAOS.
Steps
1. Add UAOS context to enriched prompts
# In enriched_spawn.py, add after project context:
def get_uaos_context_block() -> str:
"""Get cross-system context for enriched prompts."""
try:
from uaos.context import ContextBuilder
from uaos.db import StateDB
ctx = ContextBuilder(StateDB()).build()
return f"""
## UAOS Context
{ctx.brief()}
Active Dreams: {len(ctx.gestating_dreams)} gestating, {len(ctx.metamorphosis_ready)} ready
Active Sessions: {len(ctx.active_sessions)}
Hot Keywords: {', '.join(ctx.hot_keywords[:5])}
"""
except Exception:
return ""2. Feed dream context into metamorphosis sessions
- When a Pulse session is born from a dream metamorphosis, the enriched prompt includes:
- Dream synthesis
- Explored approaches
- Related plans found during incubation
- Connection graph neighbors
3. Feed Pulse learnings back to dreams
- After each iteration, extract keywords and summaries
- Update sensing patterns in state.db
- Strengthen connections to related dreams
### Definition of Done
- [ ] Enriched prompts include UAOS context
- [ ] Metamorphosis sessions have full dream context
- [ ] Pulse iteration summaries feed back to sensing patterns
---
Phase 8: Cadence Full Integration (Day 24-28)
Goal: Integrate Cadence multi-agent coordination as the orchestration layer.
Steps
1. Register agents in state.db
- `higher_level` agent with escalation capabilities
- `lower_level` agent with implementation capabilities
- `pulse_worker` agent(s) for autonomous dev
- `dream_weaver` agent for incubation
2. Migrate `cadence_bridge.py` to UAOS
- INBOX/OUTBOX detection → event bus subscriptions
- Decision sync → state.db decisions table
- Supabase sync → optional external sync from state.db
3. Implement priority queue
- Cadence router evaluates incoming handoffs against:
- Current Pulse session load
- Account usage limits
- Priority of the request
- Quiet hours
- Decides: accept now, queue for later, or reject
4. Test orchestration flows
- Dream → metamorphosis → Cadence approval → Pulse session
- Heartbeat critical alert → Cadence escalation → human notification
- Cadence delegation → Pulse worker assignment
### Definition of Done
- [ ] All agents registered in state.db
- [ ] Cadence bridge migrated from hook to UAOS listener
- [ ] Priority queue works for handoff routing
- [ ] End-to-end orchestration flows tested
---
Phase 9: Observability & Polish (Day 29-30)
Goal: Dashboard, monitoring, and documentation.
Steps
1. Implement `uaos dashboard` CLI command
python3 [home-path] dashboard
# Shows the ASCII dashboard from ARCHITECTURE.md2. Add metrics collection
- Events per hour by topic
- Average iteration duration
- Dream-to-bloom time
- Handoff completion rate
3. Write operational docs
- How to start/stop the daemon
- How to query the event log
- How to create manual handoffs
- Troubleshooting guide
4. Update HEARTBEAT.md
- Replace Dream Weaver daemon check with UAOS daemon check
- Add UAOS-specific health checks
5. Update AGENTS.md
- Document UAOS as the unified platform
- Update sub-agent spawning instructions
### Definition of Done
- [ ] Dashboard CLI works
- [ ] Metrics are queryable
- [ ] HEARTBEAT.md updated
- [ ] AGENTS.md updated
- [ ] All documentation complete
---
Timeline Summary
| Phase | Days | Risk | Dependencies |
|---|---|---|---|
| 0: Foundation | 1 | Low | None |
| 1: Import Historical | 2 | Low | Phase 0 |
| 2: Event Bus | 2 | Low | Phase 0 |
| 3: Dual-Write | 3 | Medium | Phase 1, 2 |
| 4: Unified Daemon | 4 | Medium | Phase 3 |
| 5: Unified MCP | 3 | Medium | Phase 4 |
| 6: Remove Legacy | 5 | High | Phase 5, 48h stability |
| 7: Enriched Spawn | 3 | Low | Phase 4 |
| 8: Cadence Integration | 5 | Medium | Phase 5 |
| 9: Observability | 2 | Low | Phase 6 |
| Total | ~30 days |
Critical Path
Phase 0 ──▶ Phase 1 ──▶ Phase 3 ──▶ Phase 4 ──▶ Phase 5 ──▶ Phase 6
└──▶ Phase 2 ──┘ └──▶ Phase 7
└──▶ Phase 8 ──▶ Phase 9---
Risk Register
| Risk | Impact | Mitigation |
|---|---|---|
| SQLite corruption during daemon crash | High | WAL mode + daily backups + graceful shutdown handlers |
| Dual-write inconsistency | Medium | Verify script runs after every write, reconciliation job |
| Event bus overwhelms DB with writes | Low | Batch inserts, configurable buffer, event rotation |
| Legacy system breaks during migration | High | Each phase has explicit rollback steps |
| Noosphere graph too large for JSON | Low | Only if >10K nodes; migrate to SQLite virtual table if needed |
| Rate limits exceeded during migration | Medium | Account usage tracking preserved from dual_runner.py |
---
Success Criteria
The migration is complete when:
1. ✅ All Pulse sessions, Dream Weaver dreams, and Heartbeat checks live in `[home-path]`
2. ✅ A single daemon (`[home-path]`) runs all background loops
3. ✅ A single MCP server exposes all tools under `uaos.*` namespace
4. ✅ Cross-system handoffs work (dream → pulse metamorphosis)
5. ✅ Enriched spawn prompts include cross-system context
6. ✅ Event log captures all inter-system communication
7. ✅ Cadence orchestrates priority and routing
8. ✅ `uaos.context` returns a complete cross-system snapshot
9. ✅ No legacy bridge scripts (`noosphere_bridge.py`) needed
10. ✅ System is stable for 7 consecutive days
Promotion Decision
Attach run IDs, datasets, metrics, and reproduction commands.
Source Anchor
projects/dream-metamorphosis/unified-agent-os/INTEGRATION_PLAN.md
Detected Structure
Method · Evaluation · Figures · Code Anchors · Architecture