🧡 NEEDLE

August 28, 2026 Β· View on GitHub

NEEDLE

🧡 NEEDLE

License: MIT Rust Version

Navigates Every Enqueued Deliverable, Logs Effort

Deterministic bead processing with explicit outcome paths.

NEEDLE is a universal wrapper for headless coding CLI agents. It processes a shared bead queue in deterministic order, dispatching work to any headless CLI (Claude Code, OpenCode, Codex, Aider) and handling every outcome through an explicit, predefined path.


πŸš€ Quickstart

# Install the latest release (prebuilt binary, Linux x86_64/aarch64)
curl -fsSL https://github.com/jedarden/NEEDLE/releases/latest/download/install.sh | bash

# Or build from source (needs Rust 1.75+, see rust-toolchain.toml)
cargo install --git https://github.com/jedarden/NEEDLE

# Install a bead backend (required)
# The bead-rs backend manages your workspace's bead store (SQLite + checkpoint)
cargo install --git https://github.com/jedarden/bead-rs --bin bead
# See https://github.com/jedarden/bead-rs for backend details and prebuilt installers (coming soon)

# Configure your bead workspace backend (required)
cd /path/to/your/workspace
cat > .needle.yaml << 'EOF'
bead_cli:
  backend: bead-rs  # or 'bead-forge' for legacy bf/br workspaces
EOF
# This file tells needle which bead CLI backend to use

# Initialise the workspace's bead store
bead init --prefix <short-name>

# Verify everything resolves
needle doctor

# Run a worker
needle run --agent claude --identity alpha

The installer drops needle in ~/.local/bin (override with NEEDLE_INSTALL_PATH); make sure that directory is on your PATH.

πŸ”’ Security Note

The installer automatically verifies SHA-256 checksums to ensure the downloaded binary has not been corrupted or tampered with. This verification is enabled by default for your protection.

Checksum verification safeguards against:

  • Corrupted downloads that could crash or behave unpredictably
  • Tampered binaries that could execute arbitrary malicious code
  • Supply chain attacks where a malicious actor modifies releases

To see full security options and tradeoffs:

curl -fsSL https://github.com/jedarden/NEEDLE/releases/latest/download/install.sh | bash -s -- --help

⚠️ Warning: The installer supports an opt-out flag (--skip-checksum) for emergency recovery scenarios, but this is strongly discouraged except as a temporary workaround when checksums.txt is unavailable due to network/infrastructure issues. See the help output for full security details.

A worker starts, claims the next bead, dispatches to your chosen agent CLI, and loops. Multiple workers can run in parallel against the same workspace β€” coordination is handled by the shared bead queue (no central orchestrator).

See docs/examples/ for end-to-end configurations.


🧢 What is a bead?

A bead is a work item β€” the unit of work NEEDLE processes. Think of it as a structured task ticket: a title, a body describing the deliverable and acceptance criteria, a status (open, in_progress, done), and optional metadata like priority and dependencies.

Beads live in a bead store β€” a pluggable backend managed by a bead CLI. The current primary backend is bead-rs, which uses a SQLite database (beads.db) plus a checkpoint directory (.beads/checkpoint/ with current.json, forensic.jsonl, and objects/). The legacy bead-forge backend uses issues.jsonl.

# Create a bead (bead-rs backend)
bead create --title "Add pagination to search results" --priority 2 --issue-type task

# List open beads
bead list --status open

# NEEDLE does the rest: claims, dispatches, and closes beads automatically

NEEDLE workers read from this store, claim the next available bead atomically, dispatch it to your chosen agent CLI, and close it on success β€” then loop.


πŸ€” Why NEEDLE

Existing agent orchestration tools are built for one of two shapes:

  • Conversational frameworks (LangGraph, AutoGen, CrewAI) assume a chat loop with a human-in-the-loop or another LLM. They are bad at headless, long-running, cost-bounded work.
  • Workflow engines (Temporal, Argo Workflows, Inngest) assume each step is deterministic code. They are bad at non-deterministic agent steps whose outcomes have to be classified and routed.

NEEDLE is the missing middle: a deterministic state machine that drives non-deterministic agents. Every outcome an agent can produce has an explicit handler. The agent's work is fuzzy; the orchestration around it is not.


🧠 Core Principle

NEEDLE is a state machine, not a script. Every bead transitions through a finite set of states, and every transition has a defined handler. There are no implicit fallbacks, no swallowed errors, no undefined paths.

If an outcome can happen, it has a handler.
If it doesn't have a handler, it cannot happen.

πŸ”„ The NEEDLE Algorithm

A single worker executes this loop indefinitely:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                     β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚   β”‚  πŸ” SELECT │◄────────────────────────────────┐  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                  β”‚  β”‚
β”‚         β”‚                                        β”‚  β”‚
β”‚         β–Ό                                        β”‚  β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   race lost    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚  β”‚
β”‚   β”‚  πŸ”’ CLAIM  │──────────────►│ πŸ” RETRY  β”‚β”€β”€β”€β”€β”€β”˜  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚         β”‚ claimed                                   β”‚
β”‚         β–Ό                                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚   β”‚ πŸ“‹ BUILD   β”‚                                     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚         β”‚                                           β”‚
β”‚         β–Ό                                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚   β”‚ πŸš€ DISPATCHβ”‚                                     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚         β”‚                                           β”‚
β”‚         β–Ό                                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚   β”‚ ⏳ EXECUTE β”‚                                     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚         β”‚                                           β”‚
β”‚         β–Ό                                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚   β”‚ πŸ“Š OUTCOME β”‚                                     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚         β”‚                                           β”‚
β”‚         β”œβ”€β”€ βœ… success ──► close bead β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚         β”œβ”€β”€ ❌ failure ──► log + release β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚         β”œβ”€β”€ ⏰ timeout ──► release + defer β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚         └── πŸ’€ crash ────► release + alert β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚                                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Algorithm Steps

πŸ” Step 1: Select

Query the bead queue for the next claimable bead in deterministic priority order. Selection is not random β€” given the same queue state, every worker computes the same ordering. Ties are broken by creation time (oldest first).

πŸ”’ Step 2: Claim

Attempt an atomic claim via the bead CLI (bead claim for bead-rs, bf claim for bead-forge). SQLite transaction isolation guarantees exactly one worker succeeds. If the claim fails (race lost), return to Step 1 with the losing candidate excluded.

πŸ“‹ Step 3: Build

Construct the prompt from the bead's context: title, body, workspace path, relevant files, and any dependency context. The prompt is a deterministic function of the bead state β€” same bead, same prompt.

πŸš€ Step 4: Dispatch

Load the agent adapter configuration (YAML), render the invoke template with the built prompt, and execute via bash -c. The agent runs headless β€” it receives a prompt, does work, and exits.

⏳ Step 5: Execute

The agent runs. NEEDLE waits. The only inputs are the exit code and stdout/stderr. There is no interactive communication during execution.

πŸ“Š Step 6: Outcome

Evaluate the result and follow the explicit path for the observed outcome:

OutcomeExit CodeHandler
βœ… Success0Validate output β†’ close bead β†’ log effort β†’ loop
❌ Failure1Log failure reason β†’ release bead β†’ increment retry count β†’ loop
⏰ Timeout124Release bead β†’ mark deferred β†’ loop
πŸ’€ Crash>128Release bead β†’ create alert bead β†’ loop
🏁 Race Lost4(Handled at Step 2) β†’ exclude candidate β†’ retry select
πŸ«™ Queue Emptyβ€”Enter strand escalation β†’ explore / mend / knot

Every row is implemented. There are no unhandled cases.


🧢 Strand Escalation

When the primary workspace has no claimable beads, NEEDLE follows a strand sequence to find or create work. Each strand is evaluated in order β€” the first strand that yields a bead wins.

#StrandAgent?Purpose
1πŸͺ‘ PluckYesProcess beads from the assigned workspace
2πŸ”§ MendNoCleanup: orphaned claims, stale locks, health checks
3πŸ”­ ExploreNoSearch other workspaces for claimable beads
4πŸ•ΈοΈ WeaveYesCreate beads from documentation gaps (opt-in)
5πŸͺ’ UnravelYesPropose alternatives for HUMAN-blocked beads (opt-in)
6πŸ’“ PulseYesCodebase health scans, auto-generate beads (opt-in)
7πŸͺž ReflectYesConsolidate learnings from recent beads (opt-in)
8πŸͺ‘ SpliceNoDocument worker failures, create alert beads
9πŸͺ’ KnotNoAll strands exhausted β€” alert human, wait

⚑ Parallel Workers

Multiple NEEDLE workers run independently with no central orchestrator. Coordination happens through the shared bead queue:

  • Atomicity β€” the bead CLI's claim command uses SQLite transactions; exactly one worker wins each claim
  • Determinism β€” all workers compute the same priority order; races are resolved by the database, not by timing
  • Independence β€” each worker is a self-contained loop in its own tmux session
  • Naming β€” workers use NATO alphabet identifiers: alpha, bravo, charlie, ...
  needle-claude-sonnet-alpha ──┐
  needle-claude-sonnet-bravo ───
  needle-codex-gpt4-charlie ───┼──► Shared .beads/ (SQLite + checkpoint)
  needle-opencode-qwen-delta ───
  needle-aider-sonnet-echo β”€β”€β”€β”€β”˜

πŸ—οΈ Supported Agents

NEEDLE is agent-agnostic. Any CLI that accepts a prompt and exits works.

AgentCLIInput MethodNotes
Claude Code (interactive)claude-interactivestdinRecommended β€” uses subscription billing; see plugin
Claude Code (API)claude --printstdinUses programmatic/API billing
OpenCodeopencodefile
Codex CLIcodexargs
Aideraider --messageargs
Customanyconfigurable via YAML adapter

Adding a new agent requires only a YAML configuration file β€” no code changes.


πŸ”Œ claude-interactive Plugin

The claude-interactive plugin ships as a separate release asset. It wraps the Claude Code CLI in a PTY so workers run under your Claude subscription instead of consuming programmatic API credits.

How it works: NEEDLE pipes subprocess stdio, which causes claude to detect a non-TTY and switch to API billing. claude-interactive creates an internal PTY so claude sees a real terminal, keeping it in interactive/subscription mode.

Install:

# Download the latest claude-interactive release
gh release download --repo jedarden/NEEDLE --pattern 'claude-interactive*'
chmod +x claude-interactive-install.sh
./claude-interactive-install.sh

Requirements: Python 3.10+, pyte (pip install pyte), and the claude CLI on PATH.

Run:

cd /path/to/workspace
needle run --agent claude-interactive --count 4

Source lives in plugins/claude-interactive/.


πŸ“ Repository Structure

NEEDLE/
β”œβ”€β”€ Cargo.toml             # Rust crate manifest
β”œβ”€β”€ install.sh             # One-line installer for prebuilt binaries
β”œβ”€β”€ plugins/
β”‚   └── claude-interactive/ # PTY wrapper β€” subscription billing adapter for Claude Code
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.rs            # Worker entry point
β”‚   β”œβ”€β”€ lib.rs             # Library root
β”‚   β”œβ”€β”€ agent_event.rs     # Agent event telemetry utilities
β”‚   β”œβ”€β”€ claude_md_placement.rs  # CLAUDE.md placement logic
β”‚   β”œβ”€β”€ commit_hook.rs     # Bead-Id trailer injection for git commits
β”‚   β”œβ”€β”€ routing.rs         # Model-based adapter routing
β”‚   β”œβ”€β”€ bead_store/        # Abstract bead backend interface
β”‚   β”œβ”€β”€ bin/               # Auxiliary binaries (transform helpers)
β”‚   β”œβ”€β”€ canary/            # Release channel promotion, canary tests
β”‚   β”œβ”€β”€ claim/             # Atomic bead claiming via SQLite transactions
β”‚   β”œβ”€β”€ cli/               # Command-line interface parsing
β”‚   β”œβ”€β”€ config/            # `.needle.yaml` parsing and defaults
β”‚   β”œβ”€β”€ cost/              # Token + USD spend tracking per bead and worker
β”‚   β”œβ”€β”€ decision/          # Decision point detection, ADR management
β”‚   β”œβ”€β”€ dispatch/          # Agent invocation + YAML adapter loading
β”‚   β”œβ”€β”€ drift/             # Session similarity, clustering, divergence detection
β”‚   β”œβ”€β”€ health/            # Liveness, stale-claim cleanup, watchdog
β”‚   β”œβ”€β”€ learning/          # Retrospective extraction, learnings management
β”‚   β”œβ”€β”€ mitosis/           # Child-aware bead splitting
β”‚   β”œβ”€β”€ outcome/           # Explicit handler per outcome type
β”‚   β”œβ”€β”€ peer/              # Multi-worker coordination, peer discovery
β”‚   β”œβ”€β”€ prompt/            # Deterministic prompt construction from bead
β”‚   β”œβ”€β”€ rate_limit/        # Provider/model concurrency and RPM rate limiting
β”‚   β”œβ”€β”€ registry/          # Worker state registry
β”‚   β”œβ”€β”€ sanitize/          # Output redaction (gitleaks integration)
β”‚   β”œβ”€β”€ skill/             # Skill library, retrieval, promotion
β”‚   β”œβ”€β”€ span/              # W3C trace context utilities
β”‚   β”œβ”€β”€ stats/             # Aggregation engine, A/B comparison
β”‚   β”œβ”€β”€ strand/            # Pluck / Mend / Explore / Weave / Unravel / Pulse / Reflect / Splice / Knot
β”‚   β”œβ”€β”€ supervisor/        # Fleet supervisor daemon (auto-scale)
β”‚   β”œβ”€β”€ telemetry/         # OTLP exporter, gen_ai semantic conventions
β”‚   β”œβ”€β”€ trace/             # Trace capture, storage, retention
β”‚   β”œβ”€β”€ transcript/        # Session JSONL parsing, action-outcome extraction
β”‚   β”œβ”€β”€ types/             # Shared types, error definitions
β”‚   β”œβ”€β”€ upgrade/           # Self-update, hot-reload, rollback
β”‚   β”œβ”€β”€ validation/        # Pre-dispatch and post-execution checks
β”‚   └── worker/            # Worker session and identity management
β”œβ”€β”€ tests/                 # Integration tests
β”œβ”€β”€ ci/                    # Docker images used by CI (runs on Argo Workflows)
β”œβ”€β”€ config/                # Vendored gitleaks rules
└── docs/                  # Plan, research, examples, post-mortems

πŸ” Observability

NEEDLE emits structured telemetry for every state transition, claim attempt, dispatch, and outcome. A silent worker is a broken worker.

Exported Signals

SignalDescription
TracesSpans for worker.session, bead.lifecycle, bead.claim, agent.dispatch, strand.evaluated, outcome.handled
Metricsneedle.beads.completed, needle.beads.duration, needle.agent.tokens.input, needle.cost.usd, and more
LogsAll events not represented as spans, with severity mapping (ERROR for failures, WARN for stale peers)

OpenTelemetry (OTLP) Export

NEEDLE can export telemetry to any OpenTelemetry-compatible backend (Jaeger, Tempo, Grafana, Honeycomb, Datadog, etc.) via OTLP.

Minimal configuration (.needle.yaml):

telemetry:
  otlp_sink:
    enabled: true
    endpoint: "http://localhost:4317"  # gRPC, or :4318 for HTTP
    protocol: "grpc"

Semantic conventions: NEEDLE follows OpenTelemetry's gen_ai.* semantic conventions for LLM telemetry, enabling out-of-the-box integration with GenAI dashboards (Grafana GenAI app, Langfuse, Honeycomb AI, etc.).

See docs/plan/plan.md for the complete semantic mapping table.


πŸ“Š Production Status

NEEDLE currently powers my own headless multi-agent workflow β€” workers run continuously against shared bead queues, dispatching to Claude Code and other CLIs, with full OTLP telemetry wired through. APIs are stable enough that I rebuild on top of them daily.

This is alpha software in the sense that I'm the primary user, not in the sense that "it doesn't work." Resource governance is delegated to claude-governor; session monitoring is handled by ccdash.

If you want to run NEEDLE in your own workflow, open an issue and I'll help.


  • claude-governor β€” caps API spend and enforces weekly Anthropic quotas across NEEDLE worker fleets
  • ccdash β€” TUI for monitoring Claude Code sessions, token usage, and worker activity
  • CLASP β€” drop-in proxy letting Claude Code target OpenAI, Gemini, Anthropic, or any LLM backend
  • agentists-quickstart β€” opinionated DevPod workspaces for running Claude Code + NEEDLE

πŸ“„ License

MIT


Part of jedarden.com Β· Read the write-up: jedarden.com/projects/needle/

This GitHub repo is a read-only mirror of git.ardenone.com/jedarden/NEEDLE β€” issues and PRs are welcome here either way.