Skip to content

feat(kiro): add Kiro CLI agent support#354

Open
natehardison wants to merge 15 commits into
majorcontext:mainfrom
natehardison:worktree-kiro-cli-support
Open

feat(kiro): add Kiro CLI agent support#354
natehardison wants to merge 15 commits into
majorcontext:mainfrom
natehardison:worktree-kiro-cli-support

Conversation

@natehardison
Copy link
Copy Markdown
Contributor

@natehardison natehardison commented May 19, 2026

Summary

Adds the Kiro CLI as a first-class Moat agent, at parity with the existing
Codex/Claude/Gemini providers: credential grant, transparent proxy credential
injection, container config staging, local + remote MCP, runtime-context
injection, and a moat kiro command.

What's included

  • internal/providers/kiro/ — agent + credential provider mirroring the
    codex provider: proxy Bearer injection, token grant (env KIRO_API_KEY or
    interactive hidden-input prompt), PrepareContainer staging
    ~/.kiro/{settings,agents,steering}, and the moat kiro command.
  • Wiringkiro-cli dependency (registry + native installer),
    credential.ProviderKiro, kiro: moat.yaml section (sync_logs, mcp) +
    ShouldSyncKiroLogs, image-needs detection, manager.go dispatch block
    (local + remote MCP relay, grant→env maps, cleanup/temp-dir lifecycle),
    provider registration, and the moat-init.sh block that copies the staged
    ~/.kiro tree into the container.
  • Docs — CLI reference, moat.yaml reference, a new guide
    (docs/content/guides/14-kiro.md), and a CHANGELOG entry. Design spec and
    implementation plan under docs/plans/.

Notable design decisions

  • Auth model: prompt-for-token (or KIRO_API_KEY env), stored encrypted;
    static credential, no refresh — re-grant on expiry. The container only ever
    sees a placeholder; the proxy injects the real token.
  • Credential-injection host scoping: gatekeeper v0.2.0 credential
    injection uses exact host-key lookups (no wildcard matching — verified
    against proxy.getCredentials). kiroAPIHosts is therefore scoped to the
    concrete q.us-east-1.amazonaws.com; additional regions are added
    explicitly (documented in code and the guide).
  • Remote MCP uses kiro-cli's native HTTP MCP server entry
    (url + headers).

Out of scope (intentional, documented in the spec)

Token refresh / OAuth device-login, persistent sessions volume, host
~/.kiro/skills layering, kiro subagents in the default agent, and the
moat init quickstart table (separate hand-maintained list — tracked as a
follow-up).

Testing

  • go build ./... clean; make lint 0 issues; all kiro-relevant packages
    pass under -race.
  • The only failing unit test is the pre-existing
    TestRegistryGithubBinaryURLsExist, which makes live requests to
    github.com release URLs and fails in network-restricted environments
    (fails identically on main; unrelated to this change).
  • Manually validated moat kiro end-to-end.

Test plan

  • moat grant kiro stores a token
  • moat kiro runs an isolated session with credentials injected
  • kiro.mcp (local) and top-level mcp: (remote relay) reach the agent
  • runtime context appears via ~/.kiro/steering/

🤖 Generated with Claude Code

Add kiro-cli to the dependency registry with custom install type. The Kiro CLI uses a native installer from cli.kiro.dev that places the binary in ~/.local/bin.
…MCP)

- Add needsKiroInit detection via slices.Contains(imgNeeds.initProviders, "kiro")
- Import providers/kiro for KiroAPIKeyPlaceholder in grantToPlaceholder
- Add kiro cases to grantToEnvVar (KIRO_API_KEY) and grantToPlaceholder
- Add full kiro PrepareContainer dispatch block after the gemini block,
  mirroring the codex/gemini pattern with credential lookup, remote MCP
  relay URL construction, local MCP server config, and cleanupAgentConfig
  chaining on all error paths
- Add KiroConfigTempDir field to Run struct and assign/cleanup alongside
  GeminiConfigTempDir throughout the run lifecycle
- Add cleanupAgentConfig(kiroConfig) to all downstream error paths that
  clean up geminiConfig (13 locations inside services/buildkit/container
  creation/storage/audit blocks)

Wildcard finding (Step 4): gatekeeper v0.2.0 credential injection uses
exact host-string map keys (proxy.go getCredentials), not the wildcard
pattern matching used by the network firewall. The patterns
q.*.amazonaws.com and *.q.*.amazonaws.com in kiroAPIHosts would never
match real hostnames during credential injection. Changed kiroAPIHosts to
the single concrete host "q.us-east-1.amazonaws.com". NetworkHosts()
(firewall allowlist) still uses wildcard patterns for passthrough hosts
since that path calls matchHost() which does support wildcards.
Updated cli_test.go and constants.go accordingly; fixed prealloc lint in
cli.go.
The kiro agent.go set MOAT_KIRO_INIT and mounted the staging dir, but
moat-init.sh had no block to copy it into ~/.kiro at container startup,
so cli.json/mcp.json/agents/steering never reached the container. Add a
MOAT_KIRO_INIT block mirroring the gemini block, copying the settings/,
agents/, and steering/ subdirectories. Caught in final holistic review;
the implementation plan omitted this step.
@dpup
Copy link
Copy Markdown
Collaborator

dpup commented May 26, 2026

Thanks for the patch. A few things before merging:

Memory bug: isAIAgent() in manager.go doesn't include kiro, so on Apple containers it skips the 8GB agent default and drops to 4GB. Kiro's exactly the kind of workload that'll OOM on a big task — quick fix.

Auth path: we're only injecting on q.us-east-1.amazonaws.com with a static Bearer. Did you confirm that's actually where kiro-cli authenticates, and that a plain Bearer works there (vs SigV4)? And if there's any token handshake at cli.kiro.dev/cognito, those aren't getting injection. I don't want to quietly 401 for anyone outside the path you tested — other regions especially. Also, wherever these host/auth assumptions are called out in the comments, can you link the kiro docs you're basing them on so it's checkable later?

Same spirit on the other kiro-cli assumptions the comments flag — the mcp.json key names and the --no-interactive prompt arg. Did your manual run cover a remote MCP round-trip and a -p prompt? If not, those are the bits I'd poke at.

Couple small ones: the CHANGELOG still has the #NNN placeholder, and it'll need a rebase onto main — a fair bit landed since you branched (grant.go and manager.go both moved), so worth doing carefully.

Let's also fold these into this PR rather than follow-ups, since we're calling kiro a first-class agent: it shows up blank in moat grant providers, and init/doctor don't know about it yet.

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.

2 participants