Appearance
Protocol
This project follows an ATEP-style (Agentic Task Execution Protocol) contract so the orchestration loop stays adapter-agnostic.
Overview
Every step consumes a canonical input envelope and produces a canonical output envelope. The engine uses only these contracts to decide transitions.
- input provides global objective, step context, and priming config
- output provides execution status, QA routing action, and payload mutations
- routing actions drive retry, rollback, restart, or progression
Input envelope
In this repo, the input contract is represented by InputEnvelope in src/types.ts.
json
{
"global_context": {
"workflow_id": "string",
"primary_objective": "string",
"workflow_objectives": ["string"],
"global_state": {}
},
"step_context": {
"step_id": "string",
"step_objective": "string",
"previous_output": {},
"assigned_node_type": "AGENT | HUMAN | SYSTEM"
},
"priming_configuration": {
"required_skills": ["string"],
"mcp_endpoints": ["string"],
"system_prompts": ["string"],
"context": {},
"adapter": "pi-agent | mock | acp | opencode | codex | claude-code",
"model": "string"
}
}Output envelope
In this repo, the output contract is represented by OutputEnvelope in src/types.ts.
json
{
"step_id": "string",
"execution_status": "SUCCESS | QA_REJECTED | YIELD_EXTERNAL | FAILED",
"qa_routing": {
"action": "PROCEED | RETRY_CURRENT | ROLLBACK_PREVIOUS | RESTART_ALL",
"feedback_reason": "string"
},
"mutated_payload": {},
"metadata": {
"execution_time_ms": 0,
"external_intervention_required": false,
"intervention_details": {}
}
}Routing semantics
PROCEED: mark step succeeded and move forwardRETRY_CURRENT: rerun current step until max attemptsROLLBACK_PREVIOUS: reset current + previous and move index backwardRESTART_ALL: reset all steps and restart from the first step
Human and external intervention
validation.modecan benone,human, orexternal- if confirmation is required and not provided, run moves to
waiting_for_approval YIELD_EXTERNALindicates the run should pause for non-agent input- once intervention is resolved, execution can resume with updated state
Why this contract matters
- execution backends are replaceable as long as they speak the same envelope
- workflow logic remains independent from the transport an adapter uses
- eventing and audit logs stay consistent across adapter implementations
Adapters and ACP
The engine maps each envelope onto an adapter. pi-agent (the default) drives the pi coding agent CLI through JSON file envelopes. Every other non-mock agent runs through the acp adapter, which speaks the Agent Client Protocol (JSON-RPC over stdio) to any ACP-compatible agent: it negotiates initialize, opens a session with the workflow cwd and any http(s) mcps as MCP servers, sends the composed prompt via session/prompt, streams session/update output back through the run's event log, answers session/request_permission from a per-step policy, and maps the turn's stopReason to the OutputEnvelope. The claude-code, opencode, and codex adapter keys are presets that resolve to an ACP agent command. opencode routes through ACP and runs real by default (taskSpec.payload.useRealAdapter: false opts a step out to the mock executor); acp, claude-code, and codex still opt in with useRealAdapter: true. claude-code's original bespoke executor is deprecated and reachable only via taskSpec.payload.legacyExecutor; the equivalent bespoke opencode executor has been removed entirely.