logplane 0.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. logplane-0.13.0/COMPATIBILITY.md +193 -0
  2. logplane-0.13.0/CONTRIBUTORS.md +15 -0
  3. logplane-0.13.0/LICENSE +21 -0
  4. logplane-0.13.0/MANIFEST.in +9 -0
  5. logplane-0.13.0/PKG-INFO +359 -0
  6. logplane-0.13.0/README.md +332 -0
  7. logplane-0.13.0/RECOVERY.md +265 -0
  8. logplane-0.13.0/RELEASE_NOTES.md +184 -0
  9. logplane-0.13.0/ROADMAP.md +872 -0
  10. logplane-0.13.0/benchmarks/REPLAY_RESULTS.md +168 -0
  11. logplane-0.13.0/benchmarks/RESULTS.md +44 -0
  12. logplane-0.13.0/benchmarks/replay_admission.py +130 -0
  13. logplane-0.13.0/benchmarks/task_lookup.py +76 -0
  14. logplane-0.13.0/ci/constraints-min.txt +6 -0
  15. logplane-0.13.0/docs/architecture.md +270 -0
  16. logplane-0.13.0/docs/events.md +271 -0
  17. logplane-0.13.0/docs/integration.md +346 -0
  18. logplane-0.13.0/docs/operations.md +577 -0
  19. logplane-0.13.0/docs/reviews/v0.10-operator-controls-review-c340808.md +263 -0
  20. logplane-0.13.0/docs/reviews/v0.11-baseline-review-c7a47f0.md +86 -0
  21. logplane-0.13.0/examples/README.md +25 -0
  22. logplane-0.13.0/examples/__init__.py +1 -0
  23. logplane-0.13.0/examples/audit_triage/README.md +71 -0
  24. logplane-0.13.0/examples/cli_agent/README.md +16 -0
  25. logplane-0.13.0/examples/cli_agent/TRIAL_NOTES.md +76 -0
  26. logplane-0.13.0/examples/cli_agent/__init__.py +1 -0
  27. logplane-0.13.0/examples/cli_agent/adapter.json +15 -0
  28. logplane-0.13.0/examples/cli_agent/agent.py +30 -0
  29. logplane-0.13.0/examples/hermes/README.md +206 -0
  30. logplane-0.13.0/examples/hermes/TRIAL_NOTES.md +1055 -0
  31. logplane-0.13.0/examples/hermes/__init__.py +5 -0
  32. logplane-0.13.0/examples/hermes/hermes_executor.py +650 -0
  33. logplane-0.13.0/examples/hermes/live_smoke.py +241 -0
  34. logplane-0.13.0/examples/hermes/run_worker.py +127 -0
  35. logplane-0.13.0/examples/http_agent/README.md +52 -0
  36. logplane-0.13.0/examples/http_agent/TRIAL_NOTES.md +104 -0
  37. logplane-0.13.0/examples/http_agent/__init__.py +1 -0
  38. logplane-0.13.0/examples/http_agent/adapter.json +15 -0
  39. logplane-0.13.0/examples/http_agent/agent.py +248 -0
  40. logplane-0.13.0/examples/python_agent/README.md +15 -0
  41. logplane-0.13.0/examples/python_agent/__init__.py +1 -0
  42. logplane-0.13.0/examples/python_agent/agent.py +19 -0
  43. logplane-0.13.0/examples/python_agent/run_worker.py +25 -0
  44. logplane-0.13.0/pyproject.toml +52 -0
  45. logplane-0.13.0/requirements-dev.txt +3 -0
  46. logplane-0.13.0/requirements.txt +4 -0
  47. logplane-0.13.0/scripts/capture_upgrade_fixture.py +163 -0
  48. logplane-0.13.0/scripts/check_release.py +319 -0
  49. logplane-0.13.0/scripts/operator_trial_worker.py +26 -0
  50. logplane-0.13.0/setup.cfg +4 -0
  51. logplane-0.13.0/src/logplane/__init__.py +113 -0
  52. logplane-0.13.0/src/logplane/__main__.py +5 -0
  53. logplane-0.13.0/src/logplane/adapter_check.py +209 -0
  54. logplane-0.13.0/src/logplane/adapters.py +21 -0
  55. logplane-0.13.0/src/logplane/adoption.py +231 -0
  56. logplane-0.13.0/src/logplane/artifacts.py +187 -0
  57. logplane-0.13.0/src/logplane/bus.py +2065 -0
  58. logplane-0.13.0/src/logplane/cli.py +1303 -0
  59. logplane-0.13.0/src/logplane/client.py +566 -0
  60. logplane-0.13.0/src/logplane/conformance.py +203 -0
  61. logplane-0.13.0/src/logplane/demo.py +1075 -0
  62. logplane-0.13.0/src/logplane/executor_protocol.py +120 -0
  63. logplane-0.13.0/src/logplane/executors.py +779 -0
  64. logplane-0.13.0/src/logplane/integration.py +574 -0
  65. logplane-0.13.0/src/logplane/legacy.py +46 -0
  66. logplane-0.13.0/src/logplane/limits.py +10 -0
  67. logplane-0.13.0/src/logplane/local_config.py +251 -0
  68. logplane-0.13.0/src/logplane/observer.py +169 -0
  69. logplane-0.13.0/src/logplane/operations.py +1022 -0
  70. logplane-0.13.0/src/logplane/operator_controls.py +101 -0
  71. logplane-0.13.0/src/logplane/pm_agent.py +917 -0
  72. logplane-0.13.0/src/logplane/projection.py +1793 -0
  73. logplane-0.13.0/src/logplane/projection_store.py +282 -0
  74. logplane-0.13.0/src/logplane/protocol.py +23 -0
  75. logplane-0.13.0/src/logplane/recovery.py +281 -0
  76. logplane-0.13.0/src/logplane/runtime.py +772 -0
  77. logplane-0.13.0/src/logplane/scheduling.py +31 -0
  78. logplane-0.13.0/src/logplane/telemetry.py +369 -0
  79. logplane-0.13.0/src/logplane/topics.py +54 -0
  80. logplane-0.13.0/src/logplane/version.py +3 -0
  81. logplane-0.13.0/src/logplane/worker.py +124 -0
  82. logplane-0.13.0/src/logplane.egg-info/PKG-INFO +359 -0
  83. logplane-0.13.0/src/logplane.egg-info/SOURCES.txt +124 -0
  84. logplane-0.13.0/src/logplane.egg-info/dependency_links.txt +1 -0
  85. logplane-0.13.0/src/logplane.egg-info/entry_points.txt +2 -0
  86. logplane-0.13.0/src/logplane.egg-info/requires.txt +4 -0
  87. logplane-0.13.0/src/logplane.egg-info/top_level.txt +1 -0
  88. logplane-0.13.0/tests/__init__.py +1 -0
  89. logplane-0.13.0/tests/fixtures/compatibility/v0.11.0-upgrade/README.md +30 -0
  90. logplane-0.13.0/tests/fixtures/compatibility/v0.11.0-upgrade/database.sql +79 -0
  91. logplane-0.13.0/tests/fixtures/compatibility/v0.11.0-upgrade/expected.json +2732 -0
  92. logplane-0.13.0/tests/fixtures/compatibility/v0.11.0.json +121 -0
  93. logplane-0.13.0/tests/test_adapter_check.py +297 -0
  94. logplane-0.13.0/tests/test_adoption.py +178 -0
  95. logplane-0.13.0/tests/test_artifacts.py +42 -0
  96. logplane-0.13.0/tests/test_bus.py +846 -0
  97. logplane-0.13.0/tests/test_cli.py +159 -0
  98. logplane-0.13.0/tests/test_client.py +223 -0
  99. logplane-0.13.0/tests/test_compatibility.py +62 -0
  100. logplane-0.13.0/tests/test_demo.py +295 -0
  101. logplane-0.13.0/tests/test_demo_cli.py +96 -0
  102. logplane-0.13.0/tests/test_executors.py +408 -0
  103. logplane-0.13.0/tests/test_hermes_example.py +400 -0
  104. logplane-0.13.0/tests/test_http_example.py +151 -0
  105. logplane-0.13.0/tests/test_integration.py +346 -0
  106. logplane-0.13.0/tests/test_legacy_names.py +46 -0
  107. logplane-0.13.0/tests/test_operations.py +403 -0
  108. logplane-0.13.0/tests/test_operator_cli.py +242 -0
  109. logplane-0.13.0/tests/test_pm_agent.py +1365 -0
  110. logplane-0.13.0/tests/test_release_check.py +53 -0
  111. logplane-0.13.0/tests/test_released_upgrade.py +210 -0
  112. logplane-0.13.0/tests/test_runtime.py +1083 -0
  113. logplane-0.13.0/tests/test_stream_shutdown.py +208 -0
  114. logplane-0.13.0/tests/test_telemetry.py +273 -0
  115. logplane-0.13.0/tests/test_v010_admission.py +262 -0
  116. logplane-0.13.0/tests/test_v010_hardening.py +606 -0
  117. logplane-0.13.0/tests/test_v010_phase2.py +571 -0
  118. logplane-0.13.0/tests/test_v010_phase3_accounting.py +552 -0
  119. logplane-0.13.0/tests/test_v010_phase3_fairness.py +337 -0
  120. logplane-0.13.0/tests/test_v010_phase3_policy.py +455 -0
  121. logplane-0.13.0/tests/test_v011_recovery.py +157 -0
  122. logplane-0.13.0/tests/test_v011_snapshots.py +242 -0
  123. logplane-0.13.0/tests/test_v011_streaming_admission.py +105 -0
  124. logplane-0.13.0/tests/test_v011_task_index.py +176 -0
  125. logplane-0.13.0/tests/test_v09_integration_kit.py +399 -0
  126. logplane-0.13.0/tests/test_worker.py +76 -0
@@ -0,0 +1,193 @@
1
+ # Compatibility and support policy
2
+
3
+ This document defines the pre-v1.0 baseline and the intended v1.x contract.
4
+ It does not declare v1.0 released or retroactively certify every old version.
5
+ Release status and outstanding evidence live in [ROADMAP.md](ROADMAP.md).
6
+
7
+ ## Supported deployment target
8
+
9
+ logplane targets one trusted local host running macOS or Linux, using CPython
10
+ 3.10 or newer. The CI matrix covers 3.10, 3.13, and 3.14; results for a new
11
+ matrix entry must pass before that entry is treated as verified. Other Python
12
+ versions are not verified merely because package metadata permits installation.
13
+ Native Windows is not supported: process locking uses `fcntl`. WSL, alternative
14
+ interpreters, network filesystems, and distributed deployments are not certified.
15
+
16
+ CI tests the declared direct dependency minimums on Python 3.10 separately from
17
+ latest-compatible resolution. The floor constraint file is a test input, not
18
+ a production lockfile or a claim to test every transitive dependency combination.
19
+ Resolved dependency versions are retained with each run. Supported releases
20
+ require a passing package-install smoke, not just tests in an editable checkout.
21
+
22
+ ## Versioned surfaces
23
+
24
+ | Surface | Current baseline | Compatibility boundary |
25
+ | --- | --- | --- |
26
+ | Package | `0.13.0` release | Pre-1.0 changes must be documented; do not infer a 1.x guarantee yet |
27
+ | Python integration | Names exported by `logplane`, `logplane.adapters`, `logplane.protocol` | Documented constructors, methods, typed outcomes, and effect identity |
28
+ | Executor wire format | `agent-bus.executor` v1 | Selected envelope version is explicit; headers are strict |
29
+ | Event envelope | Built-in writes use schema v2 | History is immutable; acceptance and replay semantics are part of the contract |
30
+ | Local/adapter configuration | Each uses schema v1 | Version and supported keys must match that component |
31
+ | CLI | Documented commands, options, `--json` fields, and exit statuses | Human-readable wording/layout is not an API |
32
+ | Database indexes / PM snapshots | Derived local caches | No public table layout or snapshot-file compatibility promise |
33
+ | Recovery bundles | Versioned verified local format | Unsupported formats must fail safely; hashes are integrity checks, not signatures |
34
+
35
+ Implementation modules live under `logplane.*` (for example `logplane.bus`),
36
+ but integrations should import from `logplane`, `logplane.adapters`, and
37
+ `logplane.protocol`. Private helpers, reducer dataclass internals,
38
+ SQLite tables, test fixtures, and benchmark output are not public integration
39
+ APIs. The `demo` module behind `logplane demo` is a CLI implementation detail,
40
+ not an integration API. Importable implementation modules are not a promise
41
+ to freeze their private members. Repository examples are source assets, not installed packages.
42
+
43
+ ### Additions and unknown values
44
+
45
+ - Do not remove or change the meaning/type of an existing public field silently.
46
+ A new optional field needs a default and a compatibility test. Adding a
47
+ required field or changing interpretation is a breaking change.
48
+ - Do not assume every JSON object permits arbitrary keys. Executor envelopes
49
+ and protocol headers, local/adapter configs, and some payloads use strict
50
+ shapes. A change rejected by an older supported reader needs a new format
51
+ version or an explicit coordinated upgrade, not the label "additive".
52
+ - Executor v1 `supported_versions` may advertise future versions as long as the
53
+ selected version is included. It is not automatic negotiation; use the same
54
+ selected version at both ends. Legacy unversioned v0 is limited to the existing
55
+ legacy subprocess path; new configured CLI/HTTP integrations use v1.
56
+ - New built-in writes use event schema v2. Legacy stored rows remain readable;
57
+ readable history does not mean old events satisfy every modern reducer rule.
58
+ Existing migrations and release fixtures, not a blanket "all history works"
59
+ statement, define demonstrated coverage.
60
+ - Unknown custom topics are storage extensions, not permission to influence the
61
+ PM. Keep custom readers tolerant of unrelated topics. Raw telemetry topics
62
+ are not replayed by the PM; compact `workflow.usage_recorded` coordination
63
+ events may affect budget admission.
64
+ - CLI JSON consumers should tolerate additional object fields and avoid parsing
65
+ human output. Existing fields must retain their meaning. Unknown status/enum
66
+ values should be displayed as unknown, not treated as completed/successful.
67
+ Newly emitted enum values require release notes and a consumer review.
68
+
69
+ ### CLI exit statuses
70
+
71
+ | Code | Meaning |
72
+ | ---: | --- |
73
+ | 0 | Command succeeded; inspect the result for task/diagnostic state |
74
+ | 2 | Invalid usage/configuration, transport failure, or rejected operation |
75
+ | 3 | Lookup did not find the requested task/workflow |
76
+ | 4 | An adapter probe fails/times out, a storage audit fails, or replay rejects a recorded operator intent |
77
+ | 130 | Interrupted by the operator |
78
+
79
+ Zero does not mean a submitted task completed, or that all doctor checks are
80
+ healthy: read `--json` and the check/state fields. Errors currently go to stderr
81
+ and need not be JSON even when `--json` was selected. Unexpected crashes are not
82
+ a stable error protocol. Tail output is a stream, not one JSON document.
83
+
84
+ ## Upgrade, downgrade, and deployment versions
85
+
86
+ 1. Read release notes. Stop PMs, workers, submitters, and artifact publishers.
87
+ 2. Preserve configuration and a verified database/artifact backup using
88
+ [RECOVERY.md](RECOVERY.md). Do not delete history or copy a live SQLite file
89
+ without its supported backup mechanism.
90
+ 3. Upgrade bus, PM, workers, and operator CLI together. Mixed coordination
91
+ package versions are not a supported rolling-upgrade strategy. External
92
+ adapters can remain on their explicitly supported wire version.
93
+ 4. Start the bus to run transactional migrations, then PM/workers; verify
94
+ doctor, pending work, and representative task/workflow output.
95
+
96
+ Indexes may be rebuilt and incompatible snapshots discarded. These operations
97
+ must not rewrite original events. Downgrading binaries over an upgraded live
98
+ database is unsupported and is not universally rejected by the current code.
99
+ For rollback, stop new processes and restore a pre-upgrade backup into a separate
100
+ directory with its matching version. Later work and external side effects do
101
+ not disappear or roll back automatically; reconcile them before resuming.
102
+
103
+ ## Release and deprecation rules
104
+
105
+ Before v1.0, releases may change contracts but must document known breaks and
106
+ provide tests/upgrade guidance. The readiness baseline protects v0.11.0 public
107
+ exports and representative adapter messages; it is not exhaustive coverage of
108
+ all old releases, CLI outputs, or historical database semantics.
109
+
110
+ The released-database baseline now also captures v0.11.0's actual SQLite
111
+ schema/history/snapshot as SQL, plus release-produced CLI and adapter outputs.
112
+ Tests reconstruct disposable databases, run current initialization repeatedly,
113
+ and verify raw event values/identity, idempotency, counters, snapshot fallback,
114
+ index reconstruction, and continued reconciliation. Cases include DAG result
115
+ propagation, human decisions, retry, pause/resume, cancellation, lease/deadline
116
+ expiry, and persisted policy with missing usage. Public JSON comparisons permit
117
+ additional fields but preserve existing field types and values.
118
+
119
+ This demonstrates **v0.11.0 → current development** for the captured cases.
120
+ v0.12.0 adds CLI commands and options only (`demo`, `submit --depends-on`, and
121
+ `demo-worker` outcome flags), corrects `serve`'s startup-failure status to 2,
122
+ and changes no event, executor, configuration, or `--json` field contract.
123
+ It adds no schema migration and does not certify physical WAL recovery, every
124
+ historical release, or downgrades. See the [fixture provenance](tests/fixtures/compatibility/v0.11.0-upgrade/README.md).
125
+
126
+ v0.13.0 renames the project from agent-bus to logplane: the distribution,
127
+ import package, `logplane` command, `LOGPLANE_*` environment variables, and
128
+ `logplane.local.json` config file. The pre-0.13 flat modules and the
129
+ `agent_bus` package are removed, and old `AGENT_BUS_*` variables or an
130
+ `agent-bus.local.json` without a `logplane.local.json` fail with a rename
131
+ message instead of being ignored. Identifiers stored in history or shared with
132
+ external adapters keep their original spelling, so existing databases,
133
+ backups, and adapters work unchanged: the `agent-bus` ownership owner, the
134
+ effect-key salts behind `effect_id()`, the `agent-bus.executor` protocol name,
135
+ the `X-Agent-Bus-*` HTTP headers, the `agent_bus_conformance_probe` context
136
+ key, and the backup bundle kinds. See the
137
+ [migration steps](RELEASE_NOTES.md#migrating-from-agent-bus).
138
+
139
+ The owner-approved v1.0 upgrade baseline is **v0.11.0**: this is the oldest
140
+ starting release for a supported direct upgrade to v1.0. Direct upgrades from
141
+ earlier releases are not promised. Any intervening release included in the
142
+ supported path needs its own release-derived regression coverage; do not infer
143
+ coverage solely from its version number. The final v1.0 build must pass these
144
+ upgrade checks before release. This is a selected support scope, not a claim
145
+ that v1.0 has shipped or that every historical database has been tested.
146
+
147
+ For v1.x, patches are intended for compatible fixes; minor releases may add
148
+ compatible capabilities. Removing supported APIs or changing existing wire/
149
+ event semantics requires a major version, except urgent security corrections
150
+ whose impact and mitigation must be called out explicitly. Deprecations should
151
+ be documented in release notes and remain available through the current major
152
+ series; use runtime warnings where actionable and safe for protocol output.
153
+ Bug fixes can change behavior outside the documented contract.
154
+
155
+ Maintenance targets the latest release; no LTS/backport window or response-time
156
+ SLA is promised. The project uses the [MIT License](LICENSE), with copyright
157
+ held by deki and development acknowledgements in [CONTRIBUTORS.md](CONTRIBUTORS.md).
158
+ Trials continue using GitHub source installations; PyPI publication, native
159
+ Windows, and a distributed service remain separate decisions. No package is
160
+ published by selecting a license. The public 1.x promise requires
161
+ the remaining roadmap gates, including independent onboarding evidence.
162
+
163
+ Building from source requires setuptools 77.0.3 or newer for standard SPDX
164
+ license metadata. Isolated builds install that build dependency automatically;
165
+ the runtime Python and dependency requirements are unchanged.
166
+
167
+ ## Running the release checks
168
+
169
+ From a development checkout with a supported Python:
170
+
171
+ ```sh
172
+ python -m pip install -r requirements-dev.txt
173
+ python -m pip install -e .
174
+ python -m pytest -q
175
+ python -m build
176
+ python scripts/check_release.py --wheel dist/logplane-0.13.0-py3-none-any.whl
177
+ ```
178
+
179
+ Use the wheel filename produced by the build if its version differs. The build
180
+ creates an sdist and builds the wheel from it. The check creates a fresh venv,
181
+ installs the wheel/dependencies, verifies import origins, and exercises a
182
+ successful and timed-out CLI adapter check plus a credential-free live task
183
+ outside the checkout. It also checks discovery, human response, retry, and
184
+ cancellation through a small live worker, including duplicate commands, and
185
+ runs released-database upgrade tests against the installed package. It downloads dependencies and
186
+ uses only a disposable loopback server; it makes no model calls. It reports the
187
+ retained evidence directory and stops its own processes on success or failure.
188
+ Pass `--constraints ci/constraints-min.txt` to exercise direct dependency floors.
189
+ GitHub CI uses the same check and uploads its diagnostics; configuring CI is
190
+ not evidence that remote jobs have already passed.
191
+
192
+ The workflow follows GitHub's [Python build/test guidance](https://docs.github.com/en/actions/tutorials/build-and-test-code/python),
193
+ uses read-only repository permissions, and pins official actions to commit IDs.
@@ -0,0 +1,15 @@
1
+ # Credits
2
+
3
+ Project owner and copyright holder: **deki**.
4
+
5
+ ## AI-assisted development acknowledgements
6
+
7
+ The following names are credited as requested by the project owner:
8
+
9
+ - GPT Sol
10
+ - Fable 5.1
11
+ - GPT-6 Astra
12
+
13
+ These are development acknowledgements, not additional copyright-holder
14
+ designations or endorsements. The project is distributed under the
15
+ [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 deki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include COMPATIBILITY.md RECOVERY.md RELEASE_NOTES.md ROADMAP.md
2
+ include LICENSE CONTRIBUTORS.md
3
+ include requirements.txt requirements-dev.txt
4
+ recursive-include benchmarks *.py *.md
5
+ recursive-include scripts *.py
6
+ recursive-include ci *.txt
7
+ recursive-include tests *.py *.json *.sql *.md
8
+ recursive-include examples *.py *.json *.md
9
+ recursive-include docs *.md
@@ -0,0 +1,359 @@
1
+ Metadata-Version: 2.4
2
+ Name: logplane
3
+ Version: 0.13.0
4
+ Summary: A local control plane for AI agents, built on an append-only event log
5
+ Author: deki
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/dekizk/logplane
8
+ Project-URL: Documentation, https://github.com/dekizk/logplane#documentation
9
+ Project-URL: Changelog, https://github.com/dekizk/logplane/blob/main/RELEASE_NOTES.md
10
+ Project-URL: Issues, https://github.com/dekizk/logplane/issues
11
+ Keywords: ai-agents,orchestration,control-plane,event-sourcing,llm
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: fastapi<1,>=0.115
23
+ Requires-Dist: httpx<1,>=0.27
24
+ Requires-Dist: pydantic<3,>=2.8
25
+ Requires-Dist: uvicorn<1,>=0.30
26
+ Dynamic: license-file
27
+
28
+ # logplane
29
+
30
+ **A local control plane for AI agents.** logplane assigns work, recovers from
31
+ crashes, holds risky actions for human approval, and enforces cost caps, and
32
+ it drives all of it from an append-only event log instead of a mutable task
33
+ board.
34
+
35
+ ![logplane demo recovery: a worker and the coordinator are killed mid-task, then a new worker finishes the workflow from the log](docs/demo-recovery.gif)
36
+
37
+ Agent workflows fail in ordinary ways. A worker crashes mid-task, the
38
+ coordinator restarts, two runners pick up the same job, an agent needs a human
39
+ answer, or a retry repeats an external action. A kanban-style board only shows
40
+ where a card was last moved. logplane records what actually happened, as
41
+ immutable events, and derives current state by replaying them. Ownership,
42
+ retries, dependencies, and human decisions are all events, so a crash loses
43
+ nothing and every state can be explained.
44
+
45
+ ### See it in a minute
46
+
47
+ ```sh
48
+ git clone https://github.com/dekizk/logplane.git && cd logplane
49
+ python3 -m venv .venv && . .venv/bin/activate # Python 3.10+
50
+ python -m pip install -e .
51
+
52
+ logplane demo recovery # kill the worker and the coordinator mid-task
53
+ logplane demo approval # an agent asks before an irreversible tool call
54
+ logplane demo budget # a cost cap stops a runaway bill
55
+ logplane demo audit-triage # parallel reviewers, a human severity call,
56
+ # findings submitted once despite a crash
57
+ ```
58
+
59
+ Each demo starts its own bus, coordinator, and workers as real processes in a
60
+ throwaway directory, narrates what happens, and keeps the history for you to
61
+ inspect. The crashes are real `kill -9`s. None of it touches your other
62
+ logplane data.
63
+
64
+ <details>
65
+ <summary>Watch <code>logplane demo approval</code>: an agent asks before an irreversible tool call</summary>
66
+
67
+ ![logplane demo approval: a support agent blocks before calling issue_refund, a human approves, and the refund runs once](docs/demo-approval.gif)
68
+
69
+ </details>
70
+
71
+ <details>
72
+ <summary>Watch <code>logplane demo budget</code>: a cost cap stops a runaway bill</summary>
73
+
74
+ ![logplane demo budget: ten summaries under a $2 cost cap stop at $1.60, then finish after the cap is raised](docs/demo-budget.gif)
75
+
76
+ </details>
77
+
78
+ ### What you get
79
+
80
+ - **Crash recovery by design.** Workers hold leases. A dead worker's attempt is
81
+ expired and reassigned, and a restarted coordinator rebuilds state by replay.
82
+ - **One owner per task.** Only the current attempt can advance a task, and late
83
+ results from a lost worker are rejected.
84
+ - **Dependencies.** Tasks form a DAG, wait for upstream results, and propagate
85
+ failure downstream.
86
+ - **Humans in the loop.** An agent can block with a question, such as approval
87
+ for a risky tool call. `logplane decide` answers it, and the answer is on
88
+ record.
89
+ - **Spend limits.** Model calls report tokens and cost per task and attempt.
90
+ Workflow budgets stop new work at a cap, and raising the cap is an event too.
91
+ - **Retry-safe external effects.** `assignment.effect_id(...)` is stable across
92
+ attempts, so a retry can skip work a crashed attempt already did.
93
+ - **Bring your own agents.** Wrap a Python object, a CLI, or an HTTP service.
94
+ logplane never needs your agent's internals.
95
+ - **Explainable state.** `logplane task`, `explain`, and `workflow --mermaid`
96
+ answer "why is this waiting?" from the log.
97
+
98
+ It is local-first: one machine, SQLite, loopback only. See
99
+ [trust and scope](#trust-and-scope) for what it does not do yet.
100
+
101
+ ## How it works
102
+
103
+ The bus never stores a mutable card as truth. Every action (a task created, an
104
+ attempt assigned, a worker's result, a human decision) is an immutable SQLite
105
+ event. The project manager (PM) derives current state by replaying those
106
+ events and reconciles anything missing, so any process can crash and restart
107
+ without losing ownership state.
108
+
109
+ - **You and your tools publish intent:** tasks, dependencies, policies,
110
+ decisions, cancellations.
111
+ - **The PM** replays the log, assigns work to live workers, and records lease
112
+ expiries, retries, decision requests, and terminal states.
113
+ - **Workers** execute only assignments addressed to their current process and
114
+ report one outcome per attempt.
115
+ - **Every view** (`task`, `explain`, `workflow`) is rebuilt from the log.
116
+
117
+ Four identities keep retries and replays unambiguous: `correlation_id` (one
118
+ workflow), `task_id` (one logical outcome), `assignment_id` (one execution
119
+ attempt), and `instance_id` (one worker process). The normal lifecycle is
120
+ `task.created → task.assigned → task.started → task.completed`; recovery,
121
+ human input, cancellation, and pauses are explicit events too.
122
+
123
+ [How logplane works](docs/architecture.md) covers the full lifecycle,
124
+ components, invariants, crash recovery, and trust model.
125
+
126
+ ## Install
127
+
128
+ Use macOS or Linux with Python 3.10+; native Windows is not supported (see the
129
+ [tested-platform policy](COMPATIBILITY.md#supported-deployment-target)).
130
+
131
+ ```sh
132
+ git clone --branch v0.13.0 https://github.com/dekizk/logplane.git
133
+ cd logplane
134
+ python3 -m venv .venv && . .venv/bin/activate # python3 --version must be 3.10+
135
+ python -m pip install -e .
136
+ logplane init
137
+ ```
138
+
139
+ Use `--branch main` instead for the latest development version, and follow
140
+ the README for the version you installed. If you already have a checkout, use
141
+ it rather than cloning over it, and record `git rev-parse HEAD` when reporting
142
+ trial results. Create the environment in `.venv`, not in the repository root.
143
+ If your default `python3` is older than 3.10, create `.venv` with a supported
144
+ interpreter such as `python3.11`. The editable install keeps this checkout as
145
+ the source of the `logplane` command, so after pulling changes that add
146
+ modules (for example `demo.py`), rerun `python -m pip install -e .`. logplane is not yet
147
+ published on PyPI.
148
+
149
+ ## Run your own bus
150
+
151
+ Run these in four terminals from the checkout, with `.venv` activated in each.
152
+ The generated configuration binds only to loopback and keeps runtime data in
153
+ the ignored `.logplane/` directory.
154
+
155
+ ```sh
156
+ # terminal 1
157
+ logplane serve
158
+
159
+ # terminal 2
160
+ logplane pm
161
+
162
+ # terminal 3
163
+ logplane demo-worker alice
164
+
165
+ # terminal 4
166
+ RESPONSE=$(logplane submit "Verify the logplane quick start" --json)
167
+ TASK_ID=$(printf '%s' "$RESPONSE" | python -c \
168
+ 'import json,sys; print(json.load(sys.stdin)["payload"]["task_id"])')
169
+ CORRELATION_ID=$(printf '%s' "$RESPONSE" | python -c \
170
+ 'import json,sys; print(json.load(sys.stdin)["correlation_id"])')
171
+ printf 'Task: %s\nWorkflow: %s\n' "$TASK_ID" "$CORRELATION_ID"
172
+ ```
173
+
174
+ After about one second, verify the bus, task, and derived workflow:
175
+
176
+ ```sh
177
+ logplane doctor
178
+ logplane task "$TASK_ID"
179
+ logplane workflow "$CORRELATION_ID"
180
+ ```
181
+
182
+ The expected state is a healthy schema-v2 bus with one healthy worker, a
183
+ `completed` task whose last attempt belongs to `alice`, and a one-task
184
+ `completed` workflow. The demo worker emits no model telemetry, so
185
+ `tokens not reported` and `cost not reported` are expected rather than errors.
186
+
187
+ <details>
188
+ <summary>Machine-readable pass/fail checks</summary>
189
+
190
+ ```sh
191
+ logplane task "$TASK_ID" --json | python -c '
192
+ import json, sys
193
+ task = json.load(sys.stdin)
194
+ assert task["status"] == "completed", task
195
+ assert task["assignment_active"] is False, task
196
+ print("PASS: task is completed with no active assignment")
197
+ '
198
+
199
+ logplane workflow "$CORRELATION_ID" --json | python -c '
200
+ import json, sys
201
+ workflow = json.load(sys.stdin)
202
+ assert workflow["status"] == "completed", workflow
203
+ assert workflow["task_count"] == 1, workflow
204
+ print("PASS: workflow reports one completed task")
205
+ '
206
+ ```
207
+
208
+ </details>
209
+
210
+ If the task is still `assigned` or `started`, wait briefly and check again. If
211
+ `logplane doctor` keeps warning, the PM, worker, or bus is probably using a
212
+ different URL; see [connecting to the bus](docs/operations.md#connecting-to-the-bus).
213
+ If `logplane` is not found, check that the terminal is in the checkout with
214
+ `.venv` activated before reinstalling. `logplane tasks` and
215
+ `logplane workflows` find IDs again if you lose them, and
216
+ `logplane workflow "$CORRELATION_ID" --mermaid` prints the workflow as a
217
+ Mermaid flowchart: another projection over the log, never an editable board.
218
+
219
+ These checks inspect projected state; they do not prove exactly-once execution
220
+ or external effects. To stop, press Ctrl-C in the worker terminal, then the PM,
221
+ then the server. Local history is preserved.
222
+
223
+ ### Try dependencies, decisions, and failures
224
+
225
+ The demo worker can deliberately block, fail, or work slowly so you can watch
226
+ the other paths without writing an agent. Use one outcome flag per worker; the
227
+ outcome happens once for that task ID.
228
+
229
+ ```sh
230
+ logplane demo-worker alice --block 2 # task 2 asks a human for a decision
231
+ logplane demo-worker alice --fail 2 # one retryable failure
232
+ logplane demo-worker alice --fail-permanently 2
233
+ logplane demo-worker alice --delay 30 # slow enough to kill mid-task
234
+ ```
235
+
236
+ `submit --depends-on` builds a DAG from the command line; repeat it for
237
+ fan-in. Dependents inherit the upstream workflow automatically (IDs below
238
+ assume a fresh bus):
239
+
240
+ ```sh
241
+ logplane submit "Research options" # task 1
242
+ logplane submit "Design storage" --depends-on 1 # task 2
243
+ logplane submit "Write docs" --depends-on 1 # task 3
244
+ logplane submit "Ship it" --depends-on 2 --depends-on 3 # task 4
245
+ ```
246
+
247
+ A lease expiry or retryable failure consumes one retry, and `submit` defaults
248
+ to no retries. If you plan to use `--fail` or kill a worker mid-task, submit
249
+ with `--max-retries 2` (or higher) so the next attempt is allowed; otherwise
250
+ the task correctly ends `failed`.
251
+
252
+ ## Everyday commands
253
+
254
+ | Command | What it does |
255
+ |---|---|
256
+ | `logplane submit TITLE` | Create a task (`--depends-on`, `--capability`, `--max-retries`, `--priority`, `--context`) |
257
+ | `logplane tasks` / `workflows` / `decisions` | List work, workflows, and pending questions with next-step commands |
258
+ | `logplane task ID` / `explain ID` | Show one task's state and exactly why it is waiting or finished |
259
+ | `logplane workflow ID` | Show a workflow's tasks, dependencies, policy, and token/cost usage (`--mermaid` for a diagram) |
260
+ | `logplane tail ID` | Follow a workflow's events live |
261
+ | `logplane decide` / `retry` / `cancel` | Answer a decision, grant more retries, or cancel a task |
262
+ | `logplane pause` / `resume` / `supersede` | Pause or resume a task or workflow, or replace a task with new intent |
263
+ | `logplane policy` / `agent-policy` | Set workflow concurrency and budgets, or per-agent limits |
264
+ | `logplane workers` / `doctor` | Check worker leases and overall bus health |
265
+ | `logplane adapter check` / `adapter run` | Verify and run an existing agent as a worker |
266
+ | `logplane backup` / `verify-backup` / `restore` | Verified local backups ([recovery operations](RECOVERY.md)) |
267
+
268
+ Finite commands accept `--json` for scripts. [Operating logplane](docs/operations.md)
269
+ covers every command, scheduling, fairness, budgets, and controls in detail.
270
+
271
+ ## Connect your own agent
272
+
273
+ Wrap an existing agent instead of rewriting it. A Python object with `run()`
274
+ becomes a worker:
275
+
276
+ ```python
277
+ from logplane import BusClient, Completed, PythonAgentAdapter, WorkerRuntime
278
+
279
+ class ExistingAgent:
280
+ def run(self, assignment):
281
+ result = do_existing_work(
282
+ goal=assignment.goal,
283
+ context=assignment.context,
284
+ idempotency_key=assignment.effect_id("do-existing-work"),
285
+ )
286
+ return Completed("agent finished", {"result_ref": result.ref})
287
+
288
+ bus = BusClient("http://127.0.0.1:8765", actor="existing-agent")
289
+ WorkerRuntime(
290
+ bus,
291
+ name="existing-agent",
292
+ executor=PythonAgentAdapter(ExistingAgent()),
293
+ capacity=2,
294
+ capabilities=["python"],
295
+ ).run()
296
+ ```
297
+
298
+ Check the contract before connecting it to a live bus:
299
+
300
+ ```sh
301
+ logplane adapter check --python-target my_package.agent:ExistingAgent
302
+ ```
303
+
304
+ CLI and HTTP agents use the same versioned protocol through a small JSON
305
+ config. Use `assignment.effect_id(...)` for any irreversible external effect so
306
+ a retry cannot repeat it. [Integrating agents](docs/integration.md) covers the
307
+ adapters, the safety contract, telemetry, and safe adoption alongside an
308
+ existing system; [`examples/`](examples/README.md) has copyable Python, CLI,
309
+ HTTP, and real-agent integrations.
310
+
311
+ ## Documentation
312
+
313
+ | Page | Contents |
314
+ |---|---|
315
+ | [How logplane works](docs/architecture.md) | Event log, identities, lifecycle, components, invariants, crash recovery, trust model |
316
+ | [Operating logplane](docs/operations.md) | Commands, decisions, retries, cancellation, pauses, DAGs, scheduling, fairness, budgets |
317
+ | [Integrating agents](docs/integration.md) | Python, CLI, and HTTP adapters, safety contract, telemetry, adoption modes |
318
+ | [Event contracts and the HTTP API](docs/events.md) | Envelope, topics, limits, reading and publishing events |
319
+ | [Local recovery operations](RECOVERY.md) | Artifact audits, backup and restore, task-index rebuilds, PM snapshots |
320
+ | [Compatibility and support](COMPATIBILITY.md) | Platforms, versioned surfaces, upgrades, release checks |
321
+ | [Roadmap](ROADMAP.md) and [release notes](RELEASE_NOTES.md) | Direction, remaining v1.0 gates, and what changed in each release |
322
+
323
+ ## Trust and scope
324
+
325
+ logplane is for local, single-user orchestration on one trusted host:
326
+
327
+ - **Perimeter auth is opt-in.** Set `LOGPLANE_TOKEN` to require a bearer token
328
+ on every data route; without it, anyone who can reach the port can publish.
329
+ - **Actors are self-reported.** The token authenticates clients, not
330
+ identities, so any authorized client may publish as any actor, including
331
+ `pm`.
332
+ - **It is not distributed.** Run one PM per bus and one uvicorn worker; the PM
333
+ lock is per machine and event wake-ups are per process.
334
+
335
+ See the [trust model and scope](docs/architecture.md#trust-model) for details.
336
+
337
+ ## Development
338
+
339
+ ```sh
340
+ python -m pip install -r requirements-dev.txt
341
+ python -m pytest -q
342
+ python -m build
343
+ ```
344
+
345
+ The suite focuses on orchestration failures (restarts, stale attempts, retry
346
+ exhaustion, races, DAG propagation, adapter contracts, telemetry isolation)
347
+ and includes live runs of every demo. See
348
+ [running the release checks](COMPATIBILITY.md#running-the-release-checks) for
349
+ the full pre-release procedure.
350
+
351
+ ## Status and license
352
+
353
+ logplane was called agent-bus before v0.13.0; if you used it under that name,
354
+ follow the [migration steps](RELEASE_NOTES.md#migrating-from-agent-bus).
355
+
356
+ Current release: **v0.13.0**, the rename to logplane and a `src/` layout. See the
357
+ [release notes](RELEASE_NOTES.md) and the [roadmap](ROADMAP.md) for the path to
358
+ v1.0. Licensed under the [MIT License](LICENSE). Copyright (c) 2026 deki. See
359
+ [credits and acknowledgements](CONTRIBUTORS.md).