# Next Session: Dynamic Agent Registration (No Restart) — DONE (Session 410)

## Problem

Adding a new scheduled agent currently requires **restarting Annie** because:

1. **YAML definitions** (`~/.her-os/annie/agents/*.yaml`) — already hot-reloadable via filesystem watcher in `agent_discovery.py`
2. **Python context sources + callbacks** — registered ONCE at startup in `server.py` via `register_context_source()` / `register_completion_callback()`. New Python modules are never imported at runtime.

If a YAML references a context source that hasn't been registered, the agent **fails silently** when the scheduler tries to fetch that context.

## Current Registration Chain (server.py:185-220)

```python
# Each module has a register_*() function called once at startup
from meditation import register_meditation_sources        # 3
from task_delivery import register_task_delivery_callback  # 3b
from proactive_pulse import register_pulse                 # 3c
from router_report import register_router_report_sources   # 3d (gated by env var)
from network_anomaly import register_network_anomaly_sources  # 3d
from model_watcher import register_model_watcher_sources   # 3e (NEW)
```

## Goal

Drop a YAML + Python file → agent works immediately. No restart. No `server.py` edit.

## Proposed Fix

**Auto-discover Python modules alongside YAML definitions.**

When `agent_discovery.py` finds a new/changed YAML:
1. Parse the YAML as today
2. For each `context_sources` name and `on_complete` callback name that is NOT already registered:
   - Look for a Python file with the same stem as the YAML (e.g., `model_watcher.yaml` → look for `model_watcher.py` in the agents dir or in `services/annie-voice/`)
   - Import it and call its `register()` or `register_*_sources()` function
3. For existing registered sources/callbacks, skip (idempotent)

### Alternative: Convention-based lazy loading

In `agent_scheduler.py`, when fetching context for a job:
```python
# Current: CONTEXT_SOURCES[name]() — KeyError if not registered
# Proposed: if name not in CONTEXT_SOURCES, try to import it
if name not in CONTEXT_SOURCES:
    try:
        mod = importlib.import_module(name)
        if hasattr(mod, 'register'):
            mod.register()
    except ImportError:
        logger.warning(f"Context source '{name}' not found")
```

Same pattern for `COMPLETION_CALLBACKS`.

## Files to Modify

| File | Change |
|------|--------|
| `agent_scheduler.py` | Lazy-import context sources and callbacks on first use |
| `agent_discovery.py` | Optionally trigger Python module discovery alongside YAML |
| `server.py` | Remove hardcoded `register_*()` calls (they become auto-discovered) |
| Each `*_sources` module | Ensure `register()` function is idempotent (safe to call twice) |

## Constraints

- Must be idempotent — calling register twice must not duplicate sources
- Must not break existing agents (backward compatible)
- Must log clearly when a source/callback can't be found
- Must handle import errors gracefully (one bad module doesn't crash Annie)

## Verification

After implementation, use `GET /v1/capabilities?group=agents` to verify newly loaded agents appear in real-time (the capability manifest reads from `AgentDiscovery` at request time, not at import time — so hot-loaded agents appear automatically).
