diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json deleted file mode 100644 index 8100ea5..0000000 --- a/.agents/plugins/marketplace.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "name": "holocron", - "interface": { - "displayName": "holocron" - }, - "plugins": [ - { - "name": "kyberforge", - "source": { - "source": "local", - "path": "./plugins/kyberforge" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Developer Tools" - }, - { - "name": "bin", - "source": { - "source": "local", - "path": "./plugins/bin" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Utilities" - }, - { - "name": "git", - "source": { - "source": "local", - "path": "./plugins/git" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Version Control" - }, - { - "name": "gitea", - "source": { - "source": "local", - "path": "./plugins/gitea" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Version Control" - }, - { - "name": "core", - "source": { - "source": "local", - "path": "./plugins/core" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Productivity" - }, - { - "name": "mattpocock-skills", - "source": { - "source": "url", - "url": "mattpocock/skills", - "ref": "v1.2.3", - "sha": "835450ef244ab7335f75d95b83e7d979eae22a6d", - "tag_pattern": "v{version}" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Productivity" - }, - { - "name": "lint", - "source": { - "source": "local", - "path": "./plugins/lint" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "Developer Tools" - } - ] -} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 38f696d..c8211b6 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -43,19 +43,6 @@ "category": "Productivity", "source": "./plugins/core" }, - { - "name": "mattpocock-skills", - "description": "Skills for Real Engineers — planning, TDD, architecture, and debugging workflows from Matt Pocock's .claude directory.", - "version": "1.2.3", - "category": "Productivity", - "source": { - "source": "github", - "repo": "mattpocock/skills", - "ref": "v1.2.3", - "sha": "835450ef244ab7335f75d95b83e7d979eae22a6d", - "tag_pattern": "v{version}" - } - }, { "name": "lint", "description": "Skills and agents for configuring and running linters.", diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index 38f696d..c8211b6 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -43,19 +43,6 @@ "category": "Productivity", "source": "./plugins/core" }, - { - "name": "mattpocock-skills", - "description": "Skills for Real Engineers — planning, TDD, architecture, and debugging workflows from Matt Pocock's .claude directory.", - "version": "1.2.3", - "category": "Productivity", - "source": { - "source": "github", - "repo": "mattpocock/skills", - "ref": "v1.2.3", - "sha": "835450ef244ab7335f75d95b83e7d979eae22a6d", - "tag_pattern": "v{version}" - } - }, { "name": "lint", "description": "Skills and agents for configuring and running linters.", diff --git a/AGENTS.md b/AGENTS.md index 9d705f3..92bde94 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,7 +36,7 @@ Fall back to raw shell only when no skill covers it. - **Do not add repo-owned keys to `.claude/settings.json`.** apm treats it as its own deployed artifact and `apm audit --ci` replays the install and diffs, so anything apm would not have written is permanent drift that fails the `apm-audit-ci` pre-push hook. A hook you want here is authored in `plugins//.apm/hooks/` and deployed by apm, never hand-written into that file. The `SessionStart` entry already in it is exactly that: kyberforge authors it in `plugins/kyberforge/.apm/hooks/hooks.json` and apm merges it in, so it is apm's own output, it is what the replay expects, and it belongs in the commit — do not strip it (ADR-0019). Machine-specific settings go in the gitignored `.claude/settings.local.json`; shared enforcement goes in `.pre-commit-config.yaml`. - **`apm.lock.yaml` turning up modified is expected, not a bug.** kyberforge's `SessionStart` hook runs `apm outdated` at startup and `apm update --yes` when something is behind, which rewrites the lock. Commit or discard it deliberately. - **A `.apm/` edit is not live in this session until it is pushed.** The six dependencies resolve from the holocron remote, unpinned against the default branch. `apm install` deploys from the lock; `apm update` is what re-resolves refs. -- **Pushing without a network** needs `SKIP=apm-marketplace-check,apm-pack-check-clean git push` — those two resolve a remote marketplace entry via `git ls-remote`. Skip only those two; the rest are real local checks, and adding one to `SKIP` disarms it silently. +- **No pre-push hook needs the network.** Root `apm.yml`'s marketplace has no remote package entries, so every hook resolves locally. - **This repo and Gitea are the only source of truth.** All project state, decisions, and working conventions live here. Do not use an external memory system for this project — cached state diverges from the repo and you get a split brain. Before answering any design or architecture question, check `docs/adr/` for an existing decision. ## Key documents diff --git a/README.md b/README.md index 92054f4..2fa10fe 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,7 @@ Every other pre-push hook does run. See [`docs/spec/gates.md`](docs/spec/gates.md) for what each hook enforces and why. -**Offline?** Exactly two pre-push hooks need the network, because root `apm.yml`'s marketplace contains one remote package entry that must be resolved with `git ls-remote`: - -```bash -SKIP=apm-marketplace-check,apm-pack-check-clean git push -``` - -Skip **only** those two. The remaining pre-push hooks are real local checks and pass offline; adding one of them to `SKIP` disarms it silently. +**Offline?** No pre-push hook needs the network: root `apm.yml`'s marketplace has no remote package entries (the last one, `mattpocock-skills`, was removed), so `apm-marketplace-check` and `apm-pack-check-clean` resolve everything from local sources. All pre-push hooks pass offline. ## Editing plugin content diff --git a/apm.yml b/apm.yml index b7fac37..e1f00f0 100644 --- a/apm.yml +++ b/apm.yml @@ -64,13 +64,11 @@ marketplace: # Output targets (map form). Each output writes to its profile default # path; add 'path:' under a key to override. - # 'codex' requires every package below to declare 'category:' (satisfied). outputs: claude: {} - codex: {} - # CI tip: build one or all formats with a machine-readable manifest: - # apm pack --marketplace=claude,codex --json | jq -r '.marketplace.outputs[].path' + # CI tip: build a machine-readable manifest: + # apm pack --marketplace=claude --json | jq -r '.marketplace.outputs[].path' versioning: strategy: per_package @@ -106,12 +104,6 @@ marketplace: version: 1.1.2 category: Productivity - - name: mattpocock-skills - description: Skills for Real Engineers — planning, TDD, architecture, and debugging workflows from Matt Pocock's .claude directory. - source: mattpocock/skills - version: "1.2.3" - category: Productivity - - name: lint description: Skills and agents for configuring and running linters. source: ./plugins/lint diff --git a/docs/adr/0015-apm-replaces-plugin-marketplace-authoring.md b/docs/adr/0015-apm-replaces-plugin-marketplace-authoring.md index eedcc21..e8e5c52 100644 --- a/docs/adr/0015-apm-replaces-plugin-marketplace-authoring.md +++ b/docs/adr/0015-apm-replaces-plugin-marketplace-authoring.md @@ -169,7 +169,10 @@ correction) sorted what they document into three buckets: apm has no version-bump automation (established under "Versioning" in issue #90's plan), so an ageing pin is the accepted cost of a push gate that only fires on this repo's own changes. Note the pin does not make the entry offline-resolvable: an exact version still requires a - `git ls-remote`, which is why two pre-push hooks need the network (see `AGENTS.md`). + `git ls-remote`, which is why two pre-push hooks needed the network (see `AGENTS.md`). + **Superseded 2026-09-13:** the `mattpocock-skills` entry has been removed from root `apm.yml` + entirely, along with the `codex` marketplace output profile. No pre-push hook needs the network + any longer. - **Caveat on "Status: executed" above:** issue #90's own execution comment flagged, before merge, that Claude Code's ability to actually load content out of `.apm/` was unverified — that caveat turned out to be a real defect, not a formality: the native installer has zero awareness of diff --git a/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md b/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md index 5edc04d..da05369 100644 --- a/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md +++ b/docs/adr/0021-plugin-descriptions-state-a-domain-boundary.md @@ -95,6 +95,10 @@ This decision covers the six plugins this repo authors. The root marketplace als `mattpocock-skills`, a third-party package whose description is not this repo's to write; its entry is out of scope and is left as published upstream. +*(Note, 2026-09-13: `mattpocock-skills` has since been removed from the root marketplace. This +section's scope statement is retained as the reasoning behind the boundary; the entry it describes +no longer exists.)* + ## Decision **A plugin's published `description` states the plugin's domain boundary. It does not enumerate the diff --git a/docs/spec/architecture.md b/docs/spec/architecture.md index 0d40c8c..61a2c34 100644 --- a/docs/spec/architecture.md +++ b/docs/spec/architecture.md @@ -44,7 +44,7 @@ These are routing boundaries, not inventories — they answer "where does a new Two compilers produce the plugin roots you see in the tree: -- **`apm pack` compiles the manifests** (ADR-0015). Per plugin: `.claude-plugin/plugin.json` and `.github/plugin/plugin.json`, both generated from `plugins//apm.yml`. Repo-wide, from the root `apm.yml`'s `marketplace:` block: `.claude-plugin/marketplace.json` (apm's `claude` output profile) and `.agents/plugins/marketplace.json` (its `codex` profile, a differently-shaped file). Those two are the only marketplace outputs apm has profiles for — the third root manifest, `.github/plugin/marketplace.json` (Copilot CLI's legacy path), is a byte-identical mirror of the Claude one maintained by `scripts/sync-marketplace-mirror.sh` and gated by the `check-marketplace-mirror-sync` pre-push hook. +- **`apm pack` compiles the manifests** (ADR-0015). Per plugin: `.claude-plugin/plugin.json` and `.github/plugin/plugin.json`, both generated from `plugins//apm.yml`. Repo-wide, from the root `apm.yml`'s `marketplace:` block: `.claude-plugin/marketplace.json` (apm's `claude` output profile) — the only marketplace output this repo declares. A second root manifest, `.github/plugin/marketplace.json` (Copilot CLI's legacy path), is a byte-identical mirror of the Claude one maintained by `scripts/sync-marketplace-mirror.sh` and gated by the `check-marketplace-mirror-sync` pre-push hook. - **`scripts/sync-plugin-content.sh` compiles the content mirror** (ADR-0017). It wraps `apm pack --format plugin` and copies the resulting bundle's flat `agents/`, `skills/`, `commands/`, `instructions/`, `extensions/`, and merged `hooks/hooks.json` back to the plugin root. Claude Code's installer convention-scans those flat paths and has no `.apm/` awareness whatsoever, so the mirror exists solely to satisfy the host's discovery contract. `.apm/` is the sole hand-edited authoring source for plugin content. An edit made in the flat mirror is discarded by the next sync and is reported as drift by the `check-plugin-content-sync` pre-push hook. Hand-authored material that is not an `.apm/` primitive — `README.md`, `docs/`, `bin/`, `sources.md`, `.mcp.json`, and per-plugin extras such as `plugins/gitea/references/` and `plugins/bin/evals/` — lives at the plugin **root** and is untouched by either compiler. diff --git a/docs/spec/gates.md b/docs/spec/gates.md index 439324e..436566d 100644 --- a/docs/spec/gates.md +++ b/docs/spec/gates.md @@ -888,30 +888,12 @@ fix. ## Pushing without a network -Exactly **two** pre-push hooks need the network, for one shared reason: root `apm.yml`'s -`marketplace.packages[]` contains exactly one remote entry — `mattpocock-skills`, -`source: mattpocock/skills` — and resolving it needs a `git ls-remote`. +No pre-push hook needs the network. Every entry in root `apm.yml`'s `marketplace.packages[]` +resolves from a local `./plugins/` path, so `apm-marketplace-check` and `apm-pack-check-clean` +never call `git ls-remote`. -| Hook | Offline failure | -|---|---| -| `apm-marketplace-check` (`always_run`, resolves every entry) | `No cached refs (offline)` | -| `apm-pack-check-clean` (re-resolves the same entry) | `Error: Git network timeout during ls-remote` | - -Pinning the entry to an exact version does **not** remove the call — an exact pin still ls-remotes. -`--offline` rescues neither. - -To push without a network, skip both using pre-commit's own mechanism: - -``` -SKIP=apm-marketplace-check,apm-pack-check-clean git push -``` - -**Skip those two alone.** Verified under `unshare -rn`: the other twelve pre-push hooks pass offline -because they are real local checks. (`check-executables-allow-sync` landed after that run, but reads -two local manifests and makes no network call.) Adding any other hook to `SKIP` disarms it silently. - -`apm-audit-ci` calls `apm` too but stays local: its org-policy discovery resolves nothing on this -remote *before* any network call, so it does not join the pair above. +`apm-audit-ci` calls `apm` too but was always local: its org-policy discovery resolves nothing on +this remote before any network call. --- diff --git a/scripts/sync-marketplace-mirror.sh b/scripts/sync-marketplace-mirror.sh index 6c7fd17..5587117 100755 --- a/scripts/sync-marketplace-mirror.sh +++ b/scripts/sync-marketplace-mirror.sh @@ -6,11 +6,10 @@ set -euo pipefail # that same file at .claude-plugin/marketplace.json directly, but also has a legacy # convention path at .github/plugin/marketplace.json (see # plugins/kyberforge/docs/research/docs/github-copilot-plugins/marketplace.md) -- and -# that path is a mirror of the Claude output, not a separate apm -# output profile (apm only ships "claude" and "codex" mappers; codex writes a -# differently-shaped file to .agents/plugins/marketplace.json, not this path). This -# script keeps that legacy mirror byte-identical to .claude-plugin/marketplace.json -# instead of letting it silently drift (see issue #90 comment thread). +# that path is a mirror of the Claude output, not a separate apm output profile (this +# repo declares only the "claude" output). This script keeps that legacy mirror +# byte-identical to .claude-plugin/marketplace.json instead of letting it silently +# drift (see issue #90 comment thread). # Hard error, not a `|| pwd` fallback. Every path this script touches hangs off # REPO_ROOT, and both of its exits-0 paths are "the files agree" or "neither file