Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d78f927
feat(claude-code): add the Claude Code plugin package
BrainerVirus Oct 3, 2026
2caa7f2
feat(claude-code): publish the plugin through a git-hosted marketplace
BrainerVirus Oct 3, 2026
c8366d1
feat(claude-code): detect, install and doctor Claude Code from the CLI
BrainerVirus Oct 3, 2026
08113cd
test(claude-code): add an opt-in `claude plugin eval` suite
BrainerVirus Oct 3, 2026
964b4a1
docs(claude-code): document both Claude Code install modes
BrainerVirus Oct 3, 2026
4c87c4f
test(claude-code): give the full-doctor claude_plugin test a CI-sized…
BrainerVirus Oct 3, 2026
7e88c46
Merge remote-tracking branch 'origin/main' into feature/claude-code-a…
BrainerVirus Oct 3, 2026
4a57a6b
fix(claude-code): register only effective hooks; harden the launcher …
BrainerVirus Oct 3, 2026
23b6f74
fix(core): give the Claude Code worktree implementer write guidance o…
BrainerVirus Oct 3, 2026
91bcc0c
fix(release): republish bundling packages and attempt every publish
BrainerVirus Oct 3, 2026
163734f
feat(claude-code): uninstall Claude Code through the native plugin co…
BrainerVirus Oct 3, 2026
5bfdadf
docs(claude-code): document registered hooks, fail-open and uninstall
BrainerVirus Oct 3, 2026
ceb987a
fix(release): republish every adapter whose dist inlines core, MCP or…
BrainerVirus Oct 3, 2026
84874eb
Merge remote-tracking branch 'origin/main' into feature/claude-code-a…
BrainerVirus Oct 4, 2026
6e17704
chore(claude-code): align the plugin version with the 2.2.0 release
BrainerVirus Oct 4, 2026
31bbdd4
fix(release): count the lockfile and inlined manifests as bundled pay…
BrainerVirus Oct 4, 2026
df0a743
fix(core): grant worktree write guidance only to workit:implementer
BrainerVirus Oct 4, 2026
8673c67
fix(claude-code): scope-aware Claude Code detection, doctor and unins…
BrainerVirus Oct 4, 2026
9421607
test(claude-code): isolate and time-box the full-doctor claude_plugin…
BrainerVirus Oct 4, 2026
ca12d64
fix(release): republish on inlined dependency versions, not any lockf…
BrainerVirus Oct 4, 2026
450b8f2
Merge remote-tracking branch 'origin/main' into feature/claude-code-a…
BrainerVirus Oct 4, 2026
d6c4e73
chore(claude-code): align the plugin version with the 2.2.1 release
BrainerVirus Oct 4, 2026
c675636
test(claude-code): check plugin version lockstep via the manifest syn…
BrainerVirus Oct 4, 2026
5a1e2dc
Merge branch 'main' into feature/claude-code-adapter
BrainerVirus Oct 4, 2026
99d5cda
test(claude-code): derive packed plugin versions from the tree
BrainerVirus Oct 4, 2026
9657384
Merge branch 'main' into feature/claude-code-adapter
BrainerVirus Oct 4, 2026
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
21 changes: 21 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "workit",
"description": "Workit for Claude Code: workflow rails for agentic coding (task context, branch policy, method skills, and verification agents)",
"owner": {
"name": "BrainerVirus",
"url": "https://github.com/BrainerVirus"
},
"plugins": [
{
"name": "workit",
"description": "Session and per-turn task context, branch policy on git shell commands, the workit method skills, and verifier/reviewer/implementer agents",
"source": {
"source": "npm",
"package": "@brainervirus/workit-claude-code"
},
"homepage": "https://github.com/BrainerVirus/workit#readme",
"license": "MIT",
"category": "development"
}
]
}
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ env:
NODE_CURRENT: "24.20.0"
OPENCODE_MINIMUM: "1.18.30"
OPENCODE_CURRENT: "1.18.34"
CLAUDE_CODE_VERSION: "2.1.288"
ACTIONLINT_VERSION: "1.7.12"
ACTIONLINT_SHA256: "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8"
ZIZMOR_VERSION: "1.30.1"
Expand Down Expand Up @@ -142,6 +143,23 @@ jobs:
- name: Build packages
run: bun run build

# S14 PR gate: the real Claude Code CLI (pinned in the support matrix)
# validates the built plugin and the root marketplace in strict mode.
# No credential is needed; the packaging tier reuses this binary through
# WORKIT_CLAUDE_BIN to validate and install the packed plugin.
- name: Validate Claude Code plugin and marketplace
run: | # zizmor: ignore[adhoc-packages] -- exact support-matrix pin
set -euo pipefail
# Exact version pinned in the support matrix (no lockfile for a CLI tool).
npm install --no-save --prefix "$RUNNER_TEMP/claude" "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"
claude="$RUNNER_TEMP/claude/node_modules/.bin/claude"
export HOME="$RUNNER_TEMP/claude-home" CLAUDE_CONFIG_DIR="$RUNNER_TEMP/claude-home/.claude"
mkdir -p "$CLAUDE_CONFIG_DIR"
"$claude" --version
"$claude" plugin validate --strict packages/workit-claude-code
"$claude" plugin validate --strict .
echo "WORKIT_CLAUDE_BIN=$claude" >> "$GITHUB_ENV"

# Both tiers together cover every test directory (scripts/test.ts):
# the unit tier excludes exactly the packaging suites.
- name: Test (unit tier)
Expand Down
84 changes: 84 additions & 0 deletions .github/workflows/claude-eval.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Claude Code plugin eval

# Opt-in behavioral eval of the Claude Code plugin (design S14, §0 #15): it
# needs a Claude credential, costs money, and is nondeterministic, so it is a
# nightly / `eval`-label job, never a PR gate. The deterministic PR gate is
# `claude plugin validate --strict` plus the hook-fixture suite in ci.yml.
on:
schedule:
- cron: "17 5 * * *"
pull_request:
types: [labeled, synchronize]
branches: [main]
workflow_dispatch:

permissions: {}

concurrency:
group: claude-eval-${{ github.ref }}
cancel-in-progress: true

env:
BUN_VERSION: "1.4.1"
NODE_CURRENT: "24.20.0"
CLAUDE_CODE_VERSION: "2.1.288"

jobs:
eval:
name: claude plugin eval
if: >
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'eval')
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: ${{ env.BUN_VERSION }}

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ env.NODE_CURRENT }}

- name: Install deps
run: bun install --frozen-lockfile

# The suite runs against the checkout (local-pin layout): the hooks and
# bin/workit run from source with bun; only skills are generated.
- name: Generate plugin skills
run: bun packages/workit-claude-code/scripts/build.ts --skills-only

- name: Run eval suite
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: | # zizmor: ignore[adhoc-packages] -- exact support-matrix pin
set -euo pipefail
if [[ -z "${ANTHROPIC_API_KEY}" ]]; then
echo "::warning::ANTHROPIC_API_KEY is not configured; skipping the Claude Code eval"
exit 0
fi
# Exact version pinned in the support matrix (no lockfile for a CLI tool).
npm install --no-save --prefix "$RUNNER_TEMP/claude" "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"
export HOME="$RUNNER_TEMP/claude-home" CLAUDE_CONFIG_DIR="$RUNNER_TEMP/claude-home/.claude"
mkdir -p "$CLAUDE_CONFIG_DIR"
"$RUNNER_TEMP/claude/node_modules/.bin/claude" plugin eval packages/workit-claude-code \
--trust-plugin --scaffold --allow-tools Bash \
--runs 1 -j 2 --max-cost-usd 2 --threshold 0.8 \
--no-publish --json "$RUNNER_TEMP/eval-results.json" \
--output-dir "$RUNNER_TEMP/eval-out"

- name: Upload eval results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: claude-eval
path: |
${{ runner.temp }}/eval-results.json
${{ runner.temp }}/eval-out
if-no-files-found: ignore
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
# checks-triggering runner must then finish it).
GH_TOKEN: ${{ secrets.RELEASE_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
run: |
MANIFESTS=(package.json 'packages/*/package.json' 'packages/workit-cursor/.cursor-plugin/plugin.json' 'packages/workit-codex/.codex-plugin/plugin.json')
MANIFESTS=(package.json 'packages/*/package.json' 'packages/workit-cursor/.cursor-plugin/plugin.json' 'packages/workit-codex/.codex-plugin/plugin.json' 'packages/workit-claude-code/.claude-plugin/plugin.json')
git checkout -- "${MANIFESTS[@]}" 2>/dev/null || true
bun packages/workit-core/scripts/sync-release-manifests.ts
if [[ -z "$(git status --porcelain -- "${MANIFESTS[@]}")" ]]; then
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ Thumbs.db
dist/
*.log
.cache/

# workit-claude-code: generated plugin skills and bundled CLI assets (scripts/build.ts)
packages/workit-claude-code/skills/
packages/workit-claude-code/assets/
2 changes: 2 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
".cursor-plugin/**",
"**/.cursor-plugin/**",
"**/.codex-plugin/**",
".claude-plugin/**",
"**/.claude-plugin/**",
"packages/workit-cursor/mcp.json"
]
}
12 changes: 10 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Agent Contract

Multi-platform workit: OpenCode, Cursor, Codex CLI/desktop, Pi, and the CLI share one core. Every feature must ship with **feature parity across hosts, implemented the best way each host allows**.
Multi-platform workit: OpenCode, Cursor, Codex CLI/desktop, Pi, Claude Code, and the CLI share one core. Every feature must ship with **feature parity across hosts, implemented the best way each host allows**.

## Host-native adaptation

Expand Down Expand Up @@ -59,6 +59,14 @@ human may bind a writer to a Codex session explicitly with
`workit writer acquire --actor <session-id>`; the hook honors exactly that
session and nothing else.

Claude Code uses the `packages/workit-claude-code` plugin: one exec-form hook
launcher maps every event through the shared host-hook protocol (never emitting
`allow`), skills are generated from `packages/workit-core/skills` at build time
(never committed), and `workit` reaches the Bash tool through the plugin `bin/`.
It installs either as latest published (root `.claude-plugin/marketplace.json`,
npm source) or as a local pin (`claude --plugin-dir` / `CLAUDE_CODE_PLUGIN_DIRS`),
where hooks and `bin/workit` run the sources with Bun.

Pi uses the stock 0.85.1 package contract. Its extension is self-contained
apart from the Pi peer, reports native session/UI provenance truthfully, and
bundles a coordinator for fresh stock-Pi reviewer/investigator and scoped
Expand All @@ -82,7 +90,7 @@ is never available to supervised children.
(`docs/workit-v1/qualification.md`). Do not invoke `scripts/run-v1-evaluation.ts`
or fabricate batch results without explicit model/run/time/usage authorization.
7. Stale-install auto-load repair is automatic and fail-open: the doctor's `stale_install` finding (legacy `mcp.json`/hook selectors, a local-dist install behind the current/published runtime, or an OpenCode `@latest` package cache frozen behind the published `workit-opencode`) is enforced by `install-cursor-plugin.sh` via a `doctor-check.ts cursor --stale` pre-check for Cursor — exit 2 triggers a refresh + canonical re-registration, a healthy install is byte-untouched, and a registry-unreachable comparison warns as `registry_unreachable` (never `stale_install`, never an install failure). Canonical Cursor `@latest` installs never fail on version metadata. OpenCode npm pins keep the bare `@brainervirus/workit-opencode` identity; when OpenCode's `~/.cache/opencode/packages/@brainervirus/workit-opencode@latest` lags the registry, doctor fails with the exact cache path to delete so the next launch re-resolves.
8. Agent-facing behavior rules ship in the distributed surfaces: the invariant bootstrap (injected on OpenCode, Pi, Cursor, and Codex), the method skills (copied to every host), and adapter messages. This file documents this repository's development contract; a rule that lives only here never reaches installed workit instances.
8. Agent-facing behavior rules ship in the distributed surfaces: the invariant bootstrap (injected on OpenCode, Pi, Cursor, Codex, and Claude Code), the method skills (copied to every host), and adapter messages. This file documents this repository's development contract; a rule that lives only here never reaches installed workit instances.

### Where a rule lives

Expand Down
89 changes: 86 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Workit

Multi-platform Workit workflow support for Cursor, OpenCode, Codex CLI/desktop,
Pi, and the CLI. The hosts share one task contract and eight operation families
Pi, Claude Code, and the CLI. The hosts share one task contract and eight operation families
while adapting authority and lifecycle behavior to the native surfaces each
host documents.

Expand All @@ -17,6 +17,7 @@ completion; a local commit does not prove a remote push.
| OpenCode | Native plugin with fourteen method skills, ten tools (eight shared families plus read-only context and init apply), and provider-safe schemas |
| Cursor | MCP transport, one native hook dispatcher, one contract rule, and fourteen skills |
| Codex | Native plugin manifest, shared MCP transport, documented lifecycle hooks, and fourteen skills |
| Claude Code | Native plugin: session/per-turn task context hooks, branch policy on git shell commands, fourteen skills, and verifier/reviewer/implementer agents |
| Pi | Native npm extension with nine tools (eight shared families plus external action), fourteen skills, and session continuity |
| Shared MCP | Low-level transport for the eight core operation families |
| Shared core | Task, policy, evidence, finding, decision, worker, writer, and continuity state |
Expand All @@ -25,7 +26,7 @@ completion; a local commit does not prove a remote push.
## Install

Requires **Node.js 24 or newer**. The wizard detects your hosts, configures the
OpenCode, Cursor, Codex and Pi installations you pick, and writes your global config and optional project files:
OpenCode, Cursor, Codex, Pi and Claude Code installations you pick, and writes your global config and optional project files:

```bash
npx @brainervirus/workit-cli init
Expand Down Expand Up @@ -171,6 +172,71 @@ bound session and nothing else.

</details>

<details>
<summary><strong>Claude Code</strong> — plugin (latest published, or pinned to a checkout)</summary>

**Latest published.** The repository root is a Claude Code marketplace
(`.claude-plugin/marketplace.json`) whose entry installs the published
`@brainervirus/workit-claude-code` npm package. Select Claude Code in the
wizard, or install natively:

```bash
claude plugin marketplace add BrainerVirus/workit
claude plugin install workit@workit
# later: refresh the marketplace, then update (Claude auto-update is off by default)
claude plugin marketplace update workit && claude plugin update workit@workit
```

`workit doctor` warns (`claude_plugin`) when a newer plugin version is
published than the one installed. `workit uninstall` previews and runs the
native `claude plugin uninstall workit@<marketplace> --scope <scope>` for each
Workit install that applies where you run it: user scope, plus project/local
scope installs of the current project (run from that project).

**Local pin to a checkout.** Load the package straight from this repository;
hooks and `workit` on the Bash tool then run the TypeScript sources with Bun,
so edits apply without rebuilding the plugin. Only the generated skills need a
build step:

```bash
bun install
bun packages/workit-claude-code/scripts/build.ts --skills-only # generate skills/
claude --plugin-dir "$PWD/packages/workit-claude-code" # one session
# every session: export it from your shell profile instead
export CLAUDE_CODE_PLUGIN_DIRS="$HOME/path/to/workit/packages/workit-claude-code"
```

Disable the marketplace install while pinning (`claude plugin disable
workit@workit`) so the two copies do not both load. A pinned checkout needs
Bun on `PATH`; an installed plugin needs only Node.js 24+.

The plugin ships:

- hooks: `SessionStart` (startup/resume/clear/compact/fork) injects the Workit
contract and task context and exports `WORKIT_HOST`/`WORKIT_SESSION_ID` to
the session's shell; `UserPromptSubmit` re-injects task context only when it
changed since it was last injected; `PreToolUse` on `Bash`/`PowerShell`
`git *` commands denies protected or non-compliant branch operations with a
structured `permissionDecision: "deny"` (Claude Code 2.1.288 shows it as
`PreToolUse:Bash hook error: <reason>`; it never answers `allow`, so your
permission prompts stay in charge); `SubagentStart` tells the `implementer`
it works in its own worktree and other subagents that they are read-only.
No other events are registered;
- fail-open: if the hook runtime cannot start (no Bun for a pin, a missing or
unloadable `dist/`), the hook answers nothing and prints one
`[workit] Claude Code hook unavailable: …` line, and Claude runs as if Workit
were not installed;
- skills: the fourteen method skills, namespaced as `/workit:<name>`
(`/workit:review`, `/workit:plan`, …);
- agents: `verifier` and `reviewer` (read-only) and `implementer`
(`isolation: worktree`);
- `workit` on the Bash tool's `PATH` (the plugin `bin/`).

No MCP server is registered: Claude has a shell, and tool schemas cost
resident context. To opt in, add `workit-mcp` to your own Claude settings.

</details>

<details>
<summary><strong>Pi</strong> — native extension</summary>

Expand Down Expand Up @@ -376,6 +442,21 @@ native arbitrary-question receipt or attested writer delegation.

</details>

<details>
<summary><strong>Claude Code</strong></summary>

Claude Code runs one hook process per event (`node bin/workit-hook.mjs`, exec
form, no shell) through the shared host-hook protocol. Branch policy denies use
`permissionDecision: "deny"` with the unblock hint in the reason; Workit never
emits `allow`. `PreCompact` cannot inject context, so the task context is
restored by `SessionStart` with `source: "compact"` (no `PreCompact` hook is
registered). `SubagentStart` can only add context, never block or bind: the
worktree `implementer` is told it may edit and commit in its own worktree after
switching to a policy-compliant branch (Claude names worktree branches itself),
and every other subagent is observed as read-only/agent-guided.

</details>

<details>
<summary><strong>Pi</strong></summary>

Expand Down Expand Up @@ -564,7 +645,7 @@ blocks publication on missing deterministic or live evidence. The 90-run live ba
requires explicit authorization; see `docs/workit-v1/qualification.md`.

Published bundles are built with Bun and run on Node. The Cursor, OpenCode,
Codex, and Pi package builds copy the fourteen canonical skills from `packages/workit-core`; no
Codex, Pi, and Claude Code package builds copy the fourteen canonical skills from `packages/workit-core`; no
host-specific skill forks are maintained.

## Repository layout
Expand All @@ -578,7 +659,9 @@ workit/
│ ├── workit-cursor/ # Cursor MCP, hooks, rule, and skills
│ ├── workit-codex/ # Codex CLI/desktop MCP, hooks, and skills
│ ├── workit-pi/ # Pi native extension, bundled core, and skills
│ ├── workit-claude-code/ # Claude Code plugin: hooks, agents, generated skills
│ └── workit-cli/ # CLI setup wizard
├── .cursor-plugin/ # Marketplace metadata
├── .claude-plugin/ # Claude Code marketplace (npm-sourced plugin entry)
└── test/ # repository verification
```
Loading
Loading