A fast, Git-friendly issue tracker that lives in your repository.
Rivets stores issues as JSONL files alongside your code—no external services, no context switching, no sync problems. Track bugs, features, and tasks with the same workflow you use for code.
- Git-native — Issues live in your repo, branch with your code, merge with your PRs
- Fast — Built in Rust with an in-memory query engine over Git-friendly persistence
- Dependency tracking — Model blockers and relationships between issues
- Associated Resources — Attach typed Web links and Workspace Paths with stable IDs and semantic roles
- AI-ready — MCP server for seamless integration with AI coding assistants
- Scriptable — JSON output mode for automation and custom tooling
- Human-readable — JSONL storage you can grep, diff, and edit directly
cargo install rivets# Initialize in your project (issue IDs use this prefix)
rivets init --prefix demo
# Create an issue and capture its generated ID
ID=$(rivets create --title "Add user authentication" --kind feature | sed 's/^Created issue: //')
# See what's ready to work on
rivets ready
# Start working on the issue
rivets update "$ID" --status in_progress
# Mark it done
rivets close "$ID"| Command | Purpose |
|---|---|
init |
Initialize a repository (.rivets/ and config.yaml); --prefix <name> sets the ID prefix |
info |
Repository info: database path, prefix, and summary counts |
create |
Create an issue (--title, --kind, --priority, --assignee, --labels, --deps, --design, --acceptance, --notes) |
list |
List issues; filter with --status, --priority, --kind, --assignee, --label; --sort and --limit |
show |
Show one or more issues with their dependencies and resources |
update |
Update status, Kind, assignment, design, acceptance criteria, or append a Note; labels use the label command |
close |
Close one or more issues, optionally --reason |
reopen |
Reopen a closed issue, optionally --reason |
delete |
Delete an issue permanently (--force skips the confirmation prompt) |
ready |
Issues with no blockers, hybrid-sorted by priority |
blocked |
Issues blocked by dependencies, along with their blockers |
dep |
Dependencies: add <dependent> <prerequisite> [--type blocks|related|parent-child|discovered-from], remove, list [--reverse], tree [--depth N] |
label |
Labels: add <label> [<issue-id>], remove, list <issue-id>, list-all; use --ids for batches |
resource |
Associated Resources: add, list, update, remove (see below) |
stale |
Issues not updated in N days (--days, default 30) |
stats |
Project statistics (--detailed for a breakdown) |
Global flags include --json for data-command output and -y/--yes to skip confirmation prompts.
The IDs below (demo-a3f8, demo-b2c9) are illustrative generated IDs.
Replace them with IDs printed by rivets create in your repository.
rivets create --title "Fix login bug" --kind bug --priority 1
rivets list # All issues, open and closed (priority-sorted, max 50)
rivets list --status open # Filter to open issues
rivets list --status in_progress # Filter by status
rivets show demo-a3f8 # View issue details
rivets update demo-a3f8 --priority 2 # Update fields
rivets close demo-a3f8 --reason "Fixed in commit abc123"rivets dep add demo-a3f8 demo-b2c9 --type blocks # demo-a3f8 depends on demo-b2c9, which blocks it
rivets dep remove demo-a3f8 demo-b2c9 # Remove the dependency
rivets dep list demo-a3f8 --reverse # List dependents; omit --reverse for dependencies
rivets blocked # Issues blocked by dependencies, with their blockers
rivets ready # Issues with no blockersDependency type defaults to blocks (related, parent-child, and
discovered-from are also available). ready and blocked are derived
from the dependency graph; adding or removing a dependency does not change
an issue's stored status.
rivets label add urgent demo-a3f8 # Syntax: label add <label> <issue-id>
rivets label remove urgent demo-a3f8
rivets label list demo-a3f8 # Labels on one issue
rivets label list-all # Every label in the repository
rivets list --label backendAttach absolute HTTP/HTTPS URLs or workspace-relative file paths to an
Issue, then curate them in place: update changes only the fields you
provide, and remove deletes a single resource — in both cases every
other resource keeps its stable ID and position. The same operations are
available through the MCP server as resource_add, resource_list,
resource_update, and resource_remove.
rivets resource add demo-a3f8 \
--url https://example.com/pull/123 \
--role implementation \
--label "Implementation PR"
rivets resource add demo-a3f8 --path docs/design/feature.md --role documentation
rivets resource list demo-a3f8
rivets resource update demo-a3f8 --resource r1 --role evidence --no-label
rivets resource remove demo-a3f8 --resource r2Roles are implementation, documentation, evidence, successor, and
reference. Resources retain insertion order and a stable per-Issue ID.
Workspace paths are stored normalized (docs/../docs/x becomes docs/x),
always use / as the separator, cannot be absolute or escape the
workspace root, and need not exist yet — branch-local and generated files
are fine.
Data commands accept --json for scripting (init always prints text):
rivets list --json | jq '.[] | select(.priority == 1)'
ID=$(rivets create --title "Fix login bug" --json | jq -r '.id')This workspace contains three crates:
| Crate | Description |
|---|---|
rivets |
CLI and core library |
rivets-jsonl |
General-purpose JSONL library |
rivets-mcp |
MCP server for AI assistant integration |
- Rust 1.94+ (edition 2024)
cargo build # Build all crates
cargo test # Run tests
cargo run -p rivets -- --helpPre-commit hooks enforce formatting, linting, and tests. Run manually with:
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo testThis project uses Conventional Commits:
feat(cli): add export command
fix(storage): handle empty files gracefully
docs: update installation instructions
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Make your changes with tests
- Ensure all quality checks pass
- Submit a pull request
For maintainers, see Publishing for release procedures.
Release procedure
Publish crates in dependency order:
cargo publish -p rivets-jsonl
# Wait for indexing...
cargo publish -p rivets
# Wait for indexing...
cargo publish -p rivets-mcpGenerate changelog: git cliff --unreleased --bump --prepend CHANGELOG.md
Licensed under either of MIT or Apache-2.0 at your option.