Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "samarth",
"description": "Samarth Rayar's Claude Code plugins, mods and skills",
"description": "Samarth Rayar's Claude Code plugins: mods, skills, subagents, hooks and MCP servers",
"owner": { "name": "Samarth Rayar", "url": "https://github.com/Samarth2001" },
"plugins": [
{
Expand Down
13 changes: 13 additions & 0 deletions .claude/skills/new-plugin/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: new-plugin
description: Scaffold a new plugin in this marketplace. Use when asked to add, create or start a new plugin, skill bundle, mod, subagent, hook or MCP server in this repo.
argument-hint: "<name> [what it should do]"
---

Create a new plugin from: $ARGUMENTS

1. Pick a kebab-case name and the components it needs (`skill`, `agent`, `hooks`, `mcp`, `mod`). Read `docs/plugin-anatomy.md` to choose. If the name or purpose is unclear, ask.
2. Run `node --experimental-strip-types scripts/new-plugin.mts <name> --with <components> --description "<one line>"`.
3. Fill in every TODO in `plugins/<name>/`. For a skill, follow `docs/writing-skills.md`. For a mod, load the `plugin-authoring` skill first.
4. Write the plugin README: what it adds, usage with an example, configuration, and what code it runs.
5. Run `claude plugin validate plugins/<name>`, `claude plugin test plugins/<name>` for a mod, `claude plugin validate .` and `node --experimental-strip-types scripts/catalog.mts --check`. Fix anything they report.
14 changes: 14 additions & 0 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: release
description: Release a new version of a plugin in this marketplace.
disable-model-invocation: true
argument-hint: "<plugin> [patch|minor|major]"
---

Release plugin: $ARGUMENTS

1. Read `plugins/<name>/CHANGELOG.md` and run `git log <name>--v<current-version>..HEAD -- plugins/<name>`. If that tag doesn't exist, use the full log for the folder. Then list what changed.
2. Choose the bump if none was given: patch for fixes, minor for features, major for breaking changes such as renamed commands or settings. Confirm it with me.
3. Set `version` in `plugins/<name>/.claude-plugin/plugin.json`. Add a `## [<version>] - <today>` section to the CHANGELOG under Added, Changed or Fixed, plus its compare link at the bottom.
4. Run `claude plugin validate .`, `claude plugin validate plugins/<name>`, `claude plugin test plugins/<name>` if it has tests, and `node --experimental-strip-types scripts/catalog.mts --check`.
5. Commit as `<name>: release <version>`. Then stop and show me the commands to push and tag: `git push` and `claude plugin tag plugins/<name> --push`.
9 changes: 9 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## What changed

## Plugins touched

- [ ] Version bumped in `plugin.json` and a CHANGELOG section added for each plugin whose shipped files changed
- [ ] The plugin's README is updated for anything users see
- [ ] `claude plugin validate .` and `claude plugin validate plugins/<name>` pass
- [ ] `claude plugin test plugins/<name>` passes (mods)
- [ ] `node --experimental-strip-types scripts/catalog.mts --check` passes
8 changes: 7 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
manifest="plugins/$name/.claude-plugin/plugin.json"
changelog="plugins/$name/CHANGELOG.md"

if [ ! -f "$manifest" ]; then
echo "::error::$TAG names no plugin: $manifest does not exist"
exit 1
fi

actual=$(sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' "$manifest" | head -1)
if [ "$actual" != "$version" ]; then
echo "::error::$TAG does not match $manifest ($actual)"
Expand All @@ -40,6 +45,7 @@ jobs:
on { print }
' "$changelog" > notes.md
[ -s notes.md ] || echo "See $changelog." > notes.md
printf '\nInstall or update:\n\n```bash\nclaude plugin marketplace add %s\nclaude plugin install %s@samarth\n```\n' "$GITHUB_REPOSITORY" "$name" >> notes.md
marketplace=$(jq -r .name .claude-plugin/marketplace.json)
printf '\nInstall or update:\n\n```bash\nclaude plugin marketplace add %s\nclaude plugin install %s@%s\n```\n' "$GITHUB_REPOSITORY" "$name" "$marketplace" >> notes.md

gh release create "$TAG" --title "$name $version" --notes-file notes.md --verify-tag
9 changes: 8 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ jobs:
fi
echo "::endgroup::"
done
- name: Catalog is consistent
run: node --experimental-strip-types scripts/catalog.mts --check
- name: Generated assets are up to date
run: node --experimental-strip-types scripts/render-buddy-gallery.mts --check
run: |
set -e
for script in scripts/assets/*.mts; do
[ -e "$script" ] || continue
node --experimental-strip-types "$script" --check
done
- name: Changed plugins bumped their version
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
Expand Down
19 changes: 19 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# claude-plugins

A Claude Code plugin marketplace (`samarth`). Each plugin lives in `plugins/<name>/`. Read CONTRIBUTING.md before changing structure or releasing.

## Rules

- Keep the root README neutral. Never feature one plugin there. Its catalog table is generated: edit `.claude-plugin/marketplace.json`, then run `node --experimental-strip-types scripts/catalog.mts`.
- Keep each plugin self-contained, in Claude Code's standard layout, with its own README.md and CHANGELOG.md. Dev-only tooling goes in `scripts/`, never inside a plugin.
- Never rename a plugin's `name`. Leave `version` out of marketplace entries.
- Any change to a plugin's shipped files needs a version bump and a CHANGELOG section. README, CHANGELOG, `assets/` and tests are exempt.
- Before reporting work done, run `claude plugin validate .`, `claude plugin validate plugins/<name>`, `claude plugin test plugins/<name>` (if it has tests) and `node --experimental-strip-types scripts/catalog.mts --check`.
- Before writing a mod, load the `plugin-authoring` skill.
- Guides in `docs/` summarize the official docs at code.claude.com. Link to the source and don't state behavior you haven't checked.

## Commands

- New plugin: `node --experimental-strip-types scripts/new-plugin.mts <name> --with skill,agent,hooks,mcp,mod --description "..."`
- Regenerate assets: `node --experimental-strip-types scripts/assets/<script>.mts`
- Release: `/release <name>` (bump, changelog, tag)
71 changes: 41 additions & 30 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,68 @@
# Working on this repo

Every plugin lives in `plugins/<name>/`, has an entry in `.claude-plugin/marketplace.json` and a row in the README table. CI validates and tests every plugin on each push and pull request.
Every plugin lives in `plugins/<name>/` and has an entry in `.claude-plugin/marketplace.json`. The README catalog is generated from those entries. On each push and pull request, CI validates the marketplace and every plugin, runs the tests, and checks that the catalog, generated assets and versions are up to date.

## Conventions

- **One plugin per folder, self-contained.** Everything a plugin needs lives under `plugins/<name>/`. Installed plugins are copied into a cache, so a plugin can't reach files outside its folder. Refer to bundled files with `${CLAUDE_PLUGIN_ROOT}`. Keep state that must survive updates in `${CLAUDE_PLUGIN_DATA}`.
- **Standard layout.** Put components in Claude Code's default locations (`skills/`, `agents/`, `hooks/hooks.json`, `.mcp.json`, and so on) rather than custom paths. Only `plugin.json` goes in `.claude-plugin/`. See [docs/plugin-anatomy.md](docs/plugin-anatomy.md).
- **Every plugin has a README and a CHANGELOG.** The README covers what it adds, how to use it, its configuration and how to develop it. The root README stays neutral: one generated catalog row per plugin, nothing more.
- **Names.** Use kebab-case and keep `name` the same in the folder, `plugin.json` and the marketplace entry. Names that start with `claude-` or `anthropic-` are reserved.
- **Marketplace entries** carry `name`, `source`, `description`, `category` and `tags`. Leave `version` out: `plugin.json` holds it. Suggested categories: `mods`, `skills`, `agents`, `hooks`, `mcp`, `output-styles`, `themes`, `bundles` (several kinds at once).
- **No `CLAUDE.md` inside a plugin.** Claude Code doesn't load it from a plugin. Put instructions for Claude in a skill.
- **Dev-only files stay outside plugins.** Asset generators and other tooling go in `scripts/`, because everything under `plugins/<name>/` ships to users.

## Add a plugin

1. Create `plugins/<name>/` with at least `.claude-plugin/plugin.json`:

```json
{
"name": "<name>",
"displayName": "<Name>",
"version": "0.1.0",
"description": "<one line>",
"author": { "name": "Samarth Rayar", "url": "https://github.com/Samarth2001" },
"homepage": "https://github.com/Samarth2001/claude-plugins/tree/main/plugins/<name>",
"repository": "https://github.com/Samarth2001/claude-plugins",
"license": "MIT",
"keywords": []
}
```
Scaffold it:

```bash
node --experimental-strip-types scripts/new-plugin.mts <name> --with skill --description "One line on what it does"
```

- **A mod** adds `hooks/hooks.json` (`{ "modules": ["./register.tsx"] }`), `hooks/register.tsx` and `hooks/*.test.tsx`. If it keeps values in `$.state`, add `types/index.d.ts` and `"types": "./types/index.d.ts"` to the manifest. In a Claude Code session, load the `plugin-authoring` skill before writing one.
- **Skills** go in `skills/<skill>/SKILL.md`.
`--with` takes a comma-separated list of `skill`, `agent`, `hooks`, `mcp` and `mod`. The script creates `plugins/<name>/` from [`templates/`](templates) with a manifest, a README, a CHANGELOG and the chosen components. It also adds the marketplace entry and regenerates the README catalog. Then fill in the TODOs.

2. Add `README.md` and a `CHANGELOG.md` with a `0.1.0` section.
3. Add the entry to `.claude-plugin/marketplace.json` (`name`, `source: "./plugins/<name>"`, `description`, `category`, `tags`). Keep `version` out of the entry: `plugin.json` holds it.
4. Add a row to the table in the root `README.md`.
- **Skills** live in `skills/<skill>/SKILL.md` and run as `/<plugin>:<skill>`. See [docs/writing-skills.md](docs/writing-skills.md).
- **Subagents** live in `agents/<agent>.md`.
- **Hooks** go in `hooks/hooks.json` under `"hooks"`, in the same shape as `settings.json` hooks. Reference scripts as `"${CLAUDE_PLUGIN_ROOT}"/scripts/...`.
- **MCP servers** go in `.mcp.json`.
- **A mod** puts `"modules": ["./register.ts"]` in `hooks/hooks.json`, with the hooks module and `*.test.ts` files beside it. If it keeps values in `$.state`, also add `types/index.d.ts` and `"types": "./types/index.d.ts"` to the manifest. In a Claude Code session, load the `plugin-authoring` skill before you write one.

If you edit the marketplace by hand, run `node --experimental-strip-types scripts/catalog.mts` to regenerate the catalog and check that everything agrees.

## Try it

```bash
claude plugin validate . # the marketplace
claude plugin validate plugins/<name> # the plugin
claude plugin test plugins/<name> # its tests
claude --plugin-dir plugins/<name> # a session with it loaded; saving reloads it
claude plugin test plugins/<name> # its tests (mods)
claude --plugin-dir plugins/<name> # a session with it loaded; mods hot-reload on save
```

`claude --debug` shows why a hook was skipped or a drawing refused. Loading a plugin from disk writes its types to `plugins/<name>/.claude-plugin/types/` (gitignored), which the plugin's `tsconfig.json` extends, so an editor or `npx tsc -p plugins/<name>` type-checks it.
`claude --debug` shows why a hook was skipped or a drawing refused. When Claude Code loads a mod from disk, it writes the mod's types to `plugins/<name>/.claude-plugin/types/` (gitignored). The mod's `tsconfig.json` extends them, so an editor or `npx tsc -p plugins/<name>` can type-check it.

## Generated assets

A script in `scripts/assets/` that renders a file into a plugin, such as a README image, must accept `--check`. With that flag it exits non-zero when the committed file is stale, and CI runs every such script that way. After changing what an asset is drawn from, run:

```bash
node --experimental-strip-types scripts/assets/<script>.mts
```

## Release

Users only receive a change when the plugin's `version` changes.
Users only get a change when the plugin's `version` changes. CI fails when a plugin's shipped files change without a version bump. Docs, `assets/` and tests don't count as shipped files.

1. Bump `version` in `plugins/<name>/.claude-plugin/plugin.json` ([semver](https://semver.org/): patch for fixes, minor for features, major for breaking changes such as renamed commands or settings).
2. Move the changes into a new section of `plugins/<name>/CHANGELOG.md` and update the version in the README table.
1. Bump `version` in `plugins/<name>/.claude-plugin/plugin.json` ([semver](https://semver.org/)): a patch for fixes, a minor for features, a major for breaking changes such as renamed commands or settings.
2. Move the changes into a new `## [<version>] - <date>` section of `plugins/<name>/CHANGELOG.md`.
3. Validate and test, then commit and push to `main`.
4. Tag the release and push the tag:

```bash
claude plugin tag plugins/<name> --push
```

This creates `<name>--v<version>`, after checking that `plugin.json` and the marketplace entry agree and that the tree is clean. The tag convention is what dependency version ranges resolve against. Pushing it runs the Release workflow, which publishes a GitHub release with that version's changelog section.
This creates `<name>--v<version>`. Before tagging, it checks that `plugin.json` and the marketplace entry agree and that the tree is clean. Dependency version ranges resolve against this tag convention. Pushing the tag runs the Release workflow, which publishes a GitHub release with that version's changelog section.

5. Update your own install:

Expand All @@ -62,8 +73,8 @@ Users only receive a change when the plugin's `version` changes.

## Rename or remove a plugin

Never change a plugin's `name`: it is the install id. Change `displayName` instead. If a rename or removal is unavoidable, record it in the `renames` map of `marketplace.json` (`"old": "new"` or `"old": null`), which is append-only history.
Never change a plugin's `name`, because it is the install id. Change `displayName` instead. If a rename or removal can't be avoided, record it in the `renames` map of `marketplace.json` (`"old": "new"` or `"old": null`). That map is append-only history.

## Commits

Commit as `Samarth Rayar <samarthsr2001@gmail.com>`. One change per commit, with the plugin name first in the subject (`buddy: ...`).
Commit as `Samarth Rayar <samarthsr2001@gmail.com>`. Make one change per commit. Start the subject with the plugin name for plugin changes (`buddy: ...`) and describe the area for repo-wide changes (`Release workflow: ...`).
Loading
Loading