You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
I'm always frustrated when I try to distribute a real Kiro custom (sub-)agent through APM and almost all of its configuration is silently thrown away.
APM's Kiro agent integrator emits only three frontmatter keys — description, model, and tools — and drops everything else the agent declared. A Kiro custom agent supports far more: resources (file:// and skill:// — how an agent attaches its own skills and reference files), mcpServers (inline MCP servers scoped to the agent), allowedTools and excludedTools, permissions (capability-scoped allow/ask/deny rules), toolsSettings (including toolsSettings.subagent for sub-agent gating), toolAliases, hooks, includeMcpJson, includePowers, welcomeMessage, and keyboardShortcut. Also prompt, which in Markdown form is carried by the file body — so instructions do survive — but a declared prompt: file://… in frontmatter does not.
None of the rest survive apm install to the kiro target, so the agent that lands in .kiro/agents/ is a shell of what was authored: no tool boundary beyond the coarse tools list, no attached skills, no scoped MCP servers.
One further sharp edge makes this worse than "some fields are dropped":
Fail-closed on a stale tool allow-list. The integrator validates tools: against a hard-coded set and refuses to deploy the entire agent if any value falls outside it. That set is out of date relative to current Kiro: it rejects real, current tool identifiers — grep (alias of grep_search), glob (alias of file_search), code, use_aws (alias of aws), web_search, web_fetch, introspect, tool_search. It also conflates category tags with tool names: web and context are tags that expand to tool sets (web → web_fetch + web_search; context → disclose_context + introspect + knowledge), not tool identifiers — so the allow-list is validating two different vocabularies against one flat set. The practical result is that a valid agent using, say, web_fetch is silently not deployed — with only a diagnostic.
The net effect: APM cannot today distribute a usable, fully-configured Kiro sub-agent. This blocks the single most valuable packaging use case we have — shipping focused sub-agents (information-gatherer, code-reviewer, developer) with their tool boundary, attached skills, and MCP servers as one versioned unit.
Describe the solution you'd like
Widen APM's Kiro agent support so a custom agent survives packaging intact:
Pass through the full Kiro custom-agent field set when compiling to the kiro target, rather than reducing to three keys. At minimum: prompt, resources, mcpServers, allowedTools, excludedTools, permissions, toolsSettings, toolAliases, hooks, includeMcpJson, includePowers, welcomeMessage, keyboardShortcut — in addition to the existing description, model, tools. Unknown/forward-compat keys should be preserved (pass-through), not dropped, so APM doesn't gate on a field list it has to chase.
Note that resources is not a plain string[]: alongside file:// and skill:// URIs it accepts an object form ({"type": "knowledgeBase", "source": …, "name": …, "indexType": …, "autoUpdate": …}). Any passthrough implementation needs to preserve non-string entries and nested structures verbatim rather than assuming scalars.
Fix (or remove) the tool allow-list. Either update it to the current Kiro tool vocabulary — and model tags and tool names as distinct concepts, since tools: legitimately accepts tool names, category tags, @server/@server/tool, @builtin, @mcp, and * — or stop hard-validating tool identifiers against a baked-in set and pass them through, letting the harness be the authority. If validation stays, it must warn and deploy, not fail-closed and silently drop the whole agent.
(Lower priority, not a blocker) Optional JSON agent output. Current Kiro reads both .kiro/agents/<name>.json and .kiro/agents/<name>.md (YAML frontmatter for config, body as the system prompt), with identical field support and mixed formats allowed in one workspace — so APM's existing Markdown emit is correct, and arguably the better default since it carries the prompt as the body. A JSON emit path would still be useful for authors targeting Kiro CLI 2.x, where Markdown agents are not supported, and for agents whose config is easier to express as structured data. Treat this as an option, not a fix.
The goal: apm install produces a Kiro agent that is byte-for-byte usable — its tool boundary, attached skills (resources: skill://…), and MCP servers all intact — so a package can ship an agent + its dependencies as one governed, versioned, multi-target unit.
Describe alternatives you've considered
Hand-author the agent file outside APM (commit .kiro/agents/<name>.{md,json} in the consuming repo, ship only skills+MCP via APM). Works today and is our current interim, but it forks the agent definition out of the package — it isn't versioned or governed with the rest of the bundle, defeating the point of a single distributable unit.
Package the agent as an Agent Plugin (--format agent-plugin). Not possible: the Agent Plugins spec's component types are skills and MCP servers (Kiro additionally layers a vendor dev.kiro/ directory for steering extensions), and agents and hooks are excluded. A Kiro Power — an installed Agent Plugin, for the current plugin.json format — is a payload an agent consumes, not an agent definition. So the portable-plugin path structurally cannot carry an agent.
Adopt/extend an in-house installer (a verbatim copy-into-.kiro/ tool) that preserves agent config by not transforming it. This does preserve fidelity, but it's Kiro-only, fails open (no validation — ships broken artifacts silently), and means owning a whole installer to work around one fixable passthrough gap in APM. We'd rather fix APM.
Wait for the Agent Plugins spec to add agents/hooks. The spec's own design notes say these "remain too client-specific… until their formats converge" — no committed timeline. Not a near-term option.
Additional context
We want to distribute focused sub-agents (each with instructions, a tool boundary, attached skills, and scoped MCP servers — optionally hooks) as versioned packages across Kiro and, later, other harnesses. APM is otherwise exactly right for this (multi-target, pinned, governed, fail-closed validation); the Kiro agent passthrough is the one blocker.
The strongest argument for pass-through-and-preserve over a curated field list is that Kiro's own agent-config surface is still moving, and in places the documentation disagrees with itself. Two current examples:
toolsSettings — the agent configuration reference calls it deprecated but still supported for MCP tool-specific settings and for toolsSettings.subagent (availableAgents / trustedAgents), while the CLI 3.0 and 2.x-reference pages state it was removed in V3. Sub-agent gating is precisely our use case, and it currently sits on the disputed field.
Inline agent hooks — the CLI and IDE field tables describe hooks as CLI-only ("IDE ignores agents containing this field"), the configuration reference's own Hooks section says both surfaces accept the format, and the hooks migration guide labels the embedded-in-agent form "old format — do not use in 3.0," directing hooks to standalone .kiro/hooks/*.json with a versioned schema and PascalCase triggers.
There are also real, if narrower, cross-surface differences — hooks and includePowers are surface-specific, and the IDE 1.0 field table types resources as string[], which doesn't accommodate the documented object form. An integrator that curates a field list has to track all of this and will lag it. One that preserves what the author wrote does not, and stays correct across CLI/IDE and across versions.
(Kiro capability claims above are documentation-grounded against kiro.dev CLI v3 / IDE 1.0 at time of writing, not empirically re-verified against a pinned binary. Version-specific behaviour is worth confirming against whichever Kiro version APM decides to target.)
Second pass — indication of what may need to change in the APM codebase (paths relative to the repo; verified against current main):
src/apm_cli/integration/agent_integrator.py — the core of the fix.
KIRO_AGENT_ALLOWED_TOOLS (a frozenset, ~line 31, comment "Fail closed: any value not in this set blocks deployment"): update to the current Kiro tool set — distinguishing tool identifiers from category tags and the @server / @builtin / @mcp / * selector forms — or drop the hard gate in favour of pass-through-with-warning.
_preflight_render_kiro_agent(...) (~line 520+): today it parses frontmatter, validates tools (returning (None, False) → skip the whole agent on any unknown tool), then rebuilds an allow-listed frontmatter in out_fm_ordered emitting onlydescription, model, tools (~lines 607–615). This is the exact reduction point — it must be widened to carry the additional fields (or, better, switched to preserve the source frontmatter minus any genuinely incompatible keys), and the fail-closed branch changed to warn-and-continue. Preservation needs to be structure-preserving: mcpServers, permissions.rules, toolsSettings, and object-form resources entries are nested, not scalar.
_write_kiro_agent(...) / the kiro_agent branch in integrate_agents_for_target(...): currently renders Markdown, which is valid for current Kiro — the change here is to widen the emitted frontmatter, not to replace the format. An optional JSON emit path (per solution Will there be MCP coverage? #3) would slot in alongside it.
src/apm_cli/integration/targets.py — the target mapping. The Kiro profile maps "agents": PrimitiveMapping("agents", ".md", "kiro_agent") (~line 607). This mapping is correct as-is for current Kiro; it only needs touching if optional JSON output lands, which would likely mean a new/parameterised mapping (and possibly a surface or version flag).
src/apm_cli/primitives/models.py — the data model. The Chatmode dataclass (agents are parsed as chatmodes) currently has only name, file_path, description, apply_to, content, author, version, source, handoffs. There is no field to carryresources, mcpServers, permissions, allowedTools, toolsSettings, etc. Note the Kiro integrator re-reads raw frontmatter directly (so it isn't strictly bound by the model), but a clean fix probably adds a structured agent_config / passthrough dict to the model.
src/apm_cli/primitives/parser.py — _parse_chatmode(...) (~line 113). It only extracts description, applyTo, author, version, handoffs from metadata; all other agent frontmatter keys are discarded at parse time. To preserve them end-to-end (not just in the Kiro integrator), capture the remaining frontmatter here.
Tests / fixtures. Kiro agent integrator tests asserting the three-field output and the fail-closed tool behaviour will need updating. Add round-trip fixtures proving resources (both URI and object forms), mcpServers, permissions, and unknown/forward-compat keys survive to .kiro/agents/*.md with nested structure intact, plus a case asserting an agent using web_fetch (or another currently-rejected tool) deploys rather than being skipped.
Scope guard. This is intentionally about legacy per-primitive projection to the kiro target (apm install), not the Agent Plugins (--format agent-plugin) path — agents remain out of scope for the portable plugin format by spec, and PR feat(agent-plugins): add a portable v1 foundation #2654's fail-closed plugin boundary should be left untouched.
Is your feature request related to a problem? Please describe.
I'm always frustrated when I try to distribute a real Kiro custom (sub-)agent through APM and almost all of its configuration is silently thrown away.
APM's Kiro agent integrator emits only three frontmatter keys —
description,model, andtools— and drops everything else the agent declared. A Kiro custom agent supports far more:resources(file://andskill://— how an agent attaches its own skills and reference files),mcpServers(inline MCP servers scoped to the agent),allowedToolsandexcludedTools,permissions(capability-scoped allow/ask/deny rules),toolsSettings(includingtoolsSettings.subagentfor sub-agent gating),toolAliases,hooks,includeMcpJson,includePowers,welcomeMessage, andkeyboardShortcut. Alsoprompt, which in Markdown form is carried by the file body — so instructions do survive — but a declaredprompt: file://…in frontmatter does not.None of the rest survive
apm installto thekirotarget, so the agent that lands in.kiro/agents/is a shell of what was authored: no tool boundary beyond the coarsetoolslist, no attached skills, no scoped MCP servers.One further sharp edge makes this worse than "some fields are dropped":
Fail-closed on a stale tool allow-list. The integrator validates
tools:against a hard-coded set and refuses to deploy the entire agent if any value falls outside it. That set is out of date relative to current Kiro: it rejects real, current tool identifiers —grep(alias ofgrep_search),glob(alias offile_search),code,use_aws(alias ofaws),web_search,web_fetch,introspect,tool_search. It also conflates category tags with tool names:webandcontextare tags that expand to tool sets (web→web_fetch+web_search;context→disclose_context+introspect+knowledge), not tool identifiers — so the allow-list is validating two different vocabularies against one flat set. The practical result is that a valid agent using, say,web_fetchis silently not deployed — with only a diagnostic.The net effect: APM cannot today distribute a usable, fully-configured Kiro sub-agent. This blocks the single most valuable packaging use case we have — shipping focused sub-agents (information-gatherer, code-reviewer, developer) with their tool boundary, attached skills, and MCP servers as one versioned unit.
Describe the solution you'd like
Widen APM's Kiro agent support so a custom agent survives packaging intact:
Pass through the full Kiro custom-agent field set when compiling to the
kirotarget, rather than reducing to three keys. At minimum:prompt,resources,mcpServers,allowedTools,excludedTools,permissions,toolsSettings,toolAliases,hooks,includeMcpJson,includePowers,welcomeMessage,keyboardShortcut— in addition to the existingdescription,model,tools. Unknown/forward-compat keys should be preserved (pass-through), not dropped, so APM doesn't gate on a field list it has to chase.Note that
resourcesis not a plainstring[]: alongsidefile://andskill://URIs it accepts an object form ({"type": "knowledgeBase", "source": …, "name": …, "indexType": …, "autoUpdate": …}). Any passthrough implementation needs to preserve non-string entries and nested structures verbatim rather than assuming scalars.Fix (or remove) the tool allow-list. Either update it to the current Kiro tool vocabulary — and model tags and tool names as distinct concepts, since
tools:legitimately accepts tool names, category tags,@server/@server/tool,@builtin,@mcp, and*— or stop hard-validating tool identifiers against a baked-in set and pass them through, letting the harness be the authority. If validation stays, it must warn and deploy, not fail-closed and silently drop the whole agent.(Lower priority, not a blocker) Optional JSON agent output. Current Kiro reads both
.kiro/agents/<name>.jsonand.kiro/agents/<name>.md(YAML frontmatter for config, body as the system prompt), with identical field support and mixed formats allowed in one workspace — so APM's existing Markdown emit is correct, and arguably the better default since it carries the prompt as the body. A JSON emit path would still be useful for authors targeting Kiro CLI 2.x, where Markdown agents are not supported, and for agents whose config is easier to express as structured data. Treat this as an option, not a fix.The goal:
apm installproduces a Kiro agent that is byte-for-byte usable — its tool boundary, attached skills (resources: skill://…), and MCP servers all intact — so a package can ship an agent + its dependencies as one governed, versioned, multi-target unit.Describe alternatives you've considered
.kiro/agents/<name>.{md,json}in the consuming repo, ship only skills+MCP via APM). Works today and is our current interim, but it forks the agent definition out of the package — it isn't versioned or governed with the rest of the bundle, defeating the point of a single distributable unit.--format agent-plugin). Not possible: the Agent Plugins spec's component types are skills and MCP servers (Kiro additionally layers a vendordev.kiro/directory for steering extensions), and agents and hooks are excluded. A Kiro Power — an installed Agent Plugin, for the currentplugin.jsonformat — is a payload an agent consumes, not an agent definition. So the portable-plugin path structurally cannot carry an agent..kiro/tool) that preserves agent config by not transforming it. This does preserve fidelity, but it's Kiro-only, fails open (no validation — ships broken artifacts silently), and means owning a whole installer to work around one fixable passthrough gap in APM. We'd rather fix APM.Additional context
We want to distribute focused sub-agents (each with instructions, a tool boundary, attached skills, and scoped MCP servers — optionally hooks) as versioned packages across Kiro and, later, other harnesses. APM is otherwise exactly right for this (multi-target, pinned, governed, fail-closed validation); the Kiro agent passthrough is the one blocker.
The strongest argument for pass-through-and-preserve over a curated field list is that Kiro's own agent-config surface is still moving, and in places the documentation disagrees with itself. Two current examples:
toolsSettings— the agent configuration reference calls it deprecated but still supported for MCP tool-specific settings and fortoolsSettings.subagent(availableAgents/trustedAgents), while the CLI 3.0 and 2.x-reference pages state it was removed in V3. Sub-agent gating is precisely our use case, and it currently sits on the disputed field.hooks— the CLI and IDE field tables describehooksas CLI-only ("IDE ignores agents containing this field"), the configuration reference's own Hooks section says both surfaces accept the format, and the hooks migration guide labels the embedded-in-agent form "old format — do not use in 3.0," directing hooks to standalone.kiro/hooks/*.jsonwith a versioned schema and PascalCase triggers.There are also real, if narrower, cross-surface differences —
hooksandincludePowersare surface-specific, and the IDE 1.0 field table typesresourcesasstring[], which doesn't accommodate the documented object form. An integrator that curates a field list has to track all of this and will lag it. One that preserves what the author wrote does not, and stays correct across CLI/IDE and across versions.(Kiro capability claims above are documentation-grounded against kiro.dev CLI v3 / IDE 1.0 at time of writing, not empirically re-verified against a pinned binary. Version-specific behaviour is worth confirming against whichever Kiro version APM decides to target.)
Second pass — indication of what may need to change in the APM codebase (paths relative to the repo; verified against current
main):src/apm_cli/integration/agent_integrator.py— the core of the fix.KIRO_AGENT_ALLOWED_TOOLS(afrozenset, ~line 31, comment "Fail closed: any value not in this set blocks deployment"): update to the current Kiro tool set — distinguishing tool identifiers from category tags and the@server/@builtin/@mcp/*selector forms — or drop the hard gate in favour of pass-through-with-warning._preflight_render_kiro_agent(...)(~line 520+): today it parses frontmatter, validatestools(returning(None, False)→ skip the whole agent on any unknown tool), then rebuilds an allow-listed frontmatter inout_fm_orderedemitting onlydescription,model,tools(~lines 607–615). This is the exact reduction point — it must be widened to carry the additional fields (or, better, switched to preserve the source frontmatter minus any genuinely incompatible keys), and the fail-closed branch changed to warn-and-continue. Preservation needs to be structure-preserving:mcpServers,permissions.rules,toolsSettings, and object-formresourcesentries are nested, not scalar._write_kiro_agent(...)/ thekiro_agentbranch inintegrate_agents_for_target(...): currently renders Markdown, which is valid for current Kiro — the change here is to widen the emitted frontmatter, not to replace the format. An optional JSON emit path (per solution Will there be MCP coverage? #3) would slot in alongside it.src/apm_cli/integration/targets.py— the target mapping. The Kiro profile maps"agents": PrimitiveMapping("agents", ".md", "kiro_agent")(~line 607). This mapping is correct as-is for current Kiro; it only needs touching if optional JSON output lands, which would likely mean a new/parameterised mapping (and possibly a surface or version flag).src/apm_cli/primitives/models.py— the data model. TheChatmodedataclass (agents are parsed as chatmodes) currently has onlyname, file_path, description, apply_to, content, author, version, source, handoffs. There is no field to carryresources,mcpServers,permissions,allowedTools,toolsSettings, etc. Note the Kiro integrator re-reads raw frontmatter directly (so it isn't strictly bound by the model), but a clean fix probably adds a structuredagent_config/ passthrough dict to the model.src/apm_cli/primitives/parser.py—_parse_chatmode(...)(~line 113). It only extractsdescription,applyTo,author,version,handoffsfrommetadata; all other agent frontmatter keys are discarded at parse time. To preserve them end-to-end (not just in the Kiro integrator), capture the remaining frontmatter here.Tests / fixtures. Kiro agent integrator tests asserting the three-field output and the fail-closed tool behaviour will need updating. Add round-trip fixtures proving
resources(both URI and object forms),mcpServers,permissions, and unknown/forward-compat keys survive to.kiro/agents/*.mdwith nested structure intact, plus a case asserting an agent usingweb_fetch(or another currently-rejected tool) deploys rather than being skipped.Scope guard. This is intentionally about legacy per-primitive projection to the
kirotarget (apm install), not the Agent Plugins (--format agent-plugin) path — agents remain out of scope for the portable plugin format by spec, and PR feat(agent-plugins): add a portable v1 foundation #2654's fail-closed plugin boundary should be left untouched.