5 releases (breaking)
Uses new Rust 2024
| 0.5.0 | Mar 2, 2026 |
|---|---|
| 0.4.0 | Feb 17, 2026 |
| 0.3.0 | Feb 17, 2026 |
| 0.2.0 | Feb 16, 2026 |
| 0.1.0 | Feb 16, 2026 |
#798 in Development tools
56KB
1.5K
SLoC
Tendril
Tendril is an agentic orchestration tool that parallelizes software development across multiple AI agents. It uses git worktrees to create isolated working directories — each on its own branch with Claude Code ready to go — so you can run multiple AI-assisted dev tasks simultaneously without leaving your host machine.
Instead of running one agent on one branch, Tendril lets you orchestrate many agents at once: open a terminal, run tndrl start, and fire off a task. Open another terminal, do it again. Each agent works independently in its own worktree, on its own branch, with full repo access and all your existing dev tools.
Prerequisites
- macOS (v1 target platform)
- Rust 1.85+ (uses edition 2024)
- Git with an
originremote configured - Claude Code CLI installed (
npm install -g @anthropic-ai/claude-code)
Install
git clone <this-repo>
cd tendril
cargo build --release
The binary is at target/release/tndrl. Add it to your PATH or use cargo install --path ..
Usage
Start a new session
tndrl start
This will:
- Detect your repo's git remote URL from the current directory
- Prompt you for a branch name
- Create a git worktree at
~/.tendril/worktrees/<session-id>(creates the branch if it doesn't exist) - Launch Claude Code directly in the worktree directory
After launching, you'll land in a Claude Code session inside the worktree. Open another terminal and run tndrl start again to spin up a parallel session on a different branch.
You can also pass the branch name directly:
tndrl start --branch feature/my-task
List active sessions
tndrl list
Displays a table of all sessions with their status, branch, repository, and start time.
+----------+---------+----------------+----------------------------------+------------------------+
| ID | Status | Branch | Repository | Started At |
+----------+---------+----------------+----------------------------------+------------------------+
| a1b2c3d4 | Running | feature/auth | git@github.com:user/repo.git | 2026-02-13 15:30:00 UTC|
| e5f6g7h8 | Stopped | feature/api | git@github.com:user/repo.git | 2026-02-13 14:00:00 UTC|
+----------+---------+----------------+----------------------------------+------------------------+
Watch mode
tndrl list --watch
Continuously monitors session state and updates the table in real time.
Prune stopped sessions
tndrl prune
Removes stopped and failed sessions, cleaning up their worktree directories.
Nuke everything
tndrl nuke
When worktrees and sessions.json get into a bad state, nuke provides a clean slate. It scans both sessions.json and the ~/.tendril/worktrees/ directory (catching orphaned directories too), lists every worktree and its branch, then asks for confirmation before removing everything and clearing the session file.
Sprint mode (Azure DevOps)
Automatically create sessions for every work item in your current ADO sprint:
tndrl sprint --org myorg --project MyProject
This will:
- Fetch the current sprint/iteration from Azure DevOps
- Pull all active work items (filtering out Closed/Removed/Done)
- Create a worktree and branch for each (e.g.
feature/12345/add-user-login) - Open a new Terminal.app window per work item with Claude Code pre-loaded with the work item context
Configuration
Sprint mode requires a Personal Access Token with vso.work scope. Set it as an environment variable:
export ADO_PAT="your-personal-access-token"
Organization, project, and team can be passed as flags or environment variables:
| Flag | Env Variable | Required | Description |
|---|---|---|---|
--org |
ADO_ORG |
Yes | Azure DevOps organization name |
--project |
ADO_PROJECT |
Yes | Project name |
--team |
ADO_TEAM |
No | Team name (defaults to "{project} Team") |
CLI flags take precedence over environment variables.
Options
# Preview sprint items without starting sessions
tndrl sprint --org myorg --project MyProject --dry-run
# Run Claude in the background instead of opening Terminal windows
tndrl sprint --org myorg --project MyProject --headless
# Use env vars so you don't need flags every time
export ADO_ORG=myorg
export ADO_PROJECT=MyProject
tndrl sprint
In headless mode, each Claude process runs in the background with output logged to claude.log in the worktree directory. Session status is tracked via PID liveness — tndrl list will detect when background processes finish.
How it works
Git worktrees let you check out multiple branches of the same repository simultaneously in separate directories. Tendril leverages this to create isolated workspaces without any virtualization overhead.
Each worktree session:
- Creates a new directory at
~/.tendril/worktrees/<session-id> - Checks out the specified branch (or creates it if it doesn't exist)
- Inherits your host's SSH keys, git config, dev tools, and environment
- Runs Claude Code natively — no overhead
- Tracks session state in
~/.tendril/sessions.json
This is fast, lightweight, and leverages everything already installed on your machine.
Session tracking
Session metadata is persisted to ~/.tendril/sessions.json. The list command reads this file and reconciles with the actual state by checking worktree directory existence.
Project structure
src/
main.rs -- CLI parsing, start/list/prune/nuke/sprint command orchestration
ado.rs -- Azure DevOps API interaction (sprint fetch, work item details)
worktree.rs -- Git worktree creation, branch detection, repo URL, Claude launch
session.rs -- Session persistence to ~/.tendril/sessions.json
types.rs -- Session, SessionStatus, AdoWorkItemRef types
Current limitations
- No
tndrl stopcommand — worktrees persist until manually cleaned up - SSH remotes preferred — HTTPS remotes with credential helpers aren't handled yet
- No session cleanup — stopped sessions accumulate in the JSON file until pruned
- Branch switching in worktrees is not tracked — Tendril assumes a 1:1:1 mapping between session, worktree, and branch. If you switch branches inside a worktree (e.g.
git checkout -b new-branch), session metadata becomes stale:tndrl listwill show the old branch, andtndrl start --branch new-branchwill fail because git only allows a branch to be checked out in one worktree at a time. Avoid switching branches inside a Tendril worktree — start a new session instead. - Prune doesn't check for active use —
tndrl prunewill remove worktree directories for stopped sessions even if your shell is still in that directory or you've started new work there. Make sure you've exited the worktree before pruning.
Tech stack
- Rust (edition 2024)
- clap — CLI argument parsing
- tokio — async runtime
- dialoguer — interactive terminal prompts
- comfy-table — formatted table output
- serde/serde_json — session serialization
- chrono — timestamps
- uuid — session IDs
- dirs — home directory resolution
- colored — terminal colors
- reqwest — HTTP client (ADO API)
- html2text — HTML-to-plain-text conversion for work item fields
Roadmap
tndrl stopcommand with worktree cleanup- Session descriptions and filtering
- Reconcile worktree branch state on
listandprune(detect branch drift viagit branch --show-current) - Guard
pruneagainst active worktree usage (check for running processes before removing) - Warn when running
tndrl startfrom inside an existing Tendril worktree
Dependencies
~12–28MB
~350K SLoC