Orquestrador enxuto para multi-agent tasks no OpenClaw
Transforma rough task descriptions em structured agent briefs com layered context.
Baseado em patterns do reprompter, sem flywheel/telemetry pesada. Com módulos de loop control inspirados no ralph-claude-code.
- Router: Decide execution mode (single/parallel/sequential/ACP)
- Contract Builder: Transform rough task into structured brief
- Context Builder: Build layered context (contract + facts + references + artifacts)
- Output Checker: Validate agent output quality
- Circuit Breaker: State machine (CLOSED→HALF_OPEN→OPEN) protege contra loops infinitos
- Response Analyzer: Detecta completion, stuck loops, questions, erros no output
- Exit Detector: Dual-condition exit gate — evita sair prematuramente
const { orchestrate } = require('./index');
const result = orchestrate('build a REST API with authentication', {
projectPath: './myproject',
project: 'myproject'
});
console.log(result.brief);
console.log(result.execution.mode); // 'single' | 'parallel' | 'sequential' | 'acp'const { orchestrateLoop } = require('./index');
const plan = orchestrateLoop('implement user dashboard with charts', {
projectPath: './myproject',
circuitBreaker: {
noProgressThreshold: 3,
cooldownMinutes: 30
}
});
let loopNumber = 0;
while (true) {
loopNumber++;
// Build context for this iteration
const ctx = plan.loop.buildLoopContext({
loopNumber,
remainingTasks: plan.contract.tasks?.filter(t => !t.done).length,
circuitBreakerState: plan.loop.circuitBreaker.getState().state,
previousSummary: ''
});
// Spawn agent...
const agentOutput = await spawnAgent({ task: plan.brief + '\n\n' + ctx });
// Process result
const control = plan.loopControl.next({
text: agentOutput,
filesChanged: await getGitDiffCount('./myproject'),
loopNumber,
outputLength: agentOutput.length
});
console.log(`Loop #${loopNumber}: CB=${control.cbState}, exit=${control.exitReason || 'continue'}`);
if (!control.continue) {
console.log(`Stopped: ${control.exitReason || 'circuit_breaker_open'}`);
break;
}
}const { CircuitBreaker, STATES } = require('./circuit-breaker');
const { analyzeResponse, buildLoopContext } = require('./response-analyzer');
const { ExitDetector } = require('./exit-detector');
// Circuit Breaker
const cb = new CircuitBreaker({ noProgressThreshold: 3 });
cb.record({ loopNumber: 1, filesChanged: 0, hasErrors: false });
console.log(cb.getState().state); // 'CLOSED'
// Response Analyzer
const analysis = analyzeResponse('All done! Ready for review.', { filesChanged: 2 });
console.log(analysis.exitSignal); // true
// Exit Detector
const ed = new ExitDetector();
ed.update({ hasCompletionSignal: true, exitSignal: true });
console.log(ed.shouldExit()); // { shouldExit: false, reason: null }
ed.update({ hasCompletionSignal: true, exitSignal: true });
console.log(ed.shouldExit()); // { shouldExit: true, reason: 'completion_signals' }git clone https://github.com/agentxagi/orchestrator-lite.git
cd orchestrator-lite
npm install# Test imports
node -e "require('./circuit-breaker'); require('./response-analyzer'); require('./exit-detector'); console.log('✅ All imports OK')"
# Run loop control tests
node test-loop.js┌─────────────────────────────────────────────────┐
│ index.js (orchestrate / orchestrateLoop) │
├─────────────────────────────────────────────────┤
│ router.js - Intent routing │
│ contract-builder.js - Task contracts │
│ context-builder.js - Layered context │
│ output-check.js - Quality validation │
├─────────────────────────────────────────────────┤
│ circuit-breaker.js - Loop protection (Ralph) │
│ response-analyzer.js - Pattern detection (Ralph)│
│ exit-detector.js - Dual-condition gate (Ralph)│
└─────────────────────────────────────────────────┘
CLOSED ──(2 no-progress)──→ HALF_OPEN ──(no recovery)──→ OPEN
↑ │ │
└────(progress detected)─────┘ │
└────(cooldown elapsed)─────────────────────────────────┘
| State | Meaning |
|---|---|
| CLOSED | Normal operation, everything fine |
| HALF_OPEN | Monitoring — 2+ loops without progress |
| OPEN | Circuit tripped — stop execution, wait for cooldown |
| Priority | Condition | Reason |
|---|---|---|
| 1 | N consecutive test-only loops | test_saturation |
| 2 | N consecutive done signals | completion_signals |
| 3 | N consecutive EXIT_SIGNAL=true | safety_circuit_breaker |
| 4 | 2+ completion indicators + explicit exit | project_complete |
const { orchestrateLoop } = require('./orchestrator-lite');
const { sessions_spawn } = require('openclaw');
async function runAutonomousTask(task, projectPath) {
const plan = orchestrateLoop(task, {
projectPath,
circuitBreaker: { noProgressThreshold: 3, cooldownMinutes: 30 }
});
let loop = 0;
while (true) {
loop++;
const ctx = plan.loop.buildLoopContext({
loopNumber: loop,
circuitBreakerState: plan.loop.circuitBreaker.getState().state
});
const result = await sessions_spawn({
task: plan.brief + '\n\n' + ctx,
runtime: 'acp'
});
const control = plan.loopControl.next({
text: result.output,
filesChanged: 0, // enhance with git diff
loopNumber: loop,
outputLength: result.output?.length || 0
});
if (!control.continue) break;
}
}- Simplicity first - Each module is <200 lines
- Practical - Built for real use, not demonstration
- OpenClaw-native - Integrates with existing tools
- No overhead - No flywheel, heavy telemetry, feature flags
- Loop safety - Circuit breaker prevents infinite loops and token waste
- Intent routing logic
- Task contract structure
- Layered context concept
- Output validation approach
- Circuit breaker state machine (CLOSED/HALF_OPEN/OPEN)
- Dual-condition exit gate (prevents premature termination)
- Two-stage error filtering (avoids JSON field false positives)
- Question detection (anti-headless-pattern)
- Test-only loop detection
- Claude Code coupling (we're agnostic)
- Bash/tooling specifics
- tmux monitor (OpenClaw already has it)
- Rate limiting (via OpenClaw gateway)
- Feature flags, flywheel, heavy telemetry
Transforms a rough task description into a structured execution plan.
Parameters:
rawTask(string): The task descriptionoptions(object):projectPath(string): Path to project directoryproject(string): Project namestack(array): Technology stackfiles(array): Relevant filesconstraints(array): Task constraintsrequirements(array): Task requirements
Returns: { routing, contract, context, brief, execution, metadata }
Same as orchestrate() but adds loop control modules.
Returns: Same as orchestrate() plus { loop, loopControl }
loop.circuitBreaker— CircuitBreaker instanceloop.exitDetector— ExitDetector instanceloop.analyzeResponse— analyzeResponse functionloop.buildLoopContext— buildLoopContext functionloopControl.next(iterationResult)— Process one iteration, returns{ continue, exitReason, cbState, analysis }
| Method | Description |
|---|---|
record(result) |
Record loop result, update state. Returns true if can continue |
canExecute() |
Check if circuit allows execution |
getState() |
Get current state object |
getStatus() |
Get human-readable status |
reset(reason) |
Manually reset to CLOSED |
Returns: { hasCompletionSignal, isTestOnly, isStuck, hasProgress, exitSignal, confidenceScore, workSummary, askingQuestions, questionCount, filesModified, outputLength }
| Method | Description |
|---|---|
update(analysis) |
Feed analysis result, track signals |
shouldExit(claudeExitSignal) |
Check if loop should exit |
checkPlanCompletion(tasks, isDone) |
Check if all tasks in a plan are done |
reset() |
Clear all tracked signals |
MIT
PRs welcome! Especially:
- Bug fixes
- Documentation improvements
- New templates
- Real-world usage examples
Built with ❤️ for the AI agents community