Skip to main content

An orchestration layer for agentic coding

Project description

bouquet logo

bouquet

CI

Warning โ€” Alpha Software Bouquet is under active development. APIs, config format, and CLI behavior may change without notice. Use at your own risk.

An orchestration layer for multi-agent coding โ€” multiplexing coding agents across git worktrees with isolated services, all in one tmux session.

cd my-project
bouquet start              # TUI launches, create worktrees, agents spin up

Key Features

Feature Details
๐ŸŒฟ Git worktree isolation Each feature branch gets its own worktree, venv, and node_modules โ€” no cross-contamination
๐Ÿ–ฅ๏ธ Multi-pane services Run API servers, workers, frontends alongside the agent with automatic port offsetting per worktree
๐Ÿค– Agent orchestration TUI in tmux window 0 to create, switch, and manage worktree-backed agent windows
๐Ÿ“‹ Task queue Define a backlog of tasks that get automatically delegated to worktrees โ€” agents pick up work without manual intervention
๐Ÿ”ง Rich configuration Expressive .bouquet.toml with template expressions ({{ 8000 + BOUQUET_WORKTREE_INDEX }}), per-worktree variables, agent profiles, and multi-service layouts
โšก Fast bootstrap CoW-clones .venv/node_modules (APFS), copies .env files, runs uv sync/pnpm install
๐Ÿ”Œ Agent-agnostic Named profiles let you mix Claude, Aider, Codex, or any CLI agent โ€” even different agents per worktree

Requirements

  • Python 3.14+
  • tmux (brew install tmux)
  • GitHub CLI (optional, brew install gh โ€” enables PR links in TUI and GitHub Issues task backend)
  • direnv (optional, brew install direnv)
  • Language package managers as needed (uv, pnpm)

Installation

# Run without installing
uvx pybouquet --help

# Or install via pip
pip install pybouquet

# Or from source (development)
git clone https://github.com/promptromp/bouquet.git
cd bouquet
uv sync

Quick Start

1. Initialize

cd /path/to/your/repo
bouquet init

Creates a .bouquet.toml template. Edit it to configure your project.

2. Start a session

bouquet start

This will:

  1. Create a tmux session (bouquet-<project-name>)
  2. Launch the orchestrator TUI in window 0
  3. Adopt any existing git worktrees
  4. Attach you to the session

You can also pass arguments explicitly:

bouquet start my-project --repo /path/to/repo --config /path/to/.bouquet.toml

3. Use the TUI

Key Action
N Create a new worktree (opens branch dialog with optional agent profile selector)
S / Enter Switch to the selected worktree's window
D Delete the selected worktree and its window
a Toggle auto-accept for selected worktree (auto-sends "y" at permission prompts)
A Toggle autopilot mode (auto-schedules tasks by dependency order)
P Send a prompt to selected or all agent terminal(s) via tmux send-keys
T Request a status summary from all agents (captures responses)
C Create a new task in the task queue
X Pick up the highlighted task (creates worktree and sends task to agent)
M Complete the highlighted task (optionally remove the associated worktree)
Backspace Delete the highlighted task from the queue
R Refresh the worktree list and task queue
Q Quit (with confirmation โ€” kills the session)

When you create a worktree, bouquet will:

  • Create a git worktree with a new branch
  • Bootstrap the environment (copy .env files, CoW-clone .venv/node_modules)
  • Open a new tmux window with service panes (if configured)
  • Launch the agent (e.g. claude) in pane 0

Switch back to the orchestrator: Ctrl-b 0.

4. Stop

bouquet stop

Cleans up all managed worktrees, resets any in-progress tasks back to open, kills the tmux session, and removes state.


Services

Run dev servers alongside the agent in each worktree window. Define them in .bouquet.toml:

[[services]]
name = "api"
command = "uv run uvicorn app.main:app --reload --port {{ 8000 + BOUQUET_WORKTREE_INDEX }}"

[[services]]
name = "frontend"
command = "npm run dev -- --port {{ 3000 + BOUQUET_WORKTREE_INDEX }}"

[tmux]
layout = "main-vertical"

Each worktree gets a unique index (1, 2, 3, ...) so services bind to different ports automatically.

Template Variables

Variable Type Example
BOUQUET_WORKTREE_INDEX int 1, 2, 3
BOUQUET_WORKTREE_BRANCH str feature/auth
BOUQUET_WORKTREE_PATH str /path/to/.bouquet-worktrees/feature-auth
BOUQUET_PROJECT_NAME str my-project

Arithmetic supported: {{ 8000 + BOUQUET_WORKTREE_INDEX }} โ†’ 8001.

The same template variables are also available in [bootstrap] setup_commands, post_deps_commands, and teardown_commands โ€” both as {{ โ€ฆ }} placeholders and as plain shell env vars ($BOUQUET_WORKTREE_INDEX, etc.) โ€” so setup/teardown scripts can provision and reclaim per-worktree resources (databases, queues, โ€ฆ) without external coordination.

No services defined = single pane with just the agent (backward compatible).

Bootstrap hooks: setup_commands vs post_deps_commands vs teardown_commands

The three [bootstrap] hook lists run at different points in the worktree lifecycle:

Hook When On failure Typical use
setup_commands Before python_deps_command / node_deps_command Loud โ€” raises SetupCommandsError, worktree โ†’ ERROR private-registry auth (CodeArtifact tokens), provisioning per-worktree DBs / queues
post_deps_commands After deps install, before direnv_allow (so .venv / node_modules exist) Loud โ€” same as setup_commands uv run migrate upgrade head, asset compilation, anything that needs the project's tooling
teardown_commands Before tmux window kill + git worktree removal (so the on-disk checkout is still reachable) Best-effort โ€” failures logged, cleanup proceeds reclaiming external per-worktree resources at remove time (drop DBs, delete queues)

setup_commands and post_deps_commands also have env-capture: any export FOO=bar lines in the user's commands are captured and propagated into both subsequent install commands and the tmux session, so service panes inherit them.

See docs/configuration.md for the full reference.


Agent Profiles

Named agent configurations so you can switch between Claude, Aider, Codex, etc. per worktree:

[agent]
command = "claude"
default_profile = "claude"

[[agent.profiles]]
name = "claude"
command = "claude"

[[agent.profiles]]
name = "aider"
command = "aider"
args = ["--model", "claude-sonnet-4-20250514"]

When profiles are defined, the TUI's new-worktree dialog shows a profile selector. If no profiles are defined, the top-level command/args are used (backward compatible).


Activity Detection

Bouquet polls each agent's tmux pane every 2 seconds to infer real-time status:

Status Meaning
โ— running (green) Agent output is actively changing
โ—† waiting (yellow) Agent output stopped and a permission prompt was detected
โ—‹ idle (dim) Agent output hasn't changed for several polls

This replaces the static "active" status with live feedback. The TUI table updates automatically.


Task Queue

Define a backlog of tasks that agents pick up automatically. Two backends are supported:

Local (SQLite) โ€” default

Tasks are stored in ~/.local/state/bouquet/<project>.tasks.db. No external dependencies.

[task_queue]
backend = "local"
auto_branch_prefix = "task/"

GitHub Issues

Uses your repo's GitHub Issues as the task source. Requires gh CLI authenticated.

[task_queue]
backend = "github"
label_filter = "bouquet"     # only issues with this label appear as tasks
auto_branch_prefix = "task/"

Status mapping: OPEN = open issue, IN_PROGRESS = open issue + in-progress label, DONE = closed issue.

Task workflow

  1. Create (c) โ€” opens a dialog to create a task with an optional parent dependency
  2. Pick up (x) โ€” creates a worktree from the task, marks it in-progress, and sends the task description to the agent
  3. Complete (m) โ€” marks the task as done, optionally removes the associated worktree
  4. Reconciliation โ€” on startup, tasks stuck as in-progress (from a crash or quit) are automatically reset to open if their worktree no longer exists

Task Dependencies

Tasks can declare a parent dependency, forming a DAG. A task with an unsatisfied dependency shows as blocked in the queue and cannot be picked up until its parent is done. Cycles are rejected at creation time.

Autopilot

Press A to toggle autopilot mode. When active, bouquet automatically:

  • Picks up tasks whose dependencies are satisfied (or have none)
  • Runs up to max_autopilot_concurrency tasks in parallel (default 3)
  • Enables auto-accept on all autopilot-created worktrees
  • Auto-completes tasks when their agent goes idle (~10 seconds)
  • Cascades: completing a parent unblocks its children for the next scheduling cycle
[task_queue]
max_autopilot_concurrency = 3    # max parallel worktrees
autopilot_auto_complete = true   # auto-complete IDLE tasks

Pane Layout

With layout = "main-vertical" and two services:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  โ”‚   api      โ”‚
โ”‚   agent (claude) โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                  โ”‚  frontend  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Logs & Troubleshooting

Bouquet writes a rotating log file to ~/.local/state/bouquet/<project>.log (5 MB ร— 3 backups). bouquet start prints the path to stderr on launch.

When a worktree creation fails โ€” most often because a setup_commands or post_deps_commands step exited non-zero โ€” the TUI shows a terse toast (Error creating worktree: โ€ฆ) but the captured stdout and stderr from your bash commands land in the log file, along with the phase name (setup_commands vs post_deps_commands), cwd, and exit code. Tail it to debug:

tail -f ~/.local/state/bouquet/<project>.log

The SetupCommandsError raised on failure includes the log file path in its message, so the toast will point you there directly.

teardown_commands failures are best-effort and don't block worktree removal โ€” they log a WARNING-level line in the same log file, so check there if a worktree was removed but external resources weren't reclaimed.

Pass --log-level=DEBUG to bouquet start for more verbose output (e.g. each rendered setup_commands / post_deps_commands / teardown_commands line):

bouquet start --log-level=DEBUG

Architecture

The Conceptual Stack
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚         Orchestration Layer             โ”‚  โ† TUI, agent coordination, task queue
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         Session / Mux Layer             โ”‚  โ† tmux sessions, windows, panes
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         Isolation Layer                 โ”‚  โ† git worktrees + env isolation
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         Environment Layer               โ”‚  โ† venv/node_modules/env vars
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Related Projects

Bouquet draws inspiration from and complements several tools in the multi-agent coding space:

  • claude-squad โ€” A Go-based TUI for managing multiple Claude Code instances in parallel. Claude-squad focuses on running agents side-by-side with a clean terminal UI. Bouquet goes further with declarative multi-service layouts (API servers, frontends, workers per worktree), a rich template-based configuration language with per-worktree variable expansion, and a task queue for automatic work delegation across agents.

  • ruflo โ€” A Rust-based agentic workflow orchestrator with a focus on DAG-based task execution and CI/CD integration. Ruflo takes a pipeline-oriented approach to agent coordination, while bouquet is designed around the developer's local workflow โ€” git worktrees, tmux sessions, and interactive TUI management with live activity detection.

  • Claude Code Agent Teams โ€” Anthropic's experimental built-in feature for coordinating multiple Claude Code agents. Agent Teams operates within the Claude Code runtime itself. Bouquet is agent-agnostic (works with Claude, Aider, Codex, or any CLI tool), provides full control over environment isolation, service orchestration, and configuration through .bouquet.toml.

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

pybouquet-0.6.1.tar.gz (579.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pybouquet-0.6.1-py3-none-any.whl (58.8 kB view details)

Uploaded Python 3

File details

Details for the file pybouquet-0.6.1.tar.gz.

File metadata

  • Download URL: pybouquet-0.6.1.tar.gz
  • Upload date:
  • Size: 579.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pybouquet-0.6.1.tar.gz
Algorithm Hash digest
SHA256 f16c77fda742e1993af0732acc3f594677ab6c523847558497f3e8379d09b660
MD5 1aada7bf424d41509f133f6ac010ff66
BLAKE2b-256 4b5e5153538fa5c6068f19ee1b6e54b80849203dca61407604ceb2fa28b069b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for pybouquet-0.6.1.tar.gz:

Publisher: publish-to-pypi.yml on promptromp/bouquet

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pybouquet-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: pybouquet-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 58.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pybouquet-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 be296cc701ccd7fb6f802305f4c3a7ee817e8a5668cf113a1272658005b6ea40
MD5 fe5fcfef47e0f86edb77cf4fe5f2df0f
BLAKE2b-256 0e97bdede4e386f33e4dd678b23c7824331b41aafdbeba73d97d69958293dc82

See more details on using hashes here.

Provenance

The following attestation bundles were made for pybouquet-0.6.1-py3-none-any.whl:

Publisher: publish-to-pypi.yml on promptromp/bouquet

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page