agentplane-primitives 0.1.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.
- agentplane_primitives-0.1.0/.gitignore +32 -0
- agentplane_primitives-0.1.0/CHANGELOG.md +40 -0
- agentplane_primitives-0.1.0/LICENSE +21 -0
- agentplane_primitives-0.1.0/PKG-INFO +211 -0
- agentplane_primitives-0.1.0/README.md +185 -0
- agentplane_primitives-0.1.0/docs/adr/0001-record-architecture-decisions.md +55 -0
- agentplane_primitives-0.1.0/docs/adr/0002-closed-kind-enum.md +60 -0
- agentplane_primitives-0.1.0/docs/adr/0003-api-models-live-in-control-plane.md +68 -0
- agentplane_primitives-0.1.0/docs/adr/0004-envelope-sections.md +68 -0
- agentplane_primitives-0.1.0/docs/adr/0005-three-tiers-trace-span-envelope.md +65 -0
- agentplane_primitives-0.1.0/docs/adr/README.md +50 -0
- agentplane_primitives-0.1.0/docs/adr/template.md +58 -0
- agentplane_primitives-0.1.0/docs/design.md +20 -0
- agentplane_primitives-0.1.0/docs/versioning.md +36 -0
- agentplane_primitives-0.1.0/pyproject.toml +113 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/__init__.py +10 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/_version.py +3 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/__init__.py +25 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/base_enum.py +15 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/finish_reason.py +17 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/kind.py +14 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/link_type.py +12 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/message_role.py +12 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/model_source.py +17 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/state.py +13 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/enums/status.py +14 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/__init__.py +46 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/base.py +20 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/content_block.py +19 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/envelope.py +94 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/envelope_status.py +28 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/link.py +16 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/llm_input.py +33 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/llm_output.py +43 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/llm_params.py +19 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/message.py +26 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/output_error.py +18 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/reasoning_block.py +12 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/refusal_block.py +12 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/registry.py +15 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/span.py +48 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/text_block.py +12 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/tool_call_block.py +16 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/tool_input.py +15 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/tool_output.py +17 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/trace.py +29 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/trace_context.py +29 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/models/usage.py +21 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/py.typed +0 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/schemas/Envelope.json +808 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/schemas/README.md +39 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/schemas/Span.json +116 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/schemas/Trace.json +88 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/types/__init__.py +36 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/types/id_types.py +48 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/types/metadata_types.py +32 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/types/provider_types.py +18 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/types/schema_version_types.py +18 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/__init__.py +25 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/id_utils.py +32 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/lifecycle_utils.py +33 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/metadata_utils.py +11 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/schema_utils.py +23 -0
- agentplane_primitives-0.1.0/src/agentplane_primitives/utils/traceparent_utils.py +63 -0
- agentplane_primitives-0.1.0/tests/test_base.py +17 -0
- agentplane_primitives-0.1.0/tests/test_enums.py +25 -0
- agentplane_primitives-0.1.0/tests/test_envelope.py +109 -0
- agentplane_primitives-0.1.0/tests/test_envelope_status.py +40 -0
- agentplane_primitives-0.1.0/tests/test_id_types.py +33 -0
- agentplane_primitives-0.1.0/tests/test_id_utils.py +34 -0
- agentplane_primitives-0.1.0/tests/test_llm.py +167 -0
- agentplane_primitives-0.1.0/tests/test_metadata_types.py +23 -0
- agentplane_primitives-0.1.0/tests/test_metadata_utils.py +9 -0
- agentplane_primitives-0.1.0/tests/test_package.py +15 -0
- agentplane_primitives-0.1.0/tests/test_pr_size.py +49 -0
- agentplane_primitives-0.1.0/tests/test_schemas.py +52 -0
- agentplane_primitives-0.1.0/tests/test_trace_and_span.py +97 -0
- agentplane_primitives-0.1.0/tests/test_traceparent_utils.py +76 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
|
|
7
|
+
# Environments
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
.env.*
|
|
12
|
+
!.env.example
|
|
13
|
+
|
|
14
|
+
# Build and packaging
|
|
15
|
+
build/
|
|
16
|
+
dist/
|
|
17
|
+
*.whl
|
|
18
|
+
|
|
19
|
+
# Tooling caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.mypy_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
htmlcov/
|
|
26
|
+
coverage.xml
|
|
27
|
+
|
|
28
|
+
# Editors and OS
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
.DS_Store
|
|
32
|
+
Thumbs.db
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes are recorded here, following [Keep a Changelog](https://keepachangelog.com/)
|
|
4
|
+
and [SemVer](https://semver.org/). Each entry is classified as **compatible** or **breaking** and
|
|
5
|
+
names the migration each consumer needs (see [docs/versioning.md](docs/versioning.md)).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-10-12
|
|
10
|
+
|
|
11
|
+
First release. Schema version `0.1`. Everything below is new, so every entry is **compatible**; there
|
|
12
|
+
is nothing to migrate from. Pre-1.0: pin the exact minor (`agentplane-primitives==0.1.*`).
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Entities:** `Trace` (labels are strings, no status of its own), `Span` (`parent_envelope_id`
|
|
16
|
+
links it to the caller) and `Envelope` with identity fields at the top level and nested
|
|
17
|
+
`envelope_status`, `input`, `output` and `metadata`; `attempt` and `links` (`retry_of`).
|
|
18
|
+
- **Kinds:** a closed `Kind` enum (`llm`, `tool`). `tool` input and output carry `raw` and an
|
|
19
|
+
optional `error`; `llm` input and output carry the canonical fields, `raw`, content blocks
|
|
20
|
+
(`text`, `tool_call`, `reasoning`, `refusal`), `finish_reason` and the fixed cost fields
|
|
21
|
+
`provider`, `model`, `model_source` and `usage` (five exclusive, additive token buckets).
|
|
22
|
+
- **Enums:** `Kind`, `State`, `Status`, `LinkType`, `FinishReason`, `ModelSource`, `MessageRole`.
|
|
23
|
+
A new member of any of them is a schema change.
|
|
24
|
+
- **Ids:** `TraceId` (32 hex), `SpanId` and `EnvelopeId` (16 hex), lowercase, never all zero, with
|
|
25
|
+
random generators.
|
|
26
|
+
- **`traceparent` carrier:** `TraceContext`, `parse_traceparent()` (strict, never raises:
|
|
27
|
+
anything malformed gives `None`) and `format_traceparent()`. `to_event` and `from_event` are
|
|
28
|
+
reserved names, documented and not implemented.
|
|
29
|
+
- **Metadata rules:** lowercase dot-separated keys, the reserved `chronicle.` prefix, string-valued
|
|
30
|
+
trace labels, and the well-known label keys `session_id`, `message_id` and `user_id`.
|
|
31
|
+
- **Schemas:** one committed JSON Schema file per stored entity (`Trace.json`, `Span.json`,
|
|
32
|
+
`Envelope.json`), generated by `python scripts/generate_schemas.py`; a test fails when they
|
|
33
|
+
drift from the models.
|
|
34
|
+
- **Versioning:** `schema_version` `"0.1"` on every persisted payload; unknown fields are ignored
|
|
35
|
+
on read.
|
|
36
|
+
- **Repository:** `src` layout, typed package (`py.typed`), CI, release workflow, dependency
|
|
37
|
+
updates, contribution and security docs, and ADRs 0001 to 0005 in `docs/adr/`.
|
|
38
|
+
|
|
39
|
+
**Not in this package:** HTTP request and response wrappers. The control plane owns them and
|
|
40
|
+
reuses these entities as bodies ([ADR 0003](docs/adr/0003-api-models-live-in-control-plane.md)).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tisha Chawla and Susheem Koul
|
|
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,211 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: agentplane-primitives
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Shared, versioned domain primitives (Trace, Span, Envelope) for the AgentPlane products.
|
|
5
|
+
Project-URL: Homepage, https://github.com/theagentplane/primitives
|
|
6
|
+
Project-URL: Repository, https://github.com/theagentplane/primitives
|
|
7
|
+
Project-URL: Issues, https://github.com/theagentplane/primitives/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/theagentplane/primitives/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Tisha Chawla, Susheem Koul
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,llm,observability,pydantic,schema,tracing
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: pydantic<3,>=2.6
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
|
|
29
|
+
# AgentPlane Primitives
|
|
30
|
+
|
|
31
|
+
**One schema for every agent trace.**<br>
|
|
32
|
+
<sub>Shared, versioned Trace, Span and Envelope models for Chronicle, the control plane and TokenOps.</sub>
|
|
33
|
+
|
|
34
|
+
[](https://github.com/theagentplane/primitives/actions/workflows/ci.yml)
|
|
35
|
+
[](https://github.com/theagentplane/primitives)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
[](https://peps.python.org/pep-0561/)
|
|
38
|
+
[](https://github.com/theagentplane/primitives/stargazers)
|
|
39
|
+
[](https://www.linkedin.com/company/the-agent-plane/)
|
|
40
|
+
|
|
41
|
+
<sub>Built by <b><a href="https://www.linkedin.com/in/susheemkoul/">Susheem Koul</a></b> and <b><a href="https://www.linkedin.com/in/tisha-chawla/">Tisha Chawla</a></b></sub>
|
|
42
|
+
|
|
43
|
+
<br>
|
|
44
|
+
|
|
45
|
+
[Core features](#-core-features) · [Quickstart](#-quickstart) · [How it fits](#-how-it-fits) · [Scope](#-scope) · [Versioning](#-versioning) · [Development](#-development) · [Support](#-support)
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
> ### 🚧 Pre-alpha
|
|
50
|
+
>
|
|
51
|
+
> This release is the repository scaffold. The models land in follow-up releases (see the
|
|
52
|
+
> [roadmap](#-roadmap)). Everything under *Core features* describes the
|
|
53
|
+
> [design](docs/design.md) these releases implement.
|
|
54
|
+
|
|
55
|
+
## ✨ Core features
|
|
56
|
+
|
|
57
|
+
Chronicle records what an agent did, the control plane stores and shows it, and TokenOps reads
|
|
58
|
+
it to govern spend. Those three only work together if they agree on the shape of the data.
|
|
59
|
+
This package is that agreement, and nothing else.
|
|
60
|
+
|
|
61
|
+
| | |
|
|
62
|
+
|---|---|
|
|
63
|
+
| **Three tiers** | A `Trace` is one request across services, a `Span` is one service's handling of it, an `Envelope` is one boundary crossing inside the span. |
|
|
64
|
+
| **One definition, three repos** | Chronicle, the control plane and TokenOps import the same models. None defines its own copy. |
|
|
65
|
+
| **Closed enums** | `kind`, `state`, `status` and the other enumerations are closed sets. A new value is a deliberate schema change. |
|
|
66
|
+
| **Additive-only versioning** | SemVer for the package plus a `schema_version` on every payload. Nothing breaks within a major version. |
|
|
67
|
+
| **W3C `traceparent` carrier** | Parse and format the trace-context header so a trace follows a request across services. |
|
|
68
|
+
| **No I/O, one dependency** | Data and validation only, on pydantic. No network, no disk, no business logic. |
|
|
69
|
+
| **Contract you can read** | Generated JSON Schema, committed and checked in CI, for anything that is not Python. |
|
|
70
|
+
|
|
71
|
+
## 🚀 Quickstart
|
|
72
|
+
|
|
73
|
+
Requires Python 3.10+. The package is typed ([PEP 561](https://peps.python.org/pep-0561/)).
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install agentplane-primitives # once the first release is published
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Until then, install from source:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/theagentplane/primitives.git
|
|
83
|
+
cd primitives
|
|
84
|
+
pip install -e .
|
|
85
|
+
python -c "import agentplane_primitives as p; print(p.__version__)"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### When you need more
|
|
89
|
+
|
|
90
|
+
| You want to | Go to |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Understand the entities and why there are three tiers | [Design](docs/design.md) |
|
|
93
|
+
| Know what may change between versions | [Versioning policy](docs/versioning.md) |
|
|
94
|
+
| Propose a new field or enum value | [Schema change proposal](https://github.com/theagentplane/primitives/issues/new?template=schema_change.yml) |
|
|
95
|
+
| Add a model | [Contributing](CONTRIBUTING.md) |
|
|
96
|
+
| Publish a release | [Releasing](RELEASING.md) |
|
|
97
|
+
|
|
98
|
+
## 🧩 How it fits
|
|
99
|
+
|
|
100
|
+
```mermaid
|
|
101
|
+
flowchart LR
|
|
102
|
+
P["primitives<br/>Trace · Span · Envelope"]
|
|
103
|
+
C["Chronicle<br/>edge SDK: record, save, replay"]
|
|
104
|
+
CP["Control plane<br/>storage, query, visualization"]
|
|
105
|
+
T["TokenOps<br/>governance"]
|
|
106
|
+
|
|
107
|
+
C -->|imports| P
|
|
108
|
+
CP -->|imports| P
|
|
109
|
+
T -->|imports| P
|
|
110
|
+
C -->|"envelopes over HTTP"| CP
|
|
111
|
+
T -->|"reads cost data"| CP
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The control plane owns the schema, and this package is where that schema is defined and shared.
|
|
115
|
+
Chronicle never talks to a database. It sends envelopes to the control plane, which keeps its own
|
|
116
|
+
storage layout and maps from these models.
|
|
117
|
+
|
|
118
|
+
## 🎯 Scope
|
|
119
|
+
|
|
120
|
+
| In scope | Out of scope |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `Trace`, `Span`, `Envelope` and their `llm` and `tool` payload variants | Storage, HTTP clients or servers |
|
|
123
|
+
| The `traceparent` carrier, id generation and validation | Business logic (pricing, policy, replay matching) |
|
|
124
|
+
| Enumerations and well-known metadata keys | Visualization or export (the control plane maps to OpenTelemetry) |
|
|
125
|
+
| Committed JSON Schema for every model | HTTP request and response wrappers (the control plane owns them, [ADR 0003](docs/adr/0003-api-models-live-in-control-plane.md)) |
|
|
126
|
+
| | Anything that performs I/O |
|
|
127
|
+
|
|
128
|
+
## 🔖 Versioning
|
|
129
|
+
|
|
130
|
+
SemVer for the package, plus a `schema_version` (`major.minor`) on every payload.
|
|
131
|
+
|
|
132
|
+
- **Additive-only within a major.** New optional fields are allowed. A new enum member is
|
|
133
|
+
additive for the writer, but older readers reject it, so **consumers upgrade before emitters**.
|
|
134
|
+
- **A breaking change is a new major.** The control plane accepts the current and previous major.
|
|
135
|
+
- **Pre-1.0:** pin the exact minor. From 1.0: `>=1.2,<2`.
|
|
136
|
+
|
|
137
|
+
Full policy: [docs/versioning.md](docs/versioning.md).
|
|
138
|
+
|
|
139
|
+
## 🛠 Development
|
|
140
|
+
|
|
141
|
+
Uses [uv](https://docs.astral.sh/uv/).
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uv sync # environment with the dev group
|
|
145
|
+
uv run pytest --cov # tests
|
|
146
|
+
uv run ruff check . && uv run ruff format --check .
|
|
147
|
+
uv run mypy # strict type check
|
|
148
|
+
uv build # sdist and wheel
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 🗺 Roadmap
|
|
152
|
+
|
|
153
|
+
1. ✅ Repository scaffold
|
|
154
|
+
2. ✅ `Trace`, `Span`, `Envelope`, the `llm` and `tool` payload variants, enums, ids
|
|
155
|
+
3. ✅ The `traceparent` carrier
|
|
156
|
+
4. ✅ Committed JSON Schema and the CI drift check
|
|
157
|
+
5. First release (0.1.0): see [RELEASING.md](RELEASING.md)
|
|
158
|
+
|
|
159
|
+
## Reference
|
|
160
|
+
|
|
161
|
+
<details>
|
|
162
|
+
<summary><b>Project structure</b></summary>
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
src/agentplane_primitives/ # installable package (typed; version in _version.py)
|
|
166
|
+
├── enums/ # closed lists, one file each: kind, state, status, link type
|
|
167
|
+
├── types/ # field types: id types, metadata key and label types
|
|
168
|
+
├── models/ # the models: base class now; Trace, Span, Envelope to come
|
|
169
|
+
├── utils/ # helper functions: id generation, reserved-key check (traceparent later)
|
|
170
|
+
└── schemas/ # generated JSON Schema, committed and drift-checked in CI
|
|
171
|
+
# (more models and the traceparent carrier arrive in later PRs)
|
|
172
|
+
docs/ # design notes and the versioning policy
|
|
173
|
+
tests/ # unit tests
|
|
174
|
+
.github/ # CI, release, dependency updates, templates
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
</details>
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary><b>More documentation</b></summary>
|
|
181
|
+
|
|
182
|
+
- [Design](docs/design.md): the entities and where they are specified
|
|
183
|
+
- [Versioning policy](docs/versioning.md)
|
|
184
|
+
- [Changelog](CHANGELOG.md): every change classified as compatible or breaking
|
|
185
|
+
- [Contributing](CONTRIBUTING.md) - [Releasing](RELEASING.md) - [Security](SECURITY.md)
|
|
186
|
+
|
|
187
|
+
</details>
|
|
188
|
+
|
|
189
|
+
## 🛟 Support
|
|
190
|
+
|
|
191
|
+
| Need | Where |
|
|
192
|
+
|---|---|
|
|
193
|
+
| Bug | [Open an issue](https://github.com/theagentplane/primitives/issues) |
|
|
194
|
+
| Schema change | [Schema change proposal](https://github.com/theagentplane/primitives/issues/new?template=schema_change.yml) |
|
|
195
|
+
| Security issue | [SECURITY.md](SECURITY.md) |
|
|
196
|
+
| Real-time help | [Slack](https://join.slack.com/t/theagentplane/shared_invite/zt-47lqx2xtc-0idr1cuLNJ_JDTgqxDiUsg) |
|
|
197
|
+
| Talk it through | [Office hours](https://calendly.com/theagentplane/theagentplane) |
|
|
198
|
+
|
|
199
|
+
## Contributors
|
|
200
|
+
|
|
201
|
+
Thanks to everyone who has contributed.
|
|
202
|
+
|
|
203
|
+
[](https://github.com/theagentplane/primitives/graphs/contributors)
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
<div align="center">
|
|
208
|
+
|
|
209
|
+
[Back to top](#agentplane-primitives)
|
|
210
|
+
|
|
211
|
+
</div>
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# AgentPlane Primitives
|
|
4
|
+
|
|
5
|
+
**One schema for every agent trace.**<br>
|
|
6
|
+
<sub>Shared, versioned Trace, Span and Envelope models for Chronicle, the control plane and TokenOps.</sub>
|
|
7
|
+
|
|
8
|
+
[](https://github.com/theagentplane/primitives/actions/workflows/ci.yml)
|
|
9
|
+
[](https://github.com/theagentplane/primitives)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://peps.python.org/pep-0561/)
|
|
12
|
+
[](https://github.com/theagentplane/primitives/stargazers)
|
|
13
|
+
[](https://www.linkedin.com/company/the-agent-plane/)
|
|
14
|
+
|
|
15
|
+
<sub>Built by <b><a href="https://www.linkedin.com/in/susheemkoul/">Susheem Koul</a></b> and <b><a href="https://www.linkedin.com/in/tisha-chawla/">Tisha Chawla</a></b></sub>
|
|
16
|
+
|
|
17
|
+
<br>
|
|
18
|
+
|
|
19
|
+
[Core features](#-core-features) · [Quickstart](#-quickstart) · [How it fits](#-how-it-fits) · [Scope](#-scope) · [Versioning](#-versioning) · [Development](#-development) · [Support](#-support)
|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
> ### 🚧 Pre-alpha
|
|
24
|
+
>
|
|
25
|
+
> This release is the repository scaffold. The models land in follow-up releases (see the
|
|
26
|
+
> [roadmap](#-roadmap)). Everything under *Core features* describes the
|
|
27
|
+
> [design](docs/design.md) these releases implement.
|
|
28
|
+
|
|
29
|
+
## ✨ Core features
|
|
30
|
+
|
|
31
|
+
Chronicle records what an agent did, the control plane stores and shows it, and TokenOps reads
|
|
32
|
+
it to govern spend. Those three only work together if they agree on the shape of the data.
|
|
33
|
+
This package is that agreement, and nothing else.
|
|
34
|
+
|
|
35
|
+
| | |
|
|
36
|
+
|---|---|
|
|
37
|
+
| **Three tiers** | A `Trace` is one request across services, a `Span` is one service's handling of it, an `Envelope` is one boundary crossing inside the span. |
|
|
38
|
+
| **One definition, three repos** | Chronicle, the control plane and TokenOps import the same models. None defines its own copy. |
|
|
39
|
+
| **Closed enums** | `kind`, `state`, `status` and the other enumerations are closed sets. A new value is a deliberate schema change. |
|
|
40
|
+
| **Additive-only versioning** | SemVer for the package plus a `schema_version` on every payload. Nothing breaks within a major version. |
|
|
41
|
+
| **W3C `traceparent` carrier** | Parse and format the trace-context header so a trace follows a request across services. |
|
|
42
|
+
| **No I/O, one dependency** | Data and validation only, on pydantic. No network, no disk, no business logic. |
|
|
43
|
+
| **Contract you can read** | Generated JSON Schema, committed and checked in CI, for anything that is not Python. |
|
|
44
|
+
|
|
45
|
+
## 🚀 Quickstart
|
|
46
|
+
|
|
47
|
+
Requires Python 3.10+. The package is typed ([PEP 561](https://peps.python.org/pep-0561/)).
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install agentplane-primitives # once the first release is published
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Until then, install from source:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/theagentplane/primitives.git
|
|
57
|
+
cd primitives
|
|
58
|
+
pip install -e .
|
|
59
|
+
python -c "import agentplane_primitives as p; print(p.__version__)"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### When you need more
|
|
63
|
+
|
|
64
|
+
| You want to | Go to |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Understand the entities and why there are three tiers | [Design](docs/design.md) |
|
|
67
|
+
| Know what may change between versions | [Versioning policy](docs/versioning.md) |
|
|
68
|
+
| Propose a new field or enum value | [Schema change proposal](https://github.com/theagentplane/primitives/issues/new?template=schema_change.yml) |
|
|
69
|
+
| Add a model | [Contributing](CONTRIBUTING.md) |
|
|
70
|
+
| Publish a release | [Releasing](RELEASING.md) |
|
|
71
|
+
|
|
72
|
+
## 🧩 How it fits
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
flowchart LR
|
|
76
|
+
P["primitives<br/>Trace · Span · Envelope"]
|
|
77
|
+
C["Chronicle<br/>edge SDK: record, save, replay"]
|
|
78
|
+
CP["Control plane<br/>storage, query, visualization"]
|
|
79
|
+
T["TokenOps<br/>governance"]
|
|
80
|
+
|
|
81
|
+
C -->|imports| P
|
|
82
|
+
CP -->|imports| P
|
|
83
|
+
T -->|imports| P
|
|
84
|
+
C -->|"envelopes over HTTP"| CP
|
|
85
|
+
T -->|"reads cost data"| CP
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The control plane owns the schema, and this package is where that schema is defined and shared.
|
|
89
|
+
Chronicle never talks to a database. It sends envelopes to the control plane, which keeps its own
|
|
90
|
+
storage layout and maps from these models.
|
|
91
|
+
|
|
92
|
+
## 🎯 Scope
|
|
93
|
+
|
|
94
|
+
| In scope | Out of scope |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `Trace`, `Span`, `Envelope` and their `llm` and `tool` payload variants | Storage, HTTP clients or servers |
|
|
97
|
+
| The `traceparent` carrier, id generation and validation | Business logic (pricing, policy, replay matching) |
|
|
98
|
+
| Enumerations and well-known metadata keys | Visualization or export (the control plane maps to OpenTelemetry) |
|
|
99
|
+
| Committed JSON Schema for every model | HTTP request and response wrappers (the control plane owns them, [ADR 0003](docs/adr/0003-api-models-live-in-control-plane.md)) |
|
|
100
|
+
| | Anything that performs I/O |
|
|
101
|
+
|
|
102
|
+
## 🔖 Versioning
|
|
103
|
+
|
|
104
|
+
SemVer for the package, plus a `schema_version` (`major.minor`) on every payload.
|
|
105
|
+
|
|
106
|
+
- **Additive-only within a major.** New optional fields are allowed. A new enum member is
|
|
107
|
+
additive for the writer, but older readers reject it, so **consumers upgrade before emitters**.
|
|
108
|
+
- **A breaking change is a new major.** The control plane accepts the current and previous major.
|
|
109
|
+
- **Pre-1.0:** pin the exact minor. From 1.0: `>=1.2,<2`.
|
|
110
|
+
|
|
111
|
+
Full policy: [docs/versioning.md](docs/versioning.md).
|
|
112
|
+
|
|
113
|
+
## 🛠 Development
|
|
114
|
+
|
|
115
|
+
Uses [uv](https://docs.astral.sh/uv/).
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
uv sync # environment with the dev group
|
|
119
|
+
uv run pytest --cov # tests
|
|
120
|
+
uv run ruff check . && uv run ruff format --check .
|
|
121
|
+
uv run mypy # strict type check
|
|
122
|
+
uv build # sdist and wheel
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 🗺 Roadmap
|
|
126
|
+
|
|
127
|
+
1. ✅ Repository scaffold
|
|
128
|
+
2. ✅ `Trace`, `Span`, `Envelope`, the `llm` and `tool` payload variants, enums, ids
|
|
129
|
+
3. ✅ The `traceparent` carrier
|
|
130
|
+
4. ✅ Committed JSON Schema and the CI drift check
|
|
131
|
+
5. First release (0.1.0): see [RELEASING.md](RELEASING.md)
|
|
132
|
+
|
|
133
|
+
## Reference
|
|
134
|
+
|
|
135
|
+
<details>
|
|
136
|
+
<summary><b>Project structure</b></summary>
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
src/agentplane_primitives/ # installable package (typed; version in _version.py)
|
|
140
|
+
├── enums/ # closed lists, one file each: kind, state, status, link type
|
|
141
|
+
├── types/ # field types: id types, metadata key and label types
|
|
142
|
+
├── models/ # the models: base class now; Trace, Span, Envelope to come
|
|
143
|
+
├── utils/ # helper functions: id generation, reserved-key check (traceparent later)
|
|
144
|
+
└── schemas/ # generated JSON Schema, committed and drift-checked in CI
|
|
145
|
+
# (more models and the traceparent carrier arrive in later PRs)
|
|
146
|
+
docs/ # design notes and the versioning policy
|
|
147
|
+
tests/ # unit tests
|
|
148
|
+
.github/ # CI, release, dependency updates, templates
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
<details>
|
|
154
|
+
<summary><b>More documentation</b></summary>
|
|
155
|
+
|
|
156
|
+
- [Design](docs/design.md): the entities and where they are specified
|
|
157
|
+
- [Versioning policy](docs/versioning.md)
|
|
158
|
+
- [Changelog](CHANGELOG.md): every change classified as compatible or breaking
|
|
159
|
+
- [Contributing](CONTRIBUTING.md) - [Releasing](RELEASING.md) - [Security](SECURITY.md)
|
|
160
|
+
|
|
161
|
+
</details>
|
|
162
|
+
|
|
163
|
+
## 🛟 Support
|
|
164
|
+
|
|
165
|
+
| Need | Where |
|
|
166
|
+
|---|---|
|
|
167
|
+
| Bug | [Open an issue](https://github.com/theagentplane/primitives/issues) |
|
|
168
|
+
| Schema change | [Schema change proposal](https://github.com/theagentplane/primitives/issues/new?template=schema_change.yml) |
|
|
169
|
+
| Security issue | [SECURITY.md](SECURITY.md) |
|
|
170
|
+
| Real-time help | [Slack](https://join.slack.com/t/theagentplane/shared_invite/zt-47lqx2xtc-0idr1cuLNJ_JDTgqxDiUsg) |
|
|
171
|
+
| Talk it through | [Office hours](https://calendly.com/theagentplane/theagentplane) |
|
|
172
|
+
|
|
173
|
+
## Contributors
|
|
174
|
+
|
|
175
|
+
Thanks to everyone who has contributed.
|
|
176
|
+
|
|
177
|
+
[](https://github.com/theagentplane/primitives/graphs/contributors)
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
<div align="center">
|
|
182
|
+
|
|
183
|
+
[Back to top](#agentplane-primitives)
|
|
184
|
+
|
|
185
|
+
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# 0001. Record architecture decisions
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|---|---|
|
|
5
|
+
| Status | Accepted |
|
|
6
|
+
| Date | 2026-10-05 |
|
|
7
|
+
| Deciders | Susheem Koul, Tisha Chawla |
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
Four repositories (chronicle, primitives, control-plane, tokenops) now evolve together and share
|
|
12
|
+
contracts. Decisions are made in conversations, pull request threads and long design documents,
|
|
13
|
+
and the reasoning is hard to find afterwards. New contributors, and AI coding agents working in
|
|
14
|
+
these repositories, have no reliable way to learn why something is built the way it is, so they
|
|
15
|
+
can unknowingly undo a deliberate choice.
|
|
16
|
+
|
|
17
|
+
## Options considered
|
|
18
|
+
|
|
19
|
+
### Option A: keep decisions inside design documents and pull requests
|
|
20
|
+
|
|
21
|
+
- Good: no new process.
|
|
22
|
+
- Bad: reasoning is scattered, mixed with implementation detail, and edited over time, so the
|
|
23
|
+
record of what was decided and when is lost.
|
|
24
|
+
|
|
25
|
+
### Option B: one ADR per decision, stored in each repository
|
|
26
|
+
|
|
27
|
+
- Good: small, dated, reviewable records next to the code; easy for agents to read; history
|
|
28
|
+
shows what changed and why.
|
|
29
|
+
- Bad: a little writing discipline is needed, and cross-repository decisions need a rule about
|
|
30
|
+
where they live.
|
|
31
|
+
|
|
32
|
+
## Decision
|
|
33
|
+
|
|
34
|
+
We will record architecture decisions as ADRs in `docs/adr/` of each repository, using the
|
|
35
|
+
template in this folder. Cross-repository decisions are recorded in the repository that owns the
|
|
36
|
+
decision and linked from the others. AI coding agents are told to read the ADRs before changing
|
|
37
|
+
architecture and to follow `docs/adr/README.md` when asked to record a decision.
|
|
38
|
+
|
|
39
|
+
## Consequences
|
|
40
|
+
|
|
41
|
+
- **Good:** decisions are findable and dated; superseded decisions stay visible.
|
|
42
|
+
- **Bad or risky:** ADRs go stale if nobody writes them, so writing one is part of making a
|
|
43
|
+
qualifying decision, not a follow-up.
|
|
44
|
+
- **Follow-ups:** backfill ADRs for the decisions already taken in the Chronicle technical
|
|
45
|
+
design document where they matter most.
|
|
46
|
+
|
|
47
|
+
## Impact on other repositories
|
|
48
|
+
|
|
49
|
+
The same folder, template and agent instructions are added to chronicle, primitives,
|
|
50
|
+
control-plane and tokenops.
|
|
51
|
+
|
|
52
|
+
## Links
|
|
53
|
+
|
|
54
|
+
- [How to write an ADR](README.md)
|
|
55
|
+
- [Template](template.md)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# 0002. Define envelope `kind` as a closed enum with two members
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|---|---|
|
|
5
|
+
| Status | Accepted |
|
|
6
|
+
| Date | 2026-10-06 |
|
|
7
|
+
| Deciders | Susheem Koul, Tisha Chawla |
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
Every envelope has a `kind` that selects the shape of its input and output (design sections 2.3
|
|
12
|
+
and 2.9). In Chronicle 0.5.0, `kind` is a free string, and `router` and `custom` are in use
|
|
13
|
+
alongside `llm` and `tool`. Consumers such as TokenOps read the envelope by kind, and replay
|
|
14
|
+
needs to know how to handle each one. A router is either an LLM call or, if it is a plain
|
|
15
|
+
function, a tool; delegating work to another agent is an outbound call, which is a tool envelope
|
|
16
|
+
(the link between the two services is carried by `traceparent`).
|
|
17
|
+
|
|
18
|
+
## Options considered
|
|
19
|
+
|
|
20
|
+
### Option A: keep `kind` a free string
|
|
21
|
+
|
|
22
|
+
What 0.5.0 does today.
|
|
23
|
+
|
|
24
|
+
- Good: unchanged from 0.5.0.
|
|
25
|
+
- Bad: it allows values such as `router` and `custom`, which the design retires (section 2.3).
|
|
26
|
+
|
|
27
|
+
### Option B: closed enum defined in this package
|
|
28
|
+
|
|
29
|
+
`kind` is `llm` or `tool`. Any other value is rejected at validation.
|
|
30
|
+
|
|
31
|
+
- Good: a value outside the enum is rejected at validation (section 2.3).
|
|
32
|
+
- Bad: adding a kind is a schema change made in this package (section 2.8).
|
|
33
|
+
|
|
34
|
+
## Decision
|
|
35
|
+
|
|
36
|
+
We will define `kind` as a closed enum in this package with the members `llm` and `tool`, and
|
|
37
|
+
reject every other value, including custom and unregistered kinds. `router` and `custom` from
|
|
38
|
+
0.5.0 are retired; both become `tool`.
|
|
39
|
+
|
|
40
|
+
## Consequences
|
|
41
|
+
|
|
42
|
+
- **Good:** one definition of `kind`, shared by Chronicle, the control plane and TokenOps.
|
|
43
|
+
- **Bad or risky:** a new kind is additive for the writer, but a reader on an older minor rejects
|
|
44
|
+
it, so consumers must upgrade before emitters (`docs/versioning.md`). Users cannot invent their
|
|
45
|
+
own kinds.
|
|
46
|
+
- **Follow-ups:** the input and output variants selected by `kind` arrive with the envelope
|
|
47
|
+
(tool first, then llm).
|
|
48
|
+
|
|
49
|
+
## Impact on other repositories
|
|
50
|
+
|
|
51
|
+
- **chronicle:** declaring a boundary with any other kind fails at declaration time; `router`
|
|
52
|
+
and `custom` become `tool` (design section 12.3).
|
|
53
|
+
- **control-plane:** validates ingested envelopes against this enum.
|
|
54
|
+
- **tokenops:** `delegate` is removed from its list of observation kinds, leaving `llm | tool`.
|
|
55
|
+
|
|
56
|
+
## Links
|
|
57
|
+
|
|
58
|
+
- Design: `docs/rfcs/chronicle-technical-design.md` in chronicle, sections 2.3 and 2.9, decision
|
|
59
|
+
12.
|
|
60
|
+
- [Versioning policy](../versioning.md)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 0003. Keep HTTP request and response wrappers out of primitives
|
|
2
|
+
|
|
3
|
+
| Field | Value |
|
|
4
|
+
|---|---|
|
|
5
|
+
| Status | Accepted |
|
|
6
|
+
| Date | 2026-10-06 |
|
|
7
|
+
| Deciders | Susheem Koul, Tisha Chawla |
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
The Chronicle technical design (sections 2.8 and 10.1, and the layer table in section 1.1) lists
|
|
12
|
+
"the API request and response models" as part of this package, next to Trace, Span and
|
|
13
|
+
Envelope. Decision 9 of that design says the control plane owns the schema and that Chronicle
|
|
14
|
+
"must not depend on server code".
|
|
15
|
+
|
|
16
|
+
Trace, Span and Envelope are the records the whole system stores and passes around. They are
|
|
17
|
+
data, not requests. The control plane will use them as the body of its requests and responses,
|
|
18
|
+
while the endpoints, status codes and the rest of the HTTP layer are its own concern.
|
|
19
|
+
|
|
20
|
+
## Options considered
|
|
21
|
+
|
|
22
|
+
### Option A: API models stay in primitives (the design as written)
|
|
23
|
+
|
|
24
|
+
- Good: matches the design as written (sections 1.1, 2.8 and 10.1).
|
|
25
|
+
- Bad: it treats HTTP request and response wrappers as part of the data model, when the
|
|
26
|
+
maintainers consider Trace, Span and Envelope to be data and not request objects.
|
|
27
|
+
|
|
28
|
+
### Option B: the control plane owns all API models, and Chronicle depends on primitives through it
|
|
29
|
+
|
|
30
|
+
- Good: nothing HTTP-specific in primitives.
|
|
31
|
+
- Bad: Chronicle would depend on server code, which conflicts with decision 9 of the design.
|
|
32
|
+
|
|
33
|
+
### Option C: primitives holds only the entities; the control plane owns the HTTP wrappers
|
|
34
|
+
|
|
35
|
+
Requests and responses reuse primitives types as their bodies (an upsert-span body is a `Span`; a
|
|
36
|
+
batch of envelopes is a list of `Envelope`). Wrappers that exist only because of the HTTP API
|
|
37
|
+
(the write result and the error body) belong to the control plane. Chronicle imports primitives
|
|
38
|
+
directly.
|
|
39
|
+
|
|
40
|
+
- Good: primitives stays about the data, and Chronicle depends on primitives directly.
|
|
41
|
+
- Bad: Chronicle must read the write result and error body without a shared model, so it needs a
|
|
42
|
+
few lines of its own code and a contract test against the control plane.
|
|
43
|
+
|
|
44
|
+
## Decision
|
|
45
|
+
|
|
46
|
+
We will take Option C. Primitives defines the entities, ids, enums, metadata rules, the
|
|
47
|
+
`traceparent` carrier and the committed JSON Schema, and no HTTP request or response wrappers.
|
|
48
|
+
|
|
49
|
+
## Consequences
|
|
50
|
+
|
|
51
|
+
- **Good:** a smaller package: primitives holds data only.
|
|
52
|
+
- **Bad or risky:** the result and error shapes are defined in one repository and read in
|
|
53
|
+
another, so drift is possible until a contract test exists. If those shapes grow, moving them
|
|
54
|
+
into primitives later is an additive change.
|
|
55
|
+
- **Follow-ups:** the planned primitives PR for API models is dropped. The control plane
|
|
56
|
+
defines the wrappers; Chronicle adds a contract test.
|
|
57
|
+
|
|
58
|
+
## Impact on other repositories
|
|
59
|
+
|
|
60
|
+
- **chronicle:** the technical design (sections 1.1, 2.8, 10.1) is updated to match. The client
|
|
61
|
+
imports primitives for entities and parses the write result and error body itself.
|
|
62
|
+
- **control-plane:** defines the HTTP wrappers and reuses primitives entities as bodies.
|
|
63
|
+
- **tokenops:** none.
|
|
64
|
+
|
|
65
|
+
## Links
|
|
66
|
+
|
|
67
|
+
- Design: `docs/rfcs/chronicle-technical-design.md` in chronicle, sections 1.1, 2.8, 10.1 and
|
|
68
|
+
decision 9.
|