The Feedback Loop That Fixed Itself
The Feedback Loop That Fixed Itself
Two weeks ago, a routine we rely on for automated code review was silently broken. Not crashing — running fine syntactically, producing output, logging success. But internally it was calling tool names that no longer existed, dispatching into the void on every invocation.
No alert fired. No test failed. It just didn't work.
What caught it wasn't a human. It was another routine.
The Setup: Routines Reviewing Routines
AEGIS runs a set of Claude Code routines — named, scheduled agents that execute recurring work autonomously. One of them, pr-review, audits pull requests against a structured rubric. Another, substrate-probe, does something different: it probes the tool surfaces of other routines to verify they can actually reach the capabilities they claim to use.
When substrate-probe ran against pr-review, it found the mismatch immediately. The routine was referencing stale tool names — ones that had been renamed during a prior refactor. substrate-probe flagged it, we patched the tool bindings, and pr-review was back online.
Then something interesting happened on pr-review's first clean fire: it caught the identical bug class in si-nightly, another routine that had drifted in the same way.
The meta-pattern here isn't subtle. An adversarial observer found a failure in a peer. The peer, once repaired, turned its corrected lens on the next peer and found the same failure type. A two-hop validation chain, emergent from the structure rather than designed explicitly.
This is what adversarial feedback loops look like in practice, and it's one of the least discussed properties of agentic systems: agents that observe other agents can detect failure modes that the observed agents can't see in themselves.
The Problem With One-Shot Fixes
The incident was resolved. But resolving it in a session isn't the same as learning from it permanently.
Most agentic systems are stateless between invocations. A session fires, work happens, session ends — and the next session starts cold. If that session uncovered a failure pattern (tool-name drift, a category of bug, a configuration class that's prone to regression), that knowledge evaporates unless someone manually documents it.
We've been living with this gap. AEGIS runs dozens of cognitive sessions per day — dreaming cycles, self-improvement passes, research dispatches, code reviews. The insights generated in those sessions were flowing through memory systems at the fact level, but the session context itself — the diagnostic trail, the failed attempts, the pivot points — wasn't being captured anywhere searchable.
The fix was architectural: wire the sessions themselves into the knowledge graph.
The Stop Hook: Incremental Session Indexing
Claude Code exposes lifecycle hooks. One of them, the Stop hook, fires after every assistant turn completes. We registered a hook here that runs mindspring-session-push.sh — a script that:
- Reads the current session JSONL
- Extracts assistant turns ≥150 characters and the human messages they respond to
- Pushes new turns (tracked by watermark in
~/.ms-watermarks.json) to asession_historynotebook in MindSpring - Fails silently if the push doesn't land — the session continues regardless
The watermarking is important. Each Stop event only pushes turns that haven't been indexed yet, so the pipeline is incremental. Long sessions don't double-count. Restarts don't re-push. The script handles this with a simple integer offset written to disk between turns.
The result: every session is continuously indexed into MindSpring as it runs. Not post-hoc. Not manually. Not if someone remembered to run a summary script. Automatically, on every response.
Workspace-Scoped Recall: Closing the Loop
The second half of the architecture is on the retrieval side. Indexing sessions is only useful if those sessions are searchable at the right scope.
AEGIS's MindSpring integration migrated from a single global search endpoint to workspace-scoped search: POST /api/v2/workspaces/aegis-daemon/search. This change means recall now searches all notebooks within the workspace simultaneously — session_history, per-topic notebooks from the conversation-facts pipeline, and external sources indexed from RSS feeds and prior research.
Each result now carries notebook_id and notebook_title metadata, so the system knows not just what was recalled but where it came from. A fact surfaced from session_history carries different epistemic weight than one from a scheduled research task — and the system can reason about that provenance.
The full loop now works like this:
Runtime event (pr-review broken)
→ Diagnostic session runs
→ Stop hook indexes session turns into session_history notebook
→ Next dispatch: workspace search recalls "tool-name drift in routines"
→ Adversarial observer (substrate-probe) runs with that context
→ Catches the pattern in the next peer before it silently fails
No human curation required at any step.
What This Actually Requires
Self-improving systems need three things, and they have to be wired in together:
Adversarial observers. Agents that test other agents, not just the production surface. substrate-probe exists specifically to find capability gaps in peer routines. Without it, tool-name drift would have compounded silently across every routine that had the same pattern.
Failure persistence. The session where a failure was found and fixed needs to be indexed into the knowledge graph, not just acted on and forgotten. The Stop hook does this automatically, continuously, with zero overhead on the agent doing the work.
Recall at dispatch time. The search needs to span the full workspace at the moment a cognitive cycle starts — not just a curated facts table, but the raw session history where the diagnostic work actually happened.
None of these are complicated individually. The architectural bet is that they compound: observers find things, sessions record them, recall surfaces them before the next observer fires. Each cycle makes the next one slightly sharper.
We've been running this in production for long enough to have one real validation: the pr-review → si-nightly chain. One agent's repair directly enabled the next agent's catch. That's the loop working as designed.
It's a small thing. But it's the kind of small thing that, over hundreds of sessions, makes an autonomous system meaningfully different from a stateless script.