Skip to content

feat(overseer): top-down loop-runner / overseer agent - #114

Merged
TraderSamwise merged 5 commits into
masterfrom
agent-loop-watcher
Jun 13, 2026
Merged

feat(overseer): top-down loop-runner / overseer agent#114
TraderSamwise merged 5 commits into
masterfrom
agent-loop-watcher

Conversation

@TraderSamwise

Copy link
Copy Markdown
Owner

What

Adds an optional overseer agent per project — the first entrypoint for human-initiated, top-down, cross-worktree orchestration. Its day-1 use case is loop-running: keep designated agents working until they hard-signal done or blocked beyond repair, instead of giving back their turn early (a frequent Claude Code failure mode). It's built generic so the same agent can also answer "what is everyone working on?" and direct agents across worktrees.

Built entirely on existing primitives (tasks/threads/spawn//agents/input//agents/output/topology). No new orchestration primitives.

Design

  • Daemon = heartbeat + detector (deterministic, zero tokens). A LoopWatcher runs beside PluginRuntime in the project-service host, scanning on an interval for in-loop agents that stopped (activity idle/done, attention normal, not waiting on a human).
  • Overseer = reactive brain (LLM, on-demand). The watcher only wakes the overseer when there's an actual candidate — cheaper than a self-looping LLM, agent-agnostic (wakes via tmux input), and robust (the heartbeat doesn't depend on the overseer staying awake).
  • Without an overseer, the daemon stays observe-only unless loop.autoNudgeWithoutOverseer is enabled (default off).

Phases (one commit each)

  1. Metadata flags + observe/act CLIoverseer/loop fields on SessionMetadata; GET /agents snapshot + POST /agents/loop; aimux input, aimux ps, aimux loop add/remove.
  2. Daemon loop watcher — pure findLoopCandidates + LoopWatcher; LoopConfig (15s/60s/off); listPendingInteractions so we never steamroll an agent waiting on a human.
  3. Overseer role + preamblebuildOverseerPreamble, sticky system prompt gated on team.role === "overseer"; aimux overseer start/clear.
  4. Agent self-exitaimux loop done / aimux loop block (resolve own $AIMUX_SESSION_ID, clear the loop, emit a task_done/blocked status).

Closing the loop

human aimux loop add → watcher detects a premature stop → overseer reads output and aimux inputs a continue (or releases) → agent aimux loop done/block when genuinely finished/blocked.

Verification

yarn typecheck, yarn lint, yarn build, and the full yarn vitest suite (1111 tests) pass. New unit tests cover the candidate truth table, overseer-wake vs canned-nudge dispatch + cooldowns, the overseer-present-but-offline fallthrough, metadata round-trips, the GET /agents/POST /agents/loop routes, overseer-preamble injection, and the self-exit nudge wording. CLI registration smoke-tested via --help.

A full live-agent end-to-end (spawn real agents, watch a nudge fire) was not run headless in this environment.

🤖 Generated with Claude Code

test and others added 4 commits June 13, 2026 22:07
Phase 1 of the overseer (top-down orchestration) feature. Adds the
foundation the loop watcher and overseer agent build on, with no
behavior change yet:

- metadata-store: `overseer` + `loop` fields on SessionMetadata plus
  setSessionLoop/clearSessionLoop/setSessionOverseer/findOverseerSessionId
- metadata-server: `GET /agents` cross-worktree snapshot (topology +
  derived activity/attention + loop/overseer flags + active task) and
  `POST /agents/loop` to toggle loop membership
- CLI: `aimux input <id> <text>`, `aimux ps [--json]`,
  `aimux loop add/remove`
- tests: metadata-store round-trip + GET /agents / POST /agents/loop HTTP

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2. A deterministic heartbeat that runs beside PluginRuntime in the
project-service host and keeps in-loop agents working:

- loop-watcher: pure findLoopCandidates (in-loop + activity idle/done +
  attention normal + no pending interaction, excluding the overseer) and
  a LoopWatcher class that scans on an interval. When an overseer is
  running it wakes it once with a briefing; otherwise, if
  autoNudgeWithoutOverseer is enabled, it sends a canned continue-nudge.
  Per-target cooldowns prevent storms; the interval is unref'd.
- config: LoopConfig block (scanIntervalMs/nudgeCooldownMs/
  autoNudgeWithoutOverseer), defaults 15s/60s/off
- metadata-server: listPendingInteractions accessor so the watcher can
  skip agents waiting on a human
- dashboard-model: instantiate/teardown the watcher with the project
  service lifecycle
- tests: candidate truth table, overseer-wake vs canned-nudge dispatch,
  cooldown, and the overseer-present-but-offline fallthrough

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 3. Makes the overseer a real, launchable agent category that the
loop watcher (Phase 2) wakes:

- team: buildOverseerPreamble() — the overseer's standing instructions
  (its toolset + the loop duty + generic orchestration role)
- session-bootstrap: buildSessionPreamble injects the overseer preamble
  as a sticky system prompt when team.role === "overseer"
- spawnAgent: an `overseer` option that tags the session with the
  overseer team role (drives the preamble) and sets the metadata
  overseer flag (drives loop-watcher discovery)
- metadata-server: thread `overseer` through /agents/spawn; add
  POST /agents/overseer to demote a session
- CLI: `aimux overseer start` and `aimux overseer clear`
- tests: overseer preamble injection is role-gated

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 4. Closes the loop with a hard-feedback exit the agent runs itself:

- CLI: `aimux loop done [--reason]` and `aimux loop block [--reason]`,
  run by an in-loop agent. They resolve the agent's own session from
  $AIMUX_SESSION_ID (or --session), clear the loop flag, and emit a
  task_done / blocked event so the human and overseer see the outcome.
- loop-watcher: the canned nudge now points agents at `aimux loop done`
  / `aimux loop block` instead of vague "ask to be removed" wording.
- team: the overseer preamble notes agents can self-exit a loop.
- tests: assert the canned nudge surfaces the self-exit verbs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 13, 2026 2:48pm

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@TraderSamwise, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 2 hours, 16 minutes, and 4 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0283c9dc-1e63-4257-9312-4ead477ad547

📥 Commits

Reviewing files that changed from the base of the PR and between 18b5b90 and 38842a6.

📒 Files selected for processing (13)
  • src/config.ts
  • src/loop-watcher.test.ts
  • src/loop-watcher.ts
  • src/main.ts
  • src/metadata-server.test.ts
  • src/metadata-server.ts
  • src/metadata-store.test.ts
  • src/metadata-store.ts
  • src/multiplexer/dashboard-model.ts
  • src/multiplexer/dashboard-tail-methods.ts
  • src/session-bootstrap.test.ts
  • src/session-bootstrap.ts
  • src/team.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent-loop-watcher

Comment @coderabbitai help to get the list of available commands and usage tips.

- loop-watcher: only start the nudge/briefing cooldown after the send
  actually succeeds, so a failed delivery retries on the next scan
  instead of silencing the target for a full cooldown window
- loop-watcher: include "starting" sessions in the scan so an overseer
  still coming up is discovered rather than treated as absent
- metadata-server: POST /agents/loop now requires an explicit boolean
  `active`; omitting it 400s instead of silently clearing the loop
- main: agent self-exit clears the loop first, then emits the status
  event best-effort, so a failed notification can't leave a finished
  agent still being nudged
- tests: omitted-active 400, and failed-send does not consume cooldown

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@TraderSamwise

Copy link
Copy Markdown
Owner Author

Sub-agent review (round 1) — dispositions

CodeRabbit is rate-limited on this account (≈2h), so an independent sub-agent reviewed the diff. Findings and resolutions:

# Sev Finding Resolution
1 med LoopWatcher set the nudge/briefing cooldown before the send succeeded, so a failed delivery silenced the target for a full cooldown Fixed (38842a6) — cooldown only starts after a successful send; failures retry next scan
2 med POST /agents/loop cleared the loop flag when active was omitted Fixed (38842a6) — active must be an explicit boolean, else 400
3 med Self-exit (loop done/block) did two POSTs; a failed 2nd left no status Fixed (38842a6) — clear the loop first (watcher stops nudging regardless), then emit the event best-effort. Reversing the order would be worse: a failed event would leave a finished agent still being nudged
4 low overseer metadata flag isn't cleared when the session stops By design — stop ≠ demote (a revived overseer keeps its role); graveyard is excluded from aimux ps; the watcher only acts on a running overseer. aimux overseer clear demotes explicitly
5 low An overseer in starting status wasn't discovered by the watcher Fixed (38842a6) — scan now includes starting
6 Two-hop spawn routing for the overseer flag Non-issue (confirmed correct)

New tests: omitted-active ⇒ 400; a failed nudge does not consume the cooldown.

@TraderSamwise
TraderSamwise merged commit 7b89a98 into master Jun 13, 2026
3 checks passed
@TraderSamwise
TraderSamwise deleted the agent-loop-watcher branch June 13, 2026 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant