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
1 change: 1 addition & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "han",
"owner": {
"name": "The Bushido Collective",
Expand Down
110 changes: 110 additions & 0 deletions .github/workflows/validate-plugins.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Validate Plugins

on:
pull_request:
paths:
- "plugins/**"
- "examples/**"
- ".claude-plugin/marketplace.json"
- "packages/han/lib/commands/plugin/generate-hooks.ts"
- "packages/han/lib/hooks/**"
- ".github/workflows/validate-plugins.yml"
push:
branches:
- main
paths:
- "plugins/**"
- "examples/**"
- ".claude-plugin/marketplace.json"
- "packages/han/lib/commands/plugin/generate-hooks.ts"
- "packages/han/lib/hooks/**"
- ".github/workflows/validate-plugins.yml"
workflow_dispatch:

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.2"

- name: Install dependencies
run: bun install --frozen-lockfile
working-directory: ./packages/han

- name: Generate build-info stub
working-directory: ./packages/han
run: |
cat > lib/build-info.generated.ts << 'EOF'
// Auto-generated stub for CI
export const HAN_VERSION = "0.0.0-ci";
export const DETECT_PLUGINS_PROMPT = "You are a plugin detector.";
export const version = "0.0.0-ci";
export const gitCommit = "ci";
export const buildDate = new Date().toISOString();
export const platform = "linux";
export const arch = "x64";
EOF

- name: Check generated hooks.json is up to date
working-directory: ./packages/han
run: |
if ! bun run lib/main.ts plugin generate-hooks --all --check; then
echo "::error::One or more hooks/hooks.json files are stale. Run 'han plugin generate-hooks --all' and commit the result."
exit 1
fi

- name: Validate plugins
run: |
han_cli="$PWD/packages/han/lib/main.ts"

plugin_list="$(mktemp)"
find plugins examples -type d -name .claude-plugin | sort > "$plugin_list"

plugin_dirs=()
while IFS= read -r claude_plugin_dir; do
plugin_dirs+=("${claude_plugin_dir%/.claude-plugin}")
done < "$plugin_list"
rm -f "$plugin_list"

echo "Discovered ${#plugin_dirs[@]} plugin(s)."
if [ "${#plugin_dirs[@]}" -eq 0 ]; then
echo "::error::No plugin directories discovered. Plugin validation would pass vacuously."
exit 1
fi

validated=0
failed_dirs=()

for plugin_dir in "${plugin_dirs[@]}"; do
echo "::group::$plugin_dir"
if (cd "$plugin_dir" && bun "$han_cli" plugin validate < /dev/null); then
echo "ok"
else
failed_dirs+=("$plugin_dir")
fi
validated=$((validated + 1))
echo "::endgroup::"
done

echo "Validated $validated plugin(s) of ${#plugin_dirs[@]} discovered, ${#failed_dirs[@]} failed."

if [ "$validated" -ne "${#plugin_dirs[@]}" ]; then
echo "::error::Validated $validated plugin(s) but discovered ${#plugin_dirs[@]}. Discovery and validation disagree."
exit 1
fi

if [ "${#failed_dirs[@]}" -gt 0 ]; then
for plugin_dir in "${failed_dirs[@]}"; do
echo " - $plugin_dir"
done
echo "::error::${#failed_dirs[@]} plugin(s) failed 'han plugin validate'."
exit 1
fi
93 changes: 51 additions & 42 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,31 @@ Create validation hooks for languages, frameworks, or tools.
plugins/languages/{name}/ # or plugins/validation/{name}/
├── .claude-plugin/
│ └── plugin.json
├── han-plugin.yml
├── hooks/
│ └── hooks.json
│ └── hooks.json # Generated, do not hand-edit
├── skills/ # Optional
└── README.md
```

**Example hooks.json:**

```json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "han hook run --fail-fast --dirs-with package.json -- npm test"
}
]
}
],
"SubagentStop": [
{
"hooks": [
{
"type": "command",
"command": "han hook run --fail-fast --dirs-with package.json -- npm test"
}
]
}
]
}
}
**Example `han-plugin.yml`:**

```yaml
hooks:
test:
command: npm test
dirs_with:
- package.json
description: Run the project's test suite
if_changed:
- "**/*.ts"
- "**/*.test.ts"
```

Hooks default to the `Stop` and `SubagentStop` events, so most validation plugins do not need an explicit `event:` key. Generate `hooks/hooks.json` from that file rather than writing it by hand:

```bash
han plugin generate-hooks plugins/languages/{name}
```

### 🛤️ New Discipline Plugins
Expand Down Expand Up @@ -172,15 +164,15 @@ You can also use natural language prompts to create plugins. Here are example pr

```
Add a validation plugin for <tool-name> that validates <what it validates>.
It should use --dirs-with <marker-file> and run <validation-command>.
It should use dirs_with <marker-file> and run <validation-command>.
Include skills for <skill-topics>.
```

**Real Example:**

```
Add a validation plugin for kubernetes that validates manifests.
It should use --dirs-with *.yaml,*.yml and run kubeconform.
It should use dirs_with *.yaml,*.yml and run kubeconform.
Include skills for kubernetes-manifests, kubernetes-resources, and kubernetes-security.
```

Expand Down Expand Up @@ -281,7 +273,7 @@ When you request plugin generation, Claude will:

After Claude generates files, review:

1. **Hook Commands**: Ensure they use `han hook run --fail-fast --dirs-with`
1. **Hook Commands**: Ensure hooks are declared in `han-plugin.yml` and `hooks/hooks.json` was regenerated with `han plugin generate-hooks`
2. **Marker Files**: Verify marker files match project types
3. **Skills**: Check that skills are comprehensive and accurate
4. **Examples**: Ensure code examples are correct and follow best practices
Expand Down Expand Up @@ -400,17 +392,26 @@ npm test

## Validation Hook Guidelines

### Use han hook run
### Declare hooks in han-plugin.yml

All validation plugins should use the `han hook run` command:
Validation plugins declare their hooks in `han-plugin.yml`, then generate `hooks/hooks.json` from it:

```json
{
"type": "command",
"command": "han hook run --fail-fast --dirs-with <marker-file> -- <test-command>"
}
```yaml
hooks:
test:
command: <test-command>
dirs_with:
- <marker-file>
```

```bash
han plugin generate-hooks
```

The generated `hooks.json` wires each hook to `han hook run <plugin> <hook>`. The older inline form, `han hook run --dirs-with <marker> -- <command>`, still works but is legacy: it cannot express `if_changed`, dependencies, event selection, or `${HAN_FILES}` targeting.

There is no `--fail-fast` flag. Earlier documentation prescribed one; it does not exist in the CLI.

### Choose Appropriate Marker Files

- `package.json` - JavaScript/TypeScript projects
Expand All @@ -427,14 +428,22 @@ Don't add redundant error messages after the hook command - it handles errors au

**Good:**

```json
"command": "han hook run --fail-fast --dirs-with package.json -- npm test"
```yaml
hooks:
test:
command: npm test
dirs_with:
- package.json
```

**Bad:**

```json
"command": "han hook run --fail-fast --dirs-with package.json -- npm test || (echo 'Tests failed'; exit 2)"
```yaml
hooks:
test:
command: npm test || (echo 'Tests failed'; exit 2)
dirs_with:
- package.json
```

## Review Process
Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![GitHub Release](https://img.shields.io/github/v/release/thebushidocollective/han)](https://github.com/thebushidocollective/han/releases)
[![codecov](https://codecov.io/gh/thebushidocollective/han/graph/badge.svg)](https://codecov.io/gh/thebushidocollective/han)

Ship-ready code from your AI coding agent. 139+ plugins for quality gates, tooling, memory, and specialized agents — so your AI writes code that's ready to merge.
Ship-ready code from your AI coding agent. 340 plugins for quality gates, tooling, memory, and specialized agents, so your AI writes code that's ready to merge.

## Getting Started

Expand Down Expand Up @@ -35,16 +35,19 @@ brew install thebushidocollective/tap/han

## Plugin Categories

139 plugins across six categories:
340 plugins across nine categories:

| Category | Description | Examples |
|----------|-------------|----------|
| **Core** | Essential infrastructure. Auto-installs han binary, provides metrics and MCP servers | Always required |
| **Languages** | Validation plugins for your language/runtime | TypeScript, Rust, Python, Go, Ruby |
| **Validation** | Linters, formatters, and quality tools | Biome, ESLint, ShellCheck, Pytest |
| **Disciplines** | Specialized AI agents for engineering domains | Security, accessibility, API design, architecture |
| **Services** | MCP servers for external platforms | GitHub, GitLab, Linear |
| **Tools** | MCP servers for development utilities | Playwright, Blueprints, Context7 |
| **Core** | Essential infrastructure. Auto-installs the han binary, provides metrics and MCP servers | core, bushido |
| **Language** | Deep knowledge of a programming language | TypeScript, Rust, Python, Go, Ruby |
| **Framework** | Web, mobile, and backend framework expertise | React, Next.js, Django, Rails, Phoenix |
| **Validation** | Linters, formatters, and static analysis | Biome, ESLint, RuboCop, ShellCheck |
| **Tool** | Build systems, test runners, and dev utilities | Playwright, Jest, Pytest, Terraform |
| **Integration** | MCP servers for external services | GitHub, GitLab, Linear, Sentry |
| **Discipline** | Specialized AI agents for engineering domains | Security, accessibility, API design, architecture |
| **Pattern** | Methodologies and workflow practices | TDD, BDD, AI-DLC, git worktrees |
| **Specialized** | Domain-specific plugins that don't fit elsewhere | Android, iOS, embedded |

Browse all plugins at [han.guru/plugins](https://han.guru/plugins/)

Expand Down
Loading
Loading