docs: source ADR-0029 claims and sync ADRs and hook docs with behaviour

- cite the VS Code prompt-file deprecation and the verbatim apm quote
- add ADR-0029 boundary-clause enforcement and Consequences
- mark superseded ADR-0019 passages; record neutral lock advice, source
  fork and reloadSkills, amend for the hook hardening
- move the ADR-0025 amendment out of the Decision list
- amend ADR-0022 for create keeping 0.1.0
- fix hooks.md merge and event claims, README guard caveat, gates.md Vale
  globs, and pin the research registry URL

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
This commit is contained in:
2026-09-29 08:00:39 +00:00
parent 4a4b598955
commit 641ebcac0e
12 changed files with 171 additions and 76 deletions

View File

@@ -9,9 +9,10 @@ Author hooks in `plugins/kyberforge/.apm/hooks/*.json`. `.apm/` is the only cont
`apm install` is the only supported install path (ADR-0024) — there is no generated mirror at the
plugin root and no per-plugin `plugin.json`, so `.apm/hooks/` is both where you edit and what ships.
apm merges every `*.json` in that directory into a single hook definition and writes the event
bindings into the consuming project's `.claude/settings.json`; see "Deployed shape" below. Scripts a
hook invokes live in the same directory, alongside the JSON that references them.
For Claude, apm merges the event bindings from every `*.json` in that directory into the consuming
project's `.claude/settings.json`; see "Deployed shape" below. That merge is Claude's rendering, not
a general rule: Copilot gets one file per source file (see "GitHub Copilot CLI and Codex"). Scripts
a hook invokes live in the same directory, alongside the JSON that references them.
## Hook file structure
@@ -32,14 +33,12 @@ The shape Claude Code reads, and therefore the shape to author under `.apm/hooks
}
```
Events (**partial list**): `PreToolUse`, `PostToolUse`, `Notification`, `Stop`, and `SessionStart`
(verified end-to-end by the hook below). Claude Code's plugin hook set is larger — `SessionEnd`,
`UserPromptSubmit`, `PreCompact` and `SubagentStop` also exist — and this repo's vendored corpus does
not enumerate it anywhere: `docs/research/docs/claude-code-plugins/configuration.md:100` describes
the file as "Event handlers (PreToolUse, PostToolUse, etc.)", and `agent-definition.md:53` covers
only the per-agent `hooks` field, not the plugin-level set. Treat the five names above as the ones
this repo has verified, not as the schema. Check Claude Code's own hooks documentation before wiring
an event not listed here.
Events: see `plugins/kyberforge/docs/research/docs/microsoft-apm/hooks-primitive-schema.md`,
section "Events: `_HOOK_EVENT_MAP`", for which names apm renames per target and which it passes
through unchanged. For Claude, author every event in PascalCase (`SessionStart`, `UserPromptSubmit`,
`PreCompact`, and so on). A camelCase name apm does not map, such as `userPromptSubmit`, draws only
a non-fatal warning and never fires; an all-lowercase one draws no warning at all and never fires
either.
## Referencing a script — use the `.apm/` path
@@ -85,7 +84,9 @@ mechanic. See ADR-0019, correction 2026-09-19, and the comment above `executable
`check-apm-current.sh` keeps an apm-consumed install level with its remote: it runs `apm outdated`,
and if anything is behind, runs `apm update --yes` and returns `reloadSkills: true` so the running
session picks up the redeployed content. Rationale, measurements, and the failure modes are in
session picks up the redeployed content. `reloadSkills` is a documented `SessionStart`
`hookSpecificOutput` field that makes Claude Code re-scan skill directories once the hooks finish
(code.claude.com/docs/en/hooks, checked 2026-09-29). Rationale, measurements, and the failure modes are in
ADR-0019.
**Claude Code only, and where it looks for the lockfile.** The hook exits 0 at once, silently and
@@ -101,12 +102,26 @@ host that sets no `CLAUDE_PROJECT_DIR` the lockfile guard passes in every apm co
fallback ran `apm update --yes` there (ADR-0019, correction 2026-09-28).
**The `timeout` in `hooks.json` must exceed the script's own budget.** The script spends at most
`timeout 60 apm outdated` plus `timeout 300 apm update`; the hook entry declares `timeout: 380`, the
sum plus a buffer. Set it lower and a slow remote gets the hook SIGKILLed mid-`apm update`, leaving a
`timeout -k 5 60 apm outdated` plus `timeout -k 5 300 apm update`, 370 s counting each 5 s SIGKILL
grace; the hook entry declares `timeout: 380`, the sum plus a buffer. Set it lower and a slow remote gets the hook SIGKILLed mid-`apm update`, leaving a
partially redeployed `.claude/skills/` and emitting no notice — precisely the silent failure the hook
exists to prevent. `tests/test-apm-current-hook.sh` pins the relationship (host timeout > sum of the
script's internal timeouts) rather than the literal, so raising either side alone fails the suite.
**The time limits are portable and hard to escape (ADR-0019, amendment 2026-09-29).** The script
uses `timeout`, or `gtimeout` where only Homebrew coreutils provides it (stock macOS). With neither,
it emits a notice and exits without running `apm`, instead of dying silently on exit 127. It exports
`GIT_TERMINAL_PROMPT=0`, so a remote that wants credentials fails at once instead of waiting out the
timeout on a prompt nobody can see. Where `flock` exists and `apm_modules/` does too, `apm update`
runs under a non-blocking lock on `apm_modules/.kyberforge-apm-update.lock`. A second session that
starts during a refresh skips its own and says so. Without `flock` the refresh runs unserialised.
**The lock advice is neutral when the default branch is unknown.** The notice tells you to discard
the rewritten `apm.lock.yaml` on a feature branch and to decide deliberately on the default branch.
It learns the default from `refs/remotes/origin/HEAD`, which `git remote add` never writes. When
that ref is unset, on a detached HEAD, or outside a git checkout, it says only "commit it or
discard it deliberately" rather than guessing `main` (ADR-0019, amendment 2026-09-19).
**Staleness is detected by matching apm's summary line, and both spellings count.** `apm outdated`
has no `--json` or otherwise machine-readable output (verified against apm 0.28.0), so the hook
greps its text. apm prints `1 outdated dependency found` in the singular when exactly one package is

View File

@@ -4,7 +4,7 @@ source_keys:
- apm-cli-installed-source
- apm-docs-llms-full
- apm-github-repo
- context7-microsoft-apm
- context7-microsoft-apm # partial: earlier pass only; the 2026-09-28 re-verification could not reach Context7 (see sources.md)
---
Ground truth for this file is the installed apm-cli **0.28.0** source (`apm_cli/integration/hook_integrator.py`, `hook_native_formats.py`, `hook_ir.py`, `hook_file_routing.py`, `_hook_dropped_targets.py`, `targets.py`, `security/executables.py`) plus a live `apm install` of a scratch package targeting `claude` and `copilot` (2026-09-28). Where the published docs (`llms-full.txt`) disagree with 0.28.0, the disagreement is called out; the published docs track upstream `main` and may describe a newer release.

View File

@@ -4,7 +4,7 @@ source_keys:
- apm-cli-installed-source
- apm-docs-llms-full
- apm-github-repo
- context7-microsoft-apm
- context7-microsoft-apm # partial: earlier pass only; the 2026-09-28 re-verification could not reach Context7 (see sources.md)
---
This file is checked against the installed apm-cli **0.28.0** source (`primitives/models.py`, `primitives/parser.py`, `primitives/discovery.py`, `utils/patterns.py`, `integration/instruction_integrator.py`, `integration/base_integrator.py`, `integration/targets.py`, `compilation/agents_compiler.py`, `commands/compile/cli.py`) and against a live `apm install` / `apm compile` of a scratch package (2026-09-28).

View File

@@ -4,7 +4,7 @@ source_keys:
- apm-cli-installed-source
- apm-docs-llms-full
- apm-github-repo
- context7-microsoft-apm
- context7-microsoft-apm # partial: earlier pass only; the 2026-09-28 re-verification could not reach Context7 (see sources.md)
---
Checked against the installed apm-cli **0.28.0** source (`integration/prompt_integrator.py`, `integration/command_integrator.py`, `integration/base_integrator.py`, `integration/targets.py`, `security/gate.py`) and a live `apm install` of a scratch package targeting `claude` and `copilot` (2026-09-28).

View File

@@ -16,7 +16,8 @@
## apm-cli-installed-source
- **URL:** file:///root/.local/pipx/venvs/apm-cli/lib/python3.11/site-packages/apm_cli/
- **URL:** https://github.com/microsoft/apm/tree/v0.28.0/src/apm_cli/
- **Local copy read:** the installed package at `~/.local/pipx/venvs/apm-cli/lib/python3.11/site-packages/apm_cli/` (pipx, apm-cli 0.28.0), which is what was actually read; the URL above is the matching upstream tag, for readers without that install.
- **Description:** Installed apm-cli 0.28.0 package source, which is the version this repo runs. Read as ground truth for the hooks, instructions and prompts docs, including `integration/hook_integrator.py`, `hook_native_formats.py`, `hook_ir.py`, `hook_file_routing.py`, `instruction_integrator.py`, `command_integrator.py`, `prompt_integrator.py`, `targets.py`, `primitives/`, `utils/patterns.py`, `compilation/agents_compiler.py`, `commands/compile/cli.py` and `security/executables.py`. Cross-checked by live `apm install` / `apm compile` runs of a throwaway package (claude and copilot targets) in a scratch dir on 2026-09-28.
- **Contributing files:** hooks-primitive-schema.md, instructions-primitive-schema.md, prompt-primitive-schema.md
- **Status:** `extracted`
@@ -28,6 +29,6 @@
- **Contributing files:** hooks-primitive-schema.md, instructions-primitive-schema.md, prompt-primitive-schema.md
- **Status:** `extracted`
Note (2026-09-28): during the verification pass for the hooks, instructions and prompts docs, the Context7 `/microsoft/apm` endpoint returned an invalid-API-key error. Those three files were re-verified against `apm-cli-installed-source` and `apm-docs-llms-full` only. Their `context7-microsoft-apm` key reflects the earlier pass.
Note (2026-09-28): during the verification pass for the hooks, instructions and prompts docs, the Context7 `/microsoft/apm` endpoint returned an invalid-API-key error. Those three files were re-verified against `apm-cli-installed-source` and `apm-docs-llms-full` only. Their `context7-microsoft-apm` key reflects the earlier pass, and each of the three carries a note saying so next to the key.
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.