Swarm intelligence for code review - diverse expert agents that debate your diffs
Project description
Dissent
Swarm intelligence for code review - diverse expert agents that debate your diffs.
Quickstart · GitHub Action · Custom Personas · Report a Bug
What is Dissent?
Dissent spawns a swarm of AI reviewer agents - each with a different expertise (security, performance, readability, architecture, testing) - and lets them review your code independently, then debate each other's findings. The result is consensus-ranked insights that no single reviewer would catch alone.
Inspired by MiroFish, which applies swarm intelligence to predict real-world events by simulating thousands of interacting agents, Dissent brings the same principle to code review: diverse perspectives + interaction = emergent intelligence.
How it works
- Independent review - Each agent reviews the diff through their specialized lens, in parallel
- Debate - Agents see each other's findings and endorse, challenge, or surface new issues
- Consensus - Findings are ranked by cross-agent agreement, with dissenting opinions preserved
Why Dissent?
- Swarm intelligence - Agents interact and build on each other, not just run independently
- Real debate - Agents challenge false positives and endorse findings across domains
- Emergent insights - Issues surface only because agents saw each other's work
- GitHub bot - Post inline PR review comments directly on your diffs
- Custom personas - Define your own reviewer personas for any stack via YAML
- Any LLM - Works with OpenAI, Ollama, or any OpenAI-compatible API
Quickstart
pip install dissent
export OPENAI_API_KEY="your-key"
Review local diffs
# Last commit
dissent HEAD~1
# Staged changes
dissent --staged
# Commit range
dissent abc123..def456
# Pipe in a diff
git diff main | dissent -
# Use Ollama (fully local, no API key needed)
dissent --model llama3 --base-url http://localhost:11434/v1 HEAD~1
Review a GitHub PR
dissent-pr https://github.com/owner/repo/pull/123
# Dry run - see results in terminal without posting
dissent-pr https://github.com/owner/repo/pull/123 --dry-run
dissent-pr fetches the PR diff, runs the swarm review, and posts inline comments directly on the PR at the relevant file and line.
GitHub Action
Add Dissent to any repo with 3 lines. On every pull request, the swarm reviews the diff and posts inline comments:
# .github/workflows/dissent.yml
name: Dissent Review
on:
pull_request:
jobs:
review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: itsarbit/dissent@v1
with:
api-key: ${{ secrets.OPENAI_API_KEY }}
Action inputs
| Input | Default | Description |
|---|---|---|
api-key |
required | OpenAI API key (or compatible provider) |
model |
gpt-4o |
LLM model to use |
base-url |
- | API base URL (for Ollama, vLLM, etc.) |
rounds |
2 |
Number of debate rounds |
personas |
all | Comma-separated persona list |
persona-file |
- | Path to custom persona YAML file |
github-token |
GITHUB_TOKEN |
Token for posting review comments |
Custom Personas
Dissent ships with 6 built-in personas: security, performance, readability, architecture, testing, and correctness.
Define your own by creating a .dissent.yaml in your project root (auto-loaded) or by passing --persona-file:
# .dissent.yaml
accessibility:
name: Accessibility
color: cyan
prompt: |
You are an accessibility expert reviewing code changes. Focus on:
- Missing ARIA attributes and roles
- Keyboard navigation issues
- Screen reader compatibility
Be precise. Only flag real violations. Reference specific lines.
react_hooks:
name: React Hooks
color: yellow
prompt: |
You are a React hooks expert reviewing code changes. Focus on:
- Missing or incorrect dependency arrays in useEffect/useMemo/useCallback
- Stale closure bugs
- Rules of hooks violations
Be precise. Reference specific lines.
dissent --persona-file .dissent.yaml HEAD~1
See examples/react_team.yaml for a ready-made persona file for React projects.
Configuration
dissent options
| Option | Env var | Default | Description |
|---|---|---|---|
--model |
DISSENT_MODEL |
gpt-4o |
LLM model |
--base-url |
DISSENT_BASE_URL |
- | API base URL |
--api-key |
OPENAI_API_KEY |
- | API key |
--rounds |
- | 2 |
Debate rounds |
--personas |
- | all | Comma-separated persona list |
--persona-file |
- | .dissent.yaml |
Custom persona YAML |
--output |
- | terminal |
terminal, json, markdown |
dissent-pr options
| Option | Default | Description |
|---|---|---|
--model |
gpt-4o |
LLM model |
--rounds |
2 |
Debate rounds |
--personas |
all | Comma-separated persona list |
--dry-run |
false | Print results to terminal, don't post comments |
Ollama (fully local)
ollama pull llama3
export DISSENT_MODEL=llama3
export DISSENT_BASE_URL=http://localhost:11434/v1
dissent HEAD~1
How the Swarm Works
Dissent's review process mirrors MiroFish's approach to swarm intelligence:
Round 1 - Independent review: Each agent reviews the diff in isolation through their specialized lens. All agents run in parallel.
Round 2+ - Debate: Each agent sees every other agent's findings and responds with:
- Endorsements - "I agree, this is a real issue"
- Challenges - "I disagree, and here's why"
- New findings - "Seeing your findings made me notice something I missed"
- Withdrawals - "You convinced me, I'm dropping this finding"
Consensus scoring: Each finding is scored as (1 + endorsements - challenges) * severity_weight. Cross-domain agreement pushes findings to the top. Heavy challenges bury them. Withdrawn findings are removed.
Swarm summary: The final output shows what the swarm agrees on, what it's split on, and what emerged only through debate.
Reading the Output
Each finding in the terminal output (and as a GitHub inline comment) looks like this:
╭─────────── #1 HIGH SQL Injection in query builder ───────────╮
│ src/db.py:42 │
│ User input is concatenated directly into a raw SQL string. │
│ │
│ Suggestion: Use parameterized queries or an ORM. │
│ │
│ Endorsed by: Performance, Architecture │
│ Challenged by Testing: this path is unreachable in production │
│ │
│ Found by Security | Consensus score: 6 │
╰────────────────────────────────────────────────────────────────╯
Consensus score is calculated as:
(1 + endorsements - challenges) × severity_weight
Where severity_weight is high=3, medium=2, low=1. A finding endorsed by 2 agents with no challenges gets a score of (1 + 2 - 0) × 3 = 9. A finding that gets challenged twice scores (1 + 0 - 2) × 3 = -3 and is buried at the bottom. Findings are sorted by score, so the most cross-domain-agreed issues always surface first.
Endorsements mean another agent - from a different domain - read the finding and confirmed it's a genuine issue. A security finding endorsed by performance and architecture carries more weight than one agent's opinion alone.
Challenges mean an agent pushed back with a reason. Challenges don't disqualify a finding - they reduce its score and are shown inline so you can read both sides and decide.
Withdrawn means the original agent retracted the finding after hearing the debate. Withdrawn findings are removed from the main list but counted in the swarm summary.
Swarm summary categories at the bottom of the output:
| Category | Meaning |
|---|---|
| Swarm agrees on | Endorsed by 2+ agents, no challenges - high confidence |
| Swarm split on | Both endorsed and challenged - read the debate, use your judgement |
| Emerged from debate | Not found in round 1 - only surfaced because an agent saw another's finding |
Development
git clone https://github.com/itsarbit/dissent.git
cd dissent
pip install -e ".[dev]"
pre-commit install
pytest tests/
ruff check . # lint
ruff format . # format
See CONTRIBUTING.md for guidelines.
Inspired By
MiroFish - a swarm intelligence engine that predicts real-world events by simulating thousands of interacting AI agents with distinct behavioral profiles and memory. Built by an undergraduate student in 10 days, it hit the top of GitHub trending with 18k stars. Dissent applies the same core idea - diverse agents that interact and converge - to code review.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dissent-0.2.0.tar.gz.
File metadata
- Download URL: dissent-0.2.0.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81307fbcc50555fa88153959de62e6a1cfdae3e4ec321043f3e00cd773c0b09a
|
|
| MD5 |
72bdb769da41951ff6bc4e792ca9d8d6
|
|
| BLAKE2b-256 |
01e26bf640d56e8afa55d6c52f0cc5616a2872b6d03e4ea1f47b471cd5e793f0
|
Provenance
The following attestation bundles were made for dissent-0.2.0.tar.gz:
Publisher:
publish-pypi.yml on itsarbit/dissent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dissent-0.2.0.tar.gz -
Subject digest:
81307fbcc50555fa88153959de62e6a1cfdae3e4ec321043f3e00cd773c0b09a - Sigstore transparency entry: 1107831006
- Sigstore integration time:
-
Permalink:
itsarbit/dissent@657533437c2af749511346287a666ecfdf9717e2 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/itsarbit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@657533437c2af749511346287a666ecfdf9717e2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dissent-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dissent-0.2.0-py3-none-any.whl
- Upload date:
- Size: 21.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae73f70c0dda02d0169b915cd84a92cccf456e2f4cc800d635faedcdc9247a77
|
|
| MD5 |
22fe76c24fb4af0ac4c7759bc2ba9688
|
|
| BLAKE2b-256 |
dcfb17a1b3ac8452b10aab48c3d2ee68024ad16302239c7acefdc9945a9074dc
|
Provenance
The following attestation bundles were made for dissent-0.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on itsarbit/dissent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dissent-0.2.0-py3-none-any.whl -
Subject digest:
ae73f70c0dda02d0169b915cd84a92cccf456e2f4cc800d635faedcdc9247a77 - Sigstore transparency entry: 1107831007
- Sigstore integration time:
-
Permalink:
itsarbit/dissent@657533437c2af749511346287a666ecfdf9717e2 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/itsarbit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@657533437c2af749511346287a666ecfdf9717e2 -
Trigger Event:
release
-
Statement type: