Contributions welcome. This document covers how to contribute effectively.
# Clone the repo
git clone https://github.com/antonbabenko/deliberation
cd deliberation
# Run every check (typecheck + all test suites)
npm run check
# Claude Code: load the plugin from this checkout without reinstalling
claude --plugin-dir /path/to/deliberation
# Any other MCP host (Codex, Cursor, Kiro, Antigravity, OpenCode, ...):
# point its MCP config at the server in this checkout
node /path/to/deliberation/server/mcp/index.jsAgent instructions for working on this repo (any coding agent) are in AGENTS.md.
| Area | Examples |
|---|---|
| New Providers | Ollama, Mistral, local model integrations |
| Role Prompts | New roles for prompts/, improved existing prompts |
| Rules | Better delegation triggers, model selection logic |
| Bug Fixes | Command issues, error messages |
| Documentation | README improvements, examples, troubleshooting |
deliberation/
├── core/ # Host-neutral engine: providers, orchestration, consensus loop
├── server/ # MCP server (server/mcp), provider bridges, local dashboard
├── prompts/ # Expert personas
├── rules/ # Delegation rules (installed to ~/.claude/rules/ by the Claude Code plugin)
├── commands/ # Claude Code slash commands
├── config/ # Config schema + defaults
├── scripts/ # sync-hosts.js (generates per-host files) and helpers
├── docs/ # Tool guide, per-host docs, developer docs (docs/dev/)
├── .claude-plugin/ # Claude Code plugin manifest
├── AGENTS.md # Instructions for coding agents working on this repo
└── README.md # User-facing docs
Details: docs/dev/architecture.md.
- Test your changes -
npm run check, then try the change through a real MCP host - Update docs - If you change behavior, update relevant docs
- Keep commits atomic - One logical change per commit
| Do | Don't |
|---|---|
| Focus on one change | Bundle unrelated changes |
| Write clear commit messages | Leave vague descriptions |
| Test with actual MCP calls | Assume it works |
| Update docs (see the checklist in AGENTS.md) | Ignore developer docs |
type: short description
Longer explanation if needed.
| Prefix | Version bump |
|---|---|
feat!: or BREAKING CHANGE: |
Major |
feat: |
Minor |
fix: |
Patch |
docs, refactor, build, chore, style, test, ci, perf |
None |
Only feat:, fix: and breaking changes cut a release. A push that contains only the other
types produces an empty changelog and is skipped; those commits ship with the next release.
Examples:
feat: add Ollama provider supportfix: handle Codex timeout correctlydocs: add troubleshooting for auth issues
Releases are automated from Conventional Commits. You never bump versions by hand.
- Merge a PR to
master. - The release workflow reads the commits since the last release and computes the next
version (
feat:-> minor,fix:-> patch,feat!:/BREAKING CHANGE:-> major). - It opens a
chore(release): vX.Y.ZPR that updatesversion.json,CHANGELOG.md, and the synced manifests, then auto-merges it once thevalidatecheck passes. - On merge, a second workflow tags
vX.Y.Zand publishes the GitHub Release. - The
antonbabenko/agent-pluginsmarketplace then re-pinsdeliberationto the new release (immediately if its dispatch token is set, otherwise within a day via cron).
version.json is the single source of truth. .claude-plugin/plugin.json,
.claude-plugin/marketplace.json, package.json, server.json (both version lines),
server/mcp/package.json, plugins/deliberation/.codex-plugin/plugin.json, and the
serverInfo.version literal in server/mcp/index.js are kept in sync by CI
(.github/release/pre-commit.js). Do not edit those version fields by hand - the validate
check fails if they drift.
First decide whether you need code at all.
Any endpoint that serves POST /chat/completions (Ollama, LM Studio, Mistral, DeepSeek, a
self-hosted vLLM, ...) runs through the OpenRouter transport with no code change. OpenRouter
is off by default, so enable it and declare a model record in
~/.config/deliberation/config.json:
{
"providers": {
"openrouter": { "enabled": true, "apiBase": "http://127.0.0.1:11434/v1" }
},
"models": {
"local-qwen": { "provider": "openrouter", "model": "qwen2.5-coder:32b", "askAll": true }
}
}Where the endpoint comes from depends on the server:
- The unified
deliberationserver (every non-Claude host, andask-all/consensus) uses ONE endpoint for every record:providers.openrouter.apiBase, read at startup (restart the server after changing it). It always reads the key fromOPENROUTER_API_KEY. - The standalone
deliberation-openrouterbridge (Claude Code's/ask-openrouter) also honours a per-recordapiBaseandproviders.openrouter.apiKeyEnv.
Either way the key is sent to that endpoint whenever the variable is set (an
Authorization header is added only when it is), so point apiBase only at endpoints you
trust with it. Record fields: config/config.schema.json (modelRecord) and
TECHNICAL.md.
Use this when the provider needs its own CLI, protocol, or file handling. Codex
(core/providers/codex.js, spawns a CLI), Grok (core/providers/grok.js +
server/grok/, HTTP bridge) and Gemini (core/providers/antigravity.js + server/gemini/)
are the working examples. Read docs/dev/architecture.md first,
and the matching entries in docs/dev/design-decisions.md
(timeouts, retries, stub answers, CLI resolution).
-
Adapter -
core/providers/<name>.jsreturns aProvider(core/types.js):name,capabilities(canImplement: falseunless it can write behind both implement locks),health()andask(req).health()is stat-only and side-effect-free: report a missing CLI or key as{ ok: false, reason }so the panel skips the peer.ask()returns aDelegationResultand never throws; turn failures into results withtoErrorResult(core/provider.js) and a correcterrorKind, becausecallProviderretriesnetwork,rate-limit,upstreamandemptyonce, and the circuit breaker counts every error. Core never reads config or a bridge directly: take both throughopts. -
Shared rules every adapter or bridge applies - prepend
groundingNote()(core/grounding.js) to the prompt; clamp every ceiling withclampToHostBudget(core/host-budget.js) and honourreq.hostBudgetRemainingMs; reject preamble-only replies withstubReason(core/answer-floor.js); resolve a CLI withcore/resolve-bin.js, nevershell: true. -
Bridge (HTTP or a CLI that needs its own MCP server) -
server/<name>/index.js, zero dependencies. Register it in.claude-plugin/plugin.jsonmcpServersonly if it should also run as a standalone server, with the sametimeoutandMCP_TOOL_TIMEOUTpair the other entries carry (test/plugin-manifest.test.jschecks them). -
Wire it in - construct it in
makeRuntimeinserver/mcp/index.js(readproviders.<name>config there), then add the name to:BUILTINSincore/registry.js(panel selection)BUILTIN_NAMES,ASK_PROVIDERandASK_AUTHinserver/mcp/index.js(plus anask-<name>tool if it gets one)KNOWN_PROVIDERSand, if it can arbitrate,BUILTIN_ARBITERSinserver/openrouter/config.js(timeout ladder and arbiter validation)core/settings.jsandcore/analyze.jsdefaults, the provider lists incore/config-history.js(config provenance), andFIXED_KEY_ENVSinserver/dashboard/server.jsif it reads a fixed key env
rg -n '"grok"' core server --glob '!**/dist/**'finds every list a built-in appears in; a new one belongs in each. -
Config - add
providers.<name>toconfig/config.schema.jsonANDconfig/config.default.json. State any threat model (where keys or files go) in the schema description. -
Tests - an adapter test like
test/core-grok.test.js(inject a fake bridge or CLI viaCODEX_BIN/AGY_BIN-style overrides; no network) and a registry case intest/core-registry.test.js.npm run checkmust pass. -
Host surfaces and docs -
commands/setup.mdandcommands/doctor.md(detect the CLI or key), an/ask-<name>command if it gets a tool, the docs checklist in AGENTS.md, thennpm run sync.
- Use tables for structured data
- Keep prompts concise and actionable
- Test with a real MCP host
- Plain CommonJS on Node, no runtime dependencies (esbuild is a build-time devDep for the npm bundle only)
core/**andserver/mcp/**are type-checked (tsconfig.json, strictcheckJs): give exported functions JSDoc parameter and return types- No
anywithout explicit justification; no@ts-ignoreor@ts-expect-error
After changes, verify with actual MCP calls:
- Load this checkout in an MCP host (see Quick Start)
- Claude Code only: run
/deliberation:setup - Verify the tools are listed (
ask-gpt,ask-all,consensus, ...) - Call a few tools, including an expert (
architect,code-reviewer) - Verify responses are properly synthesized
- Test error cases (timeout, missing CLI)
Open an issue for:
- Feature requests
- Bug reports
- Documentation gaps
- Architecture discussions