Graph-based issue tracker for AI agent coordination
Project description
🫘 Beans
Graph-based issue tracker for AI agent coordination.
Coding with AI makes developers absurdly productive. Coffee keeps them going. Beans keep the whole loop fed. ☕
Beans is a lightweight, embedded issue tracker designed for AI agents to coordinate work across tasks. It models issues as nodes in a dependency graph, backed by SQLite, with a CLI that both humans and agents can use.
$ beans create "Fix auth middleware"
task-a3f2dd1c 2025-06-15 10:42 Fix auth middleware
$ beans list
task-a3f2dd1c 2025-06-15 10:42 Fix auth middleware
task-7e2b9f01 2025-06-15 10:43 Add rate limiting
$ beans --json list
[{"id": "task-a3f2dd1c", "title": "Fix auth middleware", "status": "open", ...}]
Why Beans exists
Beans was born from analyzing beads, a graph-based issue tracker with a similar goal: giving AI agents a structured way to coordinate work. The idea is excellent. The execution, however, raised serious concerns.
The problem with beads
Beads is invasive software that assumes too much about the user's intentions:
- Curl-pipe-bash installer that silently escalates to
sudoto install a ~200MB binary system-wide - Strips macOS code signatures and applies ad-hoc signatures to bypass Gatekeeper — the same technique used by actual malware
- Installs 5 persistent git hooks (
pre-commit,post-merge,pre-push,post-checkout,prepare-commit-msg) that run on nearly every git operation - Runs a background database daemon (Dolt SQL server) that binds to TCP ports 3307/3308 — a MySQL-protocol server running on your machine
- Silently modifies commit messages by appending metadata trailers without asking
- Auto-pushes data to remote servers every 5 minutes
- Fingerprints your machine with unique UUIDs for the repo, clone, and project
- Injects system prompts into AI agent configuration files (e.g.,
.claude/settings.local.json) to force agents to use the tool - Includes a "stealth mode" that hides its presence from collaborators
- Ships with telemetry that records every command and all arguments, including who ran them
The core data model is a 50+ field struct covering everything from agent heartbeats to ephemeral "wisps." It's not a simple tool — it's a complex system that assumes you want all of it.
What beans does differently
Beans keeps the good idea — a dependency graph for AI agent coordination — and throws away everything else:
| Beads | Beans | |
|---|---|---|
| Storage | Dolt SQL server (~200MB, background daemon, TCP ports) | SQLite (zero-config, embedded, stdlib) |
| Installation | curl | bash + sudo + signature stripping |
uv add beans or pip install beans |
| Git hooks | 5 persistent hooks installed silently | None |
| Commit modification | Silent trailer injection | Never touches your commits |
| Background processes | Persistent MySQL-protocol daemon | None |
| Network | Opens TCP ports, auto-pushes every 5 min | Fully offline |
| Telemetry | OTel spans with actor identity + full args | None |
| Stealth mode | Yes, hides from collaborators | No — transparency is a feature |
| AI config injection | Writes to .claude/settings.local.json |
Provides a skill you copy yourself |
| Data model | 50+ fields | ~10 fields + dependency edges |
| Agent integration | Forced via injected prompts | Opt-in via AGENTS.md instructions |
Design principles
Polite software. Beans never modifies files without asking, never installs hooks, never runs background processes, and never phones home. It's a CLI tool that reads and writes to a local SQLite file. That's it.
Embedded storage. A single .beans/beans.db SQLite file with WAL mode. No servers,
no ports, no daemons. Works offline, works in CI, works anywhere Python runs.
Graph-native. Issues (beans) are nodes. Dependencies are typed edges. "What's ready to work on?" is a graph query — show me all open beans with no open blockers.
Agent-friendly. The --json flag on every command makes beans machine-readable.
Agents don't need to parse human output. The CLI is a thin wrapper around a clean Python
API — agents can also use the library directly.
Minimal by default. A bean has an id, title, status, and timestamps. Everything else is optional. No 50-field structs, no agent heartbeat tracking, no ephemeral wisps.
Journal-based sync. Changes are recorded in an append-only JSONL journal that can be committed to git. The SQLite database is a materialized view that can be rebuilt from the journal at any time. Sync through git, not through custom protocols.
Installation
pip install magic-beans
Or with uv:
uv add magic-beans
Quick start
# Initialize a project
beans init
# Create some beans
beans create "Set up database schema"
beans create "Build API endpoints" --type task
beans create "Write integration tests" --body "Cover all CRUD operations"
# Create an epic with children
beans create "Launch v1" --type epic
beans create "Deploy to staging" --parent epic-<id>
# List all beans
beans list
# JSON output for agent consumption
beans --json list
CLI Reference
Global options
| Option | Description |
|---|---|
--json |
Output as JSON (for agents) |
--dry-run |
Show what would happen without writing |
--db PATH |
Use a specific SQLite database file |
--fields id,title,... |
Limit output to specific fields |
MAGIC_BEANS_DIR |
Environment variable: override .beans/ directory discovery |
Bean CRUD
# Create (default types: task, bug, epic — configurable via beans types)
beans create "Fix auth" --type bug --body "Detailed description" --parent epic-<id>
# Show
beans show task-a3f2dd1c
# Update
beans update task-a3f2dd1c --title "New title" --status in_progress --priority 0
# Close (sets status=closed and closed_at)
beans close task-a3f2dd1c --reason "Fixed in commit abc1234"
# Delete
beans delete task-a3f2dd1c
Querying
# List all beans
beans list
# List only unblocked beans (ready to work on)
beans ready
# Search by title and body
beans search "auth"
# Aggregate counts by status, type, assignee
beans stats
# Dependency tree visualization
beans graph
Dependencies
# A blocks B (B can't start until A is closed)
beans dep add task-aaaa1111 task-bbbb2222
# Remove a dependency
beans dep remove task-aaaa1111 task-bbbb2222
Agent coordination
# Claim a bean (sets assignee + status=in_progress)
beans claim task-a3f2dd1c --actor alice
# Release a claimed bean
beans release task-a3f2dd1c --actor alice
# Release all beans claimed by an actor
beans release --mine --actor alice
Journal & sync
# Export journal to JSONL (for git-based sync)
beans export-journal > journal.jsonl
# Rebuild database from journal
beans rebuild journal.jsonl
Custom types
Beans ships with three default types: task, bug, and epic. Add your own:
# List configured types
beans types
# Add a custom type
beans types add spike --description "Time-boxed investigation"
# Remove a type
beans types remove spike
Bean IDs are prefixed with their type: task-a3f2dd1c, epic-12345678, spike-deadbeef.
Configuration
# Show config path and settings
beans config
# Agent integration skill
beans skill
Introspection
# Output JSON schemas for all models
beans schema
# Field filtering (works with show, list, ready, search)
beans --fields id,title,status list
beans --json --fields id,title show task-a3f2dd1c
Architecture
src/beans/
├── models.py # Pydantic models (pure, no I/O)
├── store.py # SQLite storage (I/O boundary)
├── api.py # Command API (composes store calls)
├── config.py # Global config (~/.config/beans/)
├── project.py # Project discovery (find .beans/)
└── cli.py # Typer CLI (thin wiring layer)
- models.py — Pure data. Bean is a Pydantic model with validation. No I/O, no side effects, easy to test.
- store.py — The I/O boundary. Store wraps a SQLite connection and composes BeanStore, DepStore, and JournalStore. Accepts an injected connection for testing.
- api.py — Command API. Each function is one use case (create, close, claim, release, stats, graph). Composes store calls.
- cli.py — Thin wiring. Parses args, calls API functions, formats output. No business logic.
For AI agents
Beans is designed to be used by AI agents as a coordination mechanism. Add this to your
project's AGENTS.md, or use beans skill for a ready-made integration:
beans skill # output agent skill to terminal
beans skill > AGENTS.md # save to file
Or add manually:
## Task tracking
This project uses `beans` for task tracking. Use `beans --json` for all commands.
- Check available work: `beans --json ready`
- Claim a task: `beans claim <id> --actor <name>`
- Show task details: `beans --json show <id>`
- Mark done: `beans close <id> --reason "Implemented in <sha>"`
- Create subtasks: `beans create "<title>" --parent <id>`
- Add dependencies: `beans dep add <blocker-id> <blocked-id>`
License
MIT
Contributing
Beans is built with Python 3.14, managed with uv.
git clone https://github.com/henriquebastos/beans.git
cd beans
uv sync
uv run pytest
uv run ruff check src/ tests/
Tests use real SQLite :memory: databases — no mocks. The test suite runs in under a
second.
Releasing
- Bump the version in
pyproject.toml - Generate changelog:
uv run git-cliff --tag v<VERSION> -o CHANGELOG.md
- Commit and tag:
git add pyproject.toml CHANGELOG.md git commit -m "chore: bump version to <VERSION>" git tag v<VERSION> git push origin main --tags
- Create a GitHub Release:
gh release create v<VERSION> --generate-notes
The release workflow runs tests, publishes to PyPI, and updates the Homebrew formula.
The package is published as magic-beans on PyPI (pip install magic-beans),
but the CLI command is beans and the import is import beans.
Project details
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 magic_beans-0.7.0.tar.gz.
File metadata
- Download URL: magic_beans-0.7.0.tar.gz
- Upload date:
- Size: 20.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5cacd02507e65bb379355aa2639ec1d5f4bb9da98f64d76ab86c81d84e19b115
|
|
| MD5 |
38216d6edb24a3c109df340d84f11f24
|
|
| BLAKE2b-256 |
5bf10dd568ab3a88dc00503917b6d809ebaa241806fced794fdd17b09e37b73b
|
Provenance
The following attestation bundles were made for magic_beans-0.7.0.tar.gz:
Publisher:
release.yml on henriquebastos/beans
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
magic_beans-0.7.0.tar.gz -
Subject digest:
5cacd02507e65bb379355aa2639ec1d5f4bb9da98f64d76ab86c81d84e19b115 - Sigstore transparency entry: 1302187597
- Sigstore integration time:
-
Permalink:
henriquebastos/beans@a411bd919525fc6051e04acfee48272e898a51fd -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/henriquebastos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a411bd919525fc6051e04acfee48272e898a51fd -
Trigger Event:
release
-
Statement type:
File details
Details for the file magic_beans-0.7.0-py3-none-any.whl.
File metadata
- Download URL: magic_beans-0.7.0-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0613d56831b89cc3b96c999388053b3efeb685b8a11af048ef52b4697d56f507
|
|
| MD5 |
e2027a6bd6416f0511c0daa1767b207a
|
|
| BLAKE2b-256 |
36cfe14330aabb84b5d2cbf6cec0f7bdf6597b07eaa0893e129b05d41becab81
|
Provenance
The following attestation bundles were made for magic_beans-0.7.0-py3-none-any.whl:
Publisher:
release.yml on henriquebastos/beans
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
magic_beans-0.7.0-py3-none-any.whl -
Subject digest:
0613d56831b89cc3b96c999388053b3efeb685b8a11af048ef52b4697d56f507 - Sigstore transparency entry: 1302187668
- Sigstore integration time:
-
Permalink:
henriquebastos/beans@a411bd919525fc6051e04acfee48272e898a51fd -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/henriquebastos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a411bd919525fc6051e04acfee48272e898a51fd -
Trigger Event:
release
-
Statement type: