Skip to content

feat(yoke): add Kiro CLI as an agent runtime via ACP#385

Open
hmkim wants to merge 2 commits into
chadbyte:mainfrom
hmkim:feat/kiro-cli-integration
Open

feat(yoke): add Kiro CLI as an agent runtime via ACP#385
hmkim wants to merge 2 commits into
chadbyte:mainfrom
hmkim:feat/kiro-cli-integration

Conversation

@hmkim

@hmkim hmkim commented Jul 21, 2026

Copy link
Copy Markdown

Implements #382 (opened first per CONTRIBUTING.md; you gave the go-ahead there).

Summary

Adds AWS Kiro CLI as a third agent runtime alongside Claude Code and Codex, through the existing YOKE adapter layer. Kiro exposes the Agent Client Protocol (ACP) via kiro-cli acp — standard JSON-RPC 2.0 over stdio, the same transport shape as the codex app-server integration.

Rebased on latest main (b04450d, 2.47.0-beta.1).

Follows the constraints from #382

  • Scoped to the adapter — no unrelated refactors.
  • Mirrors the Codex touch-points — vendor factory (yoke/index.js), install/auth detection (sdk-bridge.js detectInstalledVendors, yoke/index.js checkAuth/checkInstalled), client vendor toggle (app-panels.js, index.html, sidebar new-session buttons).
  • Strictly opt-in / detected, no bundled binary — Kiro is discovered on the system (kiro-cli binary lookup + whoami); nothing is added to package.json dependencies. Same posture as Codex.

What's included

New

  • lib/yoke/kiro-acp-server.js — child-process JSON-RPC transport
  • lib/yoke/adapters/kiro.js — YOKE adapter (dynamic model catalog, session lifecycle, session/update event flattening, permission routing, resume, abort)
  • lib/kiro-defaults.js — single source of truth for Kiro defaults
  • lib/public/kiro-avatar.svg
  • docs/guides/KIRO-INTEGRATION.md (+ EN/KO summaries)

Wiringyoke/index.js, sdk-bridge.js, sdk-message-processor.js, project-notifications.js, project-sessions.js (GUI-only, like Codex), and client vendor UI.

Design notes

  • Dynamic model catalog (like Claude, unlike Codex's hardcoded list): init() runs kiro-cli chat --list-models --format json and filters out [Internal]/[Deprecated]; default is the auto router.
  • Permission name recovery: session/request_permission carries only { toolCallId, title }, so the adapter caches kind + rawInput from the preceding tool_call notification to pass a canonical tool name (Bash, Edit, ...) to canUseTool. Without this the permission whitelist matching breaks.
  • Split tool output: Kiro emits tool output across two tool_call_update events (interim content, then status: completed with output in rawOutput). The adapter accumulates content per toolCallId and falls back to rawOutput so tool_result is never empty.

Testing

Verified end-to-end against kiro-cli 2.7.0, and on a real device (iPhone PWA over Tailscale):

  • Init discovers the filtered model list; default auto
  • Text streams in real time; result emitted with usage
  • Model switching (session/set_model; confirmed opus-4.8 / haiku-4.5 on device)
  • Tool approve and deny paths route through canUseTool with canonical Bash + {command}
  • tool_result shows real command output
  • Abort interrupts the turn cleanly
  • Registers alongside claude/codex in the daemon adapter path

Totally fine for you to reshape parts to fit Clay's conventions — treating this as a starting point as you said.

Brandon added 2 commits July 21, 2026 04:44
Integrate AWS Kiro CLI as a first-class agent runtime alongside Claude
Code and Codex, driven through `kiro-cli acp` (Agent Client Protocol,
JSON-RPC 2.0 over stdio) — mirroring the codex app-server transport.

New:
- lib/yoke/kiro-acp-server.js: child-process JSON-RPC transport
- lib/yoke/adapters/kiro.js: YOKE adapter (dynamic model catalog,
  session lifecycle, session/update event flattening, permission
  routing, resume, abort)
- lib/kiro-defaults.js: single source of truth for Kiro defaults
- lib/public/kiro-avatar.svg: branded avatar
- docs/guides/KIRO-INTEGRATION*.md: protocol reference + EN/KO summaries

Wiring (mirrors every codex touch-point):
- yoke/index.js: factory switch, auth (kiro-cli whoami), install
  detection, createAdapters
- sdk-bridge.js: detectInstalledVendors, login command, KIRO
  adapterOptions, neutral interrupt message
- sdk-message-processor.js, project-notifications.js: auth titles
- project-sessions.js: GUI-only session mode for kiro
- client UI: vendor toggle, new-session buttons (install-gated),
  effort levels, avatar/name maps

Permission requests carry only { toolCallId, title }, so the adapter
caches kind/rawInput from the preceding tool_call notification to pass a
canonical tool name to canUseTool, keeping the permission whitelist
functional.
Kiro splits tool output across two tool_call_update events: an interim one
carrying `content` (no status) and a later `status: "completed"` one whose
`content` is empty (the output lives in `rawOutput`). The adapter only read
the completed event's content, so tool_result bubbles were empty.

Accumulate content chunks per toolCallId across events and fall back to the
structured `rawOutput` (stdout/stderr) at completion, so tool_result is never
empty. Verified against kiro-cli 2.7.0: `echo hello-kiro-42` now yields the
real command output instead of a blank result.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant