diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..a1e7616 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,14 @@ +{ + "name": "holdex", + "description": "Holdex workflows as agent skills: contributing rules for issues and PRs, bug attribution, and time tracking.", + "owner": { + "name": "Holdex" + }, + "plugins": [ + { + "name": "holdex", + "source": "./", + "description": "Holdex workflows as agent skills: contributing rules for issues and PRs, bug attribution, and time tracking." + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..6eb68f2 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "holdex", + "description": "Holdex workflows as agent skills: contributing rules for issues and PRs, bug attribution, and time tracking.", + "author": { + "name": "Holdex" + }, + "homepage": "https://github.com/holdex/developers", + "repository": "https://github.com/holdex/developers", + "keywords": ["holdex", "contributing", "workflow"] +} diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json new file mode 100644 index 0000000..56aac41 --- /dev/null +++ b/.cursor-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "name": "holdex", + "owner": { + "name": "Holdex" + }, + "metadata": { + "description": "Holdex workflows as agent skills" + }, + "plugins": [ + { + "name": "holdex", + "source": ".", + "description": "Holdex workflows as agent skills: contributing rules for issues and PRs, bug attribution, and time tracking.", + "skills": "skills" + } + ] +} diff --git a/README.md b/README.md index a6aee32..e33ad2a 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,39 @@ merges. The `main` branch is the published source of truth, and merged changes are live for the whole organization immediately. There is no separate hosting to deploy. -## Claude Code Skills +## Skills and plugins -Clone this repository locally and symlink the commands directory to make all -skills available globally across every repo you work in: +The workflows live as standard Agent Skills in `skills/`, and the repository +itself is packaged as a plugin, so any supported tool can install them. + +Any coding agent — Claude Code, Codex, Cursor, OpenCode, Copilot, and more: + +```bash +npx skills add holdex/developers +``` + +Add `-g` to install them globally for every repo you work in, and run +`npx skills update` to pick up changes after pulling the repo. + +Claude Code, as a plugin from the built-in marketplace: ```bash -ln -s /path/to/holdex/developers/.claude/commands ~/.claude/commands +claude plugin marketplace add holdex/developers +claude plugin install holdex@holdex ``` -Skills stay up to date automatically as you pull the repo. Available skills: +Each skill then runs as `/holdex:`, with the bare `/` +working when no other command claims it. + +Cursor, from the repository: open Customize and import `holdex/developers` as a +marketplace, then install the `holdex` plugin from it. + +The repository is also a conformant Agent Plugin (a root `plugin.json` following +the [Agent Plugins](https://agent-plugins.org) open standard), so any other +spec-conformant tool can install it directly. Available skills: -| Command | When to use | +| Skill | When to use | | --- | --- | -| `/holdex-contributing` | Before creating or updating a GitHub issue or PR in any Holdex repository | +| `holdex-contributing` | Before creating or updating a GitHub issue or PR in any Holdex repository | +| `report-bug` | Post the bug attribution comment a `fix` PR needs before review | +| `submit-time` | Record time spent on a pull request | diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..cc4f338 --- /dev/null +++ b/plugin.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "holdex", + "description": "Holdex workflows as agent skills: contributing rules for issues and PRs, bug attribution, and time tracking.", + "version": "1.0.0", + "author": { + "name": "Holdex" + }, + "homepage": "https://github.com/holdex/developers", + "repository": "https://github.com/holdex/developers", + "keywords": ["holdex", "contributing", "workflow"] +} diff --git a/.claude/commands/holdex-contributing.md b/skills/holdex-contributing/SKILL.md similarity index 74% rename from .claude/commands/holdex-contributing.md rename to skills/holdex-contributing/SKILL.md index 6a2cfbc..d672b6f 100644 --- a/.claude/commands/holdex-contributing.md +++ b/skills/holdex-contributing/SKILL.md @@ -6,7 +6,7 @@ description: Holdex contributing rules for GitHub issues and PRs. Invoke before # Holdex Contributing All PRs and issues must follow the -[Holdex Contributing Guidelines](https://github.com/holdex/developers/blob/main/docs/CONTRIBUTING.md). +[Holdex Contributing Guidelines][contributing]. ## Issues @@ -29,20 +29,25 @@ All PRs and issues must follow the - Good: `docs: protect client funds from unauthorized contractor custody` - Bad: `Add FUND_HANDLING.md` - **Scope**: one `type(scope): action`, 3 to 15 minutes of work, per - [DEV-320](../../docs/rules/DEV-320.md). Decompose if larger. + [DEV-320][dev-320]. Decompose if larger. - **`fix` PRs**: must carry a `@holdex bug commit && bug author @` comment attributing - the commit/author that introduced the bug — use the `/report-bug` command. - Required before marking ready for review. + the commit/author that introduced the bug — use the `/report-bug` skill + (`/holdex:report-bug` when installed as a Claude Code plugin). Required before + marking ready for review. - **Lifecycle** (in order): 1. Open as a **draft PR** immediately when starting work. 1. Link to the Problem issue using a closing keyword (`Closes #123`). 1. Assign yourself. 1. If the PR title starts with `fix`, post the bug attribution comment - (`/report-bug`). + (`/report-bug`, or `/holdex:report-bug` as a Claude Code plugin). 1. Resolve all CI checks. 1. Assign a reviewer when DEV-405 requires a human (a security change, or a Spec others work from). 1. Mark ready for review only when all steps above are done. - **Do not merge** until agent review is clean and CI passes, per - [DEV-405](../../docs/rules/DEV-405.md). You merge it and own the result. + [DEV-405][dev-405]. You merge it and own the result. + +[contributing]: https://github.com/holdex/developers/blob/main/docs/CONTRIBUTING.md +[dev-320]: https://github.com/holdex/developers/blob/main/docs/rules/DEV-320.md +[dev-405]: https://github.com/holdex/developers/blob/main/docs/rules/DEV-405.md diff --git a/.claude/commands/report-bug.md b/skills/report-bug/SKILL.md similarity index 55% rename from .claude/commands/report-bug.md rename to skills/report-bug/SKILL.md index 92fa17f..31d99cb 100644 --- a/.claude/commands/report-bug.md +++ b/skills/report-bug/SKILL.md @@ -1,52 +1,57 @@ -Post a `@holdex bug commit` or `@holdex bug dispute` comment on a pull -request to attribute the commit and author that introduced a bug. +--- +name: report-bug +description: Post a `@holdex bug commit` or `@holdex bug dispute` comment on a pull request to attribute the commit and author that introduced a bug. Required for every `fix` PR before it is ready for review. +--- -**Required for every PR whose title starts with `fix` (Conventional -Commits type).** A `fix` PR is not ready for review until this comment is -posted — it's how the original bug source gets attributed. +# Report Bug + +Post a `@holdex bug commit` or `@holdex bug dispute` comment on a pull request +to attribute the commit and author that introduced a bug. + +**Required for every PR whose title starts with `fix` (Conventional Commits +type).** A `fix` PR is not ready for review until this comment is posted — it's +how the original bug source gets attributed. ## Input -`$ARGUMENTS` holds the commit URL and the GitHub handle of the commit's -author, optionally prefixed with `dispute` to correct a previous report -instead of filing a new one: +`$ARGUMENTS` holds the commit URL and the GitHub handle of the commit's author, +optionally prefixed with `dispute` to correct a previous report instead of +filing a new one: -- ` @` — report the commit/author that introduced - the bug (e.g. - `https://github.com/holdex/my-repo/commit/1234567890 @usershandle`). -- `dispute @` — dispute a previous bug report - after the PR it was filed on has already been merged, to correct an - incorrect attribution. +- ` @` — report the commit/author that introduced the + bug (e.g. `https://github.com/holdex/my-repo/commit/1234567890 @usershandle`). +- `dispute @` — dispute a previous bug report after + the PR it was filed on has already been merged, to correct an incorrect + attribution. If `$ARGUMENTS` is empty, ask the user for the commit URL and the author's GitHub handle before proceeding. Determine which mode applies: -- No `dispute` prefix: **report** — attribute the commit/author that - introduced the bug this PR fixes. -- `dispute` prefix: **dispute** — strip the `dispute` prefix to get the - commit URL and handle; use this to correct a wrong attribution after - merge. +- No `dispute` prefix: **report** — attribute the commit/author that introduced + the bug this PR fixes. +- `dispute` prefix: **dispute** — strip the `dispute` prefix to get the commit + URL and handle; use this to correct a wrong attribution after merge. -Validate the input against strict patterns — reject anything that doesn't -fully match, don't just check a prefix: +Validate the input against strict patterns — reject anything that doesn't fully +match, don't just check a prefix: - Commit URL must match `^https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+/(commit|pull/[0-9]+/(commits|changes))/[0-9a-f]{7,40}$`. -- Handle must match `^@[A-Za-z0-9](-?[A-Za-z0-9])*$` (a bare GitHub - username, `@` + up to 39 alphanumeric/hyphen characters, no spaces or - shell metacharacters). +- Handle must match `^@[A-Za-z0-9](-?[A-Za-z0-9])*$` (a bare GitHub username, + `@` + up to 39 alphanumeric/hyphen characters, no spaces or shell + metacharacters). -If either fails to match, tell the user and stop — don't attempt to sanitize -or partially accept it. +If either fails to match, tell the user and stop — don't attempt to sanitize or +partially accept it. ## Resolve the PR -Detect the current PR from the git worktree. **Report** mode targets the -PR still in progress, so open PRs are enough. **Dispute** mode corrects a -PR that "has already been merged" (per its own description above), so the -lookup must include closed/merged PRs too: +Detect the current PR from the git worktree. **Report** mode targets the PR +still in progress, so open PRs are enough. **Dispute** mode corrects a PR that +"has already been merged" (per its own description above), so the lookup must +include closed/merged PRs too: ```bash # report @@ -56,20 +61,18 @@ gh pr list --head "$(git branch --show-current)" --json number,url,title --limit gh pr list --head "$(git branch --show-current)" --state all --json number,url,title,comments --limit 1 ``` -If no PR is found for the current branch, ask the user for the PR number or -URL. +If no PR is found for the current branch, ask the user for the PR number or URL. -If the PR title does not start with `fix`, confirm with the user that they -still want to post a bug report comment before continuing — this command is -only required for `fix` PRs, but can be used on any PR. +If the PR title does not start with `fix`, confirm with the user that they still +want to post a bug report comment before continuing — this skill is only +required for `fix` PRs, but can be used on any PR. For **dispute** mode specifically, before posting: check the resolved PR's -comments for a prior `@holdex bug commit && bug author -` comment whose commit URL matches the one given in `$ARGUMENTS` -(the handle is expected to differ — that's the attribution being -corrected). Require exactly one such PR/comment match. If none match, or -more than one PR matches the branch/commit, stop without posting and tell -the user why instead of guessing. +comments for a prior `@holdex bug commit && bug author ` +comment whose commit URL matches the one given in `$ARGUMENTS` (the handle is +expected to differ — that's the attribution being corrected). Require exactly +one such PR/comment match. If none match, or more than one PR matches the +branch/commit, stop without posting and tell the user why instead of guessing. ## Post the comment diff --git a/.claude/commands/submit-time.md b/skills/submit-time/SKILL.md similarity index 82% rename from .claude/commands/submit-time.md rename to skills/submit-time/SKILL.md index dadb43b..436b03e 100644 --- a/.claude/commands/submit-time.md +++ b/skills/submit-time/SKILL.md @@ -1,4 +1,12 @@ -Post a `@holdex pr submit-time` or `@holdex pr add-time` comment on a pull request to record time spent. +--- +name: submit-time +description: Post a `@holdex pr submit-time` or `@holdex pr add-time` comment on a pull request to record time spent. +--- + +# Submit Time + +Post a `@holdex pr submit-time` or `@holdex pr add-time` comment on a pull +request to record time spent. ## Input @@ -12,8 +20,8 @@ Determine which mode applies: - No `add` prefix: **submit/update total time** — replaces any previously recorded time for this PR with the given value. -- `add` prefix: **add time on top of the previous submission** — strip the - `add` prefix to get the time value. +- `add` prefix: **add time on top of the previous submission** — strip the `add` + prefix to get the time value. Validate the time format — accepted patterns: `15m`, `1h`, `2h30m`, `1.5h`. If the format is invalid, tell the user and stop.