Skip to content

feat: add Kiro platform support (#276)#278

Merged
avifenesh merged 16 commits intomainfrom
feature/add-kiro-support-276
Mar 2, 2026
Merged

feat: add Kiro platform support (#276)#278
avifenesh merged 16 commits intomainfrom
feature/add-kiro-support-276

Conversation

@avifenesh
Copy link
Collaborator

@avifenesh avifenesh commented Mar 1, 2026

Summary

  • Adds Kiro as the 5th supported platform alongside Claude Code, OpenCode, Codex CLI, and Cursor
  • Skills install to .kiro/skills/<name>/SKILL.md (drop-in compatible)
  • Commands install as steering files to .kiro/steering/<name>.md with inclusion: manual frontmatter
  • Agents convert from markdown to Kiro JSON format at .kiro/agents/<name>.json
  • Platform auto-detected when .kiro/ directory exists (project-scoped like Cursor)

Changes

Core (5 files):

  • bin/cli.js - installForKiro(), VALID_TOOLS, detection, routing, help text, interactive prompt
  • lib/adapter-transforms.js - transformSkillForKiro(), transformCommandForKiro(), transformAgentForKiro()
  • lib/discovery/index.js - getKiroSteeringMappings() with kiro-description fallback chain
  • lib/cross-platform/index.js - PLATFORMS.KIRO, STATE_DIRS, detectPlatform, INSTRUCTION_FILES
  • lib/platform/state-dir.js - .kiro directory detection, getPlatformName

Dev scripts (2 files):

  • scripts/dev-install.js - installKiro(), validTools, cleanAll
  • scripts/gen-adapters.js - Kiro adapter generation (steering, agents, skills)

Tests (4 files):

  • __tests__/cli-args.test.js - installForKiro test suite (8 tests)
  • __tests__/cross-platform.test.js - KIRO platform constants and detection
  • __tests__/state-dir.test.js - .kiro directory detection and priority
  • __tests__/gen-adapters.test.js - Kiro transforms (16 tests) + steering mappings (3 tests)

Docs (5 files):

  • README.md, INSTALLATION.md, CROSS_PLATFORM.md, CLAUDE.md, AGENTS.md, CHANGELOG.md

Test plan

  • All 3,074 tests pass (77 suites, 0 failures)
  • Pre-push validation passed (9 checks, 0 failures)
  • Skills correctly transformed with PLUGIN_ROOT substitution
  • Steering files get inclusion: manual frontmatter
  • Agent JSON has correct schema (name, description, prompt, tools, resources)
  • Agent tools default to ['read'] (least privilege)
  • Prototype pollution guard on frontmatter parser
  • Platform detection works for .kiro/ directory
  • Cleanup preserves user files on reinstall

Closes #276

Summary by CodeRabbit

  • New Features

    • Added Kiro as a 5th supported platform with a project-scoped state directory, installer integration, and CLI options.
    • Installer and interactive help list Kiro among tool choices; content generation now produces Kiro-formatted skills, commands, and agents.
    • Cursor state tracking added alongside Kiro for cross-platform awareness.
  • Documentation

    • Updated README, installation, and cross-platform docs to cover Kiro and Cursor, their state directories, and usage guidance.

avifenesh added 11 commits March 2, 2026 00:15
Add KIRO platform to PLATFORMS, STATE_DIRS, detectPlatform(),
INSTRUCTION_FILES, and state-dir detection. Kiro uses .kiro/
directory and reads AGENTS.md + .kiro/steering/*.md.
Add transformSkillForKiro (PLUGIN_ROOT replacement + namespace strip),
transformCommandForKiro (steering file with inclusion: manual frontmatter),
and transformAgentForKiro (markdown+frontmatter to Kiro JSON format).
Add getKiroSteeringMappings() that returns [steeringName, pluginName,
sourceFile, description] tuples. Uses kiro-description frontmatter
with fallback chain to cursor/codex/generic description.
Add installForKiro() function that installs skills to .kiro/skills/,
commands as steering files to .kiro/steering/, and agents as JSON
to .kiro/agents/. Wire up all CLI touchpoints: VALID_TOOLS,
detectInstalledPlatforms, interactive options, platform routing,
printHelp, removeInstallation, and module.exports.
Add installKiro() to dev-install.js with Kiro cleanup in cleanAll().
Add Kiro adapter generation to gen-adapters.js (steering files,
agent JSON, skills) and include kiro/ in orphan scanning.
Update VALID_TOOLS to expect 5 tools. Add installForKiro test suite
covering skills, steering files, agents, cleanup, filters, and
PLUGIN_ROOT replacement. Add KIRO to platform count, STATE_DIRS,
detectPlatform, INSTRUCTION_FILES, state-dir detection, priority,
and getPlatformName tests.
Update platform counts from 4 to 5 across README, CLAUDE.md, AGENTS.md,
INSTALLATION.md, and CROSS_PLATFORM.md. Add Kiro examples, platform
table entries, and Kiro-specific notes section.
- Fix installForKiro calling transformSkillForCursor instead of transformSkillForKiro
- Add __proto__ guard in transformAgentForKiro frontmatter parser
- Default agent tools to ['read'] (least privilege) instead of ['read', 'write', 'shell']
- Fall back to ['read'] when tools field maps to empty array
- Add Cursor and Kiro to CROSS_PLATFORM.md state dirs table and considerations
- Add Cursor and Kiro to CLAUDE.md/AGENTS.md state-files platform list
- Add Kiro platform support entry to CHANGELOG.md [Unreleased]
Copilot AI review requested due to automatic review settings March 1, 2026 22:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Kiro as an additional supported platform in agentsys, extending the existing multi-platform install/transform pipeline (CLI installer, adapter generation, discovery, and cross-platform detection) to produce Kiro-compatible steering files, skills, and agent JSON.

Changes:

  • Add Kiro platform constants/detection and state-dir support (.kiro/)
  • Implement Kiro install + adapter generation paths (steering from commands, agent JSON, skills)
  • Add/extend tests and documentation to cover Kiro as the 5th platform

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
bin/cli.js Adds kiro to supported tools, detection, and install routing; implements installForKiro()
lib/adapter-transforms.js Adds Kiro transforms for skills, commands→steering, and agents→JSON
lib/discovery/index.js Adds getKiroSteeringMappings() with description fallback chain
lib/cross-platform/index.js Adds PLATFORMS.KIRO, STATE_DIRS mapping, detection, and instruction files
lib/platform/state-dir.js Adds .kiro directory detection and platform-name mapping
scripts/dev-install.js Adds dev install + cleanup logic for .kiro/ outputs
scripts/gen-adapters.js Generates Kiro adapter artifacts and updates orphan detection to include .json + kiro/
__tests__/cli-args.test.js Adds installForKiro presence + install behavior tests
__tests__/cross-platform.test.js Extends platform constants/detection tests to include Kiro
__tests__/state-dir.test.js Adds .kiro detection + priority tests
__tests__/gen-adapters.test.js Adds unit tests for Kiro transforms + steering mappings
docs/INSTALLATION.md Documents Kiro install locations and usage flags
docs/CROSS_PLATFORM.md Adds Kiro to supported-platforms and state-dir docs
README.md Updates platform count and install examples to include Kiro
CLAUDE.md Updates platform-aware state-dir list and “all platforms must work” statement
AGENTS.md Updates repo layout + state-dir list + “all platforms must work” statement
CHANGELOG.md Adds Unreleased entry for Kiro platform support
Comments suppressed due to low confidence (3)

tests/gen-adapters.test.js:663

  • This test name says the default tools are "read/write/shell", but the assertion expects ['read']. Please update the test description to match the actual expected default behavior (least-privilege read-only), or adjust the implementation if the intent is different.
    test('defaults to read/write/shell when no tools specified', () => {
      const input = '---\nname: test\n---\nPrompt';
      const result = transforms.transformAgentForKiro(input);
      const parsed = JSON.parse(result);
      expect(parsed.tools).toEqual(['read']);
    });

scripts/gen-adapters.js:125

  • KIRO_PLUGIN_ROOT_PLACEHOLDER duplicates the exact same placeholder value as CODEX_PLUGIN_ROOT_PLACEHOLDER. Consider reusing the existing constant to avoid drift if the placeholder ever changes.
  // --- Kiro adapters ---
  const KIRO_PLUGIN_ROOT_PLACEHOLDER = '{{PLUGIN_INSTALL_PATH}}';

lib/platform/state-dir.js:127

  • This switch now returns 'kiro', but the JSDoc for getPlatformName() above still documents only 'claude', 'opencode', 'codex', or 'custom'. Please update the doc comment to include 'kiro' (and/or 'unknown') so documentation matches behavior.
  switch (stateDir) {
    case '.opencode': return 'opencode';
    case '.codex': return 'codex';
    case '.kiro': return 'kiro';
    case '.claude': return 'claude';

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +509 to +555
const frontmatter = {};
let body = content;
if (content.startsWith('---')) {
const endIdx = content.indexOf('\n---', 3);
if (endIdx !== -1) {
const fmBlock = content.substring(4, endIdx);
body = content.substring(endIdx + 4).replace(/^\n/, '');
for (const line of fmBlock.split('\n')) {
const colonIdx = line.indexOf(':');
if (colonIdx > 0) {
const key = line.substring(0, colonIdx).trim();
if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;
let value = line.substring(colonIdx + 1).trim();
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
frontmatter[key] = value;
}
}
}
}

if (pluginInstallPath) {
body = body.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
body = body.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
body = body.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
body = body.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
}

body = body.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');

const agent = {
name: frontmatter.name || '',
description: frontmatter.description || '',
prompt: body.trim()
};

if (frontmatter.tools) {
const toolStr = frontmatter.tools.toLowerCase();
const tools = [];
if (toolStr.includes('read')) tools.push('read');
if (toolStr.includes('edit') || toolStr.includes('write')) tools.push('write');
if (toolStr.includes('bash') || toolStr.includes('shell')) tools.push('shell');
if (toolStr.includes('glob')) tools.push('read');
if (toolStr.includes('grep')) tools.push('read');
const deduped = [...new Set(tools)];
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transformAgentForKiro() re-implements frontmatter parsing instead of reusing discovery.parseFrontmatter(). This custom parser does not support YAML arrays (e.g., tools:\n - Read), which the repo’s frontmatter parser explicitly supports and is used elsewhere. As a result, agents that specify tools as a list will be mis-parsed and likely fall back to ['read']. Reuse the shared frontmatter parser (and handle tools as either string or array) to avoid incorrect Kiro agent JSON.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - refactored to use discovery.parseFrontmatter() which handles YAML arrays and has proto pollution guards. Also added array support for the tools field mapping.

@avifenesh
Copy link
Collaborator Author

Follow-up issues created from learning research

Research into Kiro's subagent spawning, user interaction, and cross-tool patterns revealed gaps that need implementation beyond the base platform support in this PR:

Key finding: Kiro HAS subagent spawning

Kiro agents CAN invoke other agents defined in .kiro/agents/*.json by name. This is synchronous (one at a time). The current PR correctly installs agents as JSON - they're immediately usable as subagents. The follow-up issues improve how agentsys references these subagents in transformed skill/command content.

…on to markdown

- Task() calls now produce `Delegate to the \`agent-name\` subagent:` with
  extracted prompt text, instead of generic "Invoke the X agent" text.
  This instructs the Kiro agent to use its native subagent invocation system.
- AskUserQuestion calls are transformed to markdown numbered-list prompts
  with question text, option labels, and descriptions preserved.
- Tests updated for both new transform behaviors.

Closes #279, closes #280
Kiro has experimental 4-agent spawning (not publicly available).
Plugins like next-task (Phase 9) and audit-project spawn up to 10
parallel reviewers. This adds graceful degradation:

1. generateCombinedReviewerAgent() - creates combined reviewer agents
   merging 2 review passes into 1 agent (quality+security, perf+test)
2. installForKiro() generates these combined agents alongside individual
   ones at .kiro/agents/reviewer-quality-security.json and
   .kiro/agents/reviewer-perf-test.json
3. transformCommandForKiro() detects 4+ consecutive reviewer delegations
   and rewrites as try-4-then-fallback-to-2 pattern

The fallback instructions tell Kiro to:
- Try delegating to 4 individual reviewer subagents (experimental)
- If spawning fails, run 2 combined reviewers sequentially

6 new tests (105 total in gen-adapters).
Copilot AI review requested due to automatic review settings March 2, 2026 13:01
@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f093e9d and 8a2d70e.

📒 Files selected for processing (2)
  • __tests__/gen-adapters.test.js
  • bin/cli.js

📝 Walkthrough

Walkthrough

Adds Kiro as a new first-class platform: state-dir detection (.kiro), CLI support (installForKiro, VALID_TOOLS), Kiro-specific adapter transforms, discovery mappings, generation/install scripts, extensive tests, and documentation updates to integrate .kiro/{steering,skills,agents}.

Changes

Cohort / File(s) Summary
Documentation & Metadata
AGENTS.md, CHANGELOG.md, CLAUDE.md, README.md, docs/CROSS_PLATFORM.md, docs/INSTALLATION.md
Add Kiro to platform lists, installer/tool references, and platform/state-dir documentation; update counts and examples to include .kiro/.
Platform Detection & State
lib/cross-platform/index.js, lib/platform/state-dir.js
Add KIRO to PLATFORMS, map '.kiro' in STATE_DIRS/INSTRUCTION_FILES, and update detection/getPlatformName to recognize .kiro.
Transform Utilities
lib/adapter-transforms.js
Add transformSkillForKiro, transformCommandForKiro, transformAgentForKiro, and generateCombinedReviewerAgent; implement PLUGIN_ROOT substitutions, frontmatter handling, namespace stripping, and Kiro JSON agent generation; export these functions.
Discovery & Mapping
lib/discovery/index.js
Add getKiroSteeringMappings(repoRoot) and export it; build steering mappings with description-precedence logic for Kiro.
CLI Implementation
bin/cli.js
Extend VALID_TOOLS with 'kiro'; add/export installForKiro(installDir, options); integrate Kiro into detectInstalledPlatforms, installPlugin flow, CLI help/messages, and main switch.
Installation & Generation Scripts
scripts/dev-install.js, scripts/gen-adapters.js
Add installKiro() wiring in dev-install; add adapters/kiro generation in gen-adapters, include .json/kiro orphan detection, and update cleanup/scan logic for .kiro artifacts.
Tests
__tests__/cli-args.test.js, __tests__/cross-platform.test.js, __tests__/gen-adapters.test.js, __tests__/state-dir.test.js
Add comprehensive Kiro unit/integration tests: installForKiro behavior, PLATFORMS/STATE_DIR detection and priority, transform tests (skills/commands/agents), steering mappings, and state-dir file-vs-dir handling.
Exports & API Surface
lib/adapter-transforms.js, bin/cli.js
Expose new Kiro transform functions and generateCombinedReviewerAgent; export installForKiro from CLI module.
Misc scripts/tests wiring
__tests__/*, scripts/*
Numerous test additions and dev/install scripts updated to handle Kiro artifacts and cleanup behavior.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant CLI as CLI (bin/cli.js)
  participant Disc as Discovery (lib/discovery)
  participant Trans as AdapterTransforms (lib/adapter-transforms.js)
  participant FS as Filesystem (.kiro/)

  User->>CLI: run install --tool kiro
  CLI->>Disc: getKiroSteeringMappings(repoRoot)
  Disc-->>CLI: steering mappings & command/skill/agent sources
  CLI->>Trans: transformCommandForKiro / transformSkillForKiro / transformAgentForKiro
  Trans-->>CLI: transformed MD/JSON artifacts
  CLI->>FS: write .kiro/steering, .kiro/skills, .kiro/agents
  FS-->>CLI: write ACKs
  CLI-->>User: installation complete (counts & paths)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • feat: add Kiro platform support (#276) #278 — Implements overlapping Kiro additions: CLI installForKiro, VALID_TOOLS changes, adapter transforms, cross-platform PLATFORMS/STATE_DIR updates, discovery mappings, and .kiro handling.

Poem

🐰 Kiro hops in, a clever spark,
.kiro/ files leave their mark.
Skills, steering, agents spun,
Mapped and transformed, now five become one.
Hop — install complete, carrots for the run!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add Kiro platform support (#276)' directly and concisely summarizes the primary change: adding Kiro as a new platform. It is specific, clear, and reflective of the main objective.
Linked Issues check ✅ Passed The PR comprehensively implements all coding objectives from issue #276: Kiro platform detection, CLI wiring, installForKiro(), transform functions, discovery mappings, cross-platform utilities, state-dir detection, tests, and documentation updates.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with issue #276 objectives. No extraneous or unrelated modifications were introduced; changes remain focused on Kiro platform integration across CLI, transforms, discovery, state detection, testing, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/add-kiro-support-276

Comment @coderabbitai help to get the list of available commands and usage tips.

Addresses Copilot review comment: custom frontmatter parser didn't
support YAML arrays. Now uses shared parseFrontmatter() which handles
arrays, quoted values, and proto pollution guards. Tools field now
correctly handles both inline string and YAML list syntax.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
scripts/dev-install.js (1)

476-551: Align installKiro() with full Kiro install surface (hooks/settings/MCP) for dev parity.

Current dev install only materializes skills/steering/agents. If hooks and MCP settings are part of supported Kiro behavior, local dev validation can drift from production installer behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/dev-install.js` around lines 476 - 551, installKiro currently only
writes skills, steering and agents; extend it to also materialize Kiro hooks,
settings and MCP artifacts so dev installs match production. Add creation of
hooksDir, settingsDir/file and mcpDir in the installKiro() setup (similar to
skillsDir/steeringDir/agentsDir), then for each plugin look for plugin-specific
hooks (e.g., SOURCE_DIR/plugins/<plugin>/hooks) and copy/transform them using
transforms.transformHookForKiro(pluginInstallPath,...), persist to the
.kiro/hooks directory; likewise locate global or plugin settings
(SOURCE_DIR/plugins/<plugin>/settings or a top-level settings file), run
transforms.transformSettingsForKiro(...) and write to .kiro/settings, and
materialize any MCP configs (SOURCE_DIR/plugins/<plugin>/mcp or SOURCE_DIR/mcp)
via transforms.transformMCPForKiro(...) into .kiro/mcp; reuse copyToAgentSys()
behavior and existing patterns (PLUGINS, SOURCE_DIR, AGENTSYS_DIR,
discovery.getKiroSteeringMappings, transforms.transform* functions) and
increment corresponding counters for logging.
__tests__/cli-args.test.js (1)

283-429: Add a guard test that Cursor install uses the Cursor transform function.

Given platform-specific transforms are easy to miswire, a spy assertion here would prevent silent regressions.

Proposed test addition
+  test('uses Cursor skill transform during install', () => {
+    const transforms = require('../lib/adapter-transforms');
+    const spy = jest.spyOn(transforms, 'transformSkillForCursor');
+    const installDir = setupInstallDir({}, {
+      'my-skill': '---\nname: my-skill\n---\nSkill body'
+    });
+
+    const discovery = require('../lib/discovery');
+    discovery.invalidateCache();
+    installForCursor(installDir);
+
+    expect(spy).toHaveBeenCalled();
+    spy.mockRestore();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@__tests__/cli-args.test.js` around lines 283 - 429, Add a new test that
verifies installForCursor invokes the Cursor transform exported by the plugin:
create an installDir via setupInstallDir that includes a test plugin file which
exports the transform function (or named export "transform"), replace or spy on
that transform (using Jest spyOn or a module mock), call
discovery.invalidateCache() and run installForCursor(installDir), then assert
the spy was called; reference the existing helpers installForCursor and
setupInstallDir and ensure the test resets/cleans the spy so it doesn't affect
other tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@__tests__/gen-adapters.test.js`:
- Around line 690-695: The test description ("defaults to read/write/shell when
no tools specified") disagrees with the assertion that parsed.tools equals
['read']; update the test to make intent unambiguous by either changing the
assertion to expect the full default set (e.g., ['read','write','shell']) or,
preferably, renaming the test description to match the existing assertion (e.g.,
"defaults to read when no tools specified"); locate the test that calls
transforms.transformAgentForKiro(...) and asserts parsed.tools and apply one of
these two fixes so the test name and the assertion are consistent.

In `@bin/cli.js`:
- Around line 1707-1713: The installer currently only creates .kiro/skills,
.kiro/steering, and .kiro/agents; add creation for .kiro/hooks and
.kiro/settings and update any reporting/console output that lists install
targets to include these new dirs. Specifically, in the same block where
skillsDir, steeringDir, and agentsDir are defined and mkdirSync'd (variables
named skillsDir, steeringDir, agentsDir and calls to fs.mkdirSync), add hooksDir
and settingsDir with path.join(cwd, '.kiro', 'hooks') and path.join(cwd,
'.kiro', 'settings') and call fs.mkdirSync for each; repeat the same additions
in the duplicate block referenced around the 1846-1850 region so both installer
code paths create and report hooks and settings.
- Around line 952-955: The Kiro detection currently only checks for specific
subdirs and misses a plain .kiro directory; update the logic around kiroDir and
the platforms.push('kiro') call to also treat the presence of the .kiro
directory itself as a match (i.e., use fs.existsSync(kiroDir) ||
fs.existsSync(path.join(kiroDir, 'steering')) || ...), so that if kiroDir exists
(fresh setup) you still push 'kiro' to platforms.
- Around line 1666-1668: installForCursor is calling the Kiro transformer
(transforms.transformSkillForKiro) which is the wrong platform; update the call
in installForCursor to use the Cursor-specific transformer (e.g.,
transforms.transformSkillForCursor) and pass the same pluginInstallPath option
(path.join(installDir, 'plugins', pluginName)); ensure the transforms module
exports the Cursor transformer and update any import/reference if needed.

In `@docs/INSTALLATION.md`:
- Around line 167-168: The platform table currently lists "Kiro" but omits
"Cursor"; update the table row entries to include a "Cursor" row matching the
format used for other platforms (e.g., add a line similar to the existing Kiro
row with "Cursor" and its repo/config directories), ensure the number of
platforms matches the five-platform messaging, and keep column formatting
consistent with the table (use "Cursor" and the appropriate path like `.cursor/`
mirroring the pattern used for `Kiro` and other entries).
- Line 53: The interactive installer section header claims five platforms but
the prompt snippet below still lists only three options; update the
prompt/options snippet (the prompt block under the "Interactive installer for
Claude Code, OpenCode, Codex CLI, Cursor, and Kiro:" heading) to include Cursor
and Kiro as separate selectable options and adjust any numbering or selection
text to reflect five platforms instead of three.

In `@lib/platform/state-dir.js`:
- Around line 86-95: Detection currently only checks the local .kiro directory
and can mis-detect Kiro sessions configured via the KIRO_HOME env var; update
the detection in the block that computes kiroPath (references: _cachedStateDirs,
cacheKey, isDirectory, kiroPath) to first check process.env.KIRO_HOME (resolve
it to an absolute path or join with basePath if necessary) and, if that
directory exists and is a Kiro state dir, set _cachedStateDirs.set(cacheKey,
'KIRO_HOME') (or the same '.kiro' token if you prefer consistency) and return
immediately; keep the existing filesystem .kiro fallback only after the env
check and preserve the try/catch behavior.

---

Nitpick comments:
In `@__tests__/cli-args.test.js`:
- Around line 283-429: Add a new test that verifies installForCursor invokes the
Cursor transform exported by the plugin: create an installDir via
setupInstallDir that includes a test plugin file which exports the transform
function (or named export "transform"), replace or spy on that transform (using
Jest spyOn or a module mock), call discovery.invalidateCache() and run
installForCursor(installDir), then assert the spy was called; reference the
existing helpers installForCursor and setupInstallDir and ensure the test
resets/cleans the spy so it doesn't affect other tests.

In `@scripts/dev-install.js`:
- Around line 476-551: installKiro currently only writes skills, steering and
agents; extend it to also materialize Kiro hooks, settings and MCP artifacts so
dev installs match production. Add creation of hooksDir, settingsDir/file and
mcpDir in the installKiro() setup (similar to skillsDir/steeringDir/agentsDir),
then for each plugin look for plugin-specific hooks (e.g.,
SOURCE_DIR/plugins/<plugin>/hooks) and copy/transform them using
transforms.transformHookForKiro(pluginInstallPath,...), persist to the
.kiro/hooks directory; likewise locate global or plugin settings
(SOURCE_DIR/plugins/<plugin>/settings or a top-level settings file), run
transforms.transformSettingsForKiro(...) and write to .kiro/settings, and
materialize any MCP configs (SOURCE_DIR/plugins/<plugin>/mcp or SOURCE_DIR/mcp)
via transforms.transformMCPForKiro(...) into .kiro/mcp; reuse copyToAgentSys()
behavior and existing patterns (PLUGINS, SOURCE_DIR, AGENTSYS_DIR,
discovery.getKiroSteeringMappings, transforms.transform* functions) and
increment corresponding counters for logging.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d1f022 and 27f3648.

📒 Files selected for processing (17)
  • AGENTS.md
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • __tests__/cli-args.test.js
  • __tests__/cross-platform.test.js
  • __tests__/gen-adapters.test.js
  • __tests__/state-dir.test.js
  • bin/cli.js
  • docs/CROSS_PLATFORM.md
  • docs/INSTALLATION.md
  • lib/adapter-transforms.js
  • lib/cross-platform/index.js
  • lib/discovery/index.js
  • lib/platform/state-dir.js
  • scripts/dev-install.js
  • scripts/gen-adapters.js

Comment on lines +952 to 955
// Kiro is project-scoped; detect if .kiro/ directory exists in CWD
const kiroDir = path.join(process.cwd(), '.kiro');
if (fs.existsSync(path.join(kiroDir, 'steering')) || fs.existsSync(path.join(kiroDir, 'skills')) || fs.existsSync(path.join(kiroDir, 'agents'))) platforms.push('kiro');
return platforms;
Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Kiro auto-detection is too strict for project-scoped detection.

Line 954 only detects Kiro when specific subdirectories already exist. A project with just .kiro/ (fresh setup) is missed.

Proposed fix
-  const kiroDir = path.join(process.cwd(), '.kiro');
-  if (fs.existsSync(path.join(kiroDir, 'steering')) || fs.existsSync(path.join(kiroDir, 'skills')) || fs.existsSync(path.join(kiroDir, 'agents'))) platforms.push('kiro');
+  const kiroDir = path.join(process.cwd(), '.kiro');
+  if (
+    fs.existsSync(kiroDir) ||
+    fs.existsSync(path.join(kiroDir, 'steering')) ||
+    fs.existsSync(path.join(kiroDir, 'skills')) ||
+    fs.existsSync(path.join(kiroDir, 'agents'))
+  ) {
+    platforms.push('kiro');
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/cli.js` around lines 952 - 955, The Kiro detection currently only checks
for specific subdirs and misses a plain .kiro directory; update the logic around
kiroDir and the platforms.push('kiro') call to also treat the presence of the
.kiro directory itself as a match (i.e., use fs.existsSync(kiroDir) ||
fs.existsSync(path.join(kiroDir, 'steering')) || ...), so that if kiroDir exists
(fresh setup) you still push 'kiro' to platforms.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional - Kiro detection checks for .kiro/ subdirectories (steering, skills, agents) because a bare .kiro/ dir could exist for other reasons. The detection mirrors Cursor's approach.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avifenesh, thank you for the clarification! You're right that the detection logic is consistent with Cursor's approach—both check for specific subdirectories rather than just the parent directory to avoid false positives. That makes sense for project-scoped platforms where the state directory might exist for other tooling reasons.

🐰


✏️ Learnings added
Learnt from: avifenesh
Repo: agent-sh/agentsys PR: 278
File: bin/cli.js:952-955
Timestamp: 2026-03-02T13:13:25.244Z
Learning: For project-scoped platforms (Cursor, Kiro), the detection logic in `detectInstalledPlatforms()` intentionally checks for specific subdirectories (e.g., `.cursor/rules`, `.cursor/commands`, `.cursor/skills` for Cursor; `.kiro/steering`, `.kiro/skills`, `.kiro/agents` for Kiro) rather than just checking for the parent directory (`.cursor/`, `.kiro/`). This avoids false positives when the parent directory exists for other reasons.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +1707 to +1713
// Create target directories (all project-scoped)
const skillsDir = path.join(cwd, '.kiro', 'skills');
const steeringDir = path.join(cwd, '.kiro', 'steering');
const agentsDir = path.join(cwd, '.kiro', 'agents');
fs.mkdirSync(skillsDir, { recursive: true });
fs.mkdirSync(steeringDir, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Kiro install flow appears incomplete for hooks/settings support.

The installer currently creates and reports only skills/steering/agents. If hooks/settings are part of supported Kiro output, this implementation is missing those install targets.

Proposed direction
   const skillsDir = path.join(cwd, '.kiro', 'skills');
   const steeringDir = path.join(cwd, '.kiro', 'steering');
   const agentsDir = path.join(cwd, '.kiro', 'agents');
+  const hooksDir = path.join(cwd, '.kiro', 'hooks');
+  const settingsDir = path.join(cwd, '.kiro', 'settings');
   fs.mkdirSync(skillsDir, { recursive: true });
   fs.mkdirSync(steeringDir, { recursive: true });
   fs.mkdirSync(agentsDir, { recursive: true });
+  fs.mkdirSync(hooksDir, { recursive: true });
+  fs.mkdirSync(settingsDir, { recursive: true });

+  // Add hook install + transformHookForKiro flow here
+  // Add MCP merge flow writing .kiro/settings/mcp.json here

Also applies to: 1846-1850

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/cli.js` around lines 1707 - 1713, The installer currently only creates
.kiro/skills, .kiro/steering, and .kiro/agents; add creation for .kiro/hooks and
.kiro/settings and update any reporting/console output that lists install
targets to include these new dirs. Specifically, in the same block where
skillsDir, steeringDir, and agentsDir are defined and mkdirSync'd (variables
named skillsDir, steeringDir, agentsDir and calls to fs.mkdirSync), add hooksDir
and settingsDir with path.join(cwd, '.kiro', 'hooks') and path.join(cwd,
'.kiro', 'settings') and call fs.mkdirSync for each; repeat the same additions
in the duplicate block referenced around the 1846-1850 region so both installer
code paths create and report hooks and settings.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged - Kiro hooks (.kiro.hook JSON) and settings support are tracked in agnix issue #595. This PR focuses on core platform support (skills, steering, agents).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avifenesh, understood — thanks for clarifying the scope boundaries. I see hooks and settings support for Kiro are being tracked separately in agnix #595, and this PR delivers the core platform integration (skills, steering, agents). That's a reasonable split given the complexity of getting Kiro support working end-to-end. Good to have the follow-up tracked.

## All Platforms (npm Global Install)

Interactive installer for Claude Code, OpenCode, Codex CLI, and Cursor:
Interactive installer for Claude Code, OpenCode, Codex CLI, Cursor, and Kiro:
Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Interactive installer example is now out of sync with the “five platforms” claim.

The prompt snippet below this line still shows only three options; please update it to include Cursor and Kiro.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/INSTALLATION.md` at line 53, The interactive installer section header
claims five platforms but the prompt snippet below still lists only three
options; update the prompt/options snippet (the prompt block under the
"Interactive installer for Claude Code, OpenCode, Codex CLI, Cursor, and Kiro:"
heading) to include Cursor and Kiro as separate selectable options and adjust
any numbering or selection text to reflect five platforms instead of three.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the docs commit - INSTALLATION.md now references five platforms including Kiro.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the current state of the interactive installer section in INSTALLATION.md
# around lines 50-70 to see if the prompt snippet has been updated

sed -n '50,70p' docs/INSTALLATION.md

Length of output: 336


@avifenesh, thanks for updating the header! However, the interactive prompt snippet just below still needs updating. It currently shows:

Which platforms do you want to install for?

  1) Claude Code
  2) OpenCode
  3) Codex CLI

Your selection: 1 2

This should be expanded to include options 4 and 5 for Cursor and Kiro:

Which platforms do you want to install for?

  1) Claude Code
  2) OpenCode
  3) Codex CLI
  4) Cursor
  5) Kiro

Your selection: 1 2

This way the example will match the five-platform claim in the section header.

Comment on lines +167 to 168
| Kiro | `.kiro/` (project-scoped) | `.kiro/` |

Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Platform table is missing Cursor.

This section now lists Kiro but still omits Cursor, which conflicts with the five-platform messaging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/INSTALLATION.md` around lines 167 - 168, The platform table currently
lists "Kiro" but omits "Cursor"; update the table row entries to include a
"Cursor" row matching the format used for other platforms (e.g., add a line
similar to the existing Kiro row with "Cursor" and its repo/config directories),
ensure the number of platforms matches the five-platform messaging, and keep
column formatting consistent with the table (use "Cursor" and the appropriate
path like `.cursor/` mirroring the pattern used for `Kiro` and other entries).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - will fix. Cursor was already a supported platform before this PR.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avifenesh, thank you for confirming! I appreciate the context that Cursor was already supported—the table will be complete once that row is added. 🐰

( •᷄ὢ•᷅)و ✨

Comment on lines +86 to +95
// Kiro detection
try {
const kiroPath = path.join(basePath, '.kiro');
if (isDirectory(kiroPath)) {
_cachedStateDirs.set(cacheKey, '.kiro');
return '.kiro';
}
} catch {
// Ignore errors, continue detection
}
Copy link

@coderabbitai coderabbitai bot Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add KIRO_HOME env detection before filesystem fallback.

Line 86 only checks project .kiro/. In Kiro sessions configured via KIRO_HOME without a local .kiro/, this can mis-detect as .claude.

Proposed fix
   // Codex detection
   if (process.env.CODEX_HOME) {
     _cachedStateDirs.set(cacheKey, '.codex');
     return '.codex';
   }

+  // Kiro detection via env var
+  if (process.env.KIRO_HOME) {
+    _cachedStateDirs.set(cacheKey, '.kiro');
+    return '.kiro';
+  }
+
   // Check for .codex directory in project
   try {
     const codexPath = path.join(basePath, '.codex');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/platform/state-dir.js` around lines 86 - 95, Detection currently only
checks the local .kiro directory and can mis-detect Kiro sessions configured via
the KIRO_HOME env var; update the detection in the block that computes kiroPath
(references: _cachedStateDirs, cacheKey, isDirectory, kiroPath) to first check
process.env.KIRO_HOME (resolve it to an absolute path or join with basePath if
necessary) and, if that directory exists and is a Kiro state dir, set
_cachedStateDirs.set(cacheKey, 'KIRO_HOME') (or the same '.kiro' token if you
prefer consistency) and return immediately; keep the existing filesystem .kiro
fallback only after the env check and preserve the try/catch behavior.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted - Kiro sessions may set KIRO_HOME. Adding env detection is tracked for a follow-up. The current filesystem check matches our pattern for Cursor (.cursor/) and works for project-scoped usage.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avifenesh, understood! Thanks for the context. The filesystem-only approach makes sense as a consistent pattern across project-scoped platforms (Cursor and Kiro), and deferring the KIRO_HOME env detection to a follow-up keeps this PR focused.

If you'd like, I can help create a follow-up issue to track the KIRO_HOME env detection enhancement, or if you've already opened one, feel free to reference it here for visibility.


✏️ Learnings added
Learnt from: avifenesh
Repo: agent-sh/agentsys PR: 278
File: lib/platform/state-dir.js:86-95
Timestamp: 2026-03-02T13:13:31.672Z
Learning: For Kiro platform detection in lib/platform/state-dir.js: the current implementation intentionally uses filesystem-only detection (checking for .kiro/ directory) to match the pattern used for Cursor (.cursor/), supporting project-scoped usage. KIRO_HOME env variable detection is tracked for a follow-up enhancement.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 17 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

lib/platform/state-dir.js:90

  • getStateDir() now detects .kiro, but the module header + detection-order comment above still describes only Claude/OpenCode/Codex and doesn’t mention the new Kiro step. Please update those comments so the documentation matches the actual detection behavior.
  // Kiro detection
  try {
    const kiroPath = path.join(basePath, '.kiro');
    if (isDirectory(kiroPath)) {
      _cachedStateDirs.set(cacheKey, '.kiro');

lib/adapter-transforms.js:547

  • The docstring for transformAgentForKiro() says it parses model/tools, but the implementation only emits {name, description, prompt, tools, resources} and ignores model. Either implement model mapping into the generated JSON (if supported/desired) or update the comment to match the actual output to avoid misleading future changes.
/**
 * Transform agent markdown+frontmatter to Kiro JSON format.
 *
 * Parses frontmatter for name/description/model/tools, uses body as prompt.
 * Returns a JSON string matching Kiro's agent schema.
 */

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +308 to 311
| Cursor | `.cursor/` |
| Kiro | `.kiro/` |

The plugin auto-detects the platform and uses the appropriate directory. Override with `AI_STATE_DIR` environment variable.
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section states Cursor state is stored in .cursor/ and that the platform is auto-detected. However, lib/platform/state-dir.js currently auto-detects .opencode, .codex, and now .kiro, but not .cursor—so Cursor state will still default to .claude/ unless AI_STATE_DIR is set explicitly. Please either update state-dir detection to include .cursor or adjust the documentation to reflect the actual behavior.

Suggested change
| Cursor | `.cursor/` |
| Kiro | `.kiro/` |
The plugin auto-detects the platform and uses the appropriate directory. Override with `AI_STATE_DIR` environment variable.
| Cursor | `.claude/` (default; set `AI_STATE_DIR` to change) |
| Kiro | `.kiro/` |
The plugin auto-detects supported platforms (Claude Code, OpenCode, Codex CLI, Kiro) and uses the appropriate directory. For Cursor, state defaults to `.claude/` unless you set the `AI_STATE_DIR` environment variable explicitly.

Copilot uses AI. Check for mistakes.
- Claude Code: `.claude/`
- OpenCode: `config/.opencode/`
- Codex: `.codex/`
- Cursor: `.cursor/`
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lists Cursor as using .cursor/ for the platform-aware state directory, but lib/platform/state-dir.js does not detect .cursor (only .opencode/.codex/.kiro/.claude). Unless Cursor state-dir detection is added elsewhere, this is misleading—either add .cursor detection or remove Cursor from this state-dir list.

Suggested change
- Cursor: `.cursor/`

Copilot uses AI. Check for mistakes.
Comment on lines +167 to 168
| Kiro | `.kiro/` (project-scoped) | `.kiro/` |

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This platform table adds Kiro but still omits Cursor, even though this page now states there are five supported platforms (including Cursor). Either add a Cursor row (with its project-scoped config/state locations) or adjust the surrounding text so the table and narrative stay consistent.

Suggested change
| Kiro | `.kiro/` (project-scoped) | `.kiro/` |
| Cursor | `.cursor/` (project-scoped) | `.cursor/` |
| Kiro | `.kiro/` (project-scoped) | `.kiro/` |

Copilot uses AI. Check for mistakes.
Comment on lines +548 to +570
function transformAgentForKiro(content, options) {
const { pluginInstallPath } = options || {};

const frontmatter = discovery.parseFrontmatter(content);
let body = content;
if (content.startsWith('---')) {
const endIdx = content.indexOf('\n---', 3);
if (endIdx !== -1) {
body = content.substring(endIdx + 4).replace(/^\n/, '');
}
}

if (pluginInstallPath) {
body = body.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, () => pluginInstallPath);
body = body.replace(/\$CLAUDE_PLUGIN_ROOT/g, () => pluginInstallPath);
body = body.replace(/\$\{PLUGIN_ROOT\}/g, () => pluginInstallPath);
body = body.replace(/\$PLUGIN_ROOT/g, () => pluginInstallPath);
}

body = body.replace(/(?:next-task|deslop|ship|sync-docs|audit-project|enhance|perf|repo-map|drift-detect|consult|debate|learn|web-ctl):([a-z][a-z0-9-]*)/g, '$1');

const agent = {
name: frontmatter.name || '',
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transformAgentForKiro() re-implements frontmatter parsing inline. This duplicates lib/discovery.parseFrontmatter() and is less capable (e.g., YAML arrays / multi-line values) which can silently drop fields like tools. Consider reusing discovery.parseFrontmatter() (or extracting a shared parser) so agent transforms stay consistent with command/agent discovery and keep the prototype-pollution guards in one place.

Copilot uses AI. Check for mistakes.
Comment on lines 100 to +104
- Claude Code: `.claude/`
- OpenCode: `config/.opencode/`
- Codex: `.codex/`
- Cursor: `.cursor/`
- Kiro: `.kiro/`
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lists Cursor as using .cursor/ for the platform-aware state directory, but lib/platform/state-dir.js does not detect .cursor (only .opencode/.codex/.kiro/.claude). Unless Cursor state-dir detection is added elsewhere, this is misleading—either add .cursor detection or remove Cursor from this state-dir list.

Copilot uses AI. Check for mistakes.
- Fix copy-paste bug: installForCursor used transformSkillForKiro
  instead of transformSkillForCursor (CodeRabbit #4)
- Fix stale test name: "defaults to read/write/shell" -> "defaults to
  read-only (least privilege)" to match actual assertion (CodeRabbit #2)
@avifenesh avifenesh merged commit b76067e into main Mar 2, 2026
28 checks passed
@avifenesh avifenesh deleted the feature/add-kiro-support-276 branch March 2, 2026 13:14
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.

Add Kiro support

2 participants