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

python3 -m venv .venv && . .venv/bin/activate   # Python 3.10+
python -m pip install logplane

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).

python3 -m venv .venv && . .venv/bin/activate   # python3 --version must be 3.10+
python -m pip install logplane
logplane init

logplane init writes logplane.local.json and a .logplane/ data directory in the current directory, so run it in the folder that should keep the bus's history. If your default python3 is older than 3.10, create .venv with a supported interpreter such as python3.11.

To run the examples or work on logplane itself, install from source instead:

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

Create the environment in .venv, not in the repository root. The editable install keeps this checkout as the source of the logplane command, so rerun python -m pip install -e . after pulling changes that add modules. Record git rev-parse HEAD when reporting trial results.

Run your own bus

Run these in four terminals from the folder where you ran logplane init, 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 .venv is activated in that terminal 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.1, 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.1

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.1
File Size Uploaded Provenance
logplane-0.13.1.tar.gz 336.0 kB With provenance Details

Built distribution (wheel)

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

Total release size: 470.3 kB

Release files / logplane-0.13.1.tar.gz

Download URL logplane-0.13.1.tar.gz
Size 336.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7090a130e3c6785b5cd36d78474ae1827777ec13a84253cbc4f55f523b43c620
BLAKE2b-256 checksum
How to use checksums
af14d90b6ff32f4432a15617cecf3f4dba8aa039edce1b36f74b5d27203b6418
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.1-py3-none-any.whl

Download URL logplane-0.13.1-py3-none-any.whl
Size 134.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2ff931bd77396d73cd3cad31a0f9582386d0c60dc796234ac7599a10e74cd886
BLAKE2b-256 checksum
How to use checksums
0cf3f49bdae253fb505397f9d26489d50ce9ca3d6ff1150096a3d2c76b4d3eab
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.1

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.1.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