Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `apm install --target kiro` deploys Kiro IDE steering, skills, hooks,
and MCP config to the documented `.kiro/` layout. (by @TibRib; closes #702) (#1741)
- APM now catches accidental subpath embeds in git URLs (for example, `org/repo/skills/name.git`) and points at the supported `path:` key form. (#1740)
- SHA-pinned dependencies now stay current automatically: `apm update` resolves the newest annotated release tag, rewrites the pin, and `apm outdated` reports drift. (#1738)
- `apm install --target hermes` and `apm compile -t hermes` add the Hermes
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Think `package.json`, `requirements.txt`, or `Cargo.toml` — but for AI agent configuration.

GitHub Copilot · Claude Code · Cursor · OpenCode · Codex · Gemini · Windsurf
GitHub Copilot · Claude Code · Cursor · OpenCode · Codex · Gemini · Windsurf · Kiro

**[Documentation](https://microsoft.github.io/apm/)** · **[Quick Start](https://microsoft.github.io/apm/getting-started/quick-start/)** · **[CLI Reference](https://microsoft.github.io/apm/reference/cli-commands/)** · **[Roadmap](https://github.com/orgs/microsoft/projects/2304)**

Expand Down Expand Up @@ -67,7 +67,7 @@ One command, no configuration -- VS Code and GitHub Copilot read the file automa

One `apm.yml` describes every primitive your agents need — instructions, skills, prompts, agents, hooks, plugins, MCP servers — and `apm install` reproduces the exact same setup across every client on every machine. `apm.lock.yaml` pins the resolved tree the way `package-lock.json` does for npm.

- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)** — declared once, deployed across Copilot, Claude, Cursor, OpenCode, Codex, Gemini, Windsurf
- **[One manifest for everything](https://microsoft.github.io/apm/reference/primitive-types/)** — declared once, deployed across Copilot, Claude, Cursor, OpenCode, Codex, Gemini, Windsurf, Kiro
- **[Install from anywhere](https://microsoft.github.io/apm/guides/dependencies/)** — GitHub, GitLab, Bitbucket, Azure DevOps, GitHub Enterprise, Gitea, Gogs, any git host
- **[Transitive dependencies](https://microsoft.github.io/apm/guides/dependencies/)** — packages can depend on packages; APM resolves the full tree
- **[Author plugins](https://microsoft.github.io/apm/guides/plugins/)** — build Copilot, Claude, and Cursor plugins with dependency management, then export standard `plugin.json`
Expand Down Expand Up @@ -146,7 +146,7 @@ apm marketplace add github/awesome-copilot
apm install azure-cloud-development@awesome-copilot
```

Or add an MCP server (wired into Copilot, Claude, Cursor, Codex, OpenCode, Gemini, and Windsurf):
Or add an MCP server (wired into Copilot, Claude, Cursor, Codex, OpenCode, Gemini, Windsurf, and Kiro):

```bash
apm install --mcp io.github.github/github-mcp-server --transport http # connects over HTTPS
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/concepts/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ Source: `src/apm_cli/models/apm_package.py`,

The `targets:` field in `apm.yml` (or legacy `target:`). Names which harnesses the package
compiles for (`copilot`, `claude`, `cursor`, `codex`, `gemini`,
`opencode`, `windsurf`, or `all`). Drives which integrator runs and
`opencode`, `windsurf`, `kiro`, or `all`). Drives which integrator runs and
which directories receive output during `apm compile`.

NOT the harness itself. Target is the declaration; the harness is the
Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/concepts/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Scaffolds a new APM project in the current directory.

`apm init` writes an `apm.yml` manifest with sensible defaults for `name`, `author`, and `description`, plus empty dependency and script blocks. It records selected targets in `targets:`; author `.apm/` primitives yourself and run `apm install` or `apm compile` to create target output directories.

Targets are picked in priority order. An explicit `--target copilot,claude` flag wins. Otherwise an interactive checklist runs. Otherwise APM scans the working tree for signal directories (`.github/`, `.claude/`, `.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`) and pre-checks every harness it finds. With `-y` and no flag, all detected harnesses are written into `apm.yml`. See [primitives and targets](/apm/concepts/primitives-and-targets/) for what each target actually receives.
Targets are picked in priority order. An explicit `--target copilot,claude` flag wins. Otherwise an interactive checklist runs. Otherwise APM scans the working tree for signal directories (`.github/`, `.claude/`, `.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`, `.kiro/`) and pre-checks every harness it finds. With `-y` and no flag, all detected harnesses are written into `apm.yml`. See [primitives and targets](/apm/concepts/primitives-and-targets/) for what each target actually receives.

**Common surprises**

Expand Down Expand Up @@ -74,11 +74,11 @@ Order of operations is deterministic and worth memorizing:
apm compile [--target <list>]
```

Transforms the primitives in `.apm/` (and dependencies under `apm_modules/`) into harness-native files: `AGENTS.md` for Codex, `GEMINI.md` for Gemini, populated `.cursor/`, `.opencode/`, `.windsurf/` directories, and so on.
Transforms the primitives in `.apm/` (and dependencies under `apm_modules/`) into harness-native files: `AGENTS.md` for Codex, `GEMINI.md` for Gemini, populated `.cursor/`, `.opencode/`, `.windsurf/`, `.kiro/` directories, and so on.

Most users never call `apm compile` directly. `apm install` runs it as part of the integrate phase, and `apm run` auto-compiles any `.prompt.md` files referenced by a script just before execution. Reach for `apm compile` when you want to inspect what will be deployed without changing dependencies, when you are iterating on local primitives between installs, or when you only need output for one harness.

The `--target` flag accepts a comma-separated list (`copilot,claude,cursor,opencode,codex,gemini,windsurf,agent-skills`) or `all`. `--dry-run` prints placement decisions without writing files. `--validate` checks primitive frontmatter and structure without producing output. `--watch` re-runs compilation on every change.
The `--target` flag accepts a comma-separated list (`copilot,claude,cursor,opencode,codex,gemini,windsurf,kiro,agent-skills`) or `all`. `--dry-run` prints placement decisions without writing files. `--validate` checks primitive frontmatter and structure without producing output. `--watch` re-runs compilation on every change.

**Common surprises**

Expand Down
24 changes: 13 additions & 11 deletions docs/src/content/docs/concepts/primitives-and-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Each target is identified by a slug used in `apm.yml`'s `targets:` field and on
| `gemini` | `.gemini/` | gemini |
| `opencode` | `.opencode/` (project), `~/.config/opencode/` (user) | agents |
| `windsurf` | `.windsurf/` (project), `~/.codeium/windsurf/` (user) | agents |
| `kiro` | `.kiro/` (project and user) | agents |

Notes per target:

Expand All @@ -91,6 +92,7 @@ Notes per target:
- **gemini** -- Gemini CLI. Commands are TOML. Hooks merge into `.gemini/settings.json`. No native agents or instructions primitives -- both arrive via compiled context files.
- **opencode** -- OpenCode. No hooks support.
- **windsurf** -- Windsurf / Cascade. No native agents primitive -- Cascade auto-invokes any `SKILL.md` by its `description:` frontmatter, so personas ship as skills. Workflows are the harness's name for commands.
- **kiro** -- Kiro IDE. Instructions become steering files, skills stay as `SKILL.md` folders, hooks are individual JSON files, and MCP lands in `.kiro/settings/mcp.json`.

## The compatibility matrix

Expand All @@ -101,16 +103,16 @@ Rows are primitives, columns are harnesses. Cell legend:
- **unsupported** -- APM does not deliver this primitive to this harness.
- **gated** -- delivered behind an explicit declaration or trust flag.

| Primitive | Copilot | Claude | Cursor | Codex | Gemini | OpenCode | Windsurf |
|---|---|---|---|---|---|---|---|
| instructions | native | native | native | compiled | compiled | compiled | native |
| prompts | native | compiled | compiled | unsupported | compiled | compiled | compiled |
| agents | native | native | compiled | compiled | unsupported | native | unsupported |
| skills | native | native | native | native | native | native | native |
| hooks | native | native | native | native | native | unsupported | native |
| commands | unsupported | native | compiled | unsupported | compiled | compiled | compiled |
| plugins | compiled | compiled | compiled | compiled | compiled | compiled | compiled |
| MCP servers | native | native | native | native | native | native | native |
| Primitive | Copilot | Claude | Cursor | Codex | Gemini | OpenCode | Windsurf | Kiro |
|---|---|---|---|---|---|---|---|---|
| instructions | native | native | native | compiled | compiled | compiled | native | native |
| prompts | native | compiled | compiled | unsupported | compiled | compiled | compiled | unsupported |
| agents | native | native | compiled | compiled | unsupported | native | unsupported | unsupported |
| skills | native | native | native | native | native | native | native | native |
| hooks | native | native | native | native | native | unsupported | native | native |
| commands | unsupported | native | compiled | unsupported | compiled | compiled | compiled | unsupported |
| plugins | compiled | compiled | compiled | compiled | compiled | compiled | compiled | compiled |
| MCP servers | native | native | native | native | native | native | native | native |

How to read a cell:

Expand Down Expand Up @@ -158,7 +160,7 @@ Full pattern, the three pack-time gotchas, and verification steps: [Dev-only pri

1. Explicit `--target <slug>` flag, when passed.
2. The `targets:` field in `apm.yml`, when present.
3. Auto-detection: any harness whose root directory (`.github/`, `.claude/`, `.cursor/`, `.codex/`, `.gemini/`, `.opencode/`, `.windsurf/`) already exists in the workspace is selected.
3. Auto-detection: any harness whose root directory (`.github/`, `.claude/`, `.cursor/`, `.codex/`, `.gemini/`, `.opencode/`, `.windsurf/`, `.kiro/`) already exists in the workspace is selected.
4. Fallback: `minimal` -- APM writes `AGENTS.md` only and skips folder
integration. Create one of the harness folders above (or set
`targets:` explicitly) for full integration.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/concepts/what-is-apm.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ APM borrows the manifest-plus-lockfile shape from `npm`, `pip`, and `cargo` and

`apm.yml` is the manifest. It lists agentic dependencies (skills, prompts, agents, plugins, full APM packages) and MCP servers. `apm.lock.yaml` is the lockfile. It pins every resolved package to an exact source ref and content hash, so two developers running `apm install` against the same lockfile get byte-identical context. Source authoring lives in `.apm/` inside your repo.

The compiled output lives in the directories each harness already reads: `.github/` for Copilot, `.claude/` for Claude Code, `.cursor/` for Cursor, `.codex/` and `AGENTS.md` for Codex, `.gemini/` for Gemini, `.opencode/` for OpenCode, `.windsurf/` for Windsurf. APM does not invent a runtime format. It writes the files each tool already understands and stays out of the way at agent runtime.
The compiled output lives in the directories each harness already reads: `.github/` for Copilot, `.claude/` for Claude Code, `.cursor/` for Cursor, `.codex/` and `AGENTS.md` for Codex, `.gemini/` for Gemini, `.opencode/` for OpenCode, `.windsurf/` for Windsurf, and `.kiro/` for Kiro. APM does not invent a runtime format. It writes the files each tool already understands and stays out of the way at agent runtime.

## What APM manages

Expand Down
11 changes: 7 additions & 4 deletions docs/src/content/docs/consumer/install-mcp-servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ for the full required-vs-optional runtime config rule.
| Gemini CLI | `.gemini/settings.json` (project, only if `.gemini/` exists) or `~/.gemini/settings.json` (`-g`) | both | JSON `mcpServers` |
| OpenCode | `opencode.json` | project (only if `.opencode/` exists) | JSON `mcp` |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | global | JSON `mcpServers` |
| Kiro IDE | `.kiro/settings/mcp.json` (project, only if `.kiro/` exists) or `~/.kiro/settings/mcp.json` (`-g`) | both | JSON `mcpServers` |

## How `targets:` gates which configs get written

Expand Down Expand Up @@ -126,10 +127,12 @@ fails closed with the same `[x]` voice -- consistent with how
declare one in `apm.yml`. (#1335)

`apm install -g --mcp NAME` is a deliberate carve-out: it routes the
write to each runtime's user-scope MCP config (Copilot CLI to
`~/.copilot/mcp-config.json`, Codex CLI to `~/.codex/config.toml`,
Gemini CLI to `~/.gemini/settings.json`) and does not consult the
project-scope `targets:` whitelist -- user-scope writes are by
write to each runtime's user-scope MCP config (for example, Copilot CLI to
`~/.copilot/mcp-config.json`, Claude Code to `~/.claude.json`, Codex CLI to
`~/.codex/config.toml`, Gemini CLI to `~/.gemini/settings.json`, Windsurf to
`~/.codeium/windsurf/mcp_config.json`, Kiro to `~/.kiro/settings/mcp.json`,
and JetBrains Copilot to its OS-specific user config). It does not consult
the project-scope `targets:` whitelist -- user-scope writes are by
definition not project-bound. Workspace-only runtimes (VS Code,
Cursor, OpenCode) are skipped at user scope.

Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/consumer/install-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ The pipeline is deterministic. Each phase must pass before the next runs.
`--force`.
4. **Integrate.** Write primitives into each target harness's native
directory (`.github/`, `.claude/`, `.cursor/`, `.opencode/`,
`.codex/`, `.gemini/`, `.windsurf/`) and the cross-tool
`.codex/`, `.gemini/`, `.windsurf/`, `.kiro/`) and the cross-tool
`.agents/skills/` directory.
5. **Lockfile.** Write `apm.lock.yaml` with pinned versions, content
hashes, and the resolved dependency set.
Expand All @@ -105,7 +105,7 @@ them. Detection priority:
1. `--target <slug>` flag (highest).
2. The `targets:` field in `apm.yml`.
3. Auto-detect: any harness directory (`.github/`, `.claude/`,
`.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`)
`.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`, `.kiro/`)
that already exists in the workspace.
4. Fallback: minimal output to `AGENTS.md` only.

Expand All @@ -122,7 +122,7 @@ targets:
For the full reach map of which primitive lands where on each
harness, see [Primitives and targets](../../concepts/primitives-and-targets/).

Rule sync to Cursor (`.cursor/rules/`), Claude Code (`.claude/rules/`), and Windsurf (`.windsurf/rules/`) is automatic and idempotent -- re-running `apm install` adopts unchanged rules without rewriting them.
Rule sync to Cursor (`.cursor/rules/`), Claude Code (`.claude/rules/`), Windsurf (`.windsurf/rules/`), and Kiro (`.kiro/steering/`) is automatic and idempotent -- re-running `apm install` adopts unchanged rules without rewriting them.

## Transitive dependencies and the lockfile

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/consumer/run-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ scripts:

Each value is a literal shell command. The canonical pattern is shelling
out to a runtime CLI -- `copilot`, `claude`, `codex`, `cursor-agent`,
`gemini`, `opencode`, `windsurf`, or `llm` -- with a prompt file argument.
`gemini`, `opencode`, `windsurf`, `kiro`, or `llm` -- with a prompt file argument.
APM does not bundle these runtimes; you install them yourself and APM
invokes whichever the script names.

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/enterprise/policy-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ mcp:

compilation:
target:
allow: [] # copilot | claude | cursor | opencode | codex | gemini | vscode | windsurf | agent-skills | all
allow: [] # copilot | claude | cursor | opencode | codex | gemini | vscode | windsurf | kiro | agent-skills | all
enforce: null # Enforce specific target (must be present in list)
strategy:
enforce: null # distributed | single-file
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/enterprise/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ APM deploys files only to controlled subdirectories within the project root.
All deploy paths are validated before any file operation:

1. **No `..` segments.** Any path containing `..` is rejected outright.
2. **Allowed prefixes only.** Paths must start with an allowed target-integrator prefix (`.github/`, `.claude/`, `.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`, `.agents/`). In addition, the local-bundle install path stages instructions for compile-only targets under `apm_modules/<slug>/.apm/instructions/` with its own containment check (the resolved path must remain within `apm_modules/`) and `<slug>` validation rejecting traversal sequences and characters outside `[A-Za-z0-9._-]`.
2. **Allowed prefixes only.** Paths must start with an allowed target-integrator prefix (`.github/`, `.claude/`, `.cursor/`, `.opencode/`, `.codex/`, `.gemini/`, `.windsurf/`, `.kiro/`, `.agents/`). In addition, the local-bundle install path stages instructions for compile-only targets under `apm_modules/<slug>/.apm/instructions/` with its own containment check (the resolved path must remain within `apm_modules/`) and `<slug>` validation rejecting traversal sequences and characters outside `[A-Za-z0-9._-]`.
3. **Resolution containment.** The fully resolved path must remain within the project root directory.

A path must pass all three checks. Failure on any check prevents the file from being written.
Expand Down
10 changes: 5 additions & 5 deletions docs/src/content/docs/getting-started/first-package.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Otherwise, start here.

- APM installed -- see [Installation](./installation/).
- A GitHub account and an empty repo for publishing (step 5).
- A runtime where you can try the result: GitHub Copilot, Claude Code, or
Cursor.
- A runtime where you can try the result: GitHub Copilot, Claude Code, Kiro,
or Cursor.

## 1. Scaffold

Expand Down Expand Up @@ -209,10 +209,10 @@ team-skills/
`apm install` resolves which harness directories to populate using a strict
priority chain: `--target` flag > `apm.yml` `targets:` > auto-detect from
filesystem signals (`.claude/`, `CLAUDE.md`, `.cursor/`, `.github/copilot-instructions.md`,
`.codex/`, `.gemini/`, `GEMINI.md`, `.opencode/`, `.windsurf/`). The example layout
`.codex/`, `.gemini/`, `GEMINI.md`, `.opencode/`, `.windsurf/`, `.kiro/`). The example layout
above shows `.github/` because `.github/copilot-instructions.md` exists in the
project; if you also have `.claude/`, `.cursor/`, `.opencode/`, or `.gemini/`, those
directories get populated too. With no signal at all, `apm install` exits with
project; if you also have `.claude/`, `.cursor/`, `.opencode/`, `.gemini/`, or
`.kiro/`, those directories get populated too. With no signal at all, `apm install` exits with
code 2 and a teaching message instead of silently picking a target -- declare an
intent explicitly via `--target copilot` (or another harness), or by adding
`targets: [copilot]` to `apm.yml`. Run `apm targets` to inspect what APM detects
Expand Down
Loading
Loading