Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

203 lines · 10.5 KBRaw History
1# Diffinery plugins for Claude Code and Codex
2
3A plugin marketplace, kept in the Diffinery repository itself, that makes Claude Code and
4OpenAI's Codex CLI work smoothly with repositories hosted on [Diffinery](https://diffinery.com),
5the open-source git forge built for AI agents: on diffinery.com or on any instance you deploy
6yourself (see [Any Diffinery instance](#any-diffinery-instance)).
7It has two plugins: `diffinery` (Claude Code and Codex) and `diffinery-ci` (Claude Code),
8described below.
9
10The plugin adds:
11
12| Piece | Claude Code | Codex |
13| --- | --- | --- |
14| `diffinery` MCP server (`<Diffinery URL>/mcp`, OAuth sign-in) | yes | yes (diffinery.com; see below for others) |
15| `diffinery` skill: the CLI, git auth, the branch → PR → CI → merge loop, Diffinery's agent rules | yes | yes |
16| `pr-status`: this branch's PR, its checks, and the log tail of failing jobs | `/diffinery:pr-status` command | `pr-status` skill |
17| SessionStart hook: in a Diffinery clone, tells the agent the repo is on Diffinery and whether the `diffinery` CLI is installed and signed in | yes | yes, once you trust it (`/hooks`) |
18
19`diffinery-ci` is a Claude Code [mod](https://code.claude.com/docs/en/plugins/mods/overview)
20that shows the branch's pull request and its CI checks live, and tells Claude when CI settles:
21
22| Piece | Where it works |
23| --- | --- |
24| Band above the prompt: PR number, title, checks (`✗ 1 failed · ● 3 running · ✓ 6`), review and merge state | Terminal, desktop app (Code tab), VS Code |
25| `/diffinery-ci`: a pane with every check, its time and a link to its log, plus **Fix CI** and **Refresh**; `/diffinery-ci on` / `off` | Pane where Claude Code draws; a text answer everywhere else |
26| Status line entry (`PR #7 ✓ 10/10`) and a toast when CI passes or fails | Where Claude Code draws |
27| After the session pushes a branch or opens its PR, a note to Claude once that commit's checks settle (failures where the band shows the rest, passes too where nothing draws, so a cloud thread hears either way; `/diffinery-ci notes auto|failures|all|off` changes it, nothing to set up) | Everywhere hooks run, cloud sessions and project threads included |
28
29It reads the GraphQL API of the Diffinery instance in `DIFFINERY_URL`, the plugin's Diffinery
30URL setting or the CLI's saved URL (in that order, else diffinery.com), with the token from
31`DIFFINERY_TOKEN`, `diffinery login`, or gh signed in to the host (`diffinery auth setup-gh`),
32and sends a token only to the instance it belongs to. It needs
33Claude Code 2.1.287 or later (the desktop app: 2.1.286). Cloud sessions run its hooks but
34draw no mod interface, so there it's the note to Claude and the `/diffinery-ci` text.
35
36Nothing here is needed just to use git: clone, fetch and push work with any git client
37(`diffinery auth setup-git` or a token as the HTTPS password). The plugin is for pull
38requests, CI and issues.
39
40## Install
41
42codician/diffinery is public, so adding the marketplace needs no sign-in. The plugin works through
43the `diffinery` CLI, so install it and sign in once per machine:
44
45```sh
46curl -fsSL https://diffinery.com/install | bash # Windows: irm https://diffinery.com/install.ps1 | iex
47diffinery login
48diffinery auth setup-git
49```
50
51### Claude Code
52
53```sh
54claude plugin marketplace add https://diffinery.com/codician/diffinery.git
55claude plugin install diffinery@diffinery
56```
57
58Or inside a session: `/plugin marketplace add https://diffinery.com/codician/diffinery.git`,
59then `/plugin install diffinery@diffinery`, then `/reload-plugins` (or restart).
60
61Add `claude plugin install diffinery-ci@diffinery` for the live CI band.
62
63### claude.ai, cloud sessions and projects
64
65claude.ai can't read this repository, so upload the plugins as files: download
66https://diffinery.com/-/claude/diffinery.zip and https://diffinery.com/-/claude/diffinery-ci.zip,
67then in claude.ai open **Customize → Plugins → Add → Upload plugin** for each. They reach your
68cloud sessions at their next start. For a project's threads, also add them under
69**Project settings → Plugins**. Build the same zips from a checkout with
70`python3 scripts/pack-plugins.py` at the repository root (they land in `dist/`).
71
72### Codex
73
74```sh
75codex plugin marketplace add https://diffinery.com/codician/diffinery.git
76codex plugin add diffinery@diffinery
77```
78
79Check with `codex plugin list` and `codex mcp list`. Codex runs plugin hooks only after
80you review and trust them: open `/hooks` in the Codex TUI and trust the `diffinery`
81SessionStart hook (optional; the skill works without it).
82
83## Any Diffinery instance
84
85Diffinery is open source, and every plugin here works with any instance, not only
86diffinery.com. Both Claude Code plugins have a **Diffinery URL** setting (`userConfig.url`,
87default `https://diffinery.com`). It sets the MCP server's address (`.mcp.json` uses
88`${user_config.url}/mcp`), the instance the SessionStart hook recognises in a clone (it gets
89the value as `CLAUDE_PLUGIN_OPTION_URL`), and the instance `diffinery-ci` reads.
90
91- `diffinery setup --url https://git.example.com` sets it for you, in `pluginConfigs` in
92 `~/.claude/settings.json`, for the copies it installs (`diffinery@inline`) and for
93 marketplace installs alike. Install the CLI from the instance itself:
94 `curl -fsSL https://git.example.com/install | bash`.
95- Claude Code asks for it when you enable a marketplace install; change it later in `/config`.
96- The zips an instance serves at `/-/claude/<name>.zip` default the setting to that instance
97 (`apps/diffinery/src/docs/claude-plugins.ts`), so uploads to claude.ai need nothing else.
98- The hook also knows `DIFFINERY_URL` and the URL `diffinery login` saved; `DIFFINERY_URL`
99 takes precedence for the hook and for `diffinery-ci`, as it does for the CLI.
100
101Codex substitutes no plugin settings, so the Codex manifest reads its own
102`codex.mcp.json`, which names `https://diffinery.com/mcp`. A server of your own named
103`diffinery` replaces it, and `diffinery setup --url` adds one when Codex is installed:
104`codex mcp add diffinery --url https://git.example.com/mcp`. The skills and the hook work
105with any instance in Codex too.
106
107## Sign in
108
109The MCP server signs you in with OAuth in the browser:
110
111- Claude Code: run `/mcp`, pick `plugin:diffinery:diffinery`, choose Authenticate.
112- Codex: `codex mcp login diffinery`.
113
114The skill also uses the `diffinery` CLI, which has its own sign-in:
115
116```sh
117curl -fsSL https://diffinery.com/install | bash # Windows: irm https://diffinery.com/install.ps1 | iex
118diffinery login # or: diffinery login --device
119diffinery auth setup-git # optional: git credential helper
120```
121
122## Headless use (CI, cloud sessions): `DIFFINERY_TOKEN`
123
124The `diffinery` CLI and `diffinery auth setup-git` pick up `DIFFINERY_TOKEN` on their own.
125
126The plugin's MCP server uses OAuth only. Neither client can take a token from the
127environment when it is set and fall back to OAuth when it is not, from one config:
128
129- Claude Code turns OAuth off as soon as the server config has an `Authorization`
130 header, even an empty one, and plugin header helpers do not see variables like
131 `DIFFINERY_TOKEN`.
132- Codex's `bearer_token_env_var` makes the server fail to start when the variable is unset.
133
134So on headless machines, add a token-based server of your own. It takes precedence over
135the plugin's:
136
137```sh
138# Claude Code: same URL, so the plugin's OAuth entry is hidden while this one exists
139claude mcp add --scope user --transport http diffinery https://diffinery.com/mcp \
140 --header 'Authorization: Bearer ${DIFFINERY_TOKEN}'
141
142# Codex: same name, so it replaces the plugin's server
143codex mcp add diffinery --url https://diffinery.com/mcp --bearer-token-env-var DIFFINERY_TOKEN
144# ...or just for one run, without touching config.toml:
145codex -c 'mcp_servers.diffinery.url="https://diffinery.com/mcp"' \
146 -c 'mcp_servers.diffinery.bearer_token_env_var="DIFFINERY_TOKEN"' exec "..."
147```
148
149Keep the single quotes in the Claude Code command: Claude Code expands
150`${DIFFINERY_TOKEN}` when it connects, so the token is never written to its config.
151
152## claude.ai and the Claude apps
153
154Settings → Connectors → Add custom connector, with the URL `https://diffinery.com/mcp`
155(or your own instance's `https://git.example.com/mcp`). You sign in with your Diffinery
156account when you connect it.
157
158## gh
159
160Prefer the `diffinery` CLI: it knows Diffinery's extras (`--intent`, auto-merge,
161`run logs`). `gh` works too once you run `diffinery auth setup-gh`, which signs gh in to
162the Diffinery host (diffinery.com or yours) as a GitHub Enterprise host. That is also what lets Claude Code show the
163branch's pull request with its CI status. See https://diffinery.com/docs/agents/github-cli.
164
165## Layout
166
167Paths from the repository root:
168
169```
170.claude-plugin/marketplace.json Claude Code marketplace
171.agents/plugins/marketplace.json Codex marketplace
172plugins/diffinery/
173 .claude-plugin/plugin.json Claude Code manifest
174 .codex-plugin/plugin.json Codex manifest
175 .claude-plugin/icon.png the listing icon (also in diffinery-ci)
176 .mcp.json the diffinery MCP server (Claude Code: ${user_config.url}/mcp)
177 codex.mcp.json the diffinery MCP server (Codex: diffinery.com)
178 skills/diffinery/SKILL.md the skill (both clients)
179 commands/pr-status.md /pr-status (Claude Code)
180 codex-skills/pr-status/SKILL.md pr-status skill (Codex has no plugin commands)
181 hooks/hooks.json SessionStart hook (both clients)
182 hooks/session-start.sh the hook: POSIX sh, no network, silent outside Diffinery repos
183plugins/diffinery-ci/ Claude Code only (a mod)
184 .claude-plugin/plugin.json manifest
185 hooks/hooks.json names the hooks module
186 hooks/register.tsx the mod: band, pane, status line, CI watch
187 hooks/lib.ts parsing and wording, no engine calls
188 types/index.d.ts the mod's state contract
189 tests/ci.test.tsx `claude plugin test plugins/diffinery-ci`
190scripts/pack-plugins.py builds dist/<plugin>-<version>.zip for upload
191apps/diffinery/claude-plugins/ the packed zips diffinery.com serves (see its README)
192```
193
194Check changes with `claude plugin validate .` and `claude plugin validate plugins/diffinery`
195from the repository root, and for the mod `claude plugin validate plugins/diffinery-ci` and
196`claude plugin test plugins/diffinery-ci`. Bump `version` in both plugin manifests and both marketplace entries
197together.
198
199More: https://diffinery.com/docs/connect
200
201## License
202
203Apache-2.0, like the rest of the repository. See [LICENSE](../LICENSE).