Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 63 additions & 44 deletions cli/commands/init-kiro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,74 @@ export const initKiro = new Command()
.name('init-kiro')
.description('Install Kiro agents globally for AI-assisted project configuration')
.action(async () => {
const home = homedir();
const kiroDir = join(home, '.kiro');
try {
const home = homedir();
const kiroDir = join(home, '.kiro');

// Agents
await mkdir(join(kiroDir, 'agents'), { recursive: true });
await cp(
join(paths.kiro, 'agents/bepower-setup.json'),
join(kiroDir, 'agents/bepower-setup.json'),
);
await cp(
join(paths.kiro, 'agents/functional-analyst.json'),
join(kiroDir, 'agents/functional-analyst.json'),
);
// Agents
await mkdir(join(kiroDir, 'agents'), { recursive: true });
await cp(
join(paths.kiro, 'agents/bepower-setup.json'),
join(kiroDir, 'agents/bepower-setup.json'),
);
await cp(
join(paths.kiro, 'agents/functional-analyst.json'),
join(kiroDir, 'agents/functional-analyst.json'),
);
await cp(
join(paths.kiro, 'agents/upgrade-guardian.json'),
join(kiroDir, 'agents/upgrade-guardian.json'),
);
await cp(join(paths.kiro, 'agents/rev-eng.json'), join(kiroDir, 'agents/rev-eng.json'));

// Prompts
await mkdir(join(kiroDir, 'prompts'), { recursive: true });
await cp(
join(paths.kiro, 'prompts/bepower-setup.md'),
join(kiroDir, 'prompts/bepower-setup.md'),
);
await cp(
join(paths.kiro, 'prompts/functional-analyst.md'),
join(kiroDir, 'prompts/functional-analyst.md'),
);
// Prompts
await mkdir(join(kiroDir, 'prompts'), { recursive: true });
await cp(
join(paths.kiro, 'prompts/bepower-setup.md'),
join(kiroDir, 'prompts/bepower-setup.md'),
);
await cp(
join(paths.kiro, 'prompts/functional-analyst.md'),
join(kiroDir, 'prompts/functional-analyst.md'),
);
await cp(
join(paths.kiro, 'prompts/upgrade-guardian.md'),
join(kiroDir, 'prompts/upgrade-guardian.md'),
);
await cp(join(paths.kiro, 'prompts/rev-eng.md'), join(kiroDir, 'prompts/rev-eng.md'));

// Resources (functional-analyst templates)
await cp(join(paths.kiro, 'resources'), join(kiroDir, 'resources'), { recursive: true });
// Resources (functional-analyst templates)
await cp(join(paths.kiro, 'resources'), join(kiroDir, 'resources'), { recursive: true });

// Skills (bepower-dev workflow skills)
const skillsDest = join(kiroDir, 'skills/bepower-dev');
await cp(join(paths.kiro, 'skills'), skillsDest, { recursive: true });
// Skills (bepower-dev workflow skills)
const skillsDest = join(kiroDir, 'skills/bepower-dev');
await cp(join(paths.kiro, 'skills'), skillsDest, { recursive: true });

// Copy steering files as skill references (source of truth: kiro/steering/)
await cp(join(paths.kiro, 'steering'), join(skillsDest, 'steering-templates/references'), {
recursive: true,
});
// Copy steering files as skill references (source of truth: kiro/steering/)
await cp(join(paths.kiro, 'steering'), join(skillsDest, 'steering-templates/references'), {
recursive: true,
});

// Hooks (safety gate, barrel export, context injection, post-task summary)
await mkdir(join(kiroDir, 'hooks'), { recursive: true });
await cp(join(paths.kiro, 'hooks'), join(kiroDir, 'hooks'), { recursive: true });
// Hooks (safety gate, barrel export, context injection, post-task summary)
await mkdir(join(kiroDir, 'hooks'), { recursive: true });
await cp(join(paths.kiro, 'hooks'), join(kiroDir, 'hooks'), { recursive: true });

console.log('✓ Kiro agents installed globally');
console.log(`\n Agents:`);
console.log(` ${join(kiroDir, 'agents/bepower-setup.json')}`);
console.log(` ${join(kiroDir, 'agents/functional-analyst.json')}`);
console.log(` Prompts: ${join(kiroDir, 'prompts/')}`);
console.log(` Skills: ${skillsDest}/`);
console.log(` Hooks: ${join(kiroDir, 'hooks/')}`);
console.log('\nAvailable agents:');
console.log(' • bepower-setup — Generate .kiro/ config for a project');
console.log(' • functional-analyst — Interactive requirements gathering (Italian)');
console.log('✓ Kiro agents installed globally');
console.log(`\n Agents:`);
console.log(` ${join(kiroDir, 'agents/bepower-setup.json')}`);
console.log(` ${join(kiroDir, 'agents/functional-analyst.json')}`);
console.log(` Prompts: ${join(kiroDir, 'prompts/')}`);
console.log(` Skills: ${skillsDest}/`);
console.log(` Hooks: ${join(kiroDir, 'hooks/')}`);
console.log('\nAvailable agents:');
console.log(' • bepower-setup — Generate .kiro/ config for a project');
console.log(' • functional-analyst — Interactive requirements gathering (Italian)');
console.log(' • upgrade-guardian — Assess dependency/framework upgrade safety (read-only)');
console.log(' • rev-eng — Reverse-engineer a web app API via Playwright (read-only)');
} catch (error) {
console.error(
`✗ Failed to install Kiro agents: ${error instanceof Error ? error.message : String(error)}`,
);
process.exitCode = 1;
}
});
62 changes: 62 additions & 0 deletions kiro/agents/rev-eng.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "rev-eng",
"description": "Generic reverse-engineering agent — discovers a target web app's internal API via Playwright browser automation and documents it for a TypeScript client. Read-only: never commits, pushes, publishes, or mutates project source outside the docs API folder.",
"prompt": "file://../prompts/rev-eng.md",
"resources": [
"file://README.md",
"file://AGENTS.md",
"file://package.json",
"file://.env.example",
"file://.kiro/steering/**/*.md",
"file://docs/api/**/*.md"
],
"tools": [
"read",
"write",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"@playwright"
],
Comment on lines +13 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛑 Security Vulnerability: The "write" tool is declared in the "tools" array but not in "allowedTools", which creates a security bypass. An agent could potentially use the "shell" tool with commands like echo "content" > file.txt to write to files outside the allowed paths, circumventing the write restrictions.

Remove "write" from the "tools" array to enforce the read-only guarantee.1

Suggested change
"tools": [
"read",
"write",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"@playwright"
],
"tools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"@playwright"
],

Footnotes

  1. CWE-732: Incorrect Permission Assignment for Critical Resource - https://cwe.mitre.org/data/definitions/732.html ↩

"allowedTools": [
"read",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"@playwright"
],
"toolsSettings": {
"write": {
"allowedPaths": ["docs/api/**"]
},
Comment on lines +13 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛑 Security Vulnerability: The write tool appears in tools array but not in allowedTools, yet toolsSettings.write configures allowed write paths. This creates ambiguity - either the agent can write (and should have write in allowedTools) or it's read-only (and should remove write from tools and toolsSettings). The description claims "never mutates project source outside the docs API folder", so if write access to docs/api/** is intentional, add write to allowedTools. Otherwise, remove write capability entirely.1

Footnotes

  1. CWE-284: Improper Access Control - https://cwe.mitre.org/data/definitions/284.html ↩

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rebutting — same intentional "ask-before-write" pattern as functional-analyst.json. write in tools + omitted from allowedTools + toolsSettings.write.allowedPaths: ["docs/api/**"] means the agent CAN write, but only to docs/api/** and only with per-write approval. The description ("never mutates project source outside the docs API folder") is exactly this: writing the discovered API docs there is the intended, scoped output. Adding write to allowedTools would REMOVE the approval gate — the opposite of what we want. Keeping as-is (approval-gated, path-scoped).

"shell": {
"autoAllowReadonly": true,
"deniedCommands": [
".*git commit.*",
".*git push.*",
".*git tag .*",
".*npm publish.*",
".*rm -rf.*"
]
}
},
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest",
"--browser=chromium",
"--headless",
"--caps=core,network,storage",
"--console-level=info"
]
}
}
}
52 changes: 52 additions & 0 deletions kiro/agents/upgrade-guardian.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "upgrade-guardian",
"description": "Assesses the safety of a dependency/framework upgrade in an isolated worktree. Read-only: analyzes real breaking changes, project impact and verification, then returns a reasoned LOW/MEDIUM/HIGH risk verdict. Never commits, pushes, publishes, or opens PRs.",
"prompt": "file://../prompts/upgrade-guardian.md",
"resources": [
"file://README.md",
"file://AGENTS.md",
"file://package.json",
"file://.kiro/steering/**/*.md"
],
"tools": [
"read",
"write",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
Comment on lines +11 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛑 Security Vulnerability: The "write" tool is declared in the "tools" array but not in "allowedTools", creating the same security bypass as in rev-eng.json. An agent could use shell commands to write files outside the allowed paths, violating the read-only guarantees.

Remove "write" from the "tools" array.1

Suggested change
"tools": [
"read",
"write",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"tools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],

Footnotes

  1. CWE-732: Incorrect Permission Assignment for Critical Resource - https://cwe.mitre.org/data/definitions/732.html ↩

"allowedTools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"toolsSettings": {
"write": {
"allowedPaths": [".kiro/upgrade-reports/**", "docs/upgrades/**"]
},
Comment on lines +11 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛑 Security Vulnerability: The write tool is listed in the tools array but not in allowedTools, yet toolsSettings.write configures allowed write paths. This creates ambiguity about whether write access is permitted. For a read-only agent, remove the write tool from the tools array entirely and remove the toolsSettings.write configuration to prevent any write capability.1

Suggested change
"tools": [
"read",
"write",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"allowedTools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"toolsSettings": {
"write": {
"allowedPaths": [".kiro/upgrade-reports/**", "docs/upgrades/**"]
},
{
"tools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"allowedTools": [
"read",
"shell",
"grep",
"glob",
"web_search",
"web_fetch",
"introspect",
"thinking",
"code"
],
"toolsSettings": {
"shell": {
"autoAllowReadonly": true,
"deniedCommands": [
".*git commit.*",
".*git push.*",
".*git tag .*",
".*npm publish.*",
".*gh pr create.*",
".*gh pr merge.*",
".*npm (install|i|add).*(-S|-D|-O|-E|--save).*",
".*rm -rf.*"
]
}
}

Footnotes

  1. CWE-284: Improper Access Control - https://cwe.mitre.org/data/definitions/284.html ↩

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rebutting — this is the intentional BePower "ask-before-write" pattern, not an ambiguity. write in tools but omitted from allowedTools means the tool exists but every write needs explicit approval, and toolsSettings.write.allowedPaths narrows where it may write. It is the exact shape used by the existing kiro/agents/functional-analyst.json (write allowed only under docs/** + .kiro/steering/**) and documented in kiro/skills/agent-template/SKILL.md (rule 4: "allowedTools should include everything EXCEPT write; write needs approval").

The write capability is required and deliberate: upgrade-guardian writes its report only to .kiro/upgrade-reports/** / docs/upgrades/**, gated by approval. Removing write entirely would break the agent’s one legitimate output. Keeping as-is.

"shell": {
"autoAllowReadonly": true,
"deniedCommands": [
".*git commit.*",
".*git push.*",
".*git tag .*",
".*npm publish.*",
".*gh pr create.*",
".*gh pr merge.*",
".*npm (install|i|add).*(-S|-D|-O|-E|--save).*",
".*rm -rf.*"
]
}
}
}
49 changes: 49 additions & 0 deletions kiro/hooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Hooks — `runtime` tagging + `init-kiro` filtering

Hooks are tagged by the runtime they make sense in, instead of being split into
`ide/` vs `safety/` folders. Files stay flat; a front-matter field decides who
gets them.

## The `runtime` field

| Value | Meaning | Example |
|-------|---------|---------|
| `any` | Applies in every runtime — IDE and autonomous KiroCrew alike. | `safety-gate.md` |
| `ide` | Only meaningful with a human in an editor (fires on IDE file events; no-op headless). | `barrel-export.md` |

Deprecated hooks additionally carry:

```yaml
deprecated: true
superseded_by: "<what replaces it>"
```

They are **kept, not deleted**, pending a decision on whether to archive them:

| Hook | runtime | Status |
|------|---------|--------|
| `safety-gate.md` | `any` | KEEP |
| `barrel-export.md` | `ide` | KEEP (IDE-only) |
| `context-injection.md` | `ide` | DEPRECATED → superseded by Skills-Discovered-by-Search |
| `post-task-summary.md` | `any` | DEPRECATED → superseded by native end-of-task summary |

## How `init-kiro` should filter (proposed)

`init-kiro` copies `kiro/hooks/*` into `~/.kiro/hooks/`. Proposed behavior:

- **Default (IDE developer):** install all non-deprecated hooks (`runtime: any`
and `runtime: ide`). Deprecated hooks are skipped by default.
- **Headless / autonomous mode** (e.g. a future `--headless` / `--autonomous`
flag): install only `runtime: any` hooks; skip `runtime: ide` (they can never
fire without editor events) and skip `deprecated: true`.
- The installer reads the `runtime` and `deprecated` front-matter fields to decide.

## Agent distribution decision

- **All agents ship to everyone.** No conditional selection; consistent with how
`init-kiro` copies the whole `kiro/` payload. `upgrade-guardian` and the generic
`rev-eng` are distributed globally like `bepower-setup` and `functional-analyst`.
- **`rev-eng` stays global**, not scaffolded conditionally on "is this an
api-client project". It self-contextualizes at runtime; if the project has no
target to reverse-engineer, the agent simply has nothing to do — no conditional
install logic is needed.
6 changes: 6 additions & 0 deletions kiro/hooks/barrel-export.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ name: barrel-export
description: Auto-update barrel index.ts when a new source file is created in a package.
trigger: fileCreated
fileMatch: "**/packages/*/src/**/*.ts"
runtime: ide
---

# Barrel Export Sync

> `runtime: ide` — this is an editing convenience that fires on an IDE
> `fileCreated` event. It is meaningless in an autonomous/headless run (no editor
> events), so `init-kiro` should NOT install it for headless agents. See the
> `runtime` filtering note in `README.md`.

When a new `.ts` file is created under `packages/*/src/`:

1. Find the nearest `index.ts` barrel file in the same `src/` directory
Expand Down
23 changes: 16 additions & 7 deletions kiro/hooks/context-injection.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
---
name: context-injection
description: Load relevant steering docs when specific file types are edited.
description: "[DEPRECATED] Load relevant steering docs when specific file types are edited."
trigger: fileEdited
fileMatch: "**/*.{ts,tsx,json,yml,yaml,md}"
runtime: ide
deprecated: true
superseded_by: "KiroCrew 0.7 'Skills Discovered by Search' — on-demand skill_search / steering lookup replaces the cabled file-pattern → steering-doc map."
---

# Context Injection
# Context Injection — DEPRECATED

> **DEPRECATED (kept for review, not auto-removed).**
> This hook hardwires a `file pattern → steering doc` injection map. Under
> KiroCrew 0.7 "Skills Discovered by Search", the agent looks up the relevant
> steering/skill **on demand** (`skill_search`) instead of relying on a cabled
> table, which also drifts from reality over time. Recommendation: archive.
> `runtime: ide` because it was event-driven (IDE `fileEdited`) in the first place.

---

## Original behavior (for reference)

When a file is edited, load the relevant steering doc(s) to ensure consistency:

Expand All @@ -17,8 +31,3 @@ When a file is edited, load the relevant steering doc(s) to ensure consistency:
| `biome.json`, `lefthook.yml`, `tsdown.config.ts`, `tsconfig.json`, `cdk.json` | `build-tooling.md` |
| `CHANGELOG.md`, `.github/**` | `commit-conventions.md` |
| `.kiro/specs/**` | `spec-workflow.md` |

Rules:
- Only load steering docs that exist in `.kiro/steering/`. Skip silently if not found.
- Load **all** matching docs (a file can match multiple patterns).
- Prefer specificity: `src/handlers/*.ts` matches both `code-style.md` and `architecture.md`.
15 changes: 13 additions & 2 deletions kiro/hooks/post-task-summary.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
---
name: post-task-summary
description: Summarize changes and suggest a commit message when the agent finishes a task.
description: "[DEPRECATED] Summarize changes and suggest a commit message when the agent finishes a task."
trigger: agentStop
runtime: any
deprecated: true
superseded_by: "KiroCrew 0.7 native end-of-task summary — keeping this hook produces a duplicate summary."
---

# Post-Task Summary
# Post-Task Summary — DEPRECATED

> **DEPRECATED (kept for review, not auto-removed).**
> KiroCrew 0.7 emits a native end-of-task summary, so this hook is redundant and
> would produce a second, duplicate summary. Recommendation: archive.

---

## Original behavior (for reference)

When finishing a task, provide:

Expand Down
6 changes: 6 additions & 0 deletions kiro/hooks/safety-gate.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ name: safety-gate
description: Block dangerous shell commands before execution.
trigger: preToolUse
toolName: shell
runtime: any
---

# Safety Gate

> `runtime: any` — this guard applies in every runtime (IDE and autonomous
> KiroCrew alike). It is intentionally mirrored by the `deniedCommands` in each
> agent JSON (defense in depth): the hook catches it at the event layer, the
> agent config catches it at the tool layer.

Before executing any shell command, verify it does NOT:

1. **Commit or push**: `git commit`, `git push`, `git tag`
Expand Down
Loading
Loading