| name | lean-contribute |
| description | Walk a contributor through proposing a change to the LeanCode AI plugins marketplace — tweaking an existing plugin, adding a new one, and opening a PR against `leancodepl/ai-plugins`. Use when the user invokes `/lean-contribute`, asks how to contribute, asks how to add a plugin, or wants to propose an improvement. Manual-only entry point — does not auto-fire. |
| disable-model-invocation | true |
Contribute to LeanCode AI plugins
The canonical contributor reference for leancodepl/ai-plugins. The repo's CONTRIBUTING.md is a thin pointer at this file. Read top-to-bottom for the full picture, or jump to the relevant path.
How to respond
- Ask what kind of change the user wants:
- Tweak an existing plugin (improve a skill or rule, fix a typo, sharpen wording).
- Add a new plugin (a new vertical or a new focused capability).
- Add a skill or rule to an existing plugin.
- Walk through the matching path below. Print exact commands. Do not run
git, gh, or any state-changing command on the contributor's behalf unless they explicitly ask.
- After the PR is pushed, point the user at
gh pr checks <pr-number> to follow CI verdicts. Do not run validators or linters locally — CI is the source of truth.
Reading the current state
Before answering questions about what plugins or clients exist, read the source of truth:
- Plugins:
.claude-plugin/marketplace.json at the repo root.
- Supported clients: the "Supported clients" section of the root
README.md.
Do not enumerate plugins or clients from memory.
Where to work
All contribution work happens inside a local clone of leancodepl/ai-plugins, not in a consumer project. If the contributor does not have the clone yet:
gh repo clone leancodepl/ai-plugins
cd ai-plugins
If gh is not installed, point them at https://cli.github.com/ or, for a fully GUI flow, https://desktop.github.com/.
Plugin shape
Every plugin lives under plugins/<plugin-name>/:
plugins/<plugin-name>/
skills/
<plugin-name>-usage/
SKILL.md # routing entry point, always present
<other-skill>/
SKILL.md
.cursor-plugin/plugin.json
.claude-plugin/plugin.json
README.md
CHANGELOG.md
.mcp.json # only if the plugin drives an MCP server
rules/ # optional
cursor-rules/ # generated from rules/, never hand-edited
claude-rules/ # generated from rules/, never hand-edited
Notes:
- Both manifests must agree on
name, displayName, description, version. Cursor reads .cursor-plugin/plugin.json (rules: "./cursor-rules/"), Claude Code reads .claude-plugin/plugin.json (rules: "./claude-rules/"). If your plugin has no rules/, omit the rules key from both manifests.
- Every plugin ships
skills/<plugin-name>-usage/SKILL.md as its routing entry point. The skill name: in frontmatter must exactly match the folder name.
- Skill names are unique across the whole marketplace. If your slug could collide, prefix it with the plugin name.
- Skills and rules are both first-class. Use the one that fits — skills for routing and workflows, rules for guidance the model should apply automatically (path-scoped via
globs, or agent-requested via a precise description). Mark skills that should never auto-fire on inferred intent with disable-model-invocation: true.
- Don't hand-edit
cursor-rules/ or claude-rules/. They are generated by python scripts/generate-rules.py from rules/*.md. Commit source and generated files together.
- Setup and configuration docs have one canonical home: the plugin
README.md. Anything a user has to do to make the plugin work (env vars, dependencies, post-install steps, sample directories, MCP servers, etc.) lives there in full. Other surfaces — <plugin>-usage/SKILL.md, other skills, top-level README bullets — reference the plugin README rather than restating the setup. The single exception is a skill that needs to print setup inline at runtime (because the user is not on GitHub at that moment); when you keep an inline copy for that reason, say so in the skill so the next contributor does not assume the duplication is accidental. This rule prevents the three-way drift between README.md, the usage SKILL, and any workhorse SKILL that all happen to mention the same env var.
Skill conventions
- Each skill is a folder
skills/<slug>/ containing a single SKILL.md.
- Frontmatter
name: must equal the folder name.
description should include "Use when …" with concrete trigger terms.
- Add
argument-hint: "<args>" when the skill takes arguments.
- Add
disable-model-invocation: true when the skill should never auto-fire on inferred intent.
- Skill names must be unique across the whole marketplace.
Skills are also distributed through vercel-labs/skills as a cross-client install path (npx skills add leancodepl/ai-plugins --skill <name> -a <agent>, supports Cursor, Claude Code, and 50+ other agents). When authoring: keep name: globally unique (the CLI uses a flat namespace, no plugin scoping), make description: self-contained, and don't assume the plugin's rules/ are present at runtime — a <plugin>-usage skill should be useful standalone.
Rule conventions
- Author in
rules/. A non-empty description is mandatory; globs is optional.
- Scope each rule with
globs (path-scoped) or with a precise description alone (agent-requested); never alwaysApply: true. See AGENTS.md "Rule authoring" for which to pick.
- Run
python scripts/generate-rules.py after any change. Commit source and generated files together.
- Do not hand-edit anything under
cursor-rules/ or claude-rules/.
Path 1 — tweak an existing plugin
- Open
plugins/<plugin-name>/ and find the file to change.
- Edit it. Keep the change focused — one PR per concern.
- If you edited any
rules/*.md, regenerate locally with python scripts/generate-rules.py. (Python is the only tool a contributor should need locally; CI handles the rest.)
- Bump the plugin's
version in both .cursor-plugin/plugin.json and .claude-plugin/plugin.json. PATCH for wording / docs, MINOR for new behavior, MAJOR for renames or removals. See "Versioning" below for the full rules and what each client does with the bump.
- Add a bullet to
plugins/<plugin-name>/CHANGELOG.md under a new top entry matching the new version.
- Update
plugins/<plugin-name>/README.md if the change affects what the plugin lists.
- Branch, commit, push, open a PR — see "Open the PR" below.
Path 2 — add a skill or rule to an existing plugin
Same as Path 1, plus:
- New skill →
plugins/<plugin-name>/skills/<skill-slug>/SKILL.md with frontmatter name: <skill-slug> and a description that includes "Use when …" with concrete trigger terms. Add disable-model-invocation: true if it should not auto-fire. Also append the skill's plugin-relative path (e.g. "./skills/<skill-slug>") to the plugin's skills array in .claude-plugin/marketplace.json — that's the manifest vercel-labs/skills reads for cross-client distribution.
- New rule →
plugins/<plugin-name>/rules/<rule-slug>.md with description and concrete globs. Never set alwaysApply: true. After saving, run python scripts/generate-rules.py.
- Mention the new asset in
plugins/<plugin-name>/README.md.
Path 3 — add a new plugin
- Pick a kebab-case name with a prefix that reflects scope:
<vertical>-<scope> when the plugin is tied to a specific vertical: backend-…, flutter-…, pmo-….
lean-<scope> when the plugin is cross-vertical or has no natural vertical (matches lean-core, lean-anti-ai-slop). Do not ship a bare slug. The prefix is what makes the marketplace listing predictable — users remember prefixes plus autocomplete, not full slugs.
- Create
plugins/<plugin-name>/ with at minimum:
skills/<plugin-name>-usage/SKILL.md
.cursor-plugin/plugin.json
.claude-plugin/plugin.json
README.md
CHANGELOG.md with a 0.1.0 entry
- Copy manifest shape from a sibling plugin. Set
version: "0.1.0" and stability: "experimental".
- Register the plugin in both marketplace files:
.cursor-plugin/marketplace.json — append to plugins[].
.claude-plugin/marketplace.json — append to plugins[] and include a skills array on the entry listing every skill's plugin-relative path (e.g. "./skills/<plugin-name>-usage"). vercel-labs/skills reads this for cross-client distribution; without it the CLI falls back to a recursive search.
- Bumping
metadata.version on either file is convention-only — see "Versioning" below.
- Add the plugin to the human-readable overview in the root
README.md under the matching vertical group.
- Branch, commit, push, open a PR.
Versioning
Per-plugin semver. Both plugin.json files must carry the same version.
- PATCH — wording, doc, regenerated output only.
- MINOR — new skill, new rule, new behavior; expanded scope; additive change.
- MAJOR — rename, removal, or reversal of existing guidance.
Optional stability field on each plugin: experimental, beta, or stable.
What clients actually do with these versions
This trips contributors up — be explicit when walking the user through.
- Claude Code: per-plugin
plugin.json.version is the cache key for /plugin update. Bumping it is load-bearing. If you ship changes without bumping, users running /plugin update see "already at the latest version" and never get your change. Bump it on every release. (See https://code.claude.com/docs/en/plugins-reference.md, "Version management".)
- Cursor: per-plugin
plugin.json.version is decorative. Cursor pins installs to the git commit SHA internally, so any new commit on the tracked branch is a new version regardless of the string. (See https://cursor.com/docs/reference/plugins.)
marketplace.json.metadata.version in either client: decorative — no documented refresh, cache, or update behavior. Bump by convention when plugins are added/removed/renamed if you want, but nothing depends on it.
How users get updates (no reinstall needed)
- Claude Code: user runs
/plugin update (or auto-update fires if they enabled it). Pulls the latest version using the cache key above.
- Cursor: a GitHub-push webhook re-indexes the marketplace on Cursor's side; clients pull on next refresh (window focus or periodic). If a specific user is stuck, the working fallback is Settings → Plugins → manual Refresh, and as a last resort clearing
~/.cursor/plugins/cache/<marketplace>/<plugin>/ and reinstalling. Forum reports show Cursor's auto-refresh can be flaky in practice.
No client requires a full reinstall on a normal version bump.
Open the PR
git checkout -b <short-slug>
git add -A
git commit -m "<plugin-name>: <what changed>"
git push -u origin HEAD
gh pr create --repo leancodepl/ai-plugins \
--title "<plugin-name>: <what changed>" \
--body "<one paragraph: what and why; mention any breaking changes>"
If gh is not installed, push the branch and open the PR via the GitHub web UI. The PR description should answer: what changed, why, and which plugins it touches.
CI is the safety net
Every PR runs three checks, all on GitHub Actions:
- Structure — manifest fields, marketplace registration, file shape.
- Generated rules in sync — fails if you changed a rule but forgot to regenerate.
- Lint — Go and Python formatters/linters for repo tooling.
Contributors do not need to install Go locally. Watch the verdicts with:
gh pr checks <pr-number>
A green PR means the shape is correct. Review focuses on guidance quality, not boilerplate.
What NOT to do
- Do not hand-edit
cursor-rules/ or claude-rules/. They are generated.
- Do not bundle changes across multiple plugins in a single PR. One plugin per PR keeps review tight.
- Do not ship a Claude Code-visible change without bumping
plugin.json.version — see "Versioning" above.
- Do not invent guidance that is not grounded in real usage. If you cannot point at a concrete reason for a rule or skill claim, leave it out.
- Do not enumerate plugins or clients from memory — read the source of truth.