Skip to content

Getting started

A five-minute walkthrough: install abtree, hand a tree to your agent, and watch it drive.

Install

sh
curl -fsSL https://github.com/flying-dice/abtree/releases/latest/download/install.sh | sh
powershell
irm https://github.com/flying-dice/abtree/releases/latest/download/install.ps1 | iex

Verify:

sh
abtree --version

You'll see a version number. If you don't, restart your terminal so the new PATH takes effect.

Concepts in 60 seconds

Three words worth knowing:

  • Tree — a YAML file describing a workflow. Lives in .abtree/trees/.
  • Flow — one execution of a tree, bound to a piece of work. Persists as JSON in .abtree/flows/.
  • Step — the smallest unit. Either an evaluate (a precondition the agent confirms) or an instruct (work the agent performs).

abtree is a CLI for agents. You don't drive flows yourself — you hand a brief to your agent and it runs the loop. Three commands carry the whole protocol: abtree next to ask "what now?", abtree eval to answer a precondition, abtree submit to report an outcome. JSON in, JSON out.

1. Set up a workspace

sh
mkdir my-abtree-demo && cd my-abtree-demo
mkdir -p .abtree/trees
curl -fsSL https://raw.githubusercontent.com/flying-dice/abtree/main/.abtree/trees/hello-world.yaml \
  -o .abtree/trees/hello-world.yaml

hello-world is a small tree: greet a user based on the time of day, then enrich the greeting with weather and news. It exercises all four behaviour-tree primitives in fifteen lines.

2. Hand it off to your agent

In Claude Code, ChatGPT, or any agent that can run shell commands, send:

text
Run the abtree hello-world flow end-to-end. Start by running
'abtree --help' to learn the execution protocol, then create a
flow with 'abtree flow create hello-world "first run"' and drive
it through every step until you see status: done.

That is the entire human-side interaction. The agent reads the protocol from --help, creates a flow, and runs the loop autonomously.

3. What the agent does under the hood

Each turn, the agent calls one command and reads its JSON response.

abtree next first-run__hello-world__1 returns the next step:

json
{
  "type": "instruct",
  "name": "Determine_Time",
  "instruction": "Check the system clock to get the current hour..."
}

The agent does the work — checks the clock, classifies the hour as morning — then writes the result and submits:

sh
abtree local write first-run__hello-world__1 time_of_day "morning"
abtree submit first-run__hello-world__1 success

The next call returns an evaluate:

json
{
  "type": "evaluate",
  "name": "Morning_Greeting",
  "expression": "$LOCAL.time_of_day is \"morning\""
}

The agent reads the expression, decides it holds, and answers:

sh
abtree eval first-run__hello-world__1 true

The loop repeats — next → do the work or judge the precondition → submit or eval — until:

json
{ "status": "done" }

The agent never sees the rest of the tree. Just the next request.

4. The execution diagram

abtree regenerates a Mermaid diagram at .abtree/flows/first-run__hello-world__1.mermaid after every state change. Here's what a completed hello-world run looks like — green nodes succeeded, uncoloured ones were skipped.

mermaid
---
title: "hello-world (complete)"
---
flowchart TD
    Hello_World{{"Hello World\n[sequence]"}}
    0_Determine_Time["Determine Time\n[action]"]
    Hello_World --> 0_Determine_Time
    style 0_Determine_Time fill:#4ade80,stroke:#16a34a,color:#052e16
    0_Choose_Greeting{{"Choose Greeting\n[selector]"}}
    Hello_World --> 0_Choose_Greeting
    style 0_Choose_Greeting fill:#4ade80,stroke:#16a34a,color:#052e16
    0_1_Morning_Greeting["Morning Greeting\n[action]"]
    0_Choose_Greeting --> 0_1_Morning_Greeting
    style 0_1_Morning_Greeting fill:#4ade80,stroke:#16a34a,color:#052e16
    0_1_Afternoon_Greeting["Afternoon Greeting\n[action]"]
    0_Choose_Greeting --> 0_1_Afternoon_Greeting
    0_1_Evening_Greeting["Evening Greeting\n[action]"]
    0_Choose_Greeting --> 0_1_Evening_Greeting
    0_1_Default_Greeting["Default Greeting\n[action]"]
    0_Choose_Greeting --> 0_1_Default_Greeting
    0_Gather_Context{{"Gather Context\n[parallel]"}}
    Hello_World --> 0_Gather_Context
    style 0_Gather_Context fill:#4ade80,stroke:#16a34a,color:#052e16
    0_2_Check_Weather["Check Weather\n[action]"]
    0_Gather_Context --> 0_2_Check_Weather
    style 0_2_Check_Weather fill:#4ade80,stroke:#16a34a,color:#052e16
    0_2_Check_News["Check News\n[action]"]
    0_Gather_Context --> 0_2_Check_News
    style 0_2_Check_News fill:#4ade80,stroke:#16a34a,color:#052e16
    0_Compose_Response["Compose Response\n[action]"]
    Hello_World --> 0_Compose_Response
    style 0_Compose_Response fill:#4ade80,stroke:#16a34a,color:#052e16

The cursor advanced through the sequence. The selector chose Morning Greeting and stopped — the afternoon, evening, and default branches were never entered. Both context-gathering actions ran in parallel. Every action passed its evaluate invariant before its instruct ran.

What just happened

Your agent drove a structured workflow without you writing a system prompt, without a JSON schema in its context, without chain-of-thought. The tree handed it exactly one task at a time, and only let it advance when it proved the task was complete.

That's the core idea: deterministic structure for non-deterministic agents.

Next

MIT licensed