Skip to content

vu1n/bacchus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

105 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bacchus

Workspace-based coordination CLI for multi-agent work on codebases using jj (Jujutsu).

Bacchus helps AI agents coordinate when working on the same codebase by:

  • Workspace isolation - each agent works in its own jj workspace
  • Task management - SQLite-based task tracking with dependencies and footprints
  • Session management - stop hooks keep agents working until tasks complete
  • Orchestrator-driven release - agents mark work ready, orchestrator handles merging
  • Non-blocking conflicts - jj allows conflict detection without blocking work

Installation

1. Install the binary

curl -fsSL https://raw.githubusercontent.com/vu1n/bacchus/main/scripts/install.sh | bash

This installs the bacchus binary to ~/.local/bin/ and cleans up any legacy global hooks/skills from previous versions.

2. Initialize per project

cd your-project
bacchus init

This sets up everything project-local:

  • .bacchus/ - task database, workspaces, archetypes
  • .claude/settings.json - project-level stop hook
  • .claude/skills/bacchus/SKILL.md - Claude Code skill (teaches Claude how to use bacchus)

Prerequisites

From Source

git clone https://github.com/vu1n/bacchus.git
cd bacchus
cargo build --release
cp target/release/bacchus ~/.local/bin/

Uninstall

curl -fsSL https://raw.githubusercontent.com/vu1n/bacchus/main/scripts/uninstall.sh | bash

How It Works

Bacchus coordinates multi-agent work through a plan → orchestrate → execute flow:

┌─────────────────────────────────────────────────────────────────────┐
│  1. PLAN                                                            │
│     User request → planner/architect workflow                       │
│     Breaks down work into tasks with dependencies                   │
│     Outputs: .bacchus/tasks.yaml                                    │
├─────────────────────────────────────────────────────────────────────┤
│  2. IMPORT                                                          │
│     bacchus task import --epic-id <EPIC>                           │
│     Loads tasks from YAML into SQLite                               │
│     Calculates ready tasks (no blockers, no footprint conflicts)   │
├─────────────────────────────────────────────────────────────────────┤
│  3. ORCHESTRATE                                                     │
│     session start orchestrator + session spawn-workers              │
│     Monitors progress, handles merges, manages conflicts            │
├─────────────────────────────────────────────────────────────────────┤
│  4. EXECUTE                                                         │
│     Each agent: claim → work in jj workspace → release             │
│     Orchestrator: rebase → merge to main → close task              │
└─────────────────────────────────────────────────────────────────────┘

Swarm Methodology

Bacchus runs a deterministic swarm loop:

  1. Plan - break goal into atomic tasks with dependencies and footprints
  2. Admit - only tasks that are dependency-clear and non-overlapping become ready
  3. Execute - workers claim one task each in isolated jj workspaces
  4. Reconcile - orchestrator merges ready work, reopens failed/stale work, resolves conflicts via needs_resolution
  5. Measure - bacchus eval reports throughput plus worker-reliability signals

Swarm safety comes from hard invariants:

  • Single-task ownership via task claims (claimed_by, heartbeat)
  • Leader fencing via orchestrator lease (one orchestrator run controls scheduling)
  • Workspace isolation (one jj workspace per task)
  • Failure recovery (stale worker detection, task reopen, optional stale PID kill)

How to Run

Ralph mode is the default recommendation (permissioned, auditable runs):

claude

Yolo mode is optional for trusted local repos:

claude --dangerously-skip-permissions

In both modes, keep bacchus stop hooks enabled so sessions enforce task completion and orchestration safety.

How to Prompt Claude

Tell Claude what you want and mention bacchus:

"I want to add user authentication with login, logout, and password reset.
Use bacchus to parallelize this work across multiple agents."

With the bacchus skill workflow, Claude can plan tasks, import them, and orchestrate agents with archetype prompts. Autonomous worker spawning requires BACCHUS_WORKER_CMD (see Session Management).

What you want What to say
Full automation "Use bacchus to implement X with N agents"
Plan only "Break down X into tasks for bacchus"
Single task "Work on task TASK-001 with bacchus"
Check status "Show bacchus status"

Key roles:

  • Planner: Breaks down requests into atomic tasks with dependencies
  • Orchestrator: Spawns agents, monitors progress, handles merges
  • Agent: Works on a single task in an isolated workspace (with type-specific archetype)

Agentic Quick Start (Paste Into Your LLM)

Copy/paste this and replace <GOAL>:

Use bacchus to implement: <GOAL>

Operating mode:
- Use Ralph mode by default (no --dangerously-skip-permissions).
- Keep sessions active; do not exit while bacchus session check blocks.

Execution contract:
1) Ensure jj is initialized for this repo (colocated with git if needed).
2) Create/update an epic and task plan in .bacchus/tasks.yaml (atomic tasks, dependencies, footprints, archetypes).
3) Import tasks into SQLite and verify ready queue.
4) Start orchestrator session with max concurrency 3.
5) Use bacchus session spawn-workers --dry-run first, then launch workers.
6) Continuously process releases and recover stale/failed workers.
7) Finish when all tasks are closed or explicitly blocked, then summarize outcomes and risks.

Required commands to use:
- bacchus task import --epic-id <EPIC>
- bacchus task list --ready
- bacchus session start orchestrator --max-concurrent 3
- bacchus session spawn-workers --count 3
- bacchus process-releases
- bacchus eval --days 7

Quickstart Guide

This guide walks through setting up Bacchus for a multi-agent workflow.

Step 0: Fast Initialization Check

cd your-project

# One-shot bootstrap (recommended)
bacchus init --epic-id AUTH --epic-title "Authentication"

# Initialize jj once (if repo is git-only today)
if ! jj root >/dev/null 2>&1; then
  jj git init --colocate
  jj config set --repo user.name "Your Name"
  jj config set --repo user.email "you@example.com"
  jj bookmark create main -r @
  jj describe -m "Initialize jj for bacchus"
  jj new
fi

bacchus init is idempotent: it creates .bacchus/tasks.yaml if missing, bootstraps jj unless --skip-jj, and can create an initial epic.

Step 1: Initialize Your Repository

Bacchus uses jj (Jujutsu) for version control. If your project uses git, initialize jj in colocated mode:

cd your-project
jj git init --colocate

# Set up user config for jj
jj config set --repo user.name "Your Name"
jj config set --repo user.email "you@example.com"

# Create main bookmark (like a branch)
jj bookmark create main -r @
jj describe -m "Initial commit"
jj new

Step 2: Plan Your Tasks

You can create tasks manually or ask Claude to help plan:

Option A: Ask Claude to plan (recommended for complex work)

"Break down user authentication into tasks for bacchus"

Claude will analyze your request and create tasks with proper dependencies.

Option B: Create tasks manually

bacchus task init

Option C: Generate recursively with Bun (experimental)

bun scripts/recursive-planner.ts \
  --goal "Implement user authentication with login, logout, and password reset" \
  --epic-id AUTH \
  --llm-provider claude \
  --task-granularity small \
  --import \
  --validate

The recursive planner writes .bacchus/tasks.yaml, can split broad tasks into smaller subtasks, and can optionally run task import + task validate. When your prompt is goal-only (no PRD/spec), it generates explicit spec + scaffolding + architecture tasks before implementation slices. Use --llm-provider codex to decompose with Codex headless, --llm-provider openai for API mode, or --llm-provider off for heuristic-only planning. Use --task-granularity small to force finer agent-sized tasks.

Edit .bacchus/tasks.yaml:

version: 1

tasks:
  - id: AUTH-001
    title: "Add user login endpoint"
    description: |
      Create POST /api/login that:
      - Validates credentials
      - Returns JWT token
      - Handles errors appropriately
    priority: 1
    status: open
    depends_on: []
    footprint:
      creates:
        - "src/routes/login.rs"
      modifies:
        - "src/routes/mod.rs::*"

  - id: AUTH-002
    title: "Add authentication middleware"
    description: "Protect routes with JWT validation"
    priority: 2
    status: open
    depends_on: [AUTH-001]  # Must complete login first
    footprint:
      creates:
        - "src/middleware/auth.rs"

  - id: AUTH-003
    title: "Add logout endpoint"
    description: "POST /api/logout to invalidate tokens"
    priority: 2
    status: open
    depends_on: [AUTH-001]  # Can run parallel with AUTH-002
    footprint:
      creates:
        - "src/routes/logout.rs"

Import tasks to SQLite:

bacchus task import --epic-id AUTH

# Verify import
bacchus task list
bacchus task list --ready  # Shows AUTH-001 (others blocked)

Step 3: Work on a Task (Agent Mode)

Claim your first task:

bacchus claim AUTH-001 agent-1

Output:

{
  "success": true,
  "task_id": "AUTH-001",
  "title": "Add user login endpoint",
  "workspace_path": ".bacchus/workspaces/AUTH-001"
}

Work in the isolated workspace:

# Check workspace status
jj -R .bacchus/workspaces/AUTH-001 status

# Make your changes (files are auto-tracked by jj)
# Create src/routes/login.rs, etc.

# Describe your change (like a commit message)
jj -R .bacchus/workspaces/AUTH-001 describe -m "Implement login endpoint with JWT"

# View what you've done
jj -R .bacchus/workspaces/AUTH-001 log
jj -R .bacchus/workspaces/AUTH-001 diff

Warning: Never cd into the workspace! Use jj -R <path> instead. Workspaces are deleted on release.

Step 4: Release Your Work

When done, mark the task ready for release:

bacchus release AUTH-001 --status done

Output:

{
  "success": true,
  "task_id": "AUTH-001",
  "status": "ready_for_release",
  "commit_id": "abc123...",
  "message": "Task AUTH-001 marked ready for release. Orchestrator will merge."
}

Check what's now available:

bacchus task list --ready
# Now shows AUTH-002 and AUTH-003 (AUTH-001 unblocked them)

Step 5: Handle Conflicts (If Needed)

If the orchestrator detects conflicts during merge:

# Task will be marked needs_resolution
bacchus task show AUTH-001

# Resolve conflicts in your workspace
jj -R .bacchus/workspaces/AUTH-001 resolve

# Mark resolved and ready again
bacchus resolve AUTH-001

Common Scenarios

Abandoning work:

# Discard changes and reset task to open
bacchus release AUTH-001 --status failed

Blocked on something:

# Keep workspace but mark task blocked
bacchus release AUTH-001 --status blocked

Finding stale work:

# List claims older than 30 minutes
bacchus stale --minutes 30

# Clean them up automatically
bacchus stale --minutes 30 --cleanup

Full workflow with Claude:

# Tell Claude what you want:
"Implement user authentication with bacchus using 3 agents"

# Claude will:
# 1. Plan: break down into tasks.yaml
# 2. Import: bacchus task import --epic-id AUTH
# 3. Orchestrate: spawn agents and monitor progress

Manual orchestration:

# After planning and importing, start orchestrator session
bacchus session start orchestrator --max-concurrent 3
# Optional: enable autonomous worker spawning from orchestrator checks
export BACCHUS_WORKER_CMD='claude'
# Spawn workers on demand
bacchus session spawn-workers --count 3
# Then run `bacchus session check` in your stop-hook loop

Commands

Task Management

Command Description
task init Create tasks.yaml template
task list [--status X] [--ready] List tasks
task show <task_id> Show task details
task import [--epic-id X] Import tasks from YAML to SQLite
task validate Validate task definitions

Coordination

Command Description
init [--skip-jj] [--force-tasks] [--epic-id X --epic-title Y] Bootstrap bacchus in the current repo (jj + tasks template + optional epic)
next <agent_id> Get next ready task, create workspace, claim it
claim <task_id> <agent_id> [--force] Claim specific task (must be ready unless --force)
heartbeat <task_id> <agent_id> Refresh task claim lease heartbeat
release <task_id> --status done|blocked|failed Mark task ready for release
process-releases [--limit N] Orchestrator: merge tasks in ready_for_release
stale [--minutes N] [--cleanup] Find/cleanup abandoned claims
list List all active claims
resolve <task_id> Mark task ready after resolving conflicts
abort <task_id> Reset from needs_resolution to in_progress

Review & Eval

Command Description
review <task_id> [--build-cmd X] [--test-cmd Y] Review task before release (includes symbol-aware footprint checks)
eval [--epic X] [--days N] Show completion metrics plus worker reliability counters (timeouts, stale recovery, kill attempts/successes)

Session Management

Command Description
session start agent --task-id <id> [--agent-id <agent>] Start agent session (enables stop hook and background heartbeat when owner known)
session start orchestrator [--max-concurrent N] Start orchestrator session
session start architect --agent-id <id> Start architect session
session stop Clear session, allow exit
session status Show current session state
session check Check if exit should be blocked (for hooks)
session spawn-workers [--count N] [--dry-run] Launch ready workers once for active orchestrator session
session prune [--minutes N] Remove stale scoped sessions and orphaned expired leases

Epic Management

Command Description
epic list [--status X] List epics (open, planning, active, closed)
epic show <epic_id> Show epic details with task counts
epic create --id X --title Y [--description Z] Create a new epic
epic assign <epic_id> <agent_id> Assign epic to architect for breakdown
epic set-status <epic_id> <status> Update epic status (open/planning/active/closed)

Archetype Management

Command Description
archetype list List available agent archetypes
archetype show <name> Show archetype details and keywords
archetype prompt <name> Get the specialized prompt for an archetype
archetype select <task_id> Select best archetype for a task

Messaging

Command Description
message list [--agent X] [--status Y] List agent messages
message send <agent> <type> <payload> Send message to agent
message claim <agent> [--limit N] Claim pending messages for processing
message ack <message_id> <agent> Mark claimed message as processed
message fail <message_id> <agent> [--reason X] Mark claimed message as failed
message reclaim-stale Requeue/fail stale processing messages

Symbols

Command Description
index <path> Index files for symbol search
symbols [--pattern X] [--kind Y] Search for symbols
symbols [--file X] [--lang Y] Filter by file path or language
symbols [--search X] [--fuzzy] Full-text search with fuzzy matching
symbols --handle Return handle instead of full results (token-saving)

Handles (Token-Saving)

Handles provide compact pointers to query results, reducing token overhead by 90%+.

Command Description
handle expand <handle> [-n N] [--offset M] Retrieve data from handle with pagination
handle filter <handle> [--kind X] [--file Y] Filter handle creating new handle
handle list List all active handles
handle clear Clear all handles
handle info <handle> Get metadata about a handle

Example workflow:

# Search returns a handle instead of full data
$ bacchus symbols --search "auth" --handle
{
  "handle": "$sym1",
  "count": 47,
  "preview": ["auth::login", "auth::logout", "auth::verify"]
}

# Expand to get actual data (on demand)
$ bacchus handle expand $sym1 --limit 5

# Filter to narrow results
$ bacchus handle filter $sym1 --kind function
# Returns: $sym2 with 32 functions

# Clean up when done
$ bacchus handle clear

Handles are session-scoped and automatically cleared on bacchus session stop.

Info

Command Description
status Show claims, orphaned workspaces, broken claims
context [--task-id X] Generate markdown context for agent
workflow Print protocol documentation
events [--limit N] Show recent orchestration events
self-update Update bacchus to latest version
check-update Check if newer version is available

Claude Code Integration

Bacchus integrates with Claude Code through a skill and stop hooks:

Skill

The bacchus skill (~/.claude/skills/bacchus/SKILL.md) provides:

  • Workflow guidance for planning, importing, and orchestrating tasks
  • Agent archetype prompts for specialized task execution
  • Command reference for the bacchus CLI

The skill is automatically loaded when you mention "bacchus" or multi-agent coordination.

Stop Hooks

Stop hooks in ~/.claude/settings.json prevent premature exit:

  • Agent mode: Blocks exit until assigned task is closed
  • Orchestrator mode: Blocks exit while work remains

Type vs Archetype

Tasks have two separate classifications:

Task Type (PM workflow - what kind of work): bug_fix | feature | refactor | test | docs | infra | generic

Archetype (Agent specialization - what expertise):

Default archetypes for reference:

Archetype Focus
frontend UI/UX, components, styling
backend APIs, auth, validation
data Pipelines, SQL, schemas
test Coverage, fixtures, e2e
infra CI/CD, containers, cloud
review Quality, patterns
security Vulnerabilities, OWASP
generic General development

Archetypes are explicitly set by the planner. Bacchus uses archetypes.yaml as the source of truth - customize by copying to .bacchus/archetypes.yaml in your project.

Workflow

claim/next → work in workspace → release (mark ready) → orchestrator merges

1. Get Work

# Option A: Next ready task
bacchus next agent-1

# Option B: Specific task
bacchus claim TASK-42 agent-1

Output:

{
  "success": true,
  "task_id": "TASK-42",
  "title": "Implement auth",
  "workspace_path": ".bacchus/workspaces/TASK-42"
}

2. Do Work

Work in the jj workspace. Changes are auto-snapshotted - no explicit add/commit needed.

Warning: Never cd into a workspace. Use jj -R instead - workspaces are ephemeral and get deleted on release.

# Check status
jj -R .bacchus/workspaces/TASK-42 status

# Describe your change (like a commit message)
jj -R .bacchus/workspaces/TASK-42 describe -m "Implement auth"

# View your changes
jj -R .bacchus/workspaces/TASK-42 diff

3. Release

# Success - mark ready for release (orchestrator will merge)
bacchus release TASK-42 --status done

# Blocked - keep workspace, mark task blocked
bacchus release TASK-42 --status blocked

# Failed - discard workspace, reset task to open
bacchus release TASK-42 --status failed

4. Orchestrator Merges (Automatic)

When you mark a task ready, the orchestrator:

  1. Rebases your commit onto current main
  2. If conflicts: marks task needs_resolution (you fix with jj resolve)
  3. If clean: advances main bookmark and closes task

Manual trigger (outside orchestrator stop-hook loops):

bacchus process-releases

Session Management

Sessions enable stop hooks that prevent premature exit:

# Start agent session (blocks until task closed; pass agent id for immediate heartbeat loop)
bacchus session start agent --task-id TASK-42 --agent-id agent-1

# Start orchestrator session (blocks while work remains)
bacchus session start orchestrator --max-concurrent 3

# Launch ready workers once (optional manual trigger)
bacchus session spawn-workers --count 3

# Check session state
bacchus session status

# Clear session to exit
bacchus session stop

# Cleanup stale scoped session files
bacchus session prune --minutes 240

Session state is scoped per CLI/session identity in .bacchus/sessions/<scope>.json. Set BACCHUS_SESSION_ID explicitly when running multiple concurrent sessions from the same repo root. Only one orchestrator can hold the leader lease at a time; secondary orchestrator starts are rejected.

Autonomous worker spawning controls:

  • BACCHUS_ORCHESTRATOR_AUTO_SPAWN=1 (default) enables auto-spawn attempts during session check.
  • BACCHUS_WORKER_CMD sets the worker shell command (required for auto-spawn).
  • BACCHUS_WORKER_MAX_RETRIES limits retries per task (default: 3).
  • BACCHUS_WORKER_RETRY_BACKOFF_MS sets retry backoff (default: 60000).
  • BACCHUS_WORKER_STALE_GRACE_MS extends stale-worker recovery grace beyond claim timeout (default: 60000).
  • BACCHUS_WORKER_MAX_RUNTIME_MS optionally fails/reopens long-running workers after this runtime (default: disabled).
  • BACCHUS_WORKER_KILL_STALE=1 enables best-effort PID termination before failing/reopening stale workers (default: 0). Use bacchus session spawn-workers --dry-run to preview ready candidates and slot usage without launching workers. When a worker is stale (task heartbeat expired), orchestrator recovers it by marking worker failed and reopening the task.

Stale Detection

Find and cleanup abandoned claims:

# List stale claims (>30 min old)
bacchus stale --minutes 30

# Auto-cleanup
bacchus stale --minutes 30 --cleanup

Task Definition

Tasks are defined in YAML and imported to SQLite:

# .bacchus/tasks.yaml
version: 1

tasks:
  - id: AUTH-001
    title: "Implement user authentication"
    description: "Add JWT-based auth"
    type: feature              # PM workflow: bug_fix | feature | refactor | test | docs | infra | generic
    archetype: backend         # Agent expertise: frontend | backend | data | test | infra | review | security | generic
    priority: 1
    status: open
    depends_on: []
    footprint:
      modifies:
        - "src/auth/handler.rs::AuthHandler"
      creates:
        - "src/auth/middleware.rs"

  - id: API-002
    title: "Add rate limiting"
    type: feature
    archetype: backend
    priority: 2
    depends_on: [AUTH-001]
    footprint:
      modifies: ["src/middleware/mod.rs::*"]

  - id: AUTH-001-SEC
    title: "Security review of auth"
    type: feature              # The review is a feature task
    archetype: security        # But needs security expertise
    priority: 3
    depends_on: [AUTH-001]

Import with: bacchus task import --epic-id MY-EPIC

Directory Structure

project/
├── .jj/                    # jj repository data
├── .bacchus/
│   ├── bacchus.db          # SQLite database (tasks, claims, metrics)
│   ├── tasks.yaml          # Task definitions (import source)
│   ├── sessions/           # Scoped session state files
│   │   ├── default.json
│   │   └── <scope>.json
│   └── workspaces/
│       ├── TASK-42/        # Agent 1's jj workspace
│       └── TASK-43/        # Agent 2's jj workspace

Stop Hook Architecture

┌─────────────────────────────────────────────────────────────┐
│                    ORCHESTRATOR MODE                         │
│  Spawns agents for ready tasks                              │
│  Blocks while: ready tasks exist OR agents active           │
│  Approves when: all work done or blocked                    │
├─────────────────────────────────────────────────────────────┤
│   ┌─────────┐   ┌─────────┐   ┌─────────┐                  │
│   │ Agent 1 │   │ Agent 2 │   │ Agent 3 │                  │
│   │ TASK-A  │   │ TASK-B  │   │ TASK-C  │                  │
│   └─────────┘   └─────────┘   └─────────┘                  │
│                                                              │
│  AGENT MODE                                                  │
│  Blocks while: assigned task not closed                     │
│  Approves when: task status == "closed"                     │
└─────────────────────────────────────────────────────────────┘

Supported Languages (Symbol Indexing)

  • TypeScript / JavaScript
  • Python
  • Go
  • Rust

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors