feat(yoke): add Kiro CLI as a first-class agent runtime via ACP#1
feat(yoke): add Kiro CLI as a first-class agent runtime via ACP#1hmkim wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
This PR successfully integrates Kiro CLI as a first-class agent runtime via the Agent Client Protocol (ACP). The implementation follows good patterns mirroring existing Claude and Codex adapters, includes comprehensive error handling, and maintains security best practices through tool whitelisting and permission controls.
Key Changes:
- New
KiroAcpServertransport layer for JSON-RPC 2.0 communication KiroAdapterimplementing the YOKE interface with dynamic model catalog, session lifecycle management, and permission routing- Integration wiring throughout the codebase (auth, vendor detection, UI controls)
- Comprehensive documentation
Findings:
- 1 logic error identified in binary path resolution
The changes are well-tested according to the PR description, with verification against kiro-cli 2.7.0 including model discovery, streaming, tool approval, and session management.
You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.
| var execFileSync = require("child_process").execFileSync; | ||
| var out = process.platform === "win32" | ||
| ? execFileSync("where", [binName], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }) | ||
| : execFileSync("which", ["kiro-cli"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }); |
There was a problem hiding this comment.
🛑 Logic Error: The where command on Windows receives binName as argument but which on Unix receives hardcoded "kiro-cli" string. This inconsistency causes the Windows binary name (possibly "kiro-cli.exe") to be ignored on Unix systems, preventing discovery of the correct binary when binName is set to a different value than "kiro-cli".
| : execFileSync("which", ["kiro-cli"], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }); | |
| : execFileSync("which", [binName], { timeout: 3000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }); |
* feat(auth): solo auto-login safety net for absorbed single-user (phase 1) Groundwork for folding single-user mode into multi-user. When a multi-user instance has exactly one user with no PIN, authenticate them automatically instead of showing a login wall, preserving the frictionless single-user onramp. Central change: getMultiUserFromReq() falls back to users.getSoloNoPinUser() when there's no valid token, so every HTTP and WS auth gate (all route through this) is covered by one path. Disabled the moment a PIN is set or a second user is added. Inert today: only triggers when multiUser is true (single-user deploys are unaffected until the later migration phase flips them). * feat(auth): auto-migrate legacy single-user deploys to multi-user (phase 2) On daemon boot, detect a legacy single-user deploy and fold it into the multi-user model with zero manual steps: - provision one "admin" user that inherits the single-user PIN hash (same PIN still logs in), profile.json, and settings (chatLayout, autoContinue, matesEnabled, terminalFont, deletedBuiltinKeys, mateOnboardingShown) - move legacy flat mates into the per-user mates dir - backfill ownerId onto legacy sessions so they belong to the user - flip multiUser = true Runs before projects/mates/sessions load. Heavily guarded: backs up users.json/daemon.json/profile.json first, is idempotent (config marker), tolerates partial failure per step, and is a no-op on fresh installs and already-multi-user deploys. Combined with the phase-1 solo auto-login, a no-PIN single-user deploy upgrades with no login wall. * feat(auth): default new installs to multi-user, drop the mode prompt (phase 3) There is no separate single-user runtime anymore. Every deploy runs in the (general) multi-user model: - Remove the "Just me (single user) / Multiple users" setup question. Fresh installs go straight to multi-user; OS-user isolation stays an opt-in (offered on Linux at setup, toggleable later). - daemon boot calls ensureMultiUser(): migrate a legacy single-user deploy, or provision a default no-PIN "admin" on a fresh one. With phase-1 solo auto-login, a solo user gets in with no account creation and no login wall. - Flip every mode fallback from "single" to "multi". Solo onramp is unchanged in feel (npx clay-server -> just works); it's now a one-user multi-user deploy under the hood. * docs: handoff for single-user absorption phases 4-6 Capture the plan, what's done (phases 1-3 + verification), and the remaining cleanup (phase 4 settings dual-path, phase 5 !isMultiUser branch removal, phase 6 flag/dead-code removal) with file:line targets and watch-outs.
Add the GPT-5.6 model family (gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna) to the Codex adapter's model list and make gpt-5.6-terra the default (5.5-class quality at lower cost). Register the 5.6 context window (272000) so the context panel reports usage correctly instead of falling back to 200000. Verified the bundled @openai/codex 0.144.4 binary already recognizes all three model ids.
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.
a317658 to
d81000e
Compare
|
Superseded by the upstream PR chadbyte#385 (rebased on latest main). Closing to avoid confusion — the work continues there. |
Summary
Adds AWS Kiro CLI as a first-class agent runtime in Clay, alongside Claude Code and Codex, through the YOKE adapter layer. Users pick the vendor, create a session, chat, approve tools, and switch models — with no user-visible difference between runtimes.
Kiro exposes the Agent Client Protocol (ACP) via
kiro-cli acp— standard JSON-RPC 2.0 over stdio, the same editor-agnostic protocol used by Zed. This mirrors the transport strategy already used forcodex app-server.What's included
New files
lib/yoke/kiro-acp-server.js— child-process JSON-RPC transportlib/yoke/adapters/kiro.js— YOKE adapter (dynamic model catalog, session lifecycle,session/updateevent flattening, permission routing, resume, abort)lib/kiro-defaults.js— single source of truth for Kiro defaultslib/public/kiro-avatar.svg— branded avatardocs/guides/KIRO-INTEGRATION.md+ EN/KO summariesWiring (mirrors every
codextouch-point)yoke/index.js— factory switch, auth (kiro-cli whoami), install detection,createAdapterssdk-bridge.js—detectInstalledVendors, login command,KIROadapterOptions, neutral interrupt messagesdk-message-processor.js,project-notifications.js— auth titlesproject-sessions.js— GUI-only session mode for kiroKey design decisions
init()runskiro-cli chat --list-models --format json, filtering out[Internal]/[Deprecated]entries; default is theautorouter.session/request_permissioncarries only{ toolCallId, title }, so the adapter cacheskind+rawInputfrom the precedingtool_callnotification to pass a canonical tool name (Bash,Edit, ...) tocanUseTool. Without this, Clay's permission whitelist matching would break.fixcommit): Kiro emits tool output across twotool_call_updateevents (interimcontent, thenstatus: completedwith the output inrawOutput). The adapter accumulates content pertoolCallIdand falls back torawOutputsotool_resultis never empty.Testing
Verified end-to-end against the live
kiro-cli2.7.0 binary, and on a real device (iPhone via Tailscale):autoresultemitted with usagesession/set_model; confirmed opus-4.8 / haiku-4.5 on device)canUseToolwith canonical nameBash+{command}; approve and deny paths verifiedtool_resultshows real command output (echo hello-kiro-42)Commits
feat(yoke): add Kiro CLI adapter via Agent Client Protocolfix(yoke): populate Kiro tool_result content from split ACP updates