Skip to main content

logplane

A local control plane for AI agents. logplane assigns work, recovers from crashes, holds risky actions for human approval, and enforces cost caps, and it drives all of it from an append-only event log instead of a mutable task board.

logplane demo recovery: a worker and the coordinator are killed mid-task, then a new worker finishes the workflow from the log

Agent workflows fail in ordinary ways. A worker crashes mid-task, the coordinator restarts, two runners pick up the same job, an agent needs a human answer, or a retry repeats an external action. A kanban-style board only shows where a card was last moved. logplane records what actually happened, as immutable events, and derives current state by replaying them. Ownership, retries, dependencies, and human decisions are all events, so a crash loses nothing and every state can be explained.

See it in a minute

git clone https://github.com/dekizk/logplane.git && cd logplane
python3 -m venv .venv && . .venv/bin/activate   # Python 3.10+
python -m pip install -e .

logplane demo recovery       # kill the worker and the coordinator mid-task
logplane demo approval       # an agent asks before an irreversible tool call
logplane demo budget         # a cost cap stops a runaway bill
logplane demo audit-triage   # parallel reviewers, a human severity call,
                              # findings submitted once despite a crash

Each demo starts its own bus, coordinator, and workers as real processes in a throwaway directory, narrates what happens, and keeps the history for you to inspect. The crashes are real kill -9s. None of it touches your other logplane data.

Watch logplane demo approval: an agent asks before an irreversible tool call

logplane demo approval: a support agent blocks before calling issue_refund, a human approves, and the refund runs once

Watch logplane demo budget: a cost cap stops a runaway bill

logplane demo budget: ten summaries under a $2 cost cap stop at $1.60, then finish after the cap is raised

What you get

  • Crash recovery by design. Workers hold leases. A dead worker's attempt is expired and reassigned, and a restarted coordinator rebuilds state by replay.
  • One owner per task. Only the current attempt can advance a task, and late results from a lost worker are rejected.
  • Dependencies. Tasks form a DAG, wait for upstream results, and propagate failure downstream.
  • Humans in the loop. An agent can block with a question, such as approval for a risky tool call. logplane decide answers it, and the answer is on record.
  • Spend limits. Model calls report tokens and cost per task and attempt. Workflow budgets stop new work at a cap, and raising the cap is an event too.
  • Retry-safe external effects. assignment.effect_id(...) is stable across attempts, so a retry can skip work a crashed attempt already did.
  • Bring your own agents. Wrap a Python object, a CLI, or an HTTP service. logplane never needs your agent's internals.
  • Explainable state. logplane task, explain, and workflow --mermaid answer "why is this waiting?" from the log.

It is local-first: one machine, SQLite, loopback only. See trust and scope for what it does not do yet.

How it works

The bus never stores a mutable card as truth. Every action (a task created, an attempt assigned, a worker's result, a human decision) is an immutable SQLite event. The project manager (PM) derives current state by replaying those events and reconciles anything missing, so any process can crash and restart without losing ownership state.

  • You and your tools publish intent: tasks, dependencies, policies, decisions, cancellations.
  • The PM replays the log, assigns work to live workers, and records lease expiries, retries, decision requests, and terminal states.
  • Workers execute only assignments addressed to their current process and report one outcome per attempt.
  • Every view (task, explain, workflow) is rebuilt from the log.

Four identities keep retries and replays unambiguous: correlation_id (one workflow), task_id (one logical outcome), assignment_id (one execution attempt), and instance_id (one worker process). The normal lifecycle is task.created → task.assigned → task.started → task.completed; recovery, human input, cancellation, and pauses are explicit events too.

How logplane works covers the full lifecycle, components, invariants, crash recovery, and trust model.

Install

Use macOS or Linux with Python 3.10+; native Windows is not supported (see the tested-platform policy).

git clone --branch v0.13.0 https://github.com/dekizk/logplane.git
cd logplane
python3 -m venv .venv && . .venv/bin/activate   # python3 --version must be 3.10+
python -m pip install -e .
logplane init

Use --branch main instead for the latest development version, and follow the README for the version you installed. If you already have a checkout, use it rather than cloning over it, and record git rev-parse HEAD when reporting trial results. Create the environment in .venv, not in the repository root. If your default python3 is older than 3.10, create .venv with a supported interpreter such as python3.11. The editable install keeps this checkout as the source of the logplane command, so after pulling changes that add modules (for example demo.py), rerun python -m pip install -e .. logplane is not yet published on PyPI.

Run your own bus

Run these in four terminals from the checkout, with .venv activated in each. The generated configuration binds only to loopback and keeps runtime data in the ignored .logplane/ directory.

# terminal 1
logplane serve

# terminal 2
logplane pm

# terminal 3
logplane demo-worker alice

# terminal 4
RESPONSE=$(logplane submit "Verify the logplane quick start" --json)
TASK_ID=$(printf '%s' "$RESPONSE" | python -c \
  'import json,sys; print(json.load(sys.stdin)["payload"]["task_id"])')
CORRELATION_ID=$(printf '%s' "$RESPONSE" | python -c \
  'import json,sys; print(json.load(sys.stdin)["correlation_id"])')
printf 'Task: %s\nWorkflow: %s\n' "$TASK_ID" "$CORRELATION_ID"

After about one second, verify the bus, task, and derived workflow:

logplane doctor
logplane task "$TASK_ID"
logplane workflow "$CORRELATION_ID"

The expected state is a healthy schema-v2 bus with one healthy worker, a completed task whose last attempt belongs to alice, and a one-task completed workflow. The demo worker emits no model telemetry, so tokens not reported and cost not reported are expected rather than errors.

Machine-readable pass/fail checks
logplane task "$TASK_ID" --json | python -c '
import json, sys
task = json.load(sys.stdin)
assert task["status"] == "completed", task
assert task["assignment_active"] is False, task
print("PASS: task is completed with no active assignment")
'

logplane workflow "$CORRELATION_ID" --json | python -c '
import json, sys
workflow = json.load(sys.stdin)
assert workflow["status"] == "completed", workflow
assert workflow["task_count"] == 1, workflow
print("PASS: workflow reports one completed task")
'

If the task is still assigned or started, wait briefly and check again. If logplane doctor keeps warning, the PM, worker, or bus is probably using a different URL; see connecting to the bus. If logplane is not found, check that the terminal is in the checkout with .venv activated before reinstalling. logplane tasks and logplane workflows find IDs again if you lose them, and logplane workflow "$CORRELATION_ID" --mermaid prints the workflow as a Mermaid flowchart: another projection over the log, never an editable board.

These checks inspect projected state; they do not prove exactly-once execution or external effects. To stop, press Ctrl-C in the worker terminal, then the PM, then the server. Local history is preserved.

Try dependencies, decisions, and failures

The demo worker can deliberately block, fail, or work slowly so you can watch the other paths without writing an agent. Use one outcome flag per worker; the outcome happens once for that task ID.

logplane demo-worker alice --block 2           # task 2 asks a human for a decision
logplane demo-worker alice --fail 2            # one retryable failure
logplane demo-worker alice --fail-permanently 2
logplane demo-worker alice --delay 30          # slow enough to kill mid-task

submit --depends-on builds a DAG from the command line; repeat it for fan-in. Dependents inherit the upstream workflow automatically (IDs below assume a fresh bus):

logplane submit "Research options"                                  # task 1
logplane submit "Design storage" --depends-on 1                     # task 2
logplane submit "Write docs" --depends-on 1                         # task 3
logplane submit "Ship it" --depends-on 2 --depends-on 3             # task 4

A lease expiry or retryable failure consumes one retry, and submit defaults to no retries. If you plan to use --fail or kill a worker mid-task, submit with --max-retries 2 (or higher) so the next attempt is allowed; otherwise the task correctly ends failed.

Everyday commands

Command What it does
logplane submit TITLE Create a task (--depends-on, --capability, --max-retries, --priority, --context)
logplane tasks / workflows / decisions List work, workflows, and pending questions with next-step commands
logplane task ID / explain ID Show one task's state and exactly why it is waiting or finished
logplane workflow ID Show a workflow's tasks, dependencies, policy, and token/cost usage (--mermaid for a diagram)
logplane tail ID Follow a workflow's events live
logplane decide / retry / cancel Answer a decision, grant more retries, or cancel a task
logplane pause / resume / supersede Pause or resume a task or workflow, or replace a task with new intent
logplane policy / agent-policy Set workflow concurrency and budgets, or per-agent limits
logplane workers / doctor Check worker leases and overall bus health
logplane adapter check / adapter run Verify and run an existing agent as a worker
logplane backup / verify-backup / restore Verified local backups (recovery operations)

Finite commands accept --json for scripts. Operating logplane covers every command, scheduling, fairness, budgets, and controls in detail.

Connect your own agent

Wrap an existing agent instead of rewriting it. A Python object with run() becomes a worker:

from logplane import BusClient, Completed, PythonAgentAdapter, WorkerRuntime

class ExistingAgent:
    def run(self, assignment):
        result = do_existing_work(
            goal=assignment.goal,
            context=assignment.context,
            idempotency_key=assignment.effect_id("do-existing-work"),
        )
        return Completed("agent finished", {"result_ref": result.ref})

bus = BusClient("http://127.0.0.1:8765", actor="existing-agent")
WorkerRuntime(
    bus,
    name="existing-agent",
    executor=PythonAgentAdapter(ExistingAgent()),
    capacity=2,
    capabilities=["python"],
).run()

Check the contract before connecting it to a live bus:

logplane adapter check --python-target my_package.agent:ExistingAgent

CLI and HTTP agents use the same versioned protocol through a small JSON config. Use assignment.effect_id(...) for any irreversible external effect so a retry cannot repeat it. Integrating agents covers the adapters, the safety contract, telemetry, and safe adoption alongside an existing system; examples/ has copyable Python, CLI, HTTP, and real-agent integrations.

Documentation

Page Contents
How logplane works Event log, identities, lifecycle, components, invariants, crash recovery, trust model
Operating logplane Commands, decisions, retries, cancellation, pauses, DAGs, scheduling, fairness, budgets
Integrating agents Python, CLI, and HTTP adapters, safety contract, telemetry, adoption modes
Event contracts and the HTTP API Envelope, topics, limits, reading and publishing events
Local recovery operations Artifact audits, backup and restore, task-index rebuilds, PM snapshots
Compatibility and support Platforms, versioned surfaces, upgrades, release checks
Roadmap and release notes Direction, remaining v1.0 gates, and what changed in each release

Trust and scope

logplane is for local, single-user orchestration on one trusted host:

  • Perimeter auth is opt-in. Set LOGPLANE_TOKEN to require a bearer token on every data route; without it, anyone who can reach the port can publish.
  • Actors are self-reported. The token authenticates clients, not identities, so any authorized client may publish as any actor, including pm.
  • It is not distributed. Run one PM per bus and one uvicorn worker; the PM lock is per machine and event wake-ups are per process.

See the trust model and scope for details.

Development

python -m pip install -r requirements-dev.txt
python -m pytest -q
python -m build

The suite focuses on orchestration failures (restarts, stale attempts, retry exhaustion, races, DAG propagation, adapter contracts, telemetry isolation) and includes live runs of every demo. See running the release checks for the full pre-release procedure.

Status and license

logplane was called agent-bus before v0.13.0; if you used it under that name, follow the migration steps.

Current release: v0.13.0, the rename to logplane and a src/ layout. See the release notes and the roadmap for the path to v1.0. Licensed under the MIT License. Copyright (c) 2026 deki. See credits and acknowledgements.

Metadata

Release files for logplane 0.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for logplane 0.13.0
File Size Uploaded Provenance
logplane-0.13.0.tar.gz 335.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for logplane 0.13.0
File Interpreter ABI Platform
logplane-0.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 469.7 kB

Release files / logplane-0.13.0.tar.gz

Download URL logplane-0.13.0.tar.gz
Size 335.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f7d21407d1aed2428f0f86c98f594df2f5148040773ae6e520387afba1057033
BLAKE2b-256 checksum
How to use checksums
608ab4835576e5a3cd3bcd3592097e304187ae71b485322e5d1117c4ae8031e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / logplane-0.13.0-py3-none-any.whl

Download URL logplane-0.13.0-py3-none-any.whl
Size 134.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ac6575cec72d3d4bf5efdc04d5b18466cfd9d7ab6351f5acc8983d642edf18e2
BLAKE2b-256 checksum
How to use checksums
b6e491660d9ddda618cdc24443b5408c92c739cea1764d852e38983cd477a523
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for logplane 0.13.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for logplane-0.13.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page