Files
holocron/AGENTS.md
Defame1297 f1fa65ebc2 docs: record how a plugin's .mcp.json reaches apm, and document the gitea prerequisites
A review of this PR concluded that MCP was not an apm primitive, that the
.mcp.json edit therefore did nothing, and that the declaration belonged in
plugins/gitea/apm.yml under dependencies.mcp. The first half was right about
the primitive and wrong about everything that followed.

MCP is a first-class apm primitive. But the .mcp.json route already reaches
it: apm resolves a plugin manifest in the order plugin.json,
.github/plugin/plugin.json, .claude-plugin/plugin.json, so the generated
Copilot manifest wins, its mcpServers string pointer is followed, and
.mcp.json is injected into the package's dependencies.mcp with ${VAR} env
references intact. Verified against the real remote: a git-sourced install of
plugins/gitea at this branch deploys the gitea server with both references
unexpanded. No code change is needed and none is made here.

Moving the declaration into plugins/gitea/apm.yml would have broken the
build. apm-audit-ci runs apm audit --ci inside every plugins/*/, so a declared
dependency arms lockfile-exists there, which then demands an apm.lock.yaml in
the package plus that package's whole deployed tree inside the package
directory: 93 missing deployed files and 79 drifted paths, measured.

So this commit documents rather than changes:

- AGENTS.md and docs/spec/architecture.md said .mcp.json was plugin-root
  material with no .apm/ source, true of .apm/ and read as 'apm has no MCP
  concept'. Both now state what .mcp.json is, how it reaches dependencies.mcp,
  and that a plugin's own apm.yml is the one place not to declare it.
- architecture.md also records the env-strip: apm pack inlines .mcp.json into
  .claude-plugin/plugin.json and its sanitiser drops env and headers blocks
  unconditionally, ${VAR} included. Inert under apm, which never reads that
  file, but a native Claude Code plugin install reads exactly it and would
  start the server with no credentials.
- README.md gains the go toolchain prerequisite and the two environment
  variables the server needs, with placeholder values only.
- LESSONS.md records both process failures, including that three scratch
  installs inverted the result by using local ./path dependencies, where apm
  skips the plugin normalisation that injects .mcp.json.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EmiHiknxqtZPEBnW7ujgNz
2026-09-12 09:50:48 +00:00

6.6 KiB

Working in this repo

The global AI development configuration repository — the authoritative source for agent definitions, skills, workflows, and prompts across all projects.

This file carries only what applies to every session. Setup, prerequisites, and test commands are in README.md; the reasoning behind each enforcement gate is in docs/spec/gates.md.

Structure

  • plugins/ — six installable plugin units, each an apm package (apm.yml + .apm/). Root apm.yml declares all six as dependencies.apm; apm install deploys them into .claude/skills/ and .claude/agents/, both gitignored install output.
  • providers/claude-code/ — Claude Code adapter, deployed to ~/.claude/ via scripts/install.sh.

Edit .apm/, never the flat mirror

plugins/<name>/.apm/ is the only hand-edited source for plugin content. The flat plugins/<name>/{skills,agents,commands,instructions,extensions}/ directories, the merged plugins/<name>/hooks/hooks.json, and both plugin.json manifests are generated — nothing marks them as generated, so check the path before you edit. An edit to the mirror is discarded by the next sync and reported as drift by the check-plugin-content-sync pre-push hook.

Not everything in a plugin root is generated. README.md, docs/, bin/, sources.md, .mcp.json and per-plugin extras are hand-authored there with no .apm/ source — edit those in place. The rule is per-path, not per-directory. But a file placed inside a mirrored directory is deleted on the next sync (sync_dir runs rm -rf before every copy), so plugin-root documentation goes in docs/, never in hooks/ or skills/.

.mcp.json is hand-authored but it is not outside apm. MCP is a first-class apm primitive, and a plugin's .mcp.json is how this repo declares one: apm reads the mcpServers pointer in the generated .github/plugin/plugin.json, resolves it to .mcp.json, and injects the result into that package's dependencies.mcp when a consumer installs it. Declare MCP servers there and never in the plugin's own apm.yml — that arms a per-package gate this repo cannot satisfy (LESSONS.md, 2026-09-12).

Full model: docs/spec/architecture.md.

Prefer plugin skills over raw shell

This repo dogfoods its own plugins. Before shelling out, check whether a skill already owns the operation — it usually does:

  • Commits, branches, history, worktrees, remotes → git-commits, git-branches, git-history, git-worktrees, git-remotes
  • Pre-commit hook install/config/troubleshooting → pc-run / pc-author
  • Issues, PRs, labels, milestones → gitea-issues, gitea-prs, gitea-labels-milestones; also gitea-branches, gitea-files, gitea-releases, or gitea-workflow when the domain is ambiguous
  • Vale prose linting → vale-config / vale-run
  • This repo's own AGENTS.md → agentsmd-author / agentsmd-audit

Use the bare, unnamespaced names. That is what apm install deploys and the only form this repo's own install produces — a project skill has no plugin to prefix (ADR-0018). Whether the <plugin>: form (gitea:gitea-prs) also resolves depends on native plugin installs at user scope, outside this repo; write the bare name either way.

Fall back to raw shell only when no skill covers it.

Session rules

  • 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/<name>/.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.
  • 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

Read CONTEXT.md at the start of every session — it is this repo's domain glossary, and the terms it defines are used unglossed everywhere else. It is not exhaustive: terms it does not carry are defined at their point of use, mostly in docs/spec/.

Read these on demand:

  • README.md — prerequisites, install, and test commands
  • docs/VISION.md — the phased roadmap and where this is going; read when a decision turns on product direction
  • LESSONS.md — patterns that went wrong once; read before repeating a class of change that has burned the repo before
  • docs/spec/gates.md — what each pre-commit and pre-push hook enforces and why; read when a gate fails or before changing hook config
  • docs/spec/architecture.md — directory structure, install pipeline, provider model
  • docs/adr/ — architectural decisions; read before answering design questions or proposing structural changes
  • docs/ai-constitution.md — full governance evidence base; read when a governance decision needs justification
  • docs/research/ai-coding-factory/ai-coding-factory-principles.md — factory design rationale; read when implementing, auditing, or reviewing skills or factory structure
  • docs/notes/factory-integration-decisions.md — decisions from the factory integration grill; read when making skill authoring or factory design decisions
  • Governance rules are always in effect — core/instructions/governance.md (agent rules); docs/research/governance_principles/CONTROLS.md