Skip to content

Autonomous Orchestrator

autonomous_orchestrator -- G6 Autonomous Multi-Agent Orchestration System.

Cluster: Experience & Autonomy | Type: component | MCP Tools: 27

Overview

24/7 autonomous multi-agent orchestration system that continuously processes a JSON todo list using a six-slot agent pool (design, execution, evaluation, and three proxy agents) with rate limiting, session logging, and human-review queuing. Wraps AgentPool, TaskManager, and RateLimiter into a single AIBlock with graceful shutdown via signal handling.

When to use:

  • Running an unattended agent loop that picks up tasks from a structured todo file and executes them autonomously
  • Distributing work across specialised agent roles (design → execution → evaluation) with token accounting
  • Integrating continuous background processing into G6 with HITL review hand-off

Example:

from mvp.autonomous_orchestrator import AutonomousOrchestratorBlock, OrchestratorInput

block = AutonomousOrchestratorBlock()
result = block.infer(OrchestratorInput(
    todo_path="components/mvp/workspace_manager/claude_todo_list.json",
    dry_run=True,
    stop_on_empty=True,
))
# result.ok → True; result.value → OrchestratorOutput with tasks_completed, summary

Works well with: recursive_architect, hat_orchestrator, autonomy_governor

OrchestratorInput safety-relevant fields:

  • opLiteral["describe", "status", "start_daemon"] (default start_daemon). describe/status are read-only shims that never enter the dispatch loop; only start_daemon launches the 24/7 daemon. Registry-invoked bogus ops fail validation cleanly.
  • production_modebool (default False). With op="start_daemon" and production_mode=True, the direct JSON-backed path is refused with degraded=True, degradation_reason="json_unsafe_in_production". The JSON TaskManager has no file-locking contract, so concurrent writers can corrupt the todo file. Use the SQLite-backed orchestrator_mcp store in production.

Split-brain note: the direct daemon (JSON) and the orchestrator_mcp plane (SQLite) are separate sources of truth. The MCP plane is management/inspection only — it cannot start, stop, or inspect the live daemon. ao_get_pool_status reports active SQLite sessions (not live AgentPool slots), ao_configure_limits mutates shadow state (not a running RateLimiter), and ao_capabilities reports live_control_available: false. Cross-package enrichment fallback in ao_complete_task and bad-JSON / agentic degradation in ao_run_failure_guard are surfaced via degraded/degradation_reason.

Pilot-ready, not multi-worker production hardened

The autonomous orchestrator is suitable for local development, dry runs, and early pilot workflows where a single process owns the task queue. It is not yet hardened for multi-worker production operation.

The direct AutonomousOrchestratorBlock path uses JSON-backed todo and human-review files, which are not safe for concurrent writes from multiple orchestrator processes. Runtime dollar-cost tracking is also process-local, so production deployments should rely on a single orchestrator instance, explicit token limits, the kill-switch file, and human review until durable shared spend accounting is added.

For paid self-serve or unattended production use, run an end-to-end MCP install/run smoke test first and prefer the SQLite-backed orchestrator_mcp operations for task/session inspection. Do not treat successful task completion as a proof of business or regulated-domain correctness without human review.

Public API

AgentPool

Manages 6 concurrent agent slots for dispatching tasks.

Constructor:

Parameter Type Default
task_manager TaskManager required
rate_limiter RateLimiter required
config OrchestratorInput required
governor 'AutonomyGovernorBlock \| None' None
hitl 'HITLDispatcher \| None' None
safety_policy 'RuntimePolicy \| None' None
pricing_catalog Any \| None None

Methods:

dispatch(stop_event: asyncio.Event) -> dict

Run the dispatch loop until stop_event is set or no tasks remain.

GuardSignals

Derived signals from the 20 failure-guard answers.

Field Type Default
stuck bool False
waste bool False
no_value bool False
sanity_failed bool False
degraded bool False
degradation_reason str ''

GuardVerdict

The outcome of a Ralph Wiggum loop iteration.

Field Type Default
signals GuardSignals field(default_factory=GuardSignals)
next_action str 'continue'
iteration int 0
passed bool True

FailureGuard

Asks each of the 20 questions via a cheap LLM and logs answers.

Constructor:

Parameter Type Default
logger SessionLogger \| None None

Methods:

ask_questions(context: str, task_title: str = '', dry_run: bool = False) -> list[tuple[int, str, str]]

Ask all 20 questions about the current step.

extract_signals_from_json(json_str: str) -> 'GuardSignals'

Parse structured JSON answer list into GuardSignals.

extract_signals(answers: list[tuple[int, str, str]]) -> GuardSignals

Derive 4 signals from key question answers.

RalphWiggumLoop

Orchestrates the full failure-guard + verdict pipeline per step.

Constructor:

Parameter Type Default
logger SessionLogger \| None None
dry_run bool False

Methods:

set_guard_signal_planner(planner: object) -> None

Inject an agentic failure-signal planner (test seam).

review_step(context: str, task_title: str = '', attempts: int = 0) -> GuardVerdict

Run the full 20-question review and determine next action.

AutonomousOrchestratorBlock(AIBlock[OrchestratorInput, OrchestratorOutput, None])

Top-level orchestrator that autonomously processes tasks 24/7.

Field Type Default
name str 'g6_autonomous_orchestrator'

Methods:

infer(data: OrchestratorInput) -> Result[OrchestratorOutput]

Synchronous wrapper — calls run_async() via asyncio.run().

run_async(data: OrchestratorInput) -> OrchestratorOutput

Async entry point for the 24/7 orchestrator loop.

RateLimiter

Global token budget + per-agent cooldown enforcer with optional SQLite persistence.

Constructor:

Parameter Type Default
max_tokens_per_hour int MAX_TOKENS_PER_HOUR
cooldown_min float COOLDOWN_MIN_SEC
cooldown_max float COOLDOWN_MAX_SEC
db_path str \| None _DEFAULT_DB
max_cost_usd float \| None DEFAULT_MAX_COST_USD
kill_switch_path str \| None None

Methods:

kill_switch_tripped() -> bool

Return True when the configured kill-switch file exists on disk.

record_cost(cost_usd: float) -> None

Accumulate dollar spend; used by acquire to refuse when

accumulated_cost_usd() -> float

Total USD cost recorded this process (0.0 when none).

is_budget_exhausted() -> bool

record_tokens(count: int, agent_id: str = '') -> None

tokens_last_hour() -> int

is_budget_exceeded() -> bool

mark_agent_call(agent_id: str) -> None

Record that agent_id just made a call.

wait_for_cooldown(agent_id: str) -> None

Sleep until the per-agent cooldown has expired.

wait_for_budget() -> None

Sleep until the global token budget is available again.

acquire(agent_id: str) -> str

Wait for cooldown/budget, then return the resolved model ID.

snapshot() -> dict

Return current state for diagnostics.

AgentRole(str, Enum)

Which slot an agent occupies in the pool.

AgencyLevel(int, Enum)

Progressive agency ladder — higher = more autonomous.

TaskItem(BaseModel)

A single work item in the todo queue.

Field Type Default
id str ''
title str ''
description str ''
component str ''
phase Literal['basic', 'intermediate', 'advanced'] 'basic'
status Literal['pending', 'in_progress', 'complete', 'failed'] 'pending'
parent_id str \| None None
children_ids list[str] Field(default_factory=list)
depends_on list[str] Field(default_factory=list)
inputs dict[str, Any] Field(default_factory=dict)
outputs dict[str, Any] Field(default_factory=dict)
artifacts list[str] Field(default_factory=list)
attempts int 0
interruptions int 0
created_at str ''
updated_at str ''
assigned_agent str \| None None
session_log str \| None None

Methods:

model_post_init(__context: Any) -> None

TodoList(BaseModel)

Serialisable container for claude_todo_list.json.

Field Type Default
tasks list[TaskItem] Field(default_factory=list)
summary str ''
last_updated str ''

HumanReviewEntry(BaseModel)

One completed-task entry for human_review_todo.json.

Field Type Default
task_id str ''
task_description str ''
completed_at str ''
explanation str ''
what_was_achieved str ''
session_log_path str ''
review_status Literal['pending', 'approved', 'rejected'] 'pending'

SessionEvent

A single JSONL-serialisable event within an agent session.

Field Type Default
event str required
ts str ''
session_id str ''
task_id str ''
task str ''
agent_role str ''
fn str ''
result_summary str ''
tokens int 0
q_id int 0
question str ''
answer str ''
iteration int 0
self_review str ''
passed bool True
goal_achieved bool False
summary str ''
tokens_total int 0
module str ''
root_cause str ''
detail str ''

Methods:

to_dict() -> dict[str, Any]

Return dict with zero/empty/False fields stripped (except 'event').

AgentSession

Runtime state for one agent session (in-memory only).

Field Type Default
session_id str ''
task_id str ''
agent_role AgentRole AgentRole.PROXY_1
tokens_used int 0
events list[SessionEvent] field(default_factory=list)
started_at str ''

OrchestratorInput(BaseModel)

Input for AutonomousOrchestratorBlock.infer().

Field Type Default
op Literal['describe', 'status', 'start_daemon'] 'start_daemon'
todo_path str 'components/mvp/workspace_manager/claude_todo_list.json'
review_path str 'components/mvp/workspace_manager/human_review_todo.json'
session_log_dir str 'logs/sessions'
stop_on_empty bool False
dry_run bool False
podman_host str ''
production_mode bool False

OrchestratorOutput(BaseModel)

Output from AutonomousOrchestratorBlock.infer().

Field Type Default
tasks_completed int 0
tasks_failed int 0
tasks_remaining int 0
total_tokens int 0
summary str ''
session_logs list[str] Field(default_factory=list)
degraded bool False
degradation_reason str ''
completion_state Literal['verified', 'qualified-draft', 'blocked-escalated'] 'qualified-draft'
warning_card dict[str, Any] Field(default_factory=dict)
estimated_cost_usd float 0.0
budget_remaining dict[str, Any] Field(default_factory=dict)

SessionLogger

Appends SessionEvent dicts as JSONL lines to a per-session file.

Constructor:

Parameter Type Default
session_id str required
log_dir str \| Path 'logs/sessions'

Methods:

path() -> Path

log(event: SessionEvent) -> None

Serialise event and append to the JSONL file.

log_raw(data: dict) -> None

Append an arbitrary dict (for ad-hoc events).

read_events() -> list[dict]

Read back all events from the JSONL file.

event_count() -> int

Return number of events logged so far (line count).

file_size() -> int

Return the current file size in bytes.

TaskManager

Reads/writes the todo JSON files and manages task lifecycle.

Constructor:

Parameter Type Default
todo_path str \| Path 'components/mvp/workspace_manager/claude_todo_list.json'
review_path str \| Path 'components/mvp/workspace_manager/human_review_todo.json'

Methods:

load_todo() -> TodoList

Load the todo list from disk (or return empty).

save_todo(todo: TodoList) -> None

Write the todo list to disk atomically (RS-16-F03).

load_reviews() -> list[HumanReviewEntry]

Load human review entries from disk.

save_reviews(reviews: list[HumanReviewEntry]) -> None

Write human review entries to disk atomically (RS-16-F03).

auto_populate() -> TodoList

Load existing todo list (no-op seeding — all components are implemented).

pick_next(todo: TodoList | None = None) -> TaskItem | None

Pick the next pending task.

claim_task(task_id: str, agent_id: str) -> TaskItem | None

Mark a task as in_progress and assign to agent_id.

complete_task(task_id: str, explanation: str = '', what_was_achieved: str = '', session_log_path: str = '', outputs: dict | None = None, artifacts: list[str] | None = None) -> None

Mark a task as complete and add a human review entry.

fail_task(task_id: str) -> None

Mark a task as failed and cascade-fail its pending dependents.

enqueue(task: TaskItem) -> None

Add a new task to the todo list.

increment_failure_count(component: str) -> int

Track and return cumulative failure count for a component.

reset_stale(stale_after_seconds: float = 900.0, now: datetime | None = None) -> int

Reset stale in_progress tasks back to pending (startup recovery).

checkpoint_task(task_id: str) -> bool

Return a single in-flight task to a resumable (pending) state.

create_subtasks(parent_id: str, max_children: int = 5) -> list[TaskItem]

Decompose a failed/stuck task into subtasks via GoalDecomposer.

stats(todo: TodoList | None = None) -> dict

Return task counts by status.

OrchestratorMCPBlock(AIBlock[MCPOrchestratorInput, MCPOrchestratorOutput, dict])

26-op MCP block for Autonomous Orchestrator.

Field Type Default
name str 'orchestrator_mcp'
state dict \| None None
db_path str ''

Methods:

infer(data: MCPOrchestratorInput) -> Result[MCPOrchestratorOutput]

MCPOrchestratorInput(BaseModel)

Field Type Default
op OrchestratorOp required
task_id str \| None None
title str \| None None
description str \| None None
component str \| None None
phase str \| None None
status str \| None None
agent_id str \| None None
session_id str \| None None
event_type str \| None None
event_data_json str \| None None
context str \| None None
task_title str \| None None
questions_json str \| None None
answers_json str \| None None
tokens int \| None None
max_tokens_per_hour int \| None None
cooldown_sec int \| None None
session_name str \| None None
limit int \| None None
query str \| None None

MCPOrchestratorOutput(BaseModel)

Field Type Default
ok bool required
message str required
data_json str \| None None
degraded bool False
degradation_reason str ''

OrchestratorStore

5-table SQLite store for Autonomous Orchestrator MCP.

Constructor:

Parameter Type Default
db_path str ':memory:'

Methods:

create_task(title: str, description: str = '', component: str = '', phase: str = 'basic') -> dict

get_task(task_id: str) -> dict | None

list_tasks(status: str | None = None, phase: str | None = None, component: str | None = None, limit: int = 50) -> list[dict]

update_task(task_id: str, **kwargs) -> bool

claim_task(task_id: str, agent_id: str) -> bool

complete_task(task_id: str) -> bool

fail_task(task_id: str) -> bool

reset_stale() -> int

Reset in_progress tasks back to pending. Returns count reset.

pick_next(phase: str | None = None) -> dict | None

Pick the next pending task with fewest attempts, optionally filtered by phase.

get_task_stats() -> dict

start_session(task_id: str = '', agent_role: str = '') -> dict

get_session(session_id: str) -> dict | None

list_sessions(task_id: str | None = None, status: str | None = None, limit: int = 50) -> list[dict]

end_session(session_id: str, tokens_used: int = 0) -> bool

get_session_stats() -> dict

log_event(session_id: str, event_type: str, data_json: str = '{}') -> dict

list_events(session_id: str, limit: int = 100) -> list[dict]

store_verdict(session_id: str = '', task_id: str = '', signals_json: str = '{}', next_action: str = 'continue', iteration: int = 0, passed: bool = True) -> dict

get_verdict(verdict_id: str) -> dict | None

list_verdicts(session_id: str | None = None, task_id: str | None = None, limit: int = 50) -> list[dict]

record_tokens(tokens: int, agent_id: str = '') -> dict

get_tokens_in_window(agent_id: str = '', window_seconds: int = 3600) -> int

Sum tokens recorded in the last window_seconds.

search(query: str, top_k: int = 10) -> list[dict]

Functions

list_patterns() -> dict[str, Any]

Return the autonomous_orchestrator applied-pattern + skill surface.

MCP Tools

Operation Source
create_task orchestrator_mcp
get_task orchestrator_mcp
list_tasks orchestrator_mcp
update_task orchestrator_mcp
claim_task orchestrator_mcp
complete_task orchestrator_mcp
fail_task orchestrator_mcp
reset_stale orchestrator_mcp
start_session orchestrator_mcp
log_event orchestrator_mcp
get_session orchestrator_mcp
list_sessions orchestrator_mcp
get_session_stats orchestrator_mcp
run_failure_guard orchestrator_mcp
extract_signals orchestrator_mcp
get_verdict orchestrator_mcp
list_verdicts orchestrator_mcp
get_token_budget orchestrator_mcp
record_tokens orchestrator_mcp
configure_limits orchestrator_mcp
get_pool_status orchestrator_mcp
get_task_stats orchestrator_mcp
save_session orchestrator_mcp
load_session orchestrator_mcp
search orchestrator_mcp
info orchestrator_mcp
capabilities orchestrator_mcp