Skip to content
Back to skills

Cowork Plugin Builder

ASecurity

Guide for building custom Cowork plugins that leverage CC Commander skills. Covers plugin anatomy (manifest, handler, permissions), 5 example plugins, packaging CC Commander skills as plugins, local testing, and publishing to the plugin directory.

  • 6 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
data-aijavascriptgojavashellbashnodetestingcode-reviewgitapi

Works with

  • claude desktop
  • terminal
  • api

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add KevinZai/commander --skill cowork-plugin-builder --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cowork Plugin Builder?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cowork Plugin Builder
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kevinzai-cowork-plugin-builder/badge)](https://www.skillsdirectory.com/skills/kevinzai-cowork-plugin-builder)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cowork-plugin-builder
description: |
  Guide for building custom Cowork plugins that leverage CC Commander skills. Covers plugin
  anatomy (manifest, handler, permissions), 5 example plugins, packaging CC Commander skills
  as plugins, local testing, and publishing to the plugin directory.
triggers:
  - /cowork-plugins
  - /plugin-builder
  - /cowork-plugin
  - build cowork plugin
  - create cowork plugin
  - cowork plugin builder
  - package skill as plugin
disable-model-invocation: true
---

# Cowork Plugin Builder

## Overview

Cowork plugins extend Claude Desktop's autonomous execution with custom capabilities. This skill teaches you how to package CC Commander skills, hooks, and workflows as installable Cowork plugins.

## Plugin Anatomy

Every Cowork plugin consists of three files:

```
my-plugin/
  manifest.json    # Plugin metadata, permissions, configuration
  handler.js       # Entry point -- receives events, returns results
  README.md        # Usage docs (optional but recommended)
```

### manifest.json

```json
{
  "name": "bible-daily-standup",
  "version": "1.0.0",
  "description": "Automated daily standup using CC Commander task-commander patterns",
  "author": "Kevin Z",
  "license": "MIT",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["tasks/**", "output/**", ".claude/**"],
      "write": ["output/standups/**", "tasks/todo.md"]
    },
    "terminal": {
      "commands": ["git log *", "git status", "git diff --stat *"]
    }
  },
  "config": {
    "outputDir": {
      "type": "string",
      "default": "output/standups",
      "description": "Directory for standup reports"
    },
    "includeGitLog": {
      "type": "boolean",
      "default": true,
      "description": "Include git activity in standup"
    },
    "lookbackHours": {
      "type": "number",
      "default": 24,
      "description": "Hours of activity to include"
    }
  },
  "triggers": {
    "schedule": "0 9 * * 1-5",
    "manual": true
  },
  "bible": {
    "skills": ["session-startup", "task-commander"],
    "mode": "normal"
  }
}
```

### handler.js

```javascript
#!/usr/bin/env node
'use strict';

/**
 * Plugin handler receives a context object on stdin and writes
 * results to stdout. The context includes:
 * - project: absolute path to project directory
 * - config: merged plugin config (defaults + user overrides)
 * - trigger: what triggered this run (schedule, manual, webhook)
 * - previousRun: summary of last execution (if any)
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

let data = '';
process.stdin.on('data', chunk => data += chunk);
process.stdin.on('end', () => {
  try {
    const ctx = JSON.parse(data);
    const result = run(ctx);
    console.log(JSON.stringify(result));
  } catch (e) {
    console.log(JSON.stringify({
      status: 'error',
      error: e.message
    }));
    process.exit(1);
  }
});

function run(ctx) {
  const { project, config } = ctx;

  // Read task state
  const todoPath = path.join(project, 'tasks', 'todo.md');
  const tasks = fs.existsSync(todoPath)
    ? fs.readFileSync(todoPath, 'utf8')
    : 'No tasks/todo.md found.';

  // Git activity
  let gitLog = 'Git log disabled.';
  if (config.includeGitLog) {
    try {
      gitLog = execSync(
        `git log --since="${config.lookbackHours} hours ago" --oneline`,
        { cwd: project, encoding: 'utf8', timeout: 10000 }
      ).trim() || 'No commits in the lookback window.';
    } catch {
      gitLog = 'Not a git repository or git unavailable.';
    }
  }

  // Build standup report
  const date = new Date().toISOString().split('T')[0];
  const report = [
    `# Daily Standup -- ${date}`,
    '',
    '## Task Status',
    tasks,
    '',
    '## Recent Git Activity',
    '```',
    gitLog,
    '```',
    '',
    `Generated by bible-daily-standup plugin at ${new Date().toISOString()}`
  ].join('\n');

  // Write output
  const outDir = path.join(project, config.outputDir);
  fs.mkdirSync(outDir, { recursive: true });
  const outPath = path.join(outDir, `${date}.md`);
  fs.writeFileSync(outPath, report);

  return {
    status: 'success',
    artifact: outPath,
    summary: `Standup written to ${outPath}`
  };
}
```

### Permission Model

Plugins declare permissions in `manifest.json`. Cowork enforces them at runtime:

| Permission | Scope | Example |
|---|---|---|
| `filesystem.read` | Glob patterns for read access | `["src/**", "*.md"]` |
| `filesystem.write` | Glob patterns for write access | `["output/**"]` |
| `terminal.commands` | Allowed shell command patterns | `["git *", "npm test"]` |
| `browser.urls` | Allowed URL patterns | `["https://api.github.com/*"]` |
| `network.hosts` | Allowed outbound hosts | `["localhost:3110"]` |

Users approve permissions on first install. Changes require re-approval.

## Example Plugins

### 1. Daily Standup Plugin

Generates a standup report from task state and git history.

```json
{
  "name": "bible-daily-standup",
  "version": "1.0.0",
  "description": "Morning standup from tasks/todo.md + git log",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["tasks/**", "output/**"],
      "write": ["output/standups/**"]
    },
    "terminal": { "commands": ["git log *", "git status"] }
  },
  "triggers": { "schedule": "0 9 * * 1-5" },
  "bible": { "skills": ["session-startup", "task-commander"] }
}
```

**Handler logic:**
1. Read `tasks/todo.md` for current task state
2. Run `git log --since="24 hours ago"` for recent activity
3. Identify blockers (items marked `[blocked]`)
4. Generate markdown standup report
5. Write to `output/standups/{date}.md`

### 2. Code Review Bot Plugin

Automatically reviews new PRs and posts feedback.

```json
{
  "name": "bible-code-review-bot",
  "version": "1.0.0",
  "description": "Auto-review PRs using CC Commander coding-standards skill",
  "entry": "handler.js",
  "permissions": {
    "filesystem": { "read": ["**"] },
    "terminal": { "commands": ["git *", "gh pr *", "npx tsc --noEmit"] },
    "network": { "hosts": ["api.github.com"] }
  },
  "config": {
    "severity": {
      "type": "string",
      "default": "medium",
      "description": "Minimum severity to report (low, medium, high, critical)"
    },
    "autoApprove": {
      "type": "boolean",
      "default": false,
      "description": "Auto-approve PRs with no issues found"
    }
  },
  "triggers": {
    "webhook": "github.pull_request.opened",
    "manual": true
  },
  "bible": { "skills": ["coding-standards", "review", "security-reviewer"] }
}
```

**Handler logic:**
1. Receive PR event (number, branch, author)
2. Checkout PR branch locally
3. Run typecheck (`npx tsc --noEmit`)
4. Analyze diff against coding-standards skill rules
5. Check for security issues per pentest-checklist skill
6. Write review to `output/reviews/pr-{number}.md`
7. Post review comment via `gh pr review`

### 3. Dependency Updater Plugin

Checks and updates dependencies with safety checks.

```json
{
  "name": "bible-dependency-updater",
  "version": "1.0.0",
  "description": "Safe dependency updates with test verification",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["package*.json", "pnpm-lock.yaml", "src/**", "tests/**"],
      "write": ["package*.json", "pnpm-lock.yaml", "output/deps/**"]
    },
    "terminal": {
      "commands": [
        "npm outdated *", "npm audit *", "npm update *",
        "pnpm outdated *", "pnpm update *",
        "npx tsc --noEmit", "npm test", "pnpm test",
        "git *"
      ]
    }
  },
  "config": {
    "updateType": {
      "type": "string",
      "default": "minor",
      "description": "Max update level: patch, minor, major"
    },
    "createPR": {
      "type": "boolean",
      "default": true,
      "description": "Create PR for updates"
    }
  },
  "triggers": { "schedule": "0 6 * * 1" },
  "bible": { "skills": ["verification-loop"] }
}
```

**Handler logic:**
1. Run `npm outdated` / `pnpm outdated` to list available updates
2. Filter by update type (patch/minor/major)
3. For each update: install, typecheck, run tests
4. If tests pass: keep update. If tests fail: revert and log.
5. Create branch `deps/update-{date}` with passing updates
6. Write report to `output/deps/{date}.md`
7. Optionally create PR via `gh pr create`

### 4. Test Runner Plugin

Runs test suite and generates coverage report.

```json
{
  "name": "bible-test-runner",
  "version": "1.0.0",
  "description": "Scheduled test runner with coverage tracking",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["src/**", "tests/**", "vitest.config.*", "package.json"],
      "write": ["output/tests/**", "coverage/**"]
    },
    "terminal": {
      "commands": ["npm test *", "pnpm test *", "npx vitest *", "npx jest *"]
    }
  },
  "config": {
    "coverageThreshold": {
      "type": "number",
      "default": 80,
      "description": "Minimum coverage percentage"
    },
    "failOnDecrease": {
      "type": "boolean",
      "default": true,
      "description": "Fail if coverage decreased since last run"
    }
  },
  "triggers": {
    "schedule": "0 */6 * * *",
    "manual": true
  },
  "bible": { "skills": ["tdd-workflow", "verification-loop"] }
}
```

**Handler logic:**
1. Run test suite with coverage enabled
2. Parse coverage report (JSON format)
3. Compare against previous run (stored in `output/tests/coverage-history.json`)
4. Flag coverage decreases if `failOnDecrease` is true
5. Write report to `output/tests/{date}.md`
6. Update coverage history

### 5. Report Generator Plugin

Batch-generates reports from templates and data sources.

```json
{
  "name": "bible-report-generator",
  "version": "1.0.0",
  "description": "Generate reports from templates using CC Commander patterns",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["templates/**", "data/**", "output/**"],
      "write": ["output/reports/**"]
    },
    "terminal": {
      "commands": ["git log *", "wc *"]
    }
  },
  "config": {
    "templateDir": {
      "type": "string",
      "default": "templates/reports",
      "description": "Directory containing report templates"
    },
    "dataDir": {
      "type": "string",
      "default": "data",
      "description": "Directory containing data sources"
    }
  },
  "triggers": {
    "schedule": "0 17 * * 5",
    "manual": true
  },
  "bible": { "skills": ["business-analytics"] }
}
```

**Handler logic:**
1. Scan template directory for `.md` templates
2. For each template: load data sources referenced in frontmatter
3. Fill template variables from data
4. Generate formatted report
5. Write to `output/reports/{template-name}-{date}.md`

## Packaging CC Commander Skills as Plugins

### Step-by-Step

1. **Identify the skill** -- pick a SKILL.md from `~/.claude/skills/`
2. **Extract the logic** -- determine what tools/commands the skill uses
3. **Create manifest** -- declare permissions matching the skill's requirements
4. **Write handler** -- implement the skill's workflow in JavaScript
5. **Test locally** -- verify with `cowork test` command
6. **Package** -- zip the plugin directory

### Skill-to-Plugin Mapping

```
SKILL.md section        -> manifest.json field
---
name                    -> name (prefix with "bible-")
description             -> description
triggers                -> triggers
allowed-tools           -> permissions (map tool names to plugin permissions)
```

### Converting a Skill

Example: converting `overnight-runner` skill to a plugin.

**Original skill uses:**
- Bash (terminal commands)
- Read/Write (filesystem access)
- Checkpoint files

**Plugin manifest:**
```json
{
  "name": "bible-overnight-runner",
  "version": "1.0.0",
  "entry": "handler.js",
  "permissions": {
    "filesystem": {
      "read": ["tasks/**", "output/**", "CLAUDE.md"],
      "write": ["tasks/checkpoint.json", "output/**", "logs/**"]
    },
    "terminal": {
      "commands": [
        "git *", "npm *", "pnpm *", "npx *",
        "node *", "terminal-notifier *"
      ]
    }
  },
  "config": {
    "maxRetries": { "type": "number", "default": 5 },
    "retryDelaySeconds": { "type": "number", "default": 1800 },
    "notifyOnComplete": { "type": "boolean", "default": true }
  },
  "triggers": {
    "schedule": "0 1 * * *",
    "manual": true
  }
}
```

**Handler wraps the retry/checkpoint pattern:**
```javascript
function run(ctx) {
  const checkpointPath = path.join(ctx.project, 'tasks', 'checkpoint.json');

  let checkpoint = { status: 'not-started', completedItems: 0 };
  try {
    checkpoint = JSON.parse(fs.readFileSync(checkpointPath, 'utf8'));
  } catch {
    // Fresh start
  }

  if (checkpoint.status === 'complete') {
    return { status: 'success', summary: 'Already complete.' };
  }

  // Execute batch with checkpoint updates
  // (handler delegates to Claude for actual processing)
  return {
    status: 'delegated',
    task: `Resume from checkpoint: ${JSON.stringify(checkpoint)}`,
    skills: ['overnight-runner'],
    maxTurns: 100
  };
}
```

## Testing Plugins Locally

### Manual Test

```bash
# Create test input
echo '{"project":"/path/to/project","config":{"outputDir":"output/test"},"trigger":"manual"}' | node handler.js
```

### Cowork Test Command

```bash
# Validate manifest
cowork plugin validate ./my-plugin/

# Dry run (no side effects)
cowork plugin test ./my-plugin/ --dry-run

# Full test run
cowork plugin test ./my-plugin/ --project /path/to/test-project
```

### Test Checklist

- [ ] Handler reads stdin JSON without error
- [ ] Handler writes valid JSON to stdout
- [ ] All file paths stay within declared permissions
- [ ] Terminal commands match declared patterns
- [ ] Config defaults produce valid behavior
- [ ] Error cases return `{ "status": "error", "error": "message" }`
- [ ] No hardcoded paths (use `ctx.project` as base)
- [ ] No secrets in manifest or handler

## Publishing to Plugin Directory

### Package Structure

```bash
# Create distributable
cd my-plugin/
zip -r bible-my-plugin-1.0.0.zip manifest.json handler.js README.md
```

### Plugin Directory Submission

1. **Test thoroughly** -- local testing must pass all checklist items
2. **Version correctly** -- follow semver (major.minor.patch)
3. **Write README** -- include usage examples and configuration reference
4. **Submit** -- push to plugin registry or share as a zip

### Versioning

- **Patch** (1.0.1) -- bug fixes, no config changes
- **Minor** (1.1.0) -- new features, backward-compatible config
- **Major** (2.0.0) -- breaking config changes, new permissions

## Best Practices

1. **Minimal permissions** -- request only what the plugin needs
2. **Fail gracefully** -- always return valid JSON, even on error
3. **Idempotent** -- running twice should not corrupt state
4. **Checkpoint state** -- write progress to disk for crash recovery
5. **No secrets in code** -- use environment variables or vault references
6. **Test with real projects** -- synthetic tests miss permission edge cases
7. **Document config** -- every config field needs a description
8. **Respect cost limits** -- if delegating to Claude, set maxTurns
9. **Prefix with "cc-"** -- clear naming convention for CC Commander-derived plugins
10. **Include skill references** -- the `bible.skills` field in manifest helps users understand provenance

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…