Adapter guide

What you implement

A minimal external adapter has three moving parts. That is true whether the target is a repository, a ticket system, a workflow tool, or something custom.

In any language, the shape is small:

adapter/
  state handler
  policy handler
  worker loop

You can put those pieces in one process or several processes. The protocol does not require a specific language or framework.

StateProvider

The StateProvider is the endpoint the Adapter Host calls when it needs current target state before a decision can proceed.

You implement:

  • one HTTP callback endpoint
  • target binding checks
  • a bounded state response for the requested target and scope

You do not implement:

  • final decision logic
  • WorkOrder creation
  • host-side hashing rules beyond returning the required public fields

The point is not to mirror your whole backend. The point is to return the governed state view that the decision path actually needs.

Minimal shape:

POST /state
-> validate target binding and callback token
-> read one bounded slice of target state
-> return one governed StateView response

Minimal pseudo implementation:

handleState(request):
assert request.target_adapter == cfg.target_adapter
assert request.target_ref == cfg.target_ref
assert bearer token is valid
state = readTargetState(request.target_ref, request.target_scope)
return {
state_view_ref: "state-view-1",
target_adapter: request.target_adapter,
target_ref: request.target_ref,
target_scope: request.target_scope,
content: json(state),
content_hash: sha256_hex(json(state)),
returned_view_hash: sha256_hex(json(state))
}

PolicyBoundary

The PolicyBoundary is the endpoint the Adapter Host calls to ask for a candidate decision.

You implement:

  • one HTTP callback endpoint
  • your local policy rules
  • a candidate response that matches the public contract

You do not implement:

  • final admission
  • direct work creation
  • fail-open shortcuts that bypass the host

Policy participates, but it is not the final authority by itself. Core still validates the candidate before admitted work can exist.

Minimal shape:

POST /policy
-> validate target binding and callback token
-> evaluate one bounded policy rule
-> return one candidate such as admitted or blocked

Minimal pseudo implementation:

handlePolicy(request):
assert request.target_adapter == cfg.target_adapter
assert request.policy_identity matches cfg
assert bearer token is valid
if target state allows the action:
return candidate decision "admitted"
return candidate decision "blocked"

Worker

The worker is the code that claims admitted work, performs the bounded target-side operation, and posts the outcome.

You implement:

  • the claim loop
  • target-side materialization
  • outcome submission with the required bindings

You do not implement:

  • browser-facing intent ingestion
  • policy-only write authorization
  • a replacement for host-side claim and lease semantics

Minimal shape:

loop:
  POST /v0/adapter/work-orders/claims
  if no_work_available: wait and poll again
  if claim received: apply one target-side effect
  POST /v0/adapter/outcomes

Minimal pseudo implementation:

workerLoop():
while true:
claim = claimWork(target_adapter)
if claim.reason == "no_work_available":
sleep(5 seconds)
continue
result = applyTargetEffect(claim)
postOutcome(claim, result)

What this means in plain terms

If you can answer these three questions, you can build an adapter:

  • How do we read the current target state we care about?
  • How do we decide whether that action should proceed?
  • How do we perform the final target-side effect and report the result?

Everything else stays with the bundle. That is what makes the integration surface relatively small.

Three concrete examples

Adapter exampleStateProviderPolicyBoundaryWorker
Repository adapterread branch or pull-request stateallow or block one repository changeopen one pull request or post one bounded update
Ticket adapterread ticket workflow stateallow or block one transitionmove one ticket or add one note
Impact Room-style reference adapterread room or turn stateallow or block one room-side effectmaterialize one room-side effect after claim

The shipped minimal target adapter is the smallest inspectable version of these three parts. It is generic on purpose, so you can map it onto your own target instead of inheriting someone else's demo logic.