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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ logs
!/.agents/skills/magpie-*
.claude/skills/*
!/.claude/skills/magpie-*
.kiro/skills/*
!/.kiro/skills/magpie-*
.github/skills/*
!/.github/skills/magpie-*

Expand Down
1 change: 1 addition & 0 deletions .kiro/skills/magpie-audit-finding-fix
1 change: 1 addition & 0 deletions .kiro/skills/magpie-ci-runner-audit
1 change: 1 addition & 0 deletions .kiro/skills/magpie-committer-onboarding
1 change: 1 addition & 0 deletions .kiro/skills/magpie-contributor-activity-sweep
1 change: 1 addition & 0 deletions .kiro/skills/magpie-contributor-nomination
1 change: 1 addition & 0 deletions .kiro/skills/magpie-contributor-sentiment
1 change: 1 addition & 0 deletions .kiro/skills/magpie-contributor-to-committer
1 change: 1 addition & 0 deletions .kiro/skills/magpie-dependency-audit
1 change: 1 addition & 0 deletions .kiro/skills/magpie-flaky-test-triage
1 change: 1 addition & 0 deletions .kiro/skills/magpie-good-first-issue-author
1 change: 1 addition & 0 deletions .kiro/skills/magpie-good-first-issue-sweep
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-backlog-stats
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-deduplicate
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-fix-workflow
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-reassess
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-reassess-stats
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-reproducer
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-stale-sweep
1 change: 1 addition & 0 deletions .kiro/skills/magpie-issue-triage
1 change: 1 addition & 0 deletions .kiro/skills/magpie-license-compliance-audit
1 change: 1 addition & 0 deletions .kiro/skills/magpie-list-skills
1 change: 1 addition & 0 deletions .kiro/skills/magpie-mentoring-welcome
1 change: 1 addition & 0 deletions .kiro/skills/magpie-newcomer-issue-explainer
1 change: 1 addition & 0 deletions .kiro/skills/magpie-onboarding-concierge
1 change: 1 addition & 0 deletions .kiro/skills/magpie-optimize-skill
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pairing-multi-agent-review
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pairing-self-review
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-management-code-review
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-management-mentor
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-management-quick-merge
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-management-stats
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-management-triage
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pr-stale-sweep
1 change: 1 addition & 0 deletions .kiro/skills/magpie-pre-first-pr-check
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-announce-draft
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-archive-sweep
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-audit-report
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-keys-sync
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-prepare
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-promote
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-rc-cut
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-verify-rc
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-vote-draft
1 change: 1 addition & 0 deletions .kiro/skills/magpie-release-vote-tally
1 change: 1 addition & 0 deletions .kiro/skills/magpie-reviewer-routing
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-cve-allocate
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-deduplicate
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-fix
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-import
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-import-from-md
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-import-from-pr
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-import-from-scan
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-import-via-forwarder
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-invalidate
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-sync
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-issue-triage
1 change: 1 addition & 0 deletions .kiro/skills/magpie-security-tracker-stats-dashboard
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-isolated-setup-doctor
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-isolated-setup-install
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-isolated-setup-update
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-isolated-setup-verify
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-override-upstream
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-shared-config-sync
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-status
1 change: 1 addition & 0 deletions .kiro/skills/magpie-setup-upstream-fix
1 change: 1 addition & 0 deletions .kiro/skills/magpie-skill-reconciler
1 change: 1 addition & 0 deletions .kiro/skills/magpie-workflow-security-audit
1 change: 1 addition & 0 deletions .kiro/skills/magpie-write-skill
9 changes: 5 additions & 4 deletions docs/vendor-neutrality.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,24 +583,24 @@ Organization scope (declared, orthogonal to vendor): ASF = 14, agnostic = 55.

| Substrate tool | Substrate | Harness support | Verdict |
|---|---|---|---|
| `agent-guard` | action-guard | Claude Code, OpenCode | ✅ portable |
| `agent-guard` | action-guard | Claude Code, Kiro, OpenCode | ✅ portable |
| `agent-isolation` | sandbox | any | ✅ agnostic |
| `dashboard-generator` | analytics | any | ✅ agnostic |
| `dev` | framework-dev | any | ✅ agnostic |
| `egress-gateway` | sandbox | any | ✅ agnostic |
| `permission-audit` | sandbox | Claude Code, OpenCode | ✅ portable |
| `permission-audit` | sandbox | Claude Code, Kiro, OpenCode | ✅ portable |
| `pilot-report-validator` | framework-dev | any | ✅ agnostic |
| `pr-management-stats` | analytics | any | ✅ agnostic |
| `preflight-audit` | analytics | any | ✅ agnostic |
| `privacy-llm` | privacy | any | ✅ agnostic |
| `probe-templates` | sandbox | any | ✅ agnostic |
| `sandbox-lint` | sandbox | Claude Code, OpenCode | ✅ portable |
| `sandbox-lint` | sandbox | Claude Code, Kiro, OpenCode | ✅ portable |
| `security-tracker-stats-dashboard` | analytics | any | ✅ agnostic |
| `skill-and-tool-validator` | framework-dev | any | ✅ agnostic |
| `skill-evals` | framework-dev | any | ✅ agnostic |
| `skill-reconciler-diff` | framework-dev | any | ✅ agnostic |
| `spec-inventory` | framework-dev, analytics | any | ✅ agnostic |
| `spec-loop` | framework-dev | Claude Code, Codex, Cursor, Gemini CLI, OpenCode | ✅ portable |
| `spec-loop` | framework-dev | Claude Code, Codex, Cursor, Gemini CLI, Kiro, OpenCode | ✅ portable |
| `spec-status-index` | framework-dev, analytics | any | ✅ agnostic |
| `spec-validator` | framework-dev | any | ✅ agnostic |
| `symlink-lint` | framework-dev | any | ✅ agnostic |
Expand All @@ -612,6 +612,7 @@ Harness → substrate tools it supports:
- **Codex** (1): `spec-loop`
- **Cursor** (1): `spec-loop`
- **Gemini CLI** (1): `spec-loop`
- **Kiro** (4): `agent-guard`, `permission-audit`, `sandbox-lint`, `spec-loop`
- **OpenCode** (4): `agent-guard`, `permission-audit`, `sandbox-lint`, `spec-loop`
- **any harness** (18): `agent-isolation`, `dashboard-generator`, `dev`, `egress-gateway`, `pilot-report-validator`, `pr-management-stats`, `preflight-audit`, `privacy-llm`, `probe-templates`, `security-tracker-stats-dashboard`, `skill-and-tool-validator`, `skill-evals`, `skill-reconciler-diff`, `spec-inventory`, `spec-status-index`, `spec-validator`, `symlink-lint`, `vendor-neutrality-score`

Expand Down
1 change: 1 addition & 0 deletions skills/setup/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ go"*, never as *"what files contain"*.
| `github` | `.github/skills/` | native (relay) | GitHub's skill loader |
| `windsurf` | `.windsurf/skills/` | native (relay) | Windsurf |
| `goose` | `.goose/skills/` | native (relay) | Goose |
| `kiro` | `.kiro/skills/` | native (relay) | Kiro CLI |

The table is **extensible**: a new agent that wants framework
skills is one new row (`id`, project dir, kind), nothing else —
Expand Down
46 changes: 45 additions & 1 deletion tools/agent-guard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [Per-command overrides](#per-command-overrides)
- [Wiring](#wiring)
- [OpenCode](#opencode)
- [Kiro CLI](#kiro-cli)
- [Harness-neutral path (any runtime)](#harness-neutral-path-any-runtime)
- [Contributing guards](#contributing-guards)
- [Tests](#tests)
Expand All @@ -24,7 +25,7 @@

**Capability:** substrate:action-guard

**Harness:** Claude Code, OpenCode
**Harness:** Claude Code, OpenCode, Kiro

A deterministic pre-execution guard dispatcher. It inspects every shell command
**before it runs** and **denies** the ones that would break a hard framework
Expand All @@ -40,6 +41,9 @@ so every wired harness enforces an identical rule set from one source of truth:
- **OpenCode** — a [plugin](https://opencode.ai/docs/plugins/) on the
`tool.execute.before` hook for the `bash` tool, which blocks a call by
throwing (`agent-guard.py --opencode`). See [Wiring](#wiring).
- **Kiro CLI** — a [`preToolUse`](https://kiro.dev/docs/cli/hooks) hook on the
`execute_bash` matcher, which blocks a call when the hook exits `2`
(`agent-guard.py --kiro`, reason on stderr). See [Wiring](#wiring).
- **Any other runtime** — the `--check` and `--exec` CLI modes let any
harness or shell wrapper enforce guard rules without a harness-specific hook
adapter. See [Harness-neutral path (any runtime)](#harness-neutral-path-any-runtime).
Expand Down Expand Up @@ -145,6 +149,46 @@ to point elsewhere. Because both harnesses call `dispatch()`, the bundled and
skill-contributed guards, the `MAGPIE_*` overrides, and the deny reasons are
byte-for-byte identical across the two; nothing about a guard is harness-aware.

### Kiro CLI

The same engine backs [Kiro CLI](https://kiro.dev/docs/cli/hooks) via its
`preToolUse` hook. Kiro pipes the hook event
(`{"tool_name": "execute_bash", "tool_input": {"command": …}, "cwd": …}`) to
the hook command on stdin and **blocks** the tool call when that command exits
`2`, returning its stderr to the model — so `agent-guard.py --kiro` matches the
shell tool, runs the shared core, and on a deny writes the reason to stderr and
exits `2`, the Kiro equivalent of a Claude `PreToolUse` deny.

Register it in the agent configuration's `hooks` field
([reference](https://kiro.dev/docs/cli/custom-agents/configuration-reference#hooks-field)):

```json
{
"hooks": {
"preToolUse": [
{
"matcher": "execute_bash",
"command": "python3 \"${MAGPIE_AGENT_GUARD:-.claude/hooks/agent-guard.py}\" --kiro"
}
]
}
}
```

The engine is one shared, harness-agnostic file (`--kiro` only selects the I/O
adapter). On a repo already wired for Claude Code it lives at
`.claude/hooks/agent-guard.py`, so the hook reuses it; a **Kiro-only** adopter
(no `.claude/`) points `MAGPIE_AGENT_GUARD` at wherever the engine is installed.
Note: `/magpie-setup` currently installs the engine only on the Claude path — a
general installer that drops it for non-Claude-only adopters is a pending
follow-up (see [`docs/adapters/add-a-harness.md`](../../docs/adapters/add-a-harness.md)).

Because every harness calls `dispatch()`, the bundled and skill-contributed
guards, the `MAGPIE_*` overrides, and the deny reasons are identical to the
Claude Code and OpenCode paths — verified end-to-end: with this hook wired,
Kiro refuses a `Co-Authored-By` commit (quoting the `commit-trailer` reason and
leaving the commit uncreated) while a clean commit proceeds.

### Harness-neutral path (any runtime)

For runtimes that do not expose a pre-tool hook API (Codex CLI, Gemini CLI,
Expand Down
36 changes: 36 additions & 0 deletions tools/agent-guard/src/agent_guard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,39 @@ def opencode_main() -> int:
return ALLOW_EXIT


def kiro_main() -> int:
"""Harness-neutral entry point for Kiro CLI's ``preToolUse`` hook.

Reads Kiro's hook event on stdin — ``{"tool_name": "...", "tool_input":
{"command": "..."}, "cwd": "..."}`` — matches the shell tool
(``execute_bash`` / its ``shell`` alias / ``execute_cmd``), and runs the
**same** :func:`dispatch` core as every other harness. On a deny it writes
the reason to **stderr** (which Kiro returns to the model) and exits
``DENY_EXIT`` (2 = block for ``PreToolUse``); on allow, a non-shell tool, or
any malformed input it exits ``ALLOW_EXIT`` — fail-open, exactly like the
Claude and OpenCode paths. Only this thin I/O shell differs; the guard
decisions are identical across harnesses.
"""
try:
event = json.load(sys.stdin)
except (json.JSONDecodeError, ValueError):
return ALLOW_EXIT
if not isinstance(event, dict):
return ALLOW_EXIT
if event.get("tool_name") not in ("execute_bash", "shell", "execute_cmd"):
return ALLOW_EXIT
tool_input = event.get("tool_input")
if not isinstance(tool_input, dict):
return ALLOW_EXIT
command = str(tool_input.get("command", ""))
cwd = event.get("cwd")
reason = dispatch(command, cwd if isinstance(cwd, str) else None)
if reason:
sys.stderr.write(reason + "\n")
return DENY_EXIT
return ALLOW_EXIT


def check_main(argv: list[str]) -> int:
"""Harness-neutral check-only entry point (``--check``).

Expand Down Expand Up @@ -698,6 +731,7 @@ def cli(argv: list[str] | None = None) -> int:

No argument → the Claude Code ``PreToolUse`` hook (:func:`main`).
``--opencode`` → the OpenCode adapter (:func:`opencode_main`).
``--kiro`` → the Kiro CLI adapter (:func:`kiro_main`).
``--check <cmd…>`` → harness-neutral check-only (:func:`check_main`).
``--exec <cmd…>`` → harness-neutral check-then-exec (:func:`exec_main`).

Expand All @@ -708,6 +742,8 @@ def cli(argv: list[str] | None = None) -> int:
args = sys.argv[1:] if argv is None else argv
if args and args[0] == "--opencode":
return opencode_main()
if args and args[0] == "--kiro":
return kiro_main()
if args and args[0] == "--check":
return check_main(args[1:])
if args and args[0] == "--exec":
Expand Down
Loading