Assync Adapter Architecture¶
Purpose¶
A provider-neutral boundary between the orchestrator and whatever actually executes a run — this MVP ships only deterministic, local mechanisms; real provider integrations are documented interfaces, not implementations (see "Future Integration Interfaces" below).
Protocol (adapters/base.py)¶
class AgentAdapter(Protocol):
adapter_id: str
def capabilities(self) -> AdapterCapabilities: ...
def validate(self) -> AdapterValidationResult: ...
def execute(self, request: AgentRunRequest) -> AgentRunResult: ...
AgentRunRequest carries mission_id, role_id, authorization_id,
the already-computed effective_capabilities (an adapter never
computes or grants its own capabilities), allowed_paths/forbidden_paths,
timeout, environment policy, and structured input. AgentRunResult carries
status, an optional structured report, findings, evidence, artifacts, a
logs summary, error, and timing — never hidden chain-of-thought, only
structured conclusions and tool-visible results.
Untrusted Input Boundary¶
Repository content and adapter output are treated as untrusted data. By
construction, nothing an adapter returns can alter authorization,
capability grants, role identity, allowed paths, the output schema, or
human decision authority — those are all fixed by the caller before
execute() is invoked and validated independently afterward
(runs/report_schema.py). See security-model.md.
Implemented Adapters¶
Mock Adapter (adapters/mock.py)¶
Deterministic; bound to one scenario per instance. Six scenarios: approval,
non_blocking_finding, blocking_security_finding, contradiction,
missing_evidence, execution_failure. adapter_id defaults to
mock:<scenario> but accepts an explicit adapter_id_override so two
independently-acting mock identities can run the same scenario without
being treated as the same actor (needed for separation-of-duty testing).
Local Command Adapter (adapters/local_command.py)¶
Infrastructure for future provider CLI integrations — not itself a full agent. Runs one allowlisted executable with an explicit argument array:
- Never
shell=True; arguments are always passed as a list. - Executable must be in a caller-supplied allowlist, or the run fails closed with a clear error (never an exception that could be mistaken for success).
git push,git merge, andgit cleanare hard-denied subcommands, independent of whatever capabilities the run's authorization otherwise carries (DENIED_SUBCOMMANDS).- Working directory is resolved and path-escape is rejected.
- Only a small safe-environment allowlist is passed through — never the full process environment.
- Timeout-enforced; output is size-capped and credential-pattern-redacted before being returned.
Future Integration Interfaces (not implemented)¶
Documented extension points only — implementing any of these is explicitly out of this MVP's scope:
- Claude Code adapter, ChatGPT/OpenAI adapter, Antigravity adapter, local
model adapter — all would implement
AgentAdapterthe same way the mock and local-command adapters do. ReviewPublisher(GitHub Checks / draft PR publisher) — see the "GitHub Foundation" note in the project README for the intended mapping (QA report → GitHub Check, security report → required Check, synthesis → PR summary, human decision → merge authorization). No GitHub API is called anywhere in this codebase.- Webhook receiver, web application API, worker queue, containerized execution.
MVP Limitations¶
- No retry/backoff policy is implemented beyond the
retry_countfield existing onAgentRunResult. - The local command adapter's subcommand denylist currently only covers
git; a real provider-CLI integration would need its own equivalent review before being added.