Kiro
The ACP-compliant Kiro plugin for opencode: auth via the official kiro-cli login, the live Kiro model lineup through the Agent Client Protocol, and TUI credits display
13
近 30 天 +3
1,428
近 7 天 369
52.6
生态多维模型
4 天前
2026-10-16
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-kiro@0.5.2"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-kiro@0.5.2"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D opencode-kiroOpenCode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
0.5.x is the stable OpenCode 2 line, tested on 2.0.29. OpenCode v1 users should pin
opencode-kiro@0.4.0. See docs/COMPATIBILITY.md for exact pins and the tested OpenCode SHA.
The ACP-compliant Kiro plugin for opencode.
The plugin supplies:
- Auth via the official
kiro-clilogin flow: it registers thekirointegration with a Kiro CLI Login OAuth method (opencode auth login) - Model discovery: after auth it captures Kiro's live model lineup and merges it into OpenCode's provider domain (exact ID intersection, reasoning-effort variants), with a minimal self-registration fallback when models.dev supplies no Kiro models
- Provider ownership: an AISDK hook constructs the provider from
kiro-acp-ai-providerwith the right options (cwd,agent,trustAllTools,mcpTimeout,stall,contextWindows) - TUI credits display: a live Kiro credits box in the sidebar and a compact
credits chip in the prompt footer row beside the host cost/context display, both
styled with the host's active theme tokens - discovered from the package's
./tuiexport using the same single config entry
kiro-acp-ai-provider talks to your locally installed kiro-cli over Kiro's
Agent Client Protocol (ACP). This is the supported
integration path: requests go through kiro-cli exactly like Kiro's own IDE clients,
with no credential scraping and no reuse of Kiro credentials against other providers.
Compatibility
This release is tested against OpenCode 2 stable 2.0.29:
| Item | Value | Notes |
|---|---|---|
Tested OpenCode commit (v2.0.29 tag) |
042d0832f5f3a73eaa039a58a7d565776f6d4290 |
|
@opencode/plugin |
2.0.20 |
devDependencies (exact; types and tests only); no peer dependency |
| Package version | 0.5.2 |
Full pin table and verification steps: docs/COMPATIBILITY.md.
Targets OpenCode 2 stable 2.0.x, with @opencode/cli@2.0.29 as the reference host.
0.5.2 is tested on 2.0.29; later releases are not guaranteed to work. No peer
dependency is declared because the host supplies the plugin API at runtime.
Older hosts, including build 0.0.0-beta-19271 from the
former CLI package scope, are not supported by 0.5.2; use
opencode-kiro@0.5.0-beta.5 on those hosts. There is no engines.opencode constraint.
Prerequisites
| Requirement | Notes |
|---|---|
| kiro-cli | Must be installed and on PATH; a Kiro subscription / AWS Builder ID account |
Node.js >= 20 |
Enforced via engines.node. |
| OpenCode 2 stable 2.0.x, tested on 2.0.29 | Later releases are not guaranteed to work. See Compatibility for the reference host and development pin. This release does not support OpenCode v1. |
OpenTUI 0.5.12 (@opentui/core, pulled in by @opentui/solid)
declares node >=26.4.0, so an install with engine-strict enabled refuses older
Node versions even though the plugin itself declares >=20.
Install and configure
One config entry — that's the whole setup. Add the package to the plugins
array (plural) of your OpenCode config. That is any opencode.json or opencode.jsonc
(or .opencode/opencode.json) found walking up from the project directory, or the
global ~/.config/opencode/opencode.json:
{
"plugins": ["opencode-kiro@0.5.2"]
}
⚠️ Always pin the exact version, as above. This keeps installs reproducible. The host checks unpinned specs (bare, tag or range) for newer versions in the background and marks them outdated; it installs an update only when you trigger one (
opencode2 plugin update, or the update action in the TUI Plugins dialog) or after the cache is cleared. An exact version is never re-resolved. Use the exactopencode-kiro@0.5.2spec.
The object form pins the same version and takes the plugin options described in Plugin options:
{
"plugins": [
{
"package": "opencode-kiro@0.5.2",
"options": {}
}
]
}
This loads the server entry (./server export): auth, model discovery, and provider
ownership. The host discovers the TUI half from the package's ./tui export -
the sidebar credits box and the prompt footer credits chip appear with no further
configuration. No cli.json TUI entry is needed.
Plugin options
All options are optional and apply to configured plugins from npm or a local
directory; omit the options object entirely to get the defaults.
| Option | Type | Default | Meaning |
|---|---|---|---|
agent |
string | "opencode" |
kiro-cli agent name the provider runs under |
mcpTimeout |
number | 45 |
MCP tool-call timeout, in minutes |
discover |
boolean | true |
Set false to skip the setup-time model discovery kick-off when Kiro is already connected. Discovery triggered by login/credential events still runs. |
stall |
object | { "afterMs": 10000, "live": "reasoning" } |
Stall notice for turns with no model output. afterMs is the silence threshold in milliseconds (0 disables stall detection entirely); live is "reasoning" (live notice in the transcript, visible only when thinking is shown) or "off" (no stall UX in the TUI; metadata still emitted for other consumers). See Slow responses. |
{
"plugins": [
{
"package": "opencode-kiro@0.5.2",
"options": {
"agent": "opencode",
"mcpTimeout": 45,
"discover": true,
"stall": { "afterMs": 10000, "live": "reasoning" }
}
}
]
}
A value of the wrong type falls back to its default; unknown keys are ignored. The
contract per option: mcpTimeout must be a positive number of minutes; zero, negative,
or non-numeric values fall back to the default (45); an empty agent string falls
back to "opencode". stall must be an object; both members are optional and each is
checked on its own - afterMs must be a number of milliseconds of 0 or more, live
must be exactly "off" or "reasoning". An invalid member is dropped while the valid
one is kept, and an object with nothing valid left counts as omitted (defaults apply).
Options are honored for configured plugins: npm specs and local directory specs. The host passes
optionsfor both"package": "opencode-kiro@<version>"and"package": "/absolute/path/to/opencode-kiro/dist". Configuredname@file:tarball installs also receive options. Bundled or built-in plugin loads receive{}, so the defaults always apply there regardless of what you write inoptions.
There is no cwd option. The working directory handed to kiro-cli is derived
automatically from the OpenCode location the plugin is set up for, once per location;
a user-supplied path could only be less accurate.
Slow responses
When the Kiro backend is overloaded, kiro-cli retries the request on its own and the
turn produces no output for a while - a spinner with nothing behind it. The stall
option controls how the plugin surfaces that wait:
- By default (
afterMs: 10000,live: "reasoning"): after 10 seconds without model output, a short reasoning block appears in the transcript, along the lines of "Kiro: no output for 10s - the model may be overloaded and kiro-cli is retrying." It refreshes every further 10 seconds while the silence lasts and closes with "output resumed after Ns" once real output arrives, or "turn ended after Ns without further output" if the turn ends first. When the last error kiro-cli logged during the turn yields a short reason, the closing line includes it in parentheses:output resumed after Ns (ModelOverloaded)orturn ended after Ns without further output (ModelOverloaded). The reason is best-effort; without one, the closing line has no parentheses. The block is separate from the model's own reasoning and text; the answer is unaffected. Because the live notice is rendered as a reasoning block, the TUI shows it collapsed by default (click to expand), and only when the TUI shows thinking (session.thinking: "show"incli.json); with reasoning hidden the notice is hidden too. live: "off"means no stall UX in the TUI: no transcript notice and no footer/box stall line. Stall metadata is still emitted for other consumers.afterMs: 0disables stall detection entirely: no transcript notice and no stall metadata. Any other value changes the silence threshold (in milliseconds).
{
"plugins": [
{
"package": "opencode-kiro@0.5.2",
"options": { "stall": { "live": "off" } }
}
]
}
The stall summary now lives in the notice's closing line, not in the sidebar box or
footer chip; both credits surfaces show credits only. The notice is informational
only; it never cancels or retries the turn. The stall option was introduced in
kiro-acp-ai-provider 3.2.0; see CHANGELOG.md for this release's SDK
requirement and docs/COMPATIBILITY.md for the current pin.
Disabling
One "-kiro" directive in the same plugins array disables everything: it removes
the server plugin and its discovered ./tui entrypoint, so the TUI half never
activates either:
{
"plugins": ["opencode-kiro@0.5.2", "-kiro"]
}
Legacy tui.json (v1)
tui.json is legacy v1 configuration and, under v2, is migration input only:
the host may read it when migrating old setups, and this plugin never modifies it.
Do not add new entries to tui.json (or to cli.json — neither is used by this
plugin anymore); the single plugins entry above is the only configuration.
Local development (path source)
Build a local checkout, then point the plugins entry at the absolute path of its
built dist/ directory. No pack or registry publish is needed:
git clone https://github.com/NachoFLizaur/opencode-kiro && cd opencode-kiro
npm install && npm run build
{ "plugins": ["/absolute/path/to/opencode-kiro/dist"] }
For this directory source the host resolves dist/server.js and dist/tui.js
directly. Use the directory, not the package root or a direct .js file. Rebuild
with npm run build after edits. Options also work with the object form's package
set to this directory path.
Tarball caveat (name@file: only): if you instead run npm pack and configure
opencode-kiro@file:/absolute/path/to/opencode-kiro-0.5.2.tgz, the colon in the
installed directory name defeats the host's OpenTUI loader shim. The plugin's slots
show a contained error notice instead of the credits views; the rest of the TUI
keeps working. Use the colon-free absolute dist/ directory example above or a
registry install (opencode-kiro@0.5.2) to avoid this tarball-specific issue.
For package installs, the host resolves the ./server and ./tui exports. Each
entry module exports its own id: the server plugin's id is kiro and the TUI
plugin's id is opencode-kiro. There is no separate TUI directive to manage -
-kiro (the server id) is the single kill-switch, and host logs use kiro for the
server half and opencode-kiro for the TUI half.
Auth
opencode auth login
Select the Kiro integration, then the Kiro CLI Login method:
- Already logged in to kiro-cli: immediate success; the existing kiro-cli session is reused.
- Not logged in: the plugin launches
kiro-cli login, which opens a browser window. Complete the login there; the plugin polls for up to 120 seconds and stores a minimal credential record when kiro-cli reports success.
There is no configuration prompt during login; the sidebar and footer credits surfaces
auto-load from the single plugins entry.
If the flow times out, authenticate directly with kiro-cli (kiro-cli login) and run
opencode auth login again; the fast path then completes immediately.
kiro-cli owns credential storage and refresh — OpenCode never stores real AWS tokens, and the plugin implements no refresh callback.
Logged out of Kiro CLI
If you run kiro-cli logout while OpenCode is open, the plugin checks kiro-cli's login
state on the next Kiro turn, not when you select a model. These are fresh checks, at
most once per 60 seconds per project location while authenticated. If you send within
60 seconds of an authenticated check, no new check runs; the logout is noticed on the
next Kiro turn after that window expires.
The first definitive logged-out result shows a confirm dialog titled "Kiro CLI is logged out" with the message "Reconnect now?":
- Confirm removes the stored Kiro connection and opens the connect dialog.
- Cancel or dismiss does nothing immediately and defers reconnecting. A follow-up
check runs about 6 seconds after the first logged-out result. If it also reports
logged out, the stale connection is removed automatically, even if you cancelled.
Kiro models then disappear until you reconnect through
/connect. The dialog is not shown again for the same logout. - An inconclusive check (kiro-cli unreachable or timed out) never removes the connection. An inconclusive follow-up is tried once more about 6 seconds later; if that is also inconclusive, the connection stays in place unless you confirm the dialog or a later Kiro turn's check confirms the logout. Logging back in before confirmation stops the automatic removal once an authenticated check succeeds.
To reconnect later, run kiro-cli login, then use /connect, select Kiro, and
choose Add account / Kiro CLI Login. A turn that fails with kiro-cli's
not-logged-in error is not retried; reconnect before sending again.
Models
After authentication, the plugin captures Kiro's runtime model list and uses
provider.transform to take the exact, case-sensitive intersection of runtime
modelId values and models.dev Model.Info.modelID values. Runtime reasoning-effort
levels are merged as model variants (per model family, native levels only); an optional runtime baseline effort
sets the model's base effort. A discovery failure or duplicate runtime ID leaves the
provider data unchanged (fail-open). If the models.dev seed has no kiro provider
or its model set is empty, the plugin self-registers minimal runtime model entries.
Snapshot publication requests provider.reload; no model-domain transform is registered.
The host's own variant generation uses a package-keyed protocol map in
packages/core/src/variant.ts. It has no Kiro or generic aisdk: entry, so it
generates no variants for aisdk:kiro-acp-ai-provider. Runtime effort enrichment
remains the plugin's responsibility.
Discovery is bounded and self-healing: a probe that gets no answer from kiro-cli within
60 seconds is treated as failed, and a failed probe is retried while Kiro stays
connected (after 5, 20, and 60 seconds) before giving up until the next login or
credential change. Each failure is reported on the server's stderr with an
[opencode-kiro] prefix - visible in opencode serve output, or from the TUI with
OPENCODE_PRINT_LOGS=1 - so a missing model list is never silent. A login triggers one
probe per project location, however many credential events the host emits for it.
List the resulting models with:
opencode models
opencode run -m kiro/<exact-model-id> "hello"
Effort-capable models expose their variants through OpenCode's model-variant selection: pick the variant to choose a reasoning-effort level. The selected level is applied per request, and one provider instance (one kiro-cli process) serves every effort level, so switching effort does not start additional kiro-cli processes. Kiro cannot disable thinking, so even the lowest level still produces a reasoning trail.
Credits in the TUI
Kiro is subscription-metered: requests consume credits, and the dollar cost OpenCode normally displays for Kiro turns is always $0.00. To surface credits the TUI plugin renders two surfaces:
- a Kiro credits box in the sidebar (
sidebar.contentclaim), showing the session's live credits total and unit - a compact credits chip in the prompt footer row beside the host cost/context
display (
prompt.footer.statusclaim) with the same total
Both are additive append claims — they compose with the host's built-in content and
never replace it — and both pick up the active theme's text tokens (feature-detected;
with no theme they fall back to default terminal styling). They render only for
sessions that carry Kiro credit data; other sessions are unchanged. The credits value
and unit come from the provider state the host persists on each message part
(part.state.credits / part.state.creditsUnit); nothing is hardcoded client-side.
The only configuration needed is the single plugins entry from
Install - the host discovers the TUI half from ./tui.
Durable credits are read straight from host message state (the host persists provider state on text end). While a turn is still streaming, credits for just-ended text are picked up live through a transient overlay that works around a host reducer bug at the pinned snapshot (the live event path still drops provider state); once durable state arrives it is authoritative and nothing is double-counted. See CHANGELOG.md for details.
Known limitations
- Conversations that run without tools (for example an agent with all tools disabled) can lose earlier context after the first turn, because OpenCode's title request and the main turn can end up sharing one Kiro session. This is a known, pre-existing issue with a fix planned for a later release.
- Compaction completes, but the Kiro session may not receive the earlier conversation or the compaction summary, so the following turns can miss context. This is a known, pre-existing issue with a fix planned for a later release.
- Live text credits use a transient overlay. The durable credits path is fixed
upstream, but the live
session.text.endedreducer still drops provider state at the tested SHA, so in-turn updates come from the plugin's transient overlay (durable state always wins on reconcile). See Credits in the TUI and CHANGELOG.md. - Credits render in the TUI only. Every other cost surface (ACP clients, web,
desktop, share pages, CLI cost output) shows $0.00 for Kiro sessions because the
catalog declares Kiro's per-token
costas 0 (subscription-metered, no per-token pricing). That is expected, not a defect. name@file:tarball installs show a per-slot TUI error. The colon in aname@file:install dirname defeats the host's OpenTUI loader shim; the failure is contained to the plugin's slots (dismissible error notice, host TUI unaffected). Registry installs and the absolutedist/directory source avoid that colon-path issue.- Reduced toast feedback. Auth-flow feedback is delivered as connect-flow text rather than toasts; this plugin's core deliberately does not depend on the churning TUI toast API.
- Tested reference host. 0.5.2 targets OpenCode 2 stable 2.0.x and is tested on 2.0.29; later releases are not guaranteed to work. No peer dependency is declared; the host supplies the plugin API at runtime. The exact development pin is for types and tests only. See Compatibility.
How it works
- Auth (Integration + Credential): the plugin upserts the
kirointegration with a "Kiro CLI Login" OAuth method.verifyAuthAsyncfromkiro-acp-ai-provideris the auth authority (it delegates to kiro-cli without blocking the host's event loop); success is stored as a minimalCredential.OAuthpresence record. Starting a new login while one is pending cancels the earlier attempt. - Model discovery (provider transform): after login (and on later login events) the
plugin runs
listModels()outside the transform, then applies the validated capture viaprovider.transformandprovider.reload- exact ID matching, models.dev metadata preserved, effort variants projected, fail-open on any discovery error. Each probe runs under a generation token: a logout, a newer probe, or a retry bumps the generation, and a result that arrives for an older generation is discarded instead of overwriting the catalog. - Provider ownership (AISDK hooks): the plugin's
sdkhook constructs the provider fromkiro-acp-ai-providerwith the plugin-supplied settings (identifying itself to kiro-cli asopencode-kiro) and sets it as the event's SDK, so the Kiro provider is always plugin-owned; one instance is cached per distinct settings and shared across effort variants. Thelanguagehook applies the selected effort per request. The settings relay each model's context window into the SDK'scontextWindowsmap keyed by model ID. - Effort carrier (
settings.effort): OpenCode overlays the selected variant'ssettingsonto the model'ssettingsand hands them to the plugin'saisdkhooks asevent.options; thelanguagehook readsevent.options.effortand passes it to the shared provider as a per-model override (languageModel(id, { effort })). The plugin emits the SDK's owneffortkey (notreasoningEffort). These variants come from runtime discovery, not the host's package-keyed protocol map, which has no Kiro or genericaisdk:entry. - Session affinity & reset (in-SDK): the SDK keys kiro-cli sessions off OpenCode's session affinity, isolates tool-less utility calls on an ephemeral session, detects prompt-history divergence, and starts a fresh kiro session when needed.
- Credits state: the SDK reports
credits/creditsUnitin each turn's provider metadata; OpenCode persists them key-unwrapped on message part state (part.state.credits,part.state.creditsUnit), and the TUI plugin sums them per assistant message (deduped across parts). - Stall notice and metadata: the SDK emits the live transcript notice as a
reasoning fragment, with a short reason in its closing line when available (see
Slow responses). A stalled turn's final text or reasoning part
carries
status({ stalledMs, hint?, reason? }) in provider metadata for other consumers, even withlive: "off". The TUI credits surfaces do not renderstatus.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
kiro-cli is not installed during auth |
Install kiro-cli from https://kiro.dev/docs/cli/ and ensure it is on PATH for the opencode process. |
| Auth times out after ~120s | Complete the browser login faster, or run kiro-cli login yourself, then re-run opencode auth login (fast path). |
| Kiro shows connected but prompts fail with Not logged in | The next Kiro turn offers to reconnect once the login check detects the logout (checks pause for 60 seconds after an authenticated result; see Logged out of Kiro CLI). To reconnect now, use /connect > Kiro > Add account, then Kiro CLI Login. You can also run kiro-cli login first, then use /connect. Not-logged-in failures are not retried. |
| No credits line / credits stay 0 | Credits appear after the first completed kiro turn; cancelled turns and turns without usage state contribute nothing. Check the plugin is active (no stray "-kiro" directive — note that directive residue can persist on a reused data dir). |
| Credits surfaces never appear | The host discovers the ./tui export from the same plugins entry - no separate TUI config exists. Check the entry, the built server/TUI files, and host load errors, then restart opencode. For name@file: tarball installs, a contained per-slot error notice instead of the credits views is the known colon-path caveat; use an absolute built dist/ directory or a registry install. |
kiro provider not showing in opencode models |
Run opencode auth login first: models are discovered after auth. If the loaded catalog lacks a kiro entry, the plugin self-registers a minimal fallback during discovery. If you are logged in and the list (or the effort variants) is still missing, the discovery probe may have failed or timed out: it is retried automatically for a few minutes, and each attempt is reported on the server's stderr with an [opencode-kiro] prefix (opencode serve, or OPENCODE_PRINT_LOGS=1 with the TUI). Logging in again starts a fresh probe. |
| Spinner with no output for a long time | The Kiro backend is likely overloaded and kiro-cli is retrying the request. With the default stall option a collapsed reasoning block saying so appears in the transcript after 10 seconds (only when thinking is shown; see Slow responses). Its closing line reports the duration and, when available from kiro-cli's log, a reason such as ModelOverloaded. If no such block appears and the model list or effort variants are also missing, discovery may be the problem instead: watch the server log (OPENCODE_PRINT_LOGS=1, or run under opencode serve) for [opencode-kiro] lines. kiro-cli's own errors are in its log under your temp directory (kiro-log/kiro-chat.log). |
| Local plugin does not load | Run npm run build and configure the absolute dist/ directory path, not the package root or a direct .js file. The host resolves server.js and tui.js inside that directory; both entry modules export their own ids. |
| Provider visible but runs fail | The provider can be selectable before any credential exists. Run opencode auth login first. |
| Worked yesterday, broken today | 0.5.2 targets OpenCode 2 stable 2.0.x and is tested on 2.0.29; later releases are not guaranteed to work (see Compatibility). If your OpenCode build moved past the tested SHA, the v2 plugin surface may have changed underneath it. Another possible cause is an unpinned plugins entry: the host checks unpinned specs (bare, tag or range) for newer versions in the background and marks them outdated; it installs an update only when you trigger one (or after the cache is cleared), which can move the plugin off the tested build. An exact version is never re-resolved - pin the exact opencode-kiro@0.5.2 spec for reproducible installs. |
Legacy: v1 / OpenCode v1 users (0.4.0)
opencode-kiro@0.4.0 is the supported stable line for OpenCode
v1 (opencode >= 1.16.0). It uses the v1 contract throughout: singular plugin
arrays in opencode.json and tui.json, the opencode plugin opencode-kiro
installer, and part.metadata.kiro credits. Its full documentation is the README at
the v0.4.0 tag.
Do not install 0.5.2 into an OpenCode v1 setup.
Development
npm install
npm run typecheck # tsc --noEmit
npm run build # tsup builds dist/server.js + dist/tui.js (+ d.ts)
npm test # vitest
License
MIT © Nacho F. Lizaur
同类生态推荐
Kiro Provider
opencode-kiro-provider
OpenCode provider for Kiro: every model your Kiro subscription offers (GPT-5.6, Claude Opus 5, Sonnet, open-weight), live model list, reuses your kiro-cli login
V2 Kiro Auth
opencode-v2-kiro-auth
Use Kiro models (Claude Fable 5.1, Claude Opus 5.5, GPT 5.6 Sol) in opencode v2 with AWS Builder ID, IAM Identity Center, or Kiro API-key authentication, with effort variants and Kiro-backed web search.
Kiro Auth
@hongyilyu/opencode-kiro-auth
Use Kiro models in opencode with AWS Builder ID, IAM Identity Center, or Kiro API-key authentication. Includes Claude 5, GPT 5.6, effort variants, and built-in web search.