CEO Plan: Minions as Universal Agent Orchestration Protocol
Generated by /plan-ceo-review on 2026-04-15 Branch: shubham/minions-jobs | Mode: SCOPE EXPANSION Repo: thebuildceo/modusbrainVision
10x Check
Instead of “ModusBrain has a queue, OpenClaw uses it,” make Minions a universal agent orchestration protocol. Any platform (OpenClaw, Hermes, Claude Code, Codex, custom scripts) submits, monitors, steers, and composes agents through the same Postgres-native protocol. ModusBrain IS the agent control plane.Platonic Ideal (aspirational North Star, NOT in v1 scope)
Open a terminal, typemodusbrain jobs dashboard. See every agent across every platform.
Their progress, tool calls, token spend. Click any agent for full execution trace.
Type a message to redirect a running agent mid-flight. See the governor’s decisions
visualized. Run A/B tests between agent configurations. The feeling: complete
situational awareness of your AI workforce.
Note: The dashboard, A/B testing, and visual governor are future phases. This plan
builds the primitives they would sit on top of: real-time events, structured progress,
token accounting, inbox with ack, and session transcripts.
Scope Decisions
Accepted Scope — Implementation Detail
0a. Pause/resume (from base plan)
Schema: Add'paused' to MinionJobStatus (already in migration v6 constraint).
New methods:
MinionQueue.pauseJob(id): MinionJob | nullTransitionswaitingoractive→paused. Foractivejobs, clearslock_tokenandlock_until(worker will detect lock loss and stop). Returns null if job not in pausable state.MinionQueue.resumeJob(id): MinionJob | nullTransitionspaused→waiting. Resets for claiming. Returns null if not paused.
isActive(). When a job
is paused, the lock is cleared, so renewLock() returns false and the worker stops
execution gracefully (same path as stall detection). The job’s progress and state
are preserved in the DB for when it resumes.
MCP operations: pause_job, resume_job (added in Step 3 of implementation plan).
PGLite compatibility: Full.
0b. Resource governor (from base plan)
New file:src/core/minions/governor.ts
getSystemLoad() from src/core/backoff.ts (already
implements CPU and memory checks). Add event loop lag measurement via
perf_hooks.monitorEventLoopDelay().
Worker integration: MinionWorker.start() consults governor.getEffectiveConcurrency()
before claiming new jobs. If current in-flight count >= effective concurrency, skip claim.
Circuit breaker: If memory > 90%, governor calls onCircuitBreak with the
lowest-priority active job ID. Worker cancels that job via failJob() with
UnrecoverableError("circuit breaker: memory pressure").
Prerequisite: Concurrent job processing must be implemented first (see
Concurrency Note below).
PGLite compatibility: Full (governor is app-level, not DB-level).
1. pg LISTEN/NOTIFY (real-time events)
Schema: No new columns. Add NOTIFY triggers to state transitions. SQL trigger:MinionQueue.subscribe(callback: (event) => void): () => void
Returns unsubscribe function. Requires direct Postgres connection (NOT pooled).
PGLite compatibility: PGLite does NOT support LISTEN/NOTIFY. Fallback: polling
via getJob() at configurable interval (default 2s). The subscribe() method
detects engine type and uses polling fallback automatically.
Supabase constraint: Requires direct connection (port 5432), not pgBouncer
pooler (port 6543). Document in skill file and setup guide.
2. Structured progress protocol
TypeScript interface (convention, not enforced at DB level):progress JSONB column. No schema change needed.
Handlers use ctx.updateProgress(agentProgress). Non-agent jobs can use
any JSONB shape (backward compatible).
Validation: updateProgress() accepts any JSONB. The AgentProgress
interface is a convention enforced by the agent handler, not by the queue.
3. Job cost tracking (token accounting)
Schema changes (migration v6):MinionQueue.updateTokens(id, lockToken, { input, output, cache_read, cost_usd })
Accumulates (adds to existing values, does not replace).
Parent rollup: When completeJob() is called, if parent_job_id is set,
add this job’s token counts to the parent’s via:
4. Job replay
New method:MinionQueue.replayJob(id, dataOverrides?: Record<string, unknown>): MinionJob
Implementation: Read the completed/failed/dead job. Create a NEW job with:
- Same
name,queue,priority,max_attempts,backoff_type,backoff_delay data= deep merge of original data + overrides- Fresh
attempts_made: 0,status: 'waiting' parent_job_id= null (replay is a new top-level job, not a child)- Does NOT clone children (replay is a single job, not a DAG)
5. Inbox (sidechannel messaging)
Schema changes (migration v6):MinionQueue.sendMessage(jobId, payload, sender?): InboxMessageAppends message to inbox array via atomic JSONB append (inbox = inbox || $1::jsonb), not read-modify-write. Returns the message with id + sent_at.MinionQueue.readInbox(jobId, lockToken): InboxMessage[]Returns unread messages (read_at = null). Marks them as read (sets read_at). Token-fenced: only the worker holding the lock can read.
readInbox() on each iteration.
If messages exist, injects them into the agent’s context as system messages.
PGLite compatibility: Full support (standard JSONB column).
6. Inbox acknowledgment (read receipts)
Built into the inbox design above. Theread_at field on each InboxMessage
provides the receipt. sendMessage() returns the message ID; the sender can
later check getJob(id) and inspect inbox to see which messages have been
read.
No additional schema or methods needed beyond what’s in #5.
7. Universal agent protocol (platform-agnostic framing)
This is a design decision, not code. It means:-
The skill file (
skills/minion-orchestrator/SKILL.md) is written for ANY agent platform, not just OpenClaw. Examples show MCP tool calls, not OpenClaw-specific commands. -
The agent handler (
agent-handler.ts) accepts a generic interface: -
The OpenClaw plugin is ONE consumer. Hermes, Claude Code extensions,
or custom scripts can submit
agentjobs through the same MCP operations. - NOT in v1 scope: Multi-tenant auth, cross-network connectivity, protocol versioning, API key isolation. These are Phase 2 concerns when actual multi-platform usage materializes. v1 is single-user, single-brain.
Agent Handler Architecture (critical design decision)
The agent handler does NOT live in ModusBrain. ModusBrain provides the queue infrastructure and a clean handler contract. The actual agent execution lives in the platform plugin.8. Session transcript capture
Extends existing stacktrace mechanism. Thestacktrace field (JSONB array
of strings) already captures log messages. Session transcripts use the same
field with structured entries:
stacktrace JSONB column. No schema change.
The agent handler appends TranscriptEntry objects instead of plain strings.
Backward compatible: non-agent jobs continue appending strings.
Size concern: Long agent runs could generate large transcripts. Add a
max_transcript_entries option (default 1000) that rotates oldest entries
when exceeded (FIFO). The full transcript for forensic analysis can be
stored as a brain file via modusbrain files upload-raw.
Schema Migration v6
All schema changes are additive (ALTER TABLE ADD COLUMN). No backfill needed. Existing jobs continue to work with default values.PGLite Compatibility Matrix
Concurrency Note
The currentMinionWorker.start() processes jobs sequentially (one at a time)
despite concurrency being declared in MinionWorkerOpts. Implementing actual
concurrent job processing (Promise pool) is a prerequisite for the resource
governor to be meaningful. The governor adjusts effective concurrency, which
requires actual concurrent processing to exist.
Action: Implement concurrent job processing in worker.ts before or as
part of the governor step. Use a semaphore pattern: maintain up to N in-flight
promises, claim new jobs as slots free up.
Outside Voice Decisions (from adversarial review)
-
AbortController for pause/resume — Handler contract gets
signal: AbortSignal. Pause clears lock AND signals abort. Handler must checksignal.abortedon each iteration. Without this, pausing active jobs creates duplicate execution. -
Drop cost_usd column — Token counts (input/output/cache_read) are stable facts.
USD pricing is volatile. Compute cost at display/read time from a pricing table,
not at write time. Removes
cost_usd NUMERIC(10,6)from migration v6. -
Separate minion_inbox table — Instead of JSONB array on job row, use a dedicated
table for inbox messages. Avoids row bloat from rewriting entire inbox on every send.
Properly concurrent-safe with standard INSERT (no JSONB append concerns).
- One release, not two — Ship all features in one migration (v6). User prefers cohesive release over incremental delivery for this feature set.
- Selective column projection — Fix SELECT * queries in getJobs(), claim(), handleStalled() to exclude stacktrace column. Include stacktrace only in getJob() detail view. Prevents transcript bloat from affecting query performance.
Future Phases (accepted trajectory)
- Phase 2: Dashboard CLI —
modusbrain jobs dashboardlive TUI showing all agents. Enabled by: LISTEN/NOTIFY, structured progress, token accounting. - Phase 3: Multi-tenant auth — Runtime MCP access control, per-platform API keys. Enabled by: platform-agnostic framing, sender validation on inbox.
- Phase 4: Agent composition patterns — Map-reduce, pipeline, approval gates as first-class primitives. Enabled by: parent-child DAGs, inbox sidechannel.
Deferred to TODOS.md
- Job groups / waves (parent-child covers this; revisit if real grouping need emerges)
- cost_usd column (compute from pricing table at read time when pricing API exists)
Key Premises Confirmed
- ModusBrain is intentionally evolving from knowledge brain to agent infrastructure (user confirmed)
- Coupling between OpenClaw and ModusBrain’s Postgres is acceptable (OpenClaw already depends on ModusBrain)
- Full Infrastructure approach (all 8+ steps) selected over Minimal Viable or Sidecar Tracking
- Prior learning [agent-dx-instruction-layer] validates that the teaching layer (skill + evals) is mandatory