# 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.

## 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).
