feat(kyberforge): add instructions-author skill for .apm/instructions files #154

Open
Claude wants to merge 5 commits from feat/148-instructions-author into main
pull from: feat/148-instructions-author
4 changed files with 250 additions and 42 deletions
Showing only changes of commit 529ed31cef - Show all commits

No files matched your search

@@ -0,0 +1,82 @@
---
topic: instructions-gotchas
source_keys:
- apm-cli-0-28-0-experiments
- apm-docs-site
- claude-code-memory-docs
- cursor-rules-docs
- github-copilot-custom-instructions-docs
---
Surprising behaviours and source contradictions for the instructions primitive. "Verified" means observed with the installed apm 0.28.0 in a throwaway directory outside the repo. Everything else is stated as sourced or inferred.
## Verified failure modes
### Unquoted glob silently widens scope
`applyTo: **/*.py` (unquoted) is a YAML alias error. Verified outcome:
- `apm compile` and `apm compile --validate` print "Failed to parse" and skip the file, exit 0; the validated-primitive count is one lower.
- `apm install` still deploys the file, to `.claude/rules/<name>.md` with no `paths:` frontmatter. A rule meant for Python files becomes an unconditional rule loaded in every session. Nothing errors.
- Any frontmatter that is broken YAML (for example `description: [broken`) behaves the same way.
- Claude Code itself behaves consistently: invalid frontmatter is ignored and the rule loads without `paths`.
Rule for the skill: always quote `applyTo`, and after scaffolding check that the deployed file has the expected `paths:`; a missing frontmatter block is the symptom.
### Validation never fails
Missing `description`, missing `applyTo` and an empty body are warnings only. `apm compile --validate` prints "All primitives validated successfully" and exits 0 even for those, and shows none of the warnings. Only a real `apm compile` prints them. `apm install` and `apm audit --ci` print nothing about instruction content. The official docs call `description` and `applyTo` required; the binary does not enforce either. Any enforcement has to live in this repo's own checks.
### Nested files: compile sees them, install does not
`.apm/instructions/sub/x.instructions.md` is folded into compiled root files but never deployed natively. A plain `x.md` (no `.instructions` infix) is ignored by both.
### Compile writes nothing when native rules exist (Claude, Copilot, Antigravity)
`apm compile --target claude` after an install exits 0, prints "produced no output files" and creates no `CLAUDE.md`. Use `--force-instructions` or compile in a project with no native rules. A test that only checks the exit code passes without testing anything.
### Compile duplicates content for the other targets
For cursor, windsurf, kiro, codex (and grok, opencode by source) compile still writes `AGENTS.md` even though native rules exist, so the same instruction reaches the agent twice.
### Install overwrites hand-authored rule files
For claude, cursor, windsurf, kiro and antigravity, an existing file at the deployed path is replaced without warning. Copilot skips it and asks for `--force`.
### Empty-source compile is not an error
Plain `apm compile` and `--target all` in a project with no instruction primitives print "no source primitives remain" and exit 0. The apm-workflow compile reference currently says this hard-fails with exit 1 and "No instruction files found in .apm/ directory"; that does not hold in 0.28.0 (see contradictions).
## Cursor-specific
- Install emits `globs` plus `description` and never `alwaysApply`. Per the Cursor docs a rule with only a `description` is "Apply Intelligently", so an unscoped apm instruction does not become always-on in Cursor (inferred from docs plus verified output; Cursor runtime not tested).
- Multiple globs are emitted as a YAML list (Kiro likewise). The Cursor docs show only a comma-separated string. Unverified whether Cursor honours the list form.
## Claude-specific
- `description` is dropped, so it can never appear in a `.claude/rules/` file; do not rely on it for Claude Code. Source: the apm source transform and verified deployed output. The apm docs do not state this.
- A rule with no `applyTo` becomes a file with no frontmatter and loads at every launch, which costs context. Claude Code guidance is to keep each file short (under 200 lines).
- The documented Claude `paths` budget is 1,000 brace-expanded patterns and 4 MiB.
## Contradictions between sources
| Point | Official apm docs | Installed 0.28.0 behaviour |
|---|---|---|
| `description` | Required | Warning only |
| `applyTo` | Listed as required and also as optional | Optional, warning only |
| Instruction with no `applyTo` | Folded into compiled root files instead of a per-file rule | Still deployed per-file on every rule-directory target (Claude: no frontmatter; Cursor: description only; Windsurf: `always_on`; Kiro: `always`) and also compiled |
| Grok deployed name | `.grok/rules/<name>.md` | `.grok/rules/<name>.instructions.md` |
| Compile with nothing to compile | apm-workflow compile reference: exit 1 with a "No instruction files found" message | Exit 0 |
| Compile scope | Docs say compile "only handles instructions" | Consistent for content, but compile also emits GEMINI.md and honours the agents_md mode |
| Cursor and Windsurf at user scope | Two fetches of the docs disagreed | Source excludes both at user scope; the source was preferred |
An earlier version of this topic's schema file described missing `description` and empty content as errors and `skip_instructions` as a config flag; both were wrong for 0.28.0 (warnings; internal variable).
## Unverified
- Whether Cursor accepts a YAML list for `globs`.
- Whether Copilot ignores unknown frontmatter keys such as `description`; its docs list only `applyTo` and `excludeAgent`.
- Runtime behaviour of Windsurf, Kiro and Antigravity on the emitted frontmatter; no downstream docs were fetched.
- Windsurf user-scope global rules.
- The Context7 step was unavailable (invalid API key), so the registry carries no fresh Context7 pull. Doc pages were summarised by a smaller model before reaching this file and can be lossy.
- Apm versions other than 0.28.0 were not tested.
@@ -3,64 +3,72 @@ topic: instructions-primitive-schema
source_keys:
- context7-microsoft-apm
- apm-github-repo
- apm-docs-site
- apm-cli-0-28-0-experiments
---
## File location, naming, and frontmatter
Scope of this file: what an instructions source file is, where it lives, what its frontmatter means, how `applyTo` is parsed, and what validation exists. Per-target output is in `instructions-target-mapping.md`; behaviours that surprised us and where sources disagree are in `instructions-gotchas.md`. Everything here was re-checked against apm 0.28.0 (the installed binary) in this revision.
`.apm/instructions/*.instructions.md`. Confirmed as the genuine required extension (not assumed) via APM's own discovery glob in `apm_cli/primitives/discovery.py`: `**/.apm/instructions/*.instructions.md` (and the `.github/instructions/` mirror, plus a bare `**/*.instructions.md` fallback).
## File location, naming, and discovery
Unlike prompts and hooks, instructions **do** have a small, concretely modeled dataclass — `apm_cli.primitives.models.Instruction` — because instructions feed APM's own compile pipeline (they get folded into root context files), not just pass-through deployment:
Source files live at `.apm/instructions/<name>.instructions.md`. The `.instructions.md` double extension is the real discovery key: the parser strips `.instructions.md` to get the primitive name, and a plain `.md` file in `.apm/instructions/` is ignored by both compile and install (verified by experiment).
```python
@dataclass
class Instruction:
name: str
file_path: Path
description: str
apply_to: str # from frontmatter key "applyTo"; empty means global/unconditional
content: str
author: str | None = None
version: str | None = None
source: str | None = None
```
Discovery is not identical in compile and install:
Frontmatter fields: `description` (required by convention — its absence is a validation error) and `applyTo` (a glob or comma-separated glob list, or a YAML sequence — APM normalizes all three input shapes into one canonical comma-separated form internally via `normalize_apply_to`/`parse_apply_to`). No `applyTo` means the rule is treated as **unconditional** — folded into root context files as always-on guidance rather than scoped to specific paths.
- `apm install` (the per-target deploy step) looks only in `.apm/instructions/` of the package, non-recursively. An instruction placed in a subdirectory such as `.apm/instructions/sub/x.instructions.md` is not deployed to any target (verified by experiment).
- `apm compile` (the root-context fold-in) discovers with a wider glob set: `.apm/instructions/`, a `.github/instructions/` mirror, and a bare `**/*.instructions.md` fallback. The same nested file that install ignores is picked up by compile (verified by experiment). An author who nests files therefore gets them in `CLAUDE.md`/`AGENTS.md` but not in `.claude/rules/` or any other native rules directory.
- Dependency packages are scanned the same way: `instructions/*.instructions.md` under the dependency's `.apm/` (and `.github/` as a fallback).
- Primitive name collisions across local and dependency sources are tracked as conflicts; local wins.
`Instruction.validate()` produces these built-in errors/warnings:
- Missing `description` → error: `"Missing 'description' in frontmatter"`.
- Missing `applyTo` → warning-level: `"No 'applyTo' pattern specified -- instruction will apply globally"` (not fatal — it's accepted, just broad).
- Empty body → error: `"Empty content"`.
The deployed filename derives from the source stem: `<stem>.instructions.md` becomes `<stem>.md`, `<stem>.mdc`, or stays `<stem>.instructions.md`, depending on target.
## Compile-time mapping: two entirely different mechanisms per target
## Frontmatter fields
This is the biggest divergence from the agent/skill/prompt primitives, and the one most likely to surprise: **Claude Code does not get a verbatim copy of the `.instructions.md` file at all.**
The parser reads exactly these keys from the frontmatter into the `Instruction` model: `description`, `applyTo`, plus optional `author` and `version`. Nothing else is modelled. There is no `name` field; the name always comes from the filename.
**Copilot CLI — verbatim, native primitive.** `PrimitiveMapping("instructions", ".instructions.md", "github_instructions")` on the `copilot` target has no `output_compare` flag, so `InstructionIntegrator` copies content through unchanged, preserving the original `applyTo:` frontmatter byte-for-byte (per the integrator's own docstring: "Copilot: `.github/instructions/` (verbatim, preserving applyTo:)"). This is deployed by `apm install`, not `apm compile`.
- `description`: one-line summary. The official authoring page lists it as required. In the binary it is only a warning when missing (see Validation). It is consumed by Cursor (kept in the `.mdc`, and auto-generated from the first body sentence when missing) and by Copilot (verbatim file). It is discarded for Claude Code, Windsurf, Kiro, Antigravity, and in all compiled root files.
- `applyTo`: a glob that scopes the rule. See the grammar below. The official authoring page labels it required for instructions, yet states elsewhere that omitting it is supported and yields an unconditional rule. The binary treats it as optional with a warning.
- `author`, `version`: parsed into the model but never emitted to any target.
At **Copilot user scope only** (`~/.copilot/`), individual files are not deployed — Copilot CLI at user scope reads a single `copilot-instructions.md`, so APM concatenates all instructions into that one file instead (`user_primitive_overrides: {"instructions": PrimitiveMapping("", ".md", "copilot_user_instructions")}`). Project-scope behavior (per-file, `.github/instructions/`) is unaffected.
Body is plain markdown. An empty body is a validation warning. The official guidance for body style is: bullets over prose, one topic per file (split `python-style` from `python-testing`), cite paths in backticks, no greetings or meta-commentary, and do not assume other context is loaded. No numeric size limit is documented by apm; the downstream tools give their own (Claude Code recommends under 200 lines per instruction file; Cursor recommends under 500 lines per rule; Copilot says repository-wide instructions should be no longer than two pages).
**Claude Code — real reconstruction into `.claude/rules/`, with field-dropping.** `PrimitiveMapping("rules", ".md", "claude_rules", output_compare=True)` marks this as one of APM's four "rule formats" (`RULE_FORMATS = {cursor_rules, claude_rules, windsurf_rules, kiro_steering}`) that transform their source rather than copy it. `InstructionIntegrator._convert_to_claude_rules()`:
## applyTo grammar
- Parses the source frontmatter and pulls only `applyTo` — **`description` is dropped entirely**, not carried into the output in any form.
- Converts `applyTo` into a `paths:` YAML list (one `parse_apply_to()`-split glob per line), e.g. `applyTo: "**/*.py"` → `paths:\n - "**/*.py"`.
- If there was no `applyTo` (unconditional instruction), the output has **no frontmatter at all** — just the raw body, matching Claude's convention that files without `paths:` in `.claude/rules/` apply unconditionally.
- Filename is renamed: `<x>.instructions.md` → `<x>.md` (the primitive's `extension` field, `.md`, replaces the source suffix — this is the general rule for every `output_compare=True` "rule format").
`applyTo` is normalised to one comma-separated string and then split by `parse_apply_to`:
This is architecturally the same category of lossy, real transformation the prior agent-primitive research found for Codex/Kiro agents — except here it's the default behavior for Claude specifically (not an opt-out edge case), and it applies even though Claude and Copilot are both first-class, actively-supported targets.
- A single glob: `"**/*.py"`.
- A comma-separated list in one string: `"**/*.css,**/*.scss"`. Whitespace around segments is trimmed and empty segments are dropped, so `"**/*.py, **/*.go"` is fine.
- A YAML sequence: every non-null entry is kept and joined into the same comma form; an entry that itself contains a top-level comma is escaped so it stays one pattern.
- Brace alternation `{a,b}` is never split: `"**/*.{css,scss},**/*.py"` yields two patterns.
- A literal top-level comma in a pattern is written `\,`; a literal backslash is `\\`.
- Always quote glob values in YAML. An unquoted value starting with `*` (for example `applyTo: **/*.py`) is a YAML alias token and fails to parse. What apm then does is the most dangerous failure mode in this primitive; see `instructions-gotchas.md`.
## Compile-time file placement
When `applyTo` is empty or absent the instruction is unconditional ("global"). Distributed compile places it in the root `AGENTS.md`/`CLAUDE.md`; native deploy produces an always-on rule in the target's own syntax.
| Target | Output path | Transform |
|---|---|---|
| Copilot CLI (project scope) | `.github/instructions/<name>.instructions.md` | Verbatim byte copy, `applyTo:` preserved as-is |
| Copilot CLI (user scope, `~/.copilot/`) | `~/.copilot/copilot-instructions.md` | Concatenated — all instructions merged into one file, because Copilot CLI at user scope reads only that single file |
| Claude Code | `.claude/rules/<name>.md` | Reconstructed: `applyTo` → `paths:` YAML list; `description` dropped; no frontmatter at all if unconditional |
Scoped patterns in distributed compile may match files under dot-directories apm knows about (`.agents`, `.apm`, `.claude`, `.codex`, `.cursor`, `.gemini`, `.github`, `.kiro`, `.opencode`, `.windsurf`); other hidden directories are excluded from matching.
Additionally, **`apm compile`** (distinct from `apm install`) can also fold instruction content directly into root context files — `AGENTS.md` (single-file or per-directory "distributed" mode) and the Claude-specific parallel format `CLAUDE.md`/per-directory `CLAUDE.md` — grouped by directory using `applyTo` pattern analysis (`context_optimizer.optimize_instruction_placement`). To avoid duplicating content between the native `.claude/rules/`+`.github/instructions/` deployment (from `apm install`) and this root-context fold-in (from `apm compile`), a `skip_instructions` config flag (and `compilation.placement.min_instructions_per_file` in `apm.yml`) actively suppresses the redundant copy in AGENTS.md/CLAUDE.md once native per-target files exist — `apm compile --target claude --force-instructions` overrides this dedup when an author explicitly wants both.
## Validation
## Validation constraints and gotchas
`Instruction.validate()` returns up to three findings:
- **The `description` field is real for Copilot but silently discarded for Claude.** An author who relies on `description` to explain *why* a rule exists (common practice, since Copilot's `.instructions.md` UI can surface it) gets that context deleted on every Claude compile — there's no config to keep it as a comment or otherwise.
- **No content-level validation for the `paths:` conversion** — if `applyTo` contains a pattern `parse_apply_to` can't split sensibly, the resulting `paths:` list is whatever falls out; no dedicated schema check catches a malformed glob before deploy.
- **Directory-distribution logic for AGENTS.md/CLAUDE.md is heuristic, not declarative** — `context_optimizer.optimize_instruction_placement` picks placement directories from `applyTo` patterns algorithmically; `compilation.placement.min_instructions_per_file` in `apm.yml` (default effectively 1) is the only tuning knob, and setting it above 1 causes under-populated directories to have their instructions bubbled up to the parent directory rather than dropped.
- **Same "no dedicated primitive validation function" gap noted for agents** — `Instruction.validate()` in `primitives/models.py` is the only validation, and it is invoked as part of the generic primitive-discovery/compile pipeline, not as a standalone `apm audit` check comparable to what exists for `apm.yml` itself.
- Missing `description`: "Missing 'description' in frontmatter".
- Missing `applyTo`: "No 'applyTo' pattern specified -- instruction will apply globally".
- Empty body: "Empty content".
All three are demoted to warnings by the compiler, so none of them fails any command. Verified by experiment: a file with no `description` and an empty body compiles with exit 0 and three warnings, and `apm install` deploys it (to `.claude/rules/` it produces a file holding only the `paths:` frontmatter). `apm compile --validate` calls the same code but discards warnings: it prints "All primitives validated successfully!" and exits 0 even for the bad file, so it is not a usable lint gate for instruction content. The warnings appear only on a real `apm compile` run, and `apm install` prints none of them.
Markdown links in the body are also checked at compile time; a broken relative link is a warning with the same non-fatal behaviour.
Files whose frontmatter does not parse as YAML are skipped by compile with a "Failed to parse" message (and `--validate` then counts one fewer primitive), but are still deployed by install. This asymmetry is covered in the gotchas file.
There is no standalone instructions validator and `apm audit` does not check instruction content; `apm audit --ci` checks lockfile consistency, deployed-file presence, content hash drift, and hidden Unicode only (verified by experiment on a clean install).
## Instructions versus AGENTS.md and CLAUDE.md
An instruction is an input primitive; `AGENTS.md`, `CLAUDE.md`, and `GEMINI.md` are outputs that `apm compile` generates from instructions (and, in this repo, hand-authored root files are a separate concern owned by the AGENTS.md skills). Generated root files carry a "Generated by APM CLI" header and a build id, and must not be hand-edited. Hand-authored files are never deleted by `apm compile --clean`.
Claude Code's own side of the story: it reads `.claude/rules/*.md` natively; `paths` is the only frontmatter field it reads and any other field is ignored without error; a rule without `paths` loads unconditionally at launch; if the frontmatter YAML does not parse, the frontmatter is ignored and the rule loads as if it had no `paths`. Claude Code reads `AGENTS.md` only when no `CLAUDE.md` exists on the path (unless configured otherwise), which is one reason apm emits `CLAUDE.md` for the claude target instead of relying on `AGENTS.md`.
## Package type
`apm.yml` `type: instructions` is a routing hint documented as "compiles to AGENTS.md only". It validates nothing about what is in `.apm/`; see the apm-workflow configure reference for the confirmed behaviour. An install with `targets:` set deploys instructions regardless of the declared type.
@@ -0,0 +1,83 @@
---
topic: instructions-target-mapping
source_keys:
- apm-cli-0-28-0-experiments
- apm-docs-site
- claude-code-memory-docs
- github-copilot-custom-instructions-docs
- cursor-rules-docs
---
What each target receives from an instruction file, at install time (native per-file deploy) and at compile time (folded into a root context file). Verified against apm 0.28.0 source and throwaway installs unless marked otherwise. Field syntax of the source file is in `instructions-primitive-schema.md`.
## Two separate output paths
`apm install` writes native files, one per instruction, into each target's own rules directory. `apm compile` writes root context files (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`) that concatenate instruction bodies. The two overlap, which is why compile has a dedup rule (below). A skill author should treat install as the primary path for Claude Code and Copilot, and compile as the path for targets that have no native instructions directory.
## Install-time mapping
| Target | Deployed path | Transform |
|---|---|---|
| copilot | `.github/instructions/<n>.instructions.md` | Verbatim copy, frontmatter untouched |
| copilot, user scope | `~/.copilot/copilot-instructions.md` | All bodies concatenated into one file, frontmatter stripped, provenance markers added |
| claude | `.claude/rules/<n>.md` | `applyTo` becomes a `paths:` list; `description` dropped; no frontmatter at all when there is no `applyTo` |
| cursor | `.cursor/rules/<n>.mdc` | `applyTo` becomes `globs:` (scalar for one pattern, list for several); `description` kept, auto-generated from the first body sentence when missing; no `alwaysApply` is written; not deployed at user scope |
| windsurf | `.windsurf/rules/<n>.md` | `trigger: glob` plus `globs:`, or `trigger: always_on` when unscoped; `description` dropped; not deployed at user scope |
| kiro | `.kiro/steering/<n>.md` | `inclusion: fileMatch` plus `fileMatchPattern`, or `inclusion: always` when unscoped; `description` dropped |
| antigravity | `.agents/rules/<n>.md` | `trigger: glob` plus `globs`, or no frontmatter when unscoped; not deployed at user scope |
| grok-build | `.grok/rules/<n>.instructions.md` | Verbatim copy; keeps the `.instructions.md` name |
| codex, gemini, opencode, agent-skills, openclaw, hermes, grok-cloud, copilot-cowork, copilot-app | none | No instructions mapping; these targets receive instructions only through compile |
Rename rule: the source suffix `.instructions.md` is replaced by the target's extension (`.md`, `.mdc`) except for Copilot and Grok, which keep the full suffix.
### Ownership and overwrite
The rule-directory targets (cursor, claude, windsurf, kiro, antigravity) are treated as APM-owned per file: install overwrites an existing hand-authored file with the same deployed name without a prompt (verified: a hand-written `.claude/rules/u.md` was replaced). Copilot behaves differently: an existing unmanaged file is skipped with the message "local files exist, not managed by APM" and needs `apm install --force` to overwrite. A name collision with a hand-authored rule in `.claude/rules/` is therefore silent data loss, so authors should not reuse stems of existing hand-written rules.
Removing or renaming a source instruction makes the next install delete the previously deployed file ("Cleaned N stale files"), and `apm audit --ci` passes after a clean install.
Install with explicit `targets:` in `apm.yml` creates the target directories (`.claude/`, `.github/`) if they do not exist.
## Per-target field survival
| Field | Claude | Copilot | Cursor | Windsurf | Kiro | Antigravity | Compiled root file |
|---|---|---|---|---|---|---|---|
| `applyTo` | as `paths` | kept verbatim | as `globs` | as `globs` | as `fileMatchPattern` | as `globs` | used for grouping only |
| `description` | dropped | kept (verbatim file) | kept | dropped | dropped | dropped | dropped |
| `author`, `version` | dropped | kept only because the file is verbatim | dropped | dropped | dropped | dropped | dropped |
Consequence for authors: a `description` is useful only for Copilot and Cursor. For Claude Code the first line or heading of the body is the only descriptive text that survives, so the body must be self-explanatory.
## Native format facts from the downstream tools
Claude Code: `.claude/rules/*.md` is found recursively. `paths` is the only field read; it accepts a YAML list or a comma-separated string. Other fields are ignored with no error. Rules without `paths` load unconditionally at launch; path-scoped rules load when matching files are read. Invalid frontmatter YAML is ignored and the rule loads without `paths`. Brace expansion in `paths` is capped at 1,000 patterns and 4 MiB.
Copilot: path-specific files live at `.github/instructions/**/NAME.instructions.md`. `applyTo` is required and is a quoted, comma-joined string. An optional `excludeAgent` takes `"code-review"` or `"cloud-agent"`. The docs do not mention a `description` key. Repository-wide instructions use the separate `.github/copilot-instructions.md`, which has no frontmatter. Path-specific files apply on GitHub.com only to the cloud agent and code review; IDE use differs.
Cursor: project rules must have the `.mdc` extension; a plain `.md` in `.cursor/rules` is ignored. Fields are `description`, `globs` (documented as a comma-separated string) and `alwaysApply` (boolean). A rule with only a `description` is "Apply Intelligently" (the agent decides), not always-on. The documented limit is 500 lines per rule.
Windsurf, Kiro, Antigravity: the apm source emits their trigger keys, but no downstream documentation was fetched for them, so runtime behaviour is unverified.
## Compile-time behaviour
Output file by target:
- `--target claude` writes `CLAUDE.md`.
- Gemini writes `GEMINI.md` (which imports `AGENTS.md`) and `AGENTS.md`.
- Every other target writes `AGENTS.md`.
Instructions are grouped by `applyTo`: a "Global Instructions" section for unscoped ones and one "Files matching `<pattern>`" section per distinct pattern. Descriptions are omitted. In distributed strategy, scoped instructions are placed in nested directory files near the matching files, subject to `placement.min_instructions_per_file` (default 1); `single-file` strategy puts everything in one root file.
### Dedup against native files
Compile skips instructions already deployed natively, but only for three targets: Claude (`.claude/rules/`), Copilot (`.github/instructions/`) and Antigravity (`.agents/rules/`). With populated native rules, `apm compile --target claude` prints a dedup message and "produced no output files" and exits 0 without writing `CLAUDE.md`. `--force-instructions` (alias `--no-dedup`) overrides it and writes the file. Cursor, Windsurf, Kiro, Grok, Codex and OpenCode have no dedup, so compile writes `AGENTS.md` that duplicates the native rules already loaded by the tool (verified for cursor, windsurf, kiro, codex).
Test implication: a compile-based test for the Claude target must run in a project with no populated `.claude/rules/`, or pass `--force-instructions`; otherwise it produces no file and silently asserts nothing.
### apm.yml compilation block
Keys: `target`, `strategy` (`distributed` or `single-file`), `single_file`, `output`, `chatmode`, `resolve_links`, `source_attribution`, `exclude`, `placement.min_instructions_per_file`, and `agents_md.mode` (`full` or `managed_section`; the latter writes only between markers and leaves the rest of the file alone).
### Relevant compile flags
`--validate` (parse only; see schema file for why it is a weak check), `--dry-run`, `--clean` (removes orphaned generated files, never hand-authored ones), `--target`, `--all`, `--root`, `-g`, `--local-only`, `--single-agents`, `--no-links`, `--with-constitution`, `--force-instructions`. Documented exit codes: 0 success, 1 error, 2 conflicting flags. A compile with no instruction primitives at all exits 0 in 0.28.0.
@@ -15,3 +15,38 @@
- **Status:** `extracted`
Note: `releasing.md`'s `--check-clean`/`--check-versions` scope, `apm pack` exit-code semantics, and the `.apm/`-vs-root-flat-dir mutual exclusivity referenced there were additionally cross-checked directly against `apm_cli/bundle/plugin_exporter.py`, `apm_cli/commands/pack.py`, and `apm_cli/marketplace/drift_check.py` in the installed `apm-cli` 0.28.0 package (`/root/.local/pipx/venvs/apm-cli/`), not just Context7 doc snippets — confirmed by a live `apm pack --format plugin` run inside `plugins/bin` that reproduced the documented `[!] Skipping root-level skills/ because .apm/ is present` warning.
## apm-docs-site
- **URL:** https://microsoft.github.io/apm/
- **Description:** Official apm documentation site, specifically the instructions-and-agents authoring page and the targets and compile pages: frontmatter requirements, unconditional-rule wording, per-target deploy paths, compile behaviour and flags. Fetched through subagent summaries, so lossy.
- **Contributing files:** instructions-primitive-schema.md, instructions-target-mapping.md, instructions-gotchas.md
- **Status:** `extracted`
## claude-code-memory-docs
- **URL:** https://code.claude.com/docs/en/memory
- **Description:** Claude Code memory documentation: `.claude/rules/` loading, the `paths` frontmatter field (only field read, invalid YAML ignored), AGENTS.md versus CLAUDE.md precedence, size guidance.
- **Contributing files:** instructions-primitive-schema.md, instructions-target-mapping.md, instructions-gotchas.md
- **Status:** `extracted`
## github-copilot-custom-instructions-docs
- **URL:** https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions
- **Description:** GitHub Copilot repository custom-instructions documentation: `.github/instructions/*.instructions.md`, the `applyTo` and `excludeAgent` frontmatter, the separate repo-wide `copilot-instructions.md`, where path-specific files apply.
- **Contributing files:** instructions-target-mapping.md, instructions-gotchas.md
- **Status:** `extracted`
## cursor-rules-docs
- **URL:** https://cursor.com/docs/context/rules
- **Description:** Cursor project rules documentation: `.mdc` requirement, `description`, `globs` and `alwaysApply` frontmatter, rule types (always, auto-attached, apply intelligently, manual), size guidance.
- **Contributing files:** instructions-target-mapping.md, instructions-gotchas.md
- **Status:** `extracted`
## apm-cli-0-28-0-experiments
- **URL:** https://pypi.org/project/apm-cli/0.28.0/
- **Description:** The installed apm-cli 0.28.0 package (source under the pipx venv for apm-cli) read for integrator, target-table and pattern-parsing code, plus throwaway install, compile and audit experiments run in a scratchpad outside the repo to confirm validation severity, unquoted-glob handling, discovery asymmetry, dedup, overwrite and exit-code behaviour.
- **Contributing files:** instructions-primitive-schema.md, instructions-target-mapping.md, instructions-gotchas.md
- **Status:** `extracted`