Skip to content

Contracts AO Reach

Zlatko Lakisic edited this page Aug 7, 2026 · 2 revisions

Contracts — AO Reach

Status: VERIFIED — Ada AO at https://10.0.10.16:8765 with mTLS (AO ≥ 1.29 / vendor Reach ≥ 0.4.1). Cleartext HTTP disabled on that host. Speech prefer path requires AO ≥ 1.28 / Reach ≥ 0.2; mTLS requires Reach ≥ 0.4.

AO Reach session


Connection

When orchestration.mtls.enabled is true, base_url must be https://… and session open passes ReachMtlsConfig(materialDir: …). Fail closed if PEMs are missing. Warpgate orchestration.token is optional / transitional for non-mTLS hosts. Speech sidecars remain cleartext HTTP.

await bridge.start(
  config: ReachConnectionConfig(
    baseUrl: cfg.orchestration.baseUrl, // https://… when mtls.enabled
    headers: {
      'x-agentic-user-name': identity.userid,
      'x-agentic-session-id': 'comstar-${identity.userid}',
      // optional transitional: 'x-warpgate-token': cfg.orchestration.token,
    },
    ttlSeconds: cfg.orchestration.ttlSeconds,
    // speechToken: optional from COMSTAR_SPEECH_TOKEN
    mtls: cfg.orchestration.mtls.enabled
        ? ReachMtlsConfig(materialDir: cfg.orchestration.mtls.resolvedMaterialDir())
        : null,
  ),
  overlayRoot: cfg.orchestration.overlayRoot,
  mcpBootstrap: ComstarMcpBootstrap(cfg),
);

Enroll once via Admin AO pairing or make ao-mtls-enroll (ADR 0013). Material: ~/.local/share/comstar/ao-mtls/ (cert.pem, key.pem, ca.pem, meta.json).


Turn

final result = await bridge.directAgent(
  agentProviderId: 'client.voice_responder',
  text: transcript,
  mcpProviderIds: [/* allowlisted ids for this session */],
);

Do not request MCP ids that this host does not serve — AO rejects the turn. Observed hosted ids: fetch_url, filesystem_local, home_assistant, media_audio_transcribe, media_understand, media_video_analyze. Do not request memory / time / math / vision on the verified host unless they appear in catalog.


Speech (preferred path)

When hello.speech.enabled is true, SessionBridge.speechClient is non-null:

final speech = bridge.speechClient;
if (speech != null) {
  final text = await speech.transcribe(wavBytes);
  final wav = await speech.synthesize(replyText);
} else {
  // COMSTAR_STT_URL / COMSTAR_TTS_URL HTTP clients
}

Rules (ADR 0003):

  • Prefer Reach speech after session start.
  • Fall back to env URLs when speechClient == null.
  • Do not ferry PCM on the Reach WebSocket.
  • Do not route turns through the planner solely for STT.
  • Overlay / directAgent must work with speechClient == null.

Speech client prefer path


Session lifecycle rules

  • One SessionBridge per identity. Switching identity = stop() then start().
  • Sessions are not opened on Noticed — only on Engaged (or wake-from-empty anonymous).
  • Anonymous / guest: x-agentic-user-name: guest + restricted overlay.
  • stop() on SIGTERM — overlay leakage on the daemon is a real failure mode.

Overlay agents

Agent Purpose
client.voice_responder Conversational — spoken-output constraint (no markdown/lists/URLs, ~40 words)
client.greeter Engaged greeting — target <1.5 s, small MCP set

Live timings observed: greeter ~0.85 s, voice_responder ~1.0 s (2026-08-02).


Related pages

Clone this wiki locally