boundflow-charter 0.1.0.dev122__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.
- boundflow_charter-0.1.0.dev122/LICENSE +201 -0
- boundflow_charter-0.1.0.dev122/PKG-INFO +480 -0
- boundflow_charter-0.1.0.dev122/README.md +442 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/PKG-INFO +480 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/SOURCES.txt +55 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/dependency_links.txt +1 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/entry_points.txt +2 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/requires.txt +23 -0
- boundflow_charter-0.1.0.dev122/boundflow_charter.egg-info/top_level.txt +1 -0
- boundflow_charter-0.1.0.dev122/charter/__init__.py +0 -0
- boundflow_charter-0.1.0.dev122/charter/artifact.py +205 -0
- boundflow_charter-0.1.0.dev122/charter/cli.py +1942 -0
- boundflow_charter-0.1.0.dev122/charter/compile.py +158 -0
- boundflow_charter-0.1.0.dev122/charter/config/__init__.py +0 -0
- boundflow_charter-0.1.0.dev122/charter/config/agent.py +648 -0
- boundflow_charter-0.1.0.dev122/charter/config/lifecycle.py +120 -0
- boundflow_charter-0.1.0.dev122/charter/config/loader.py +282 -0
- boundflow_charter-0.1.0.dev122/charter/config/runtime.py +240 -0
- boundflow_charter-0.1.0.dev122/charter/config/worker.py +264 -0
- boundflow_charter-0.1.0.dev122/charter/console.py +33 -0
- boundflow_charter-0.1.0.dev122/charter/harness/__init__.py +30 -0
- boundflow_charter-0.1.0.dev122/charter/harness/callbacks.py +100 -0
- boundflow_charter-0.1.0.dev122/charter/harness/capabilities.py +99 -0
- boundflow_charter-0.1.0.dev122/charter/harness/durable.py +260 -0
- boundflow_charter-0.1.0.dev122/charter/harness/gates.py +86 -0
- boundflow_charter-0.1.0.dev122/charter/harness/metering.py +137 -0
- boundflow_charter-0.1.0.dev122/charter/harness/middleware.py +208 -0
- boundflow_charter-0.1.0.dev122/charter/mcp/__init__.py +0 -0
- boundflow_charter-0.1.0.dev122/charter/mcp/client.py +406 -0
- boundflow_charter-0.1.0.dev122/charter/notify.py +148 -0
- boundflow_charter-0.1.0.dev122/charter/policy.py +198 -0
- boundflow_charter-0.1.0.dev122/charter/provisioning/__init__.py +0 -0
- boundflow_charter-0.1.0.dev122/charter/provisioning/apply.py +227 -0
- boundflow_charter-0.1.0.dev122/charter/trace.py +57 -0
- boundflow_charter-0.1.0.dev122/charter/ui.py +165 -0
- boundflow_charter-0.1.0.dev122/charter/worker.py +317 -0
- boundflow_charter-0.1.0.dev122/charter/workflows/loop.py +802 -0
- boundflow_charter-0.1.0.dev122/charter/workflows/spawning.py +308 -0
- boundflow_charter-0.1.0.dev122/charter/workflows/subagents.py +115 -0
- boundflow_charter-0.1.0.dev122/pyproject.toml +84 -0
- boundflow_charter-0.1.0.dev122/setup.cfg +4 -0
- boundflow_charter-0.1.0.dev122/tests/test_agent_config.py +301 -0
- boundflow_charter-0.1.0.dev122/tests/test_apply.py +242 -0
- boundflow_charter-0.1.0.dev122/tests/test_artifact.py +93 -0
- boundflow_charter-0.1.0.dev122/tests/test_cli.py +660 -0
- boundflow_charter-0.1.0.dev122/tests/test_compile.py +194 -0
- boundflow_charter-0.1.0.dev122/tests/test_console.py +46 -0
- boundflow_charter-0.1.0.dev122/tests/test_docs.py +59 -0
- boundflow_charter-0.1.0.dev122/tests/test_harness.py +114 -0
- boundflow_charter-0.1.0.dev122/tests/test_harness_bounds.py +199 -0
- boundflow_charter-0.1.0.dev122/tests/test_loader.py +356 -0
- boundflow_charter-0.1.0.dev122/tests/test_loop.py +904 -0
- boundflow_charter-0.1.0.dev122/tests/test_mcp_live.py +300 -0
- boundflow_charter-0.1.0.dev122/tests/test_spawning.py +274 -0
- boundflow_charter-0.1.0.dev122/tests/test_subagents.py +116 -0
- boundflow_charter-0.1.0.dev122/tests/test_trace.py +112 -0
- boundflow_charter-0.1.0.dev122/tests/test_worker.py +45 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
95
|
+
Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and do
|
|
117
|
+
not modify the License. You may add Your own attribution notices
|
|
118
|
+
within Derivative Works that You distribute, alongside or as an
|
|
119
|
+
addendum to the NOTICE text from the Work, provided that such
|
|
120
|
+
additional attribution notices cannot be construed as modifying
|
|
121
|
+
the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Arjun Lama
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: boundflow-charter
|
|
3
|
+
Version: 0.1.0.dev122
|
|
4
|
+
Summary: Declarative, governed agents on BoundFlow — objective, tools, and policy as YAML.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Project-URL: Homepage, https://github.com/boundflow/charter
|
|
7
|
+
Project-URL: Source, https://github.com/boundflow/charter
|
|
8
|
+
Project-URL: Issues, https://github.com/boundflow/charter/issues
|
|
9
|
+
Keywords: agents,llm,deepagents,mcp,governance,control-plane
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: boundflow>=0.6.0
|
|
18
|
+
Requires-Dist: deepagents>=0.7.7
|
|
19
|
+
Requires-Dist: langchain-core>=1.5
|
|
20
|
+
Requires-Dist: langgraph>=1.2
|
|
21
|
+
Requires-Dist: langgraph-checkpoint-postgres>=3.1
|
|
22
|
+
Requires-Dist: langchain-anthropic>=0.3
|
|
23
|
+
Requires-Dist: oras>=0.2
|
|
24
|
+
Requires-Dist: langchain-mcp-adapters>=0.1
|
|
25
|
+
Requires-Dist: mcp>=1.0
|
|
26
|
+
Requires-Dist: pydantic>=2.0
|
|
27
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
33
|
+
Provides-Extra: ui
|
|
34
|
+
Requires-Dist: boundflow[ui]; extra == "ui"
|
|
35
|
+
Provides-Extra: otel
|
|
36
|
+
Requires-Dist: boundflow[otel]; extra == "otel"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# Charter
|
|
40
|
+
|
|
41
|
+
**The easiest way to build and manage production-ready agents.**
|
|
42
|
+
|
|
43
|
+
> **Pre-alpha, and in the open early.** The design is settled enough to read and
|
|
44
|
+
> argue with; the code is not settled enough to run anything you care about.
|
|
45
|
+
> Expect the configuration format to change.
|
|
46
|
+
|
|
47
|
+
A prototype agent is a prompt and some tools. A production agent needs more: a
|
|
48
|
+
defined responsibility, explicit authority over what it may touch, a budget it
|
|
49
|
+
can't exceed, a way for humans to intervene while it works, and someone watching
|
|
50
|
+
its behavior over time.
|
|
51
|
+
|
|
52
|
+
Charter is that, as configuration. You describe an agent in YAML — what it's
|
|
53
|
+
responsible for, which tools it gets, what needs a human, what it may spend — and
|
|
54
|
+
Charter deploys it as a durable, governed service you can operate.
|
|
55
|
+
|
|
56
|
+
The agent runs in your environment. Its state, policy and history live in a
|
|
57
|
+
control plane, so a task survives a closed laptop, a restarted worker, or an
|
|
58
|
+
approval that takes until tomorrow.
|
|
59
|
+
|
|
60
|
+
> [!WARNING]
|
|
61
|
+
> **Pre-alpha.** Charter agents have run end-to-end against a live control plane,
|
|
62
|
+
> a real model and real MCP servers — but plenty hasn't. Expect rough edges and
|
|
63
|
+
> expect the configuration format to change.
|
|
64
|
+
|
|
65
|
+
## Define an agent
|
|
66
|
+
|
|
67
|
+
An agent is a directory with a version file in it — `refund-triage/v1.yaml`:
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
apiVersion: charter/v1
|
|
71
|
+
kind: AgentConfig
|
|
72
|
+
|
|
73
|
+
name: refund-triage
|
|
74
|
+
version: 1
|
|
75
|
+
model: claude-haiku-4-5
|
|
76
|
+
|
|
77
|
+
objective: |
|
|
78
|
+
Resolve the refund request on ticket {{ inputs.ticket_id }}.
|
|
79
|
+
Look up the ticket and the charge before proposing anything.
|
|
80
|
+
Never propose a refund above ${{ inputs.max_refund_usd }}.
|
|
81
|
+
|
|
82
|
+
inputs:
|
|
83
|
+
ticket_id: { type: string, required: true }
|
|
84
|
+
max_refund_usd: { type: number, default: 100 }
|
|
85
|
+
|
|
86
|
+
mcp:
|
|
87
|
+
- name: stripe
|
|
88
|
+
url: https://mcp.stripe.com
|
|
89
|
+
env: [STRIPE_API_KEY]
|
|
90
|
+
tools:
|
|
91
|
+
- tool: get_charge
|
|
92
|
+
- tool: create_refund
|
|
93
|
+
approval: always
|
|
94
|
+
|
|
95
|
+
response_format:
|
|
96
|
+
resolution: { type: string }
|
|
97
|
+
refunded_usd: { type: number }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
That file is the whole agent. Budgets and lifecycle rules live in two optional
|
|
101
|
+
files beside it — see [a project](#a-project) — and a conservative default
|
|
102
|
+
ceiling applies until you add them.
|
|
103
|
+
|
|
104
|
+
Deploy it, create an instance, and give it work:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
charter agent create refund-triage
|
|
108
|
+
charter apply .
|
|
109
|
+
charter run refund-triage --instance a3f9c012 --ticket-id 4821
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Suppose the agent reads the ticket and the charge and concludes a $240 refund is
|
|
113
|
+
warranted. It cannot issue it. `create_refund` requires approval, so Charter
|
|
114
|
+
parks the task and surfaces the proposed action and the agent's reasoning to a
|
|
115
|
+
human:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
charter approve apr_01J8Z --reason "third dispute this month"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Only then is the refund executed. The agent receives the result, finishes the
|
|
122
|
+
task, and reports what happened. The task didn't live in your terminal in the
|
|
123
|
+
meantime.
|
|
124
|
+
|
|
125
|
+
## What makes it production-ready
|
|
126
|
+
|
|
127
|
+
### Explicit authority
|
|
128
|
+
|
|
129
|
+
Access to an MCP server is not access to everything that server exposes. The
|
|
130
|
+
model only ever sees the tools you declared:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
mcp stripe: 34 tools available, 2 declared (32 ignored)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If the server adds a tool tomorrow, your agent doesn't silently gain a capability.
|
|
137
|
+
And tools marked `approval: always` aren't callable inside the agent loop at all —
|
|
138
|
+
the agent can propose them, but a separate step executes them after a human signs
|
|
139
|
+
off. The model can propose authority it doesn't have; it can't grant it to itself.
|
|
140
|
+
|
|
141
|
+
### A budget per task
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
per_run:
|
|
145
|
+
max_cost_usd: 0.30
|
|
146
|
+
max_llm_calls: 40
|
|
147
|
+
max_tool_failures: 3
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Limits hold across the whole task — reasoning rounds, retries, human feedback and
|
|
151
|
+
tool calls alike. When one is exhausted, Charter tells you the operational reason
|
|
152
|
+
rather than collapsing it into a generic failure:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
stripe__create_refund failed 3 times (max_tool_failures=3)
|
|
156
|
+
the integration looks broken
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Humans in the loop, durably
|
|
160
|
+
|
|
161
|
+
An agent stops for a human for two reasons: it needs information it shouldn't
|
|
162
|
+
guess, or it wants to do something beyond its authority.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
charter pending refund-triage
|
|
166
|
+
charter approve apr_01J8Z --reason "confirmed duplicate"
|
|
167
|
+
charter answer inp_01J8Z "use the March charge"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Neither is a process sitting around waiting. Charter checkpoints the task; it can
|
|
171
|
+
wait overnight and resume on another worker with everything it had discovered,
|
|
172
|
+
spent and been told. Rejection carries a reason back to the agent, so a "no" is
|
|
173
|
+
feedback it can act on, not just a closed door.
|
|
174
|
+
|
|
175
|
+
### Policy that acts on its own
|
|
176
|
+
|
|
177
|
+
Humans govern individual actions. Lifecycle rules govern the agent itself:
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
rules:
|
|
181
|
+
- when: { metric: num_failures, threshold: 2 }
|
|
182
|
+
then: { pause: { window: 5 } }
|
|
183
|
+
|
|
184
|
+
- when: { metric: cost, threshold: 5.00 }
|
|
185
|
+
then: { cooldown: { window: 20, seconds: 300 } }
|
|
186
|
+
|
|
187
|
+
- when: { metric: approval_rejections, threshold: 3 }
|
|
188
|
+
then: { set_version: { target: 1 } }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
A noisy agent gets cooled down. A repeatedly failing one gets paused. A new
|
|
192
|
+
version whose decisions keep getting rejected rolls back to the one that worked —
|
|
193
|
+
and because versions are immutable specifications, rollback restores the whole
|
|
194
|
+
agent, not just a prompt string. What changed is a file in Git, with an author and
|
|
195
|
+
a diff.
|
|
196
|
+
|
|
197
|
+
## Operate agents, not sessions
|
|
198
|
+
|
|
199
|
+
An agent persists beyond any single task.
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
$ charter agents
|
|
203
|
+
|
|
204
|
+
AGENT VER STATUS ACTIVITY
|
|
205
|
+
invoice-chaser v1 paused idle
|
|
206
|
+
refund-triage v1 active awaiting_approval
|
|
207
|
+
ticket-sweeper v1 active idle
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Inspect its authority and how close it is to tripping a rule:
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
$ charter describe refund-triage
|
|
214
|
+
|
|
215
|
+
limits per task
|
|
216
|
+
max_cost_usd 0.25
|
|
217
|
+
max_llm_calls 20
|
|
218
|
+
|
|
219
|
+
rules
|
|
220
|
+
num_failures 1 of 2 -> pause window=5
|
|
221
|
+
cost 5.2 of 5 -> cooldown window=20 seconds=300
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
And reconstruct, afterwards, every governance decision that was made:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
$ charter audit refund-triage
|
|
228
|
+
|
|
229
|
+
2026-08-18 03:47 approval rejected by dana@example.com
|
|
230
|
+
refund-triage: run stripe__create_refund
|
|
231
|
+
amount_usd: 240
|
|
232
|
+
reason: wrong charge — ch_9001 is the original
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Getting started
|
|
236
|
+
|
|
237
|
+
1. **Define the agent** — `v1.yaml`: its objective, the tools it may call, which of
|
|
238
|
+
them need a human.
|
|
239
|
+
2. **Set its policy** — `runtime.yaml` for budgets and authority, `lifecycle.yaml`
|
|
240
|
+
for pause, cooldown and rollback rules.
|
|
241
|
+
3. **Package it** — `charter push` seals the version into your registry. Skip it
|
|
242
|
+
while developing: a worker reads a directory just as well.
|
|
243
|
+
4. **Configure a worker** — `worker.yaml`: credentials, and which agents and
|
|
244
|
+
versions this process serves.
|
|
245
|
+
5. **Apply it** — `charter apply` arms config and policy on the control plane;
|
|
246
|
+
`charter agent create` instantiates the agent.
|
|
247
|
+
6. **Run it** — `charter run` starts a task; `charter status` says how it went.
|
|
248
|
+
7. **Manage it** — the step that doesn't end: approve what it proposes, watch what
|
|
249
|
+
it spends, add a `v2.yaml` when it should behave differently. `charter ui` puts
|
|
250
|
+
the same thing in a browser, for whoever decides an approval.
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
pip install --pre boundflow-charter # add [ui] for the console, [otel] for traces
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`--pre` is required for now: every green build of main is published, and there is
|
|
257
|
+
no stable release yet. Once one is tagged, `pip install boundflow-charter` gets it
|
|
258
|
+
and `--pre` keeps meaning "whatever main is".
|
|
259
|
+
|
|
260
|
+
### A control plane
|
|
261
|
+
|
|
262
|
+
Charter needs one to run agents against, and there are two ways to have one:
|
|
263
|
+
|
|
264
|
+
**BoundFlow Cloud** — managed, early access. Nothing to deploy, and you get two
|
|
265
|
+
addresses and an API key. This is the shorter path and what the rest of this
|
|
266
|
+
assumes; [request access](mailto:hello@boundflow.dev).
|
|
267
|
+
|
|
268
|
+
**Self-hosted** — the BoundFlow backend is open source and runs as a container.
|
|
269
|
+
Its [deployment docs](https://github.com/boundflow/boundflow/blob/main/docs/deployment.md)
|
|
270
|
+
own that story; Charter only needs the addresses it gives you.
|
|
271
|
+
|
|
272
|
+
Either way, inference stays yours. The control plane never sees your model key or
|
|
273
|
+
its traffic.
|
|
274
|
+
|
|
275
|
+
### A project
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
.
|
|
279
|
+
├── worker.yaml # which agents this worker serves, pricing, channels
|
|
280
|
+
└── leads-finder/
|
|
281
|
+
├── v1.yaml # objective, tools, gates — versioned, immutable
|
|
282
|
+
├── v1/skills/ # procedures for that version, shipped with it
|
|
283
|
+
├── runtime.yaml # budgets, limits, authority — policy, not versioned
|
|
284
|
+
└── lifecycle.yaml # pause, cooldown and rollback rules
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Only `v1.yaml` is required; a version file plus credentials is enough to run an
|
|
288
|
+
agent. The split matters: `v1.yaml` is what the agent *does* and is versioned, so
|
|
289
|
+
a rollback restores behavior. Budgets and lifecycle rules are today's guardrails
|
|
290
|
+
and stay in force across one.
|
|
291
|
+
|
|
292
|
+
Skills are the procedures the agent should follow once it gets there — how your
|
|
293
|
+
refunds policy works, the runbook a new hire would be handed. Drop them in
|
|
294
|
+
`v1/skills/<name>/SKILL.md` and they ship with that version; the layout is
|
|
295
|
+
deepagents' own, so skills you already have work unchanged. They live inside `v1/`
|
|
296
|
+
because rolling back to v1 should restore the instructions v1 was running with.
|
|
297
|
+
|
|
298
|
+
### Traces
|
|
299
|
+
|
|
300
|
+
Every model call and tool call, with its prompts, results and token counts, goes to
|
|
301
|
+
a sink the worker owns:
|
|
302
|
+
|
|
303
|
+
```yaml
|
|
304
|
+
trace_sink:
|
|
305
|
+
kind: otel
|
|
306
|
+
endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`otel` speaks OTLP and follows OpenTelemetry's GenAI conventions, so Jaeger, Tempo,
|
|
310
|
+
Datadog and Langfuse all read it without a translation layer — `jsonl` and
|
|
311
|
+
`logging` are there for when you just want to look. Traces are captured worker-side
|
|
312
|
+
and carry prompts, so they go to your backend and never to the control plane.
|
|
313
|
+
|
|
314
|
+
That is separate from `store.url`, which holds checkpoints and the agent's files —
|
|
315
|
+
state a parked task resumes from, not telemetry.
|
|
316
|
+
|
|
317
|
+
### Which agents a worker serves
|
|
318
|
+
|
|
319
|
+
```yaml
|
|
320
|
+
serves:
|
|
321
|
+
- agent: leads-finder # from ./leads-finder, while you develop
|
|
322
|
+
versions: [1]
|
|
323
|
+
- agent: refund-triage # from the registry, once it is real
|
|
324
|
+
versions: [1, 2]
|
|
325
|
+
repository: ghcr.io/acme/agents
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
A repository derives one address per version — `<repository>/<agent>:v<N>`, the
|
|
329
|
+
address `charter push` writes. List every version a lifecycle rule can roll back
|
|
330
|
+
to: a worker that cannot build the old version leaves the control plane
|
|
331
|
+
dispatching work nobody can handle.
|
|
332
|
+
|
|
333
|
+
### Credentials
|
|
334
|
+
|
|
335
|
+
`worker.yaml` is committed, so nothing secret goes in it. Credentials are `${VAR}`
|
|
336
|
+
references resolved from the environment when the worker starts:
|
|
337
|
+
|
|
338
|
+
```yaml
|
|
339
|
+
control_plane:
|
|
340
|
+
endpoint: ${BOUNDFLOW_SERVER_ADDRESS} # the control API, for the CLI
|
|
341
|
+
worker_endpoint: ${BOUNDFLOW_WORKER_ADDRESS} # where workers claim tasks
|
|
342
|
+
api_key: ${BOUNDFLOW_API_KEY}
|
|
343
|
+
tenant: default
|
|
344
|
+
|
|
345
|
+
llm:
|
|
346
|
+
provider: anthropic
|
|
347
|
+
api_key: ${ANTHROPIC_API_KEY}
|
|
348
|
+
|
|
349
|
+
store:
|
|
350
|
+
url: ${CHARTER_STORE_URL}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Two addresses, because BoundFlow serves the control API and worker dispatch
|
|
354
|
+
separately — on two ports locally, and on two hosts in Cloud. Leave
|
|
355
|
+
`worker_endpoint` out and workers fall back to `BOUNDFLOW_WORKER_ADDRESS`, then to
|
|
356
|
+
localhost, which is what you want while developing and never what you want against
|
|
357
|
+
a remote control plane.
|
|
358
|
+
|
|
359
|
+
Inference is bring-your-own: your model key stays in the worker environment and
|
|
360
|
+
model traffic never reaches the control plane. The CLI reads this same file, so
|
|
361
|
+
the control plane is configured once and every command talks to the one your
|
|
362
|
+
worker does.
|
|
363
|
+
|
|
364
|
+
### First run
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
charter validate . # parse and cross-check every file
|
|
368
|
+
charter agent create leads-finder # bring one instance into existence
|
|
369
|
+
charter apply . # arm config, policy and pricing
|
|
370
|
+
charter worker . # in its own terminal — this is the process
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`create` is separate from `apply` because an instance owns state — its own store,
|
|
374
|
+
budget and lifecycle history — so bringing one into existence is a decision a
|
|
375
|
+
person makes, not something CI does on their behalf. `apply` is safe to re-run as
|
|
376
|
+
often as you like.
|
|
377
|
+
|
|
378
|
+
`create` prints an instance id; keep it. Commands that act on an agent name an
|
|
379
|
+
instance, because the instance is the thing holding the state:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
charter run leads-finder --instance a3f9c012 --topic "..."
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Deploying
|
|
386
|
+
|
|
387
|
+
Locally, `charter worker .` is the whole thing, which is what you want while
|
|
388
|
+
iterating — the agent's MCP servers and your logs are right in front of you.
|
|
389
|
+
|
|
390
|
+
For anything long-lived, run the worker as a container. The reason is isolation
|
|
391
|
+
rather than packaging: an agent can declare MCP servers as commands, and the
|
|
392
|
+
worker executes them. [deploy/](deploy/) has a Dockerfile that mounts the project
|
|
393
|
+
rather than baking it in, so changing an objective is a restart, not a rebuild.
|
|
394
|
+
|
|
395
|
+
## CLI
|
|
396
|
+
|
|
397
|
+
Working with configuration:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
charter validate . # parse and cross-check configuration
|
|
401
|
+
charter diff . # compare declared and deployed state
|
|
402
|
+
charter apply . # update config, policy and pricing
|
|
403
|
+
charter push <agent> <ref> # publish a version to an OCI registry
|
|
404
|
+
charter worker . # run agents in this environment
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Operating an agent:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
charter agent create <agent> # bring an instance into existence
|
|
411
|
+
charter run <agent> --flags # start a task
|
|
412
|
+
charter agents # every agent and what it's doing
|
|
413
|
+
charter describe <agent> # authority, limits, rules, any hold
|
|
414
|
+
charter tasks <agent> # task history
|
|
415
|
+
charter status <task-id> # result, cost and why it stopped
|
|
416
|
+
charter audit <agent> # every governance decision recorded
|
|
417
|
+
|
|
418
|
+
charter pending <agent> # the open gate, if it's parked on one
|
|
419
|
+
charter approve / reject / answer <id>
|
|
420
|
+
charter ui # the same, in a browser
|
|
421
|
+
|
|
422
|
+
charter pause <agent> # stop it taking work
|
|
423
|
+
charter resume <agent> --suspension <id>
|
|
424
|
+
charter agent delete <agent> # destroy an instance and its history
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Read commands take `--json` for the complete record instead of the curated view.
|
|
428
|
+
|
|
429
|
+
## Architecture
|
|
430
|
+
|
|
431
|
+
Charter is an opinionated agent layer built on
|
|
432
|
+
[BoundFlow](https://github.com/boundflow/boundflow).
|
|
433
|
+
|
|
434
|
+
`charter apply` compiles your configuration into workflows and policy on the
|
|
435
|
+
BoundFlow control plane. Charter workers run the actual agent loop in your
|
|
436
|
+
environment, talking to your MCP servers with credentials that never leave it.
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
BoundFlow
|
|
440
|
+
Control Plane
|
|
441
|
+
state • policy • lifecycle
|
|
442
|
+
│
|
|
443
|
+
RPC
|
|
444
|
+
│
|
|
445
|
+
▼
|
|
446
|
+
Your environment
|
|
447
|
+
┌─────────────────────────┐
|
|
448
|
+
│ Charter worker │
|
|
449
|
+
│ │
|
|
450
|
+
│ model ↔ agent loop │
|
|
451
|
+
│ │ │
|
|
452
|
+
│ MCP tools │
|
|
453
|
+
└─────────────────────────┘
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Charter introduces no database or service of its own. If the Charter CLI vanished,
|
|
457
|
+
deployed agents would keep running through their workers and the control plane.
|
|
458
|
+
|
|
459
|
+
See [DESIGN.md](DESIGN.md) for the full configuration reference and the design
|
|
460
|
+
decisions behind it, and [examples/](examples/) for complete configurations.
|
|
461
|
+
|
|
462
|
+
## Development
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
python -m venv .venv
|
|
466
|
+
.venv/bin/pip install -e ../boundflow/sdk/python # your BoundFlow checkout
|
|
467
|
+
.venv/bin/pip install -e '.[dev]'
|
|
468
|
+
.venv/bin/pytest
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
End-to-end tests require a BoundFlow control plane and are excluded by default:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
docker compose -f ../boundflow/docker-compose.dist.yml up -d
|
|
475
|
+
export BOUNDFLOW_API_KEY=<...>
|
|
476
|
+
pytest tests/e2e
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
They use a real control plane, a real MCP subprocess and real governance gates.
|
|
480
|
+
Only the model is faked, so the suite stays deterministic and free.
|