Skip to content

SK-697: Add agent asset support for Kiro client - #206

Merged
detkin merged 7 commits into
mainfrom
detkin/SK-697-kiro-agents
Jul 17, 2026
Merged

SK-697: Add agent asset support for Kiro client#206
detkin merged 7 commits into
mainfrom
detkin/SK-697-kiro-agents

Conversation

@detkin

@detkin detkin commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Mirrors #204 (thanks @tmack8001!) onto a maintainer branch and fixes the issues found in review. Trevor's three commits are preserved as-is; the fixes land on top.

  • Add type = "agent" support to the Kiro client with dual-write output: {name}.md (IDE / CLI v3, YAML frontmatter) and {name}.json (CLI v2) in .kiro/agents/ — see SK-697 Add agent asset support for Kiro client #204 for the full design and live-harness validation
  • Fix the permissions decode bug: BurntSushi decodes [[agent.kiro.permissions]] inside map[string]any as []map[string]any, not []any, so permissions were silently dropped from the .md output on the real TOML parse path; both shapes are now normalized (covered by a real-TOML round-trip test)
  • Reject a table-shaped [agent.kiro.permissions] with guidance instead of silently dropping it
  • Reserve the agent name default.kiro/agents/default.json is the sx-managed Kiro CLI hooks config; install rejects the name and remove never deletes that file
  • VerifyInstalled now requires both output files so a missing half gets repaired
  • Frontmatter fields are all emitted via yaml.Marshal (correct YAML escaping) and marshal errors propagate instead of silently dropping fields

Closes #204.

Security implications of changes have been considered

tmack8001 and others added 4 commits July 16, 2026 13:17
Installs agents to ~/.kiro/agents/ in two formats simultaneously:
- {name}.md — IDE + CLI v3 (YAML frontmatter + system prompt body)
- {name}.json — CLI v2 default (JSON with prompt field)

Field routing: known v2-only fields (allowedTools, toolAliases, toolsSettings,
hooks, includeMcpJson, keyboardShortcut) are excluded from .md; permissions is
excluded from .json (CLI v2 has no permissions model). Unknown fields pass
through to both formats for forward compatibility — verified by live harness
test against kiro-cli v2 and v3 engines.
Separate third-party yaml import into its own group (gci).
Replace sb.WriteString(string(out)) with sb.Write(out) (mirror).
1. writeCLIFormat: guard reserved keys (name, prompt, description) in the
   [agent.kiro] passthrough loop so they cannot overwrite Asset metadata
   or zip content
2. permissions: tighten type guard from !isList||len>0 to isList&&len>0 so
   a TOML table ([agent.kiro.permissions]) is rejected instead of silently
   producing the wrong schema {rules:{key:val}}
3. model: write with %q (same as description) so values containing ": " do
   not produce invalid YAML
4. readAgentContent: fallback tries canonical "AGENT.md" (was lowercase
   "agent.md"); error now names both files tried, mirroring
   opencode/handlers/rule.go
5. Promote mdV2Only and mdExplicitFields to package-level vars (same pattern
   as hook event maps in every other handler)
- Accept []map[string]any permissions from TOML decode
- Reject table-shaped permissions with guidance
- Reserve "default" agent name to protect hooks config
- Verify both agent files, propagate YAML errors
@detkin
detkin requested review from inesp, mrdon and mzgajner as code owners July 17, 2026 22:20
@linear-code

linear-code Bot commented Jul 17, 2026

Copy link
Copy Markdown

SK-697

@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

Claude finished @detkin's task in 2m 25s —— View job


Solid, well-documented PR — the review fixes (permissions decode normalization, reserved default name, dual-file VerifyInstalled, yaml.Marshal for frontmatter) are correct and well-tested; a few low-severity notes below.

[MEDIUM] No black-box integration test exercising agent install through the Kiro client

Location: internal/clients/kiro/handlers/agent_test.go (present) vs. missing internal/commands/integration_*_test.go

Issue: The add-ai-client-support skill (Step 20 and "Common Mistakes" #10) calls for black-box integration tests that run sx install end-to-end and verify results. The handler unit tests here are thorough, but nothing exercises the full path through Client.InstallAssetsAgentHandler → files on disk for type = "agent", including scope resolution (determineTargetBase) and the reserved-name/verify behavior at the client layer.

Suggestion: Add an agent case to the Kiro integration test suite that installs a real agent bundle via the client for global + repo scope and asserts both .kiro/agents/{name}.md and {name}.json land correctly (and that default is rejected).

[LOW] Known fields with an unexpected type are silently dropped from the .md

Location: internal/clients/kiro/handlers/agent.go:139 (and 164, 146)

Issue: model and welcomeMessage are read via kiro["model"].(string) / .(string), and tools/resources via .([]any). If a field is present but has an unexpected type (e.g. model set to a non-string, or resources authored as an array-of-tables — the exact []map[string]any shape that just bit permissions), the type assertion fails and the field is in knownHandled, so the generic pass-through loop skips it too. The value is dropped from the .md with no error — the same silent-drop class the PR set out to fix for permissions.

Suggestion: For the known scalar/collection fields, either fall through to the generic pass-through on type mismatch, or return an error with guidance (mirroring normalizePermissions). At minimum, worth a comment noting these are string/[]any-only by design.

[LOW] Dual-write is not atomic — a partial failure leaves a half-installed agent

Location: internal/clients/kiro/handlers/agent.go:77-83

Issue: Install writes the .md then the .json sequentially. If writeCLIFormat fails (or the process dies) after the .md is written, the agent is left half-installed. This is mitigated — VerifyInstalled now requires both files, so --repair heals it — and is essentially unavoidable for a two-file write, so this is informational rather than a blocker.

Suggestion: None required; the VerifyInstalled repair path already covers it. Optionally note the non-atomicity in the Install doc comment.

[LOW] Redundant prompt-file fallback produces a confusing error message

Location: internal/clients/kiro/handlers/agent.go:319-335

Issue: getPromptFile() defaults to "AGENT.md" when unset, and readAgentContent falls back to the literal "AGENT.md". When the prompt file is unset (the common case) and missing, the error reads prompt file not found (tried "AGENT.md" and "AGENT.md").

Suggestion: Skip the fallback when promptFile == fallback, so the message lists a single filename.

- Black-box agent install/uninstall tests via Kiro client
- Mistyped known fields fall through to pass-through
- Clearer error when default prompt file is missing
@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

Claude finished @detkin's task in 2m 45s —— View job


PR Review — SK-697: Kiro agent asset support

The four issues from the prior review are all correctly addressed — silent-type-drops now fall through to pass-through (agent.go:134-138), the non-atomic dual-write and reserved default name are documented, the prompt-file fallback no longer double-lists (agent.go:339-346), and black-box integration tests now cover install/uninstall/reserved-name end-to-end through the client; one new low-severity latent issue below.

[LOW] A description key under [agent.kiro] is emitted twice in the .md frontmatter

Location: internal/clients/kiro/handlers/agent.go:126-130 and 198-209

Issue: writeIDEFormat writes description from getDescription() (i.e. [asset].description) at the top of the frontmatter, but "description" is never added to the handled set. If an author also sets description inside [agent.kiro], the generic pass-through loop emits a second description: key, producing duplicate-key YAML frontmatter (some parsers reject it, others silently take the last value). writeCLIFormat already guards this by skipping name/prompt/description in its pass-through (agent.go:275), so the two writers are inconsistent. The same applies to a stray name key, which the IDE writer would pass through unfiltered.

Suggestion: Add "description" (and "name") to the handled map in writeIDEFormat so the reserved top-level fields can't be duplicated from [agent.kiro], mirroring the guard in writeCLIFormat.

Fix this →

[LOW] Integration test comment says "Global scope" but the test installs via a path vault in a git repo

Location: internal/commands/integration_kiro_test.go:616

Issue: The comment reads // Global scope → ~/.kiro/agents/, but the test uses SetupPathVault() and installs from inside a git repo. The assertion (files land under $HOME/.kiro/agents) is correct, but the "Global scope" label is misleading for a future reader.

Suggestion: Reword the comment to match the actual scope being exercised, or drop the scope label.

- Never pass name/description through from [agent.kiro]
- Fix stale scope comment in integration test
@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

Claude finished @detkin's task in 1m 37s —— View job


PR Review — SK-697: Kiro agent asset support

All findings from the previous review rounds are correctly resolved — silent type-drops fall through to pass-through, name/description are now reserved in writeIDEFormat (agent.go:141) so they can't be duplicated in frontmatter, the prompt-file fallback no longer double-lists (agent.go:343), the reserved default name and non-atomic dual-write are documented, and the integration tests (TestKiroAgentInstall/Uninstall/DefaultNameRejected) exercise the full install path with the misleading scope comment corrected (integration_kiro_test.go:616); one minor consistency note below.

[LOW] A prompt key under [agent.kiro] would leak into the .md frontmatter

Location: internal/clients/kiro/handlers/agent.go:141 and 278

Issue: The handled set in writeIDEFormat now reserves permissions, name, and description, but not prompt. In the .md (IDE / CLI v3) format the system prompt is the document body (written from the zip content at agent.go:215), so a stray prompt key authored under [agent.kiro] would fall through the generic pass-through loop and be emitted as a prompt: frontmatter key — competing with the actual body. writeCLIFormat already reserves prompt (agent.go:278), so the two writers guard different sets — the exact inconsistency the last round fixed for name/description.

Suggestion: Add "prompt" to the handled map in writeIDEFormat so all three reserved top-level keys (name, prompt, description) are guarded consistently across both writers.

Fix this →

@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown

Claude finished @detkin's task in 1m 33s —— View job


PR Review — SK-697: Kiro agent asset support

All findings from the four prior review rounds are correctly resolved and the latest commit closes the last one — prompt is now reserved in writeIDEFormat (agent.go:142) alongside name/description, so the two writers guard a consistent reserved-key set; no new issues found.

Verification of prior findings against the current code:

  • Silent type-drops → known scalar/collection fields (model, tools, resources, mcpServers, welcomeMessage) only mark handled inside a successful type assertion, so a type mismatch falls through to the generic pass-through instead of being dropped (agent.go:144-185).
  • Permissions decode bugnormalizePermissions accepts both []any and BurntSushi's []map[string]any, and rejects a table-shaped [agent.kiro.permissions] with guidance (agent.go:240-255).
  • Reserved default name → rejected on install and never deleted on remove, both documented (agent.go:56-60, 88-93).
  • Non-atomic dual-write → documented on Install, healed by the two-file VerifyInstalled (agent.go:52-54, 104-114).
  • Prompt-file fallback → no longer double-lists when promptFile == fallback (agent.go:343-346).
  • Reserved-key consistencyname/prompt/description guarded in both writeIDEFormat (agent.go:142) and writeCLIFormat (agent.go:279).
  • Integration coverageTestKiroAgentInstall/Uninstall/DefaultNameRejected exercise the full client path; the misleading scope comment was corrected.

Review complete. No issues found.
detkin/SK-697-kiro-agents

@detkin
detkin merged commit 65e6c56 into main Jul 17, 2026
4 checks passed
@detkin
detkin deleted the detkin/SK-697-kiro-agents branch July 17, 2026 22:39
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