CLAUDE.md · git:20261010.0431ab1 · 2026-10-10 · sha256 56578569b52217ec
CLAUDE.md git:20261010.0431ab1A
Immutable. This exact content never changes and is served at /api/v1/blob/56578569b52217ec.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this repo is
A public Claude Code **plugin marketplace** of "mods": plugins built from function hooks (TypeScript modules that hook engine events like `tool.call`, `ui.render`, `prompt.submit`, `command.run`). Users install with `/plugin marketplace add ibrahimkobeissy/claude-mods` then `/plugin install <mod>@claude-mods`.
For the hooks API itself, load the built-in `plugin-authoring` skill; it points at this build's exact type definitions (`claude-code.d.ts`). Don't guess API shapes — grep those types.
## Branch and release rule
This is a public repo. Every new mod is built on its own branch (`git switch -c mod/<name>`) and committed there only. Never push the branch, open a PR, or merge into `main` until the maintainer explicitly says so. They test each mod by hand before it ships. When a mod is ready, run `scripts/validate.sh mods/<name>` and give the steps to try it (`claude --plugin-dir mods/<name>`), then stop.
## Commands
```bash
scripts/new-mod.sh <kebab-name> "description" # copy template/ to mods/<name>, add marketplace entry
scripts/validate.sh # marketplace consistency + validate & test template/ and every mod
scripts/validate.sh mods/<name> # one mod only
claude plugin validate . # marketplace manifest only
claude plugin validate mods/<name> # one mod's manifest + hooks
claude plugin test mods/<name> # run that mod's *.test.ts files
claude --plugin-dir mods/<name> # load a mod into a session; saves hot-reload it
```
CI (`.github/workflows/validate.yml`) runs `claude plugin validate .` and `scripts/validate.sh`.
## Structure and invariants
- `.claude-plugin/marketplace.json` is the catalog. Each entry's `source` is `./mods/<name>`. `scripts/validate.sh` fails if a `mods/` folder is unlisted, a listed source is missing, or a mod's `plugin.json` `name` differs from its folder name — keep all three identical.
- Each mod: `.claude-plugin/plugin.json`, `hooks/hooks.json` (`{ "modules": ["./register.ts"] }`), `hooks/register.ts` exporting `register: Register` (type from `'claude-code'`), `*.test.ts` files (in `hooks/` or `tests/`) using `claude-code/testing`. A mod may ship its own `tsconfig.json` extending `./.claude-plugin/types/tsconfig.json`, which only exists after Claude Code has loaded the mod once.
- A mod that keeps values in `$.state` must declare them in `types/index.d.ts` (`interface PluginState`) and name it via `"types"` in `plugin.json`; `claude plugin validate` enforces this.
- `template/` is the starter that `new-mod.sh` copies; it is not listed in the marketplace. Changes to it affect every future mod.
- `.claude-plugin/types/` inside a mod is generated by Claude Code on load and is gitignored.
- Installed users get a copy from git, so a change reaches them only via a `version` bump in the mod's `plugin.json`.
## Testing notes
In `claude plugin test`, the test's own `on(...)` hooks sit *beneath* the plugin and stand in for the engine; with no such hook, the event throws. A `tool.call` stand-in returns `{ result }` (or `{ deny }`); a plugin's deny reaches `$.tool.call` in the test as `{ deny }`. See `template/hooks/register.test.ts`.
## Adding a mod (repo checklist)
New mods also need a `README.md` in their folder and a row in the root `README.md` **Mods** table (alphabetical). See `CONTRIBUTING.md` for the merge checklist.
## Assets
`assets/banner.svg` and `assets/social-preview.svg` are the sources; regenerate PNGs with:
```bash
rsvg-convert -w 2560 assets/banner.svg -o assets/banner.png
rsvg-convert -w 1280 -h 640 assets/social-preview.svg -o assets/social-preview.png
```
`social-preview.png` is uploaded manually in GitHub Settings → Social preview (no API for it).