AGENTS.md ยท diff
git:20260915.2b1355b to git:20260928.3a54312
77 added, 61 removed. Audit A to A.
- # Foundry project instructions
+ # Foundry
- Node and npm are managed by fnm. Initialize the shell environment with
- `fnm env --use-on-cd | Out-String | Invoke-Expression` in PowerShell.
- Check the branch before edits and work on a non-main branch. Preserve existing
- work in the parent and plugin checkouts.
+ Foundry is the marketplace that lists the Foreman, Hush and Razor plugins for Claude Code and
+ Codex. The plugins are Git submodules pinned by commit; this repository holds the two catalogs,
+ the release procedure, the README contract the plugins share and the brand kit their images come
+ from. Foreman and Razor also run on Antigravity, which has no catalog: its users install a plugin
+ directory from a Foundry clone, which checks the plugin out at its pinned commit, and Antigravity
+ reads that plugin's own root `plugin.json` and `hooks.json`. Nothing is installed here, and the
+ only build is the artwork under `brand/`. The plugins run their hooks and tests with Node.js 22 or
+ later and Git.
- ## One project roadmap
+ ## Start here
- Foundry's root ROADMAP.jsonl owns development work for this collection. Do not
- create another project roadmap inside a plugin or its platform worktree. Run
- roadmap commands from Foundry, with host project-directory overrides pointing
- at that root; plugin source commands and tests keep their own working directory.
- This does not change roadmaps in unrelated projects where a plugin is installed.
- Version Foundry's root ROADMAP.jsonl and .foreman/config.json, notes.jsonl and
- archive.jsonl when present. Keep trial logs, session markers, locks and temporary
- execution state local; do not expose the entire .foreman directory.
- Preserve test fixtures and archival evidence. During consolidation, retain
- history and acceptance states, and record any ID remapping explicitly.
+ - For installation and the plugin table, read [README.md](README.md).
+ - Before changing a catalog or cutting a release, read [the release procedure](.claude/skills/cut-release/SKILL.md).
+ - Before changing a plugin, read that plugin's own `AGENTS.md`; each submodule is a separate repository with its own rules, tests and changelog.
+ - Before editing or reviewing a plugin README, read [the README contract](docs/knowledge/plugin-readme-template.md).
+ - Before changing any banner, icon, host card, Ember scene or evidence graphic, read [the brand guide](docs/knowledge/brand.md).
- ## Coordinated documentation
+ ## Rules that outrank everything
- For a plugin with Claude and Codex editions, main is a product overview page containing README.md,
- LICENSE, the branding assets, the shared animated mascot and the minimal documentation check in
- .github/check-main-frontpage.cjs and .github/workflows/test.yml. Use
- check-main-frontpage.js for that contract; the paired README rules below apply
- to Claude/Codex editions. Keep product runtime and unrelated CI out of main,
- and publish linked edition branches before their selector. Flint is explicitly
- outside this cleanup. Main carries the same product story, benefits, mechanism,
- usage examples and general limitations as both editions. It also gives a clear
- edition choice; host-specific install commands, compatibility and measurements
- stay in the edition pages. Validate the five shared sections and branding against
- both edition refs when changing main. Do not reduce it to a thin link selector.
+ - A catalog entry never carries a version. The version lives in the plugin's manifests, and a release moves only `source.sha` and the gitlink.
+ - A plugin listed in both catalogs pins the same `main` commit in both. Hush ships for Claude Code only and stays out of the Codex catalog. Antigravity needs no catalog entry; a plugin that ships for it carries a root `plugin.json` with the same version as its other manifests.
+ - Plugin source changes happen in the plugin's repository on a topic branch, never as loose edits on the pinned checkout.
- Foreman and Razor ship one package for Claude Code and Codex on main (ADRs 0011
- and 0013). Their main is the product, and each single README names the host
- beside every host-specific instruction and result, so the selector and paired
- README rules do not apply to them. Hush ships one package for Claude Code on
- main under the same rules (ADR 0012); it has no Codex package. The former
- `Claude` and `Codex` branches of all three were deleted on 2026-09-15.
+ ## Commands
- Benchmark runners, datasets, measurement tests and experiments belong in
- Foundry's `benchmarks/<plugin>/`, not inside the installable plugin. Product
- functional tests stay in the plugin. Use `.scratch/` for maintenance output,
- backups and temporary validation dependencies; do not recreate `.benchmarks/`.
+ Run from the repository root unless a row names another directory.
- For a plugin with editions, the Claude and Codex README share their product narrative,
- headings, order, common outcomes and decorative branding. Change common content
- in both editions together. Only the six bounded native exceptions may differ:
- identity, installation, commands, compatibility and actual availability,
- benchmarks, and edition-specific links. Main headings stay outside exceptions.
+ | Command | Purpose | Cost |
+ | --- | --- | --- |
+ | `claude plugin validate .` | Validate the Claude Code catalog | Local |
+ | `agy plugin validate foreman` or `agy plugin validate razor` | Validate a plugin's Antigravity package | Local; needs the Antigravity CLI |
+ | `node --test tests/*.test.js` from `foreman/`, `hush/` or `razor/` | One plugin's suite | Local temporary fixtures; razor's suite fails under the system temp directory. Foreman's suite takes about 300 s: run it in the background or with a timeout above 300 s, or narrow it with `--test-name-pattern` |
+ | The pin check in [cut-release step 4](.claude/skills/cut-release/SKILL.md) | Pins, gitlinks and manifest versions agree | Local Git reads in each plugin. It reads catalogs and gitlinks from the checkout it runs in and plugin history from the Foundry root it is given; from a worktree, pass the Foundry root |
+ | `node scripts/check-shared-copies.js`, `node --test scripts/check-shared-copies.test.js` | Hush's and Razor's hand-copied `hooks/lib/safe-write.js` code and turn-boundary `FIXTURES` agree, and so do the seven whole files of the README nav check and the pre-commit hook with its test in Foreman, Hush and Razor, and so does the Node.js and fnm lookup in Foreman's and Razor's `hooks/windows-launcher.ps1`; the test proves a changed copy fails | Local reads; a plugin with no checkout is skipped and named, and a run that compared nothing fails. It reads gitlinks, staged ones included, from the checkout it runs in and plugin history from the root argument: from the top of a worktree without plugin checkouts, `node scripts/check-shared-copies.js <root>` checks the worktree's gitlinks against the Foundry root's plugins. The test takes about a minute and prints nothing until it ends; `--test-reporter=spec` shows progress |
+ | `node --test scripts/cut-release-block.test.js` | The bash block of [cut-release step 4](.claude/skills/cut-release/SKILL.md) parses, and runs as written from this checkout with exit 0 | Local; needs a bash that finds `node` and `git`, which on Windows is Git's own, and the run needs the `claude` CLI. The run is skipped and names the plugins when a catalogued plugin has no checkout, as in a worktree; CI checks out no submodules, so this test stays local |
+ | `git submodule update --init` | Check every plugin out at its pinned commit | Network on a fresh clone |
+ | `node --test scripts/claude-hooks/*.test.js` | The repository's own hook, which reruns a plugin's suite after an edit under its `scripts/` or `hooks/`; for Foreman, only the test files that cover the edited module | Local temporary fixtures |
+ | `node brand/mascot/build.cjs`, `node brand/graphics/build.cjs` | Rebuild the Ember scenes or the evidence graphics | Local |
+ | `node brand/identity/build.cjs` | Rebuild icons, README banners, wordmarks and social cards | Local; needs Sharp and Segoe UI |
+ | `node brand/identity/build-review.cjs` | Refresh the review gallery `brand/identity/index.html` | Local |
+ | `node brand/check-timing.js <svg>` | Check the SMIL timing lists of an animated SVG | Local |
- Benchmark questions and columns stay the same. Results identify the actual host,
- model, source and date. Preserve negative results and limits. Never relabel a
- Claude measurement as Codex evidence, infer performance from unit tests, or fill
- missing results with invented values. Use `Not measured` and state when an edition
- is unavailable. Keep research and extensive methodology in Foundry documentation;
- keep usage guides and plugin-specific decisions with their plugin.
+ CI runs `.github/workflows/validate-marketplace.yml` on pushes and pull requests to `main`. Its
+ `validate` job is the check the default branch's ruleset requires. It checks both catalogs: no
+ entry carries a version, each has a full `source.sha` and a `ref`, each name is a submodule path
+ whose gitlink names that same commit, and a plugin in both catalogs has one pin. Then it runs
+ `claude plugin validate .`. A gitlink moved off its pin therefore fails CI. The cut-release
+ step 4 pin check and shared-copy check stay local steps, because they read the plugin checkouts
+ and CI checks out no submodules.
- Use `coordinate-readmes` for paired README changes and benchmark updates. Run
- `node scripts/git-hooks/check-readme-parity.js --pair <Claude-README> <Codex-README>`
- and `check-readme-nav.js` before considering the change ready. For committed
- revisions use `--git-pair <plugin-repo> <Claude-ref> <Codex-ref>`. Also inspect the
- original evidence: parser success is not proof of measurement quality.
+ ## Where things live
- Both native review agents use the Foundry README template and the same review
- criteria. Platform-specific skills, rules and CI must keep this policy aligned.
- Foundry hosts both platforms; its plugin-only platform-isolation rule does not
- apply to the parent repository.
- Common README changes in separate platform PRs use the reciprocal PR/SHA
- protocol in `.github/README_COORDINATION.md`. A candidate-pair check does not
- replace the final integrated-branch comparison before selectors or pins publish.
+ | Path | Content |
+ | --- | --- |
+ | `.claude-plugin/marketplace.json` | Claude Code catalog: foreman, hush, razor |
+ | `.agents/plugins/marketplace.json` | Codex catalog: foreman, razor |
+ | `foreman/`, `hush/`, `razor/` | Plugin repositories, mounted as submodules |
+ | `flint/` | Plain-text writing and coding instructions; a submodule outside both catalogs |
+ | `.claude/skills/cut-release/`, `.agents/skills/cut-release/` | The release procedure, user-invoked only: Claude Code's skill holds the steps, and the Codex skill delegates to it with Codex notes |
+ | `.claude/skills/brand/`, `.agents/skills/brand/` | The artwork procedure for Claude Code and Codex; the two files stay identical |
+ | `.claude/agents/`, `.codex/agents/` | `plugin-docs-reviewer`, the read-only README review, for Claude Code and Codex |
+ | `.claude/settings.json`, `.codex/hooks.json` | Shared Claude Code settings and the Codex hook registration for this checkout |
+ | `.github/workflows/validate-marketplace.yml` | The CI workflow that produces the required `validate` check |
+ | `scripts/claude-hooks/` | The post-edit hook that reruns the touched plugin's tests, with its own test |
+ | `scripts/check-shared-copies.js` | The check that the plugins' hand-copied files agree, with its own test |
+ | `brand/` | The brand kit: sources, generators and the exported images each plugin copies into its `assets/` |
+ | `docs/knowledge/` | Public documentation: the plugin README contract and the brand guide |
+
+ ## Conventions
+
+ `CLAUDE.md` imports this file; keep shared project facts here. Codex reads this file directly.
+
+ Each plugin keeps its README, `AGENTS.md`, tests and `docs/knowledge/changelog.md` in its own
+ repository. Edit them there, merge into that plugin's `main`, then re-pin here through the
+ release procedure. This repository carries no single plugin's documentation, only the README
+ contract the three share.
+
+ ## Pitfalls
+
+ - **A fresh clone leaves every plugin on a detached HEAD at its pin.** A commit made there lands on no branch; switch to a branch in the plugin first.
+ - **A plugin checkout serves one session at a time.** When another task holds a branch or uncommitted edits in `foreman/`, `hush/` or `razor/`, work in a separate worktree under the root's ignored `.private/`: `git -C <plugin> worktree add ../.private/<plugin>-<id> -b <branch> main`, where `<id>` names your task. The post-edit hook reruns the worktree's suite after an edit in its `scripts/` or `hooks/`. To compare its committed shared copies before merge, run `node scripts/check-shared-copies.js --<plugin> .private/<plugin>-<id>`, which reads that plugin at the worktree's HEAD and the others at their pins. When an entry changes a shared file in several plugins, pass one override per worktree in the same run; one worktree alone is compared with the others' old pins. After the branch merges, remove it with `git -C <plugin> worktree remove ../.private/<plugin>-<id>`. A session the desktop app started in its own worktree under `.claude/worktrees/` keeps the plugin worktree inside it. First run `git -C <app worktree> rev-parse --show-toplevel`. When it prints the Foundry root, called `<root>` below, the app folder is not a worktree and Git there acts on the root: if the folder is empty, run `git -C <root> worktree add --detach <app worktree> main`; if it is not empty, stop and report it rather than clear it, because that command then fails with `already exists`. Otherwise run `git -C <app worktree> switch --detach main`. After either command, `.private/` is ignored there; add the plugin worktree at `<app worktree>/.private/<plugin>-<id>`. Pass that absolute path to `--<plugin>`, as in `node scripts/check-shared-copies.js --<plugin> <app worktree>/.private/<plugin>-<id> <root>`, because a relative override resolves against the root argument, not the current directory.
+ - **A pushed gitlink ships to Antigravity.** Claude Code and Codex install the catalog's `source.sha`, but a Foundry clone checks each plugin out at its gitlink, and Antigravity installs that checkout. A release moves both together; never push a `main` where they differ.
+ - **`git submodule update` moves each plugin back to its pin.** It stops on uncommitted edits to tracked files; untracked files stay.
+ - **An Antigravity install is a copy of a checkout, not a pin.** `agy plugin install` copies the directory it is given; a plugin checked out anywhere but its pinned commit installs that other state. An install takes a new release only when its user pulls the clone, runs `git submodule update --init` and installs again.
+ - **A plugin's `assets/` holds copies.** An image edited there is overwritten by the next copy from `brand/`; change the kit, rebuild, then copy.
+ - **Codex trusts the Foundry root, not a worktree.** Codex loads `.codex/agents/` and `.codex/hooks.json` only in a trusted project, and it keys that trust on the main checkout's path. From a worktree, trust the Foundry root, as in `codex -c "projects.'<root>'.trust_level='trusted'"`; Codex reports a worktree path under `projects` as an ignored setting.