Imran Khan
← Back to blog
How to Integrate Beads into an AI-Orchestrated System for Agentic Task Planning
AI orchestrationagentic systemstask managementBeadsplanner agentskillsworkflow automationLLM systemssoftware deliveryproject managementarchitecturedeveloper productivity

How to Integrate Beads into an AI-Orchestrated System for Agentic Task Planning

By Imran Khan·18m read

Integrate the Beads CLI with planner and worker agents using JSON output, real dependency edges, atomic claims, and an explicit adapter contract for review and completion.

Modern AI-orchestrated systems tend to accumulate “planning exhaust”: ad‑hoc TODOs in READMEs, a tasks.md in each service, Jira tickets that drift away from reality, and a pile of half-finished notes no one trusts. When you add planner agents into the mix—agents that reason about work, generate subtasks, and coordinate execution—the cost of that fragmentation multiplies. The system needs a single source of truth for tasks that is accessible to both humans and agents, with enough structure to support automation but not so heavy that developers avoid it.

This is where Beads fits as a task management backbone. It is a dependency-aware issue tracker operated through the bd CLI, not a hosted project-management API implied by the examples below. Current Beads documentation describes Dolt-backed storage. Pin the version you integrate and read its upgrade guidance: older SQLite/JSONL workflows are not interchangeable with the current database and sync model.

This article walks through an architecture where:

  • Your orchestration has a Task Planner agent responsible for decomposing goals into actionable tasks.
  • The planner interacts with Beads through a dedicated skill (a tool interface).
  • Worker agents execute tasks and report progress back into Beads.
  • Developers stop scattering Markdown task files across the repo and instead get a living, queryable task graph.

Along the way, we’ll cover design patterns, a practical skill contract, task lifecycle mechanics, and how this affects delivery quality.

Why Beads as the task system in an AI orchestration stack?

AI orchestration systems typically solve three problems:

  1. Planning (turn a goal into tasks),
  2. Execution (run tasks via tools/agents),
  3. Coordination (state, dependencies, progress, handoffs).

Unstructured Markdown lists make coordination harder. Markdown can have identifiers, schemas, and automation, but those conventions and validators become your responsibility. Beads supplies a task model and query interface instead.

A task system like Beads becomes the “coordination substrate” because it can offer:

  • Stable task IDs for referencing work in code, commits, PRs, and agent messages.
  • Structured fields (status, priority, owner, due dates, labels) that agents can read/write reliably.
  • Centralized visibility for humans and agents: the planner can “see” what exists and avoid duplicates.
  • Automation hooks: the orchestration layer can build predictable workflows around task creation, transitions, and reporting.

The key is not simply “tracking tasks”, but enabling a closed loop:

Plan → Create tasks → Execute → Report → Replan based on reality

With scattered Markdown, that loop breaks at “create tasks” (no consistent format) and “report” (no canonical destination).

The core architecture: Planner agent + Beads skill + Worker agents

Treat Beads as a local task store and CLI, with your orchestration acting as the control plane. Any web dashboard is an additional integration, not something the core CLI requires.

Components

1) Task Planner Agent

  • Input: high-level goal (e.g., “Add OAuth login”, “Refactor billing pipeline”).
  • Reads context: repo structure, existing tasks in Beads, recent changes.
  • Outputs: task breakdown with dependencies, acceptance criteria, and suggested execution order.

2) Beads Skill (tool interface)

  • Provides structured operations for the planner/agents:
    • list/search tasks,
    • create tasks,
    • update tasks,
    • link tasks (dependencies, parent/child),
    • comment/log progress.

3) Worker Agents

  • Pick up tasks from Beads (or assigned via orchestrator).
  • Execute: code changes, tests, documentation, deployment steps.
  • Report results back into Beads: status updates, notes, links to PRs/commits/build logs.

4) Orchestrator

  • Routes tasks to workers, enforces policies (e.g., required reviews), resolves concurrency.
  • Maintains run state, retries, tool credentials, and auditing.

The data flow

A typical run looks like this:

  1. A user (or CI trigger) submits a goal: “Implement feature X.”
  2. Orchestrator asks Planner: “Propose a plan and tasks.”
  3. Planner uses beads.searchTasks() to see what already exists and avoid duplication.
  4. Planner uses beads.createTask() to create a parent “Epic/Initiative” plus child tasks.
  5. Orchestrator assigns tasks to Worker agents.
  6. Worker agents execute tasks; they use beads.updateTask() and beads.addComment() to report.
  7. Planner periodically re-checks Beads to adjust plan based on what’s done, blocked, or failing.

This turns Beads into the shared memory for the system.

Designing the Beads skill: keep it boring, strict, and predictable

Agent tooling succeeds when it has stable contracts and low ambiguity. The Beads skill should be intentionally limited and explicit—agents shouldn’t be “clicking around” or scraping HTML; they should call a small, well-defined interface.

The beads.* methods in this article are an application-owned adapter design, not published Beads JavaScript methods. Implement them over bd ... --json, or deliberately choose the separate MCP integration and inspect its actual tool schema. Do not assume the pseudo-API names are accepted by either. Beads MCP integration

Start with the real CLI

Install a chosen release using the official installation instructions, then initialize only the intended project. A basic loop is:

bd version
bd init
bd create "Implement OAuth callback" --description "Validate state and PKCE, exchange the code, create a secure session, and test failure paths." -t task -p 1 --json
bd ready --json
bd show <returned-id> --json
bd update <returned-id> --claim --json
bd close <returned-id> --reason "Accepted implementation and verification in PR #77" --json

<returned-id> means the real ID from creation, typically with a project prefix and hash. Do not copy it as a literal argument. Check the claim result before starting work: another worker may already own the issue. Closing comes after your acceptance policy passes, not just after an agent says it finished. CLI reference, atomic claim behavior

  • search_tasks(query, status?, labels?, assignee?, limit?)
  • get_task(task_id)
  • create_task(title, description, labels?, priority?, parent_id?, links?, acceptance_criteria?)
  • update_task(task_id, status?, title?, description?, labels?, priority?, assignee?)
  • add_comment(task_id, comment, artifacts?)
  • link_tasks(task_id, links=[{type, target_task_id}])

An adapter tool-call payload (example)

{
  "tool": "beads.create_task",
  "arguments": {
    "title": "Add OAuth callback route",
    "description": "Implement /auth/callback handler for Google OAuth. Store tokens securely and create session.",
    "labels": ["auth", "backend", "oauth"],
    "priority": "P1",
    "parent_id": "bd-a1b2",
    "acceptance_criteria": [
      "Callback exchanges code for tokens",
      "Tokens stored using existing secret storage",
      "Session cookie set with correct flags",
      "Unit tests cover error cases",
      "Docs updated in /docs/auth.md"
    ],
    "links": [
      {"type": "relates_to", "url": "https://github.com/org/repo/issues/77"}
    ]
  }
}

This is a sample tool-call payload, not a JSON Schema or the native issue JSON. Validate it with a real schema in the adapter, map priority to the supported CLI representation, and resolve parent_id to an existing record. Acceptance criteria become the worker’s checklist, but checking that they were fulfilled still belongs to tests and review.

Task statuses as a lifecycle, not decoration

The biggest improvement you can make is to standardize a small set of statuses and enforce valid transitions. For example:

  • Proposed → Ready → In Progress → In Review → Done
  • Side states: Blocked, Won’t Do

Your orchestrator should treat status transitions as events:

  • When a task moves to Ready, it becomes eligible for assignment.
  • When it moves to In Review, the orchestrator triggers a PR review workflow.
  • When Blocked, the planner is invoked to either resolve dependencies or propose alternatives.

These labels describe an orchestration workflow, not the default status values to send to bd. Use bd statuses --json to inspect the installed version. open, in_progress, blocked, and closed are native concepts; ready is a dependency-aware query rather than a status to invent. A review phase needs an explicitly configured custom status/category or a documented label policy. Status configuration

How the planner agent should think: task graphs, not checklists

Planner agents fail when they produce shallow TODO lists. What you want is a task graph: tasks with dependencies, clear deliverables, and verification steps.

A robust planner prompt (conceptually) should push toward:

  • identifying unknowns and creating “spike” tasks,
  • separating architecture decisions from implementation,
  • including test and deployment work,
  • capturing cross-cutting changes (docs, monitoring, migration scripts).

Example: from goal to Beads tasks

Goal: “Replace ad-hoc Markdown task tracking with Beads-integrated orchestration.”

The planner might create:

  • Epic: “Adopt Beads as orchestration task backend”
    • Task: “Define Beads task schema (fields, labels, lifecycle)”
    • Task: “Implement Beads skill wrapper (search/create/update/comment/link)”
    • Task: “Add task-to-PR linkage convention using the returned Beads ID”
    • Task: “Implement worker reporting (auto comment with build logs + commit hash)”
    • Task: “Migrate existing tasks.md files into Beads (script + manual review)”
    • Task: “Add CI policy: reject PRs without Beads task reference (optional)”
    • Task: “Documentation: contributor workflow update”

Notice how this is not just “use Beads”; it’s a system integration plan with enforcement and migration.

Integrating Beads into orchestration: practical patterns

Pattern 1: Treat Beads as the authoritative task store

Avoid duplicating task state inside the orchestrator beyond transient run context. Your orchestrator can cache, but the truth lives in Beads:

  • Task descriptions, acceptance criteria, and status are read from Beads.
  • Worker results are written to Beads.
  • Planner decisions can be justified by task history in Beads.

This reduces drift and gives humans a single place to look.

Pattern 2: Use task IDs as the thread that ties everything together

Adopt a convention:

  • Branch names: beads/bd-a1b2-add-oauth-callback
  • PR title includes the actual issue ID
  • Commit messages include the actual issue ID
  • Build artifacts reference the same record

Then automate:

  • When a PR opens, the orchestrator posts a comment on the corresponding task with the PR link.
  • When CI passes, it updates the task or adds a status comment.
  • When merged, it moves task status to Done (or In Review → Done).

This is the antidote to “random MD files”: everything points to a stable task record.

Pattern 3: Planner creates tasks; workers only update and comment

To prevent chaos, separate responsibilities:

  • Planner agent is allowed to create_task and link_tasks.
  • Worker agents are allowed to update_task (limited fields) and add_comment.

This avoids a scenario where every worker invents new tasks with inconsistent naming and labels. It also makes auditing easier: new tasks represent planning events, not execution noise.

Pattern 4: Use dependencies to manage parallelism safely

AI orchestration often over-parallelizes and causes merge conflicts or architectural inconsistency. Dependencies fix that:

  • “Implement schema migration” must complete before “Deploy migration to prod”.
  • “Decide token storage mechanism” must complete before “Implement OAuth callback”.

Beads natively supports blocking edges. bd dep add <dependent-id> <prerequisite-id> means the first issue depends on the second. Parent-child relationships organize an epic but do not impose that execution order. Use blocking edges for readiness, and separately coordinate workers that would edit the same files. Dependency semantics

Pattern 5: Capture “unknowns” explicitly with spike tasks

A planner should create tasks like:

  • “Spike: choose CLI or MCP integration and define adapter permissions”
  • “Spike: map Beads labels to team workflow”
  • “Spike: verify storage concurrency, query limits, and sync behavior”

Then mark them Done with findings in a comment. This turns ephemeral exploration into durable project knowledge, without burying it in chat logs or MD files.

Replacing scattered Markdown tasks: what actually improves

Markdown task files feel lightweight, but they become liabilities in multi-service systems:

  • Queries such as “show blocked tasks across repos” require your own parser and routing.
  • Structure and valid status changes need explicit validation.
  • Stale lists can drift from the actual repository.
  • Concurrent file edits can conflict without coordination.

Beads improves three things immediately

1) Discoverability A single system to search beats grep across repositories. Agents can query tasks the same way humans do.

2) Consistency A task template with required fields (title, problem statement, acceptance criteria, status) makes tasks executable. The planner can rely on that structure.

3) Automation You can build workflows: auto-assign, auto-comment, auto-transition, and reporting dashboards. Markdown doesn’t do that without bolting on more tooling.

A subtle but important win: less “orchestration hallucination”

When an agent has no canonical task store, it tends to “invent” tasks or misinterpret stale notes. When it can read Beads and see what’s active, what’s blocked, and what’s done, it plans against reality.

Implementation approach: a step-by-step integration plan

Step 1: Define a task taxonomy (labels, priority, ownership)

Before you write code, decide how you’ll represent work. A practical starting point:

  • Labels by domain: frontend, backend, infra, docs, security
  • Labels by type: bug, feature, refactor, spike
  • Priority: P0–P3
  • Status lifecycle as described earlier

Write this down once (ironically, a small doc is fine) and encode it in the planner prompt and validators.

Step 2: Build the Beads skill wrapper with guardrails

Wrap the CLI or the chosen MCP tools instead of exposing arbitrary shell execution:

  • Normalize fields (e.g., priority names, statuses).
  • Enforce maximum lengths and required fields.
  • Provide idempotency helpers (e.g., “create if not exists” based on fingerprinting).

A useful trick is to add a fingerprint in the task description or metadata, derived from (repo, goal_id, task_type, key_path). Then the planner can re-run without duplicating tasks.

A search followed by creation is not atomic. Serialize creation for a planning run or enforce uniqueness in your adapter so two planners cannot both create the same fingerprint. Pass arguments as an array to a process API, validate the project path, and keep untrusted titles and descriptions out of interpolated shell commands.

Step 3: Add orchestration policies

Policies turn “task tracking” into “delivery system”:

  • Only tasks in Ready are assignable.
  • A task must have acceptance criteria to move to Ready.
  • A task can’t move to Done unless it has at least one artifact link (PR, commit, build).
  • If a task is Blocked, require a comment explaining why and what unblocks it.

These are small rules that prevent the system from becoming a dumping ground.

Step 4: Connect Beads tasks to code changes

Implement PR/commit hooks:

  • Parse task ID from branch/PR title.
  • Post PR link to the Beads task.
  • On merge, transition status and summarize changes.

If you don’t want full automation at first, start with “comment only” and keep transitions manual. The key is establishing the linkage.

Step 5: Migrate existing Markdown tasks

Don’t try to perfectly preserve everything. The best migrations:

  • Create a “Migration” epic in Beads.
  • For each MD file, create tasks for items still relevant.
  • Archive or delete the MD after migration to avoid split-brain.

A small script can help by parsing common checkbox formats and turning them into candidate tasks for human review.

A concrete example: Planner agent using the Beads skill

Imagine the user asks:

“Integrate Beads into our orchestration, add a planner agent that creates tasks, and stop using MD files.”

A planner flow could look like:

  1. beads.search_tasks("Beads integration orchestration", status=["Proposed","Ready","In Progress"])
  2. If none found:
    • beads.create_task("Adopt Beads for orchestration task management", ...) → returns an actual issue ID such as bd-a1b2
    • beads.create_task(..., parent_id="bd-a1b2") for each subtask.
  3. Link dependencies:
    • Skill call to link “Implement Beads skill wrapper” → blocks “Enable worker agents to fetch tasks”
  4. Assign ownership (if Beads supports assignees) or leave unassigned and let orchestrator assign based on capability.

Worker agents then:

  • Pull next Ready task,
  • Do work,
  • beads.add_comment(task_id, "Opened PR ..., CI run ..."),
  • beads.update_task(task_id, status="In Review").

This becomes repeatable across all initiatives.

Operational considerations: auth, rate limits, and auditability

Authentication and permissions

Local CLI use relies on OS and repository/database access; it does not automatically require a hosted-service credential or provide your planner/worker role policy. If you expose it remotely, enforce authentication and authorization in that service. The following are adapter permissions you must implement:

  • Planner: create/update/link tasks
  • Workers: update status + comment, not create
  • Humans: full access as needed

Store secrets in your existing secret manager; do not embed in agent prompts or logs.

Database concurrency and bounded queries

Agent loops can be chatty. Your wrapper should bound result sizes, avoid polling full lists, and use targeted bd show calls. Current Beads offers embedded storage with a single writer and a separate server mode for concurrent writers; select deliberately rather than assuming all agents can write an embedded database at once. Dolt backend and storage modes

For a remote adapter, also:

  • Use pagination properly,
  • Cache common queries briefly,
  • Prefer targeted lookups (get_task) over repeated searches.

Audit trail

One of the best reasons to centralize tasks is accountability. Make sure:

  • Every task update includes “who/what” (agent name, run ID).
  • Comments include artifacts (PR URL, CI URL, logs, benchmarks).
  • The orchestrator logs tool calls in a secure audit sink.

This also helps diagnose “why did the planner create 30 tasks?” after the fact.

What changes for developers day-to-day?

If the integration is done well, developers feel three improvements:

  1. Less cognitive load: no hunting for “where are the real tasks?”
  2. Fewer interruptions: the planner agent pre-structures work with acceptance criteria, so reviews are easier.
  3. Cleaner repositories: fewer stale TODO.md files, fewer conflicting lists across services.

A practical developer workflow becomes:

  • Pick a Beads task,
  • Create branch with task ID,
  • Implement and open PR,
  • Let automation update Beads,
  • Move on.

If an external tracker remains authoritative, define one-way synchronization or field ownership. Adding Beads as a second independent source of truth can create the same drift you were trying to remove.

Common failure modes (and how to avoid them)

“The planner creates too many tasks”

Fix by:

  • enforcing task granularity (e.g., “1–2 days of work per task”),
  • using parent/child structure,
  • limiting the number of tasks per planning run unless requested.

“Tasks are vague and not testable”

Fix by:

  • requiring acceptance criteria before Ready,
  • adding a template that includes “How will we verify this?”

“Workers flip statuses incorrectly”

Fix by:

  • limiting worker permissions,
  • using orchestrator-driven transitions for key states like In Review and Done.

“Beads becomes another tool no one checks”

Fix by:

  • making Beads the entry point for work assignment,
  • integrating with PRs/CI so it stays current,
  • building a simple dashboard view (e.g., Ready/Blocked/In Review).

A good end state: Beads as the living work graph of your system

When Beads is integrated into your orchestration with a planner agent and a disciplined skill interface, you end up with something stronger than “task tracking”:

  • a living map of intended work,
  • a reliable backlog that an agent can reason over,
  • a consistent narrative linking goals → tasks → code → artifacts,
  • a scalable alternative to scattered Markdown lists.

And the most important part: planning becomes a first-class, automatable part of development—without turning your repository into a graveyard of half-updated files.

For the native-task approach used by my later product preview, see BCO and Critical Boiler. That workflow uses BCO’s task system; it is not a Beads setup instruction.