boundflow-charter 0.1.0.dev122__py3-none-any.whl

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.
@@ -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.
@@ -0,0 +1,36 @@
1
+ boundflow_charter-0.1.0.dev122.dist-info/licenses/LICENSE,sha256=IkG13LTZByzZgwJZDltMgTwKOsQ3mIU_kkHTF7ZRxrk,11340
2
+ charter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ charter/artifact.py,sha256=ytZNKbWSAlIRuILngu3xt274nkWbZtvjhBoOlQe8dNY,8500
4
+ charter/cli.py,sha256=NSdxAaATIRayivtrpPGIf6LhD2eG3jT7heYlCiFFV2E,83121
5
+ charter/compile.py,sha256=xEHiEjYW489Cw_d4Dg0dmi9aRnU4MmRjAVUbFEmt9Pg,6788
6
+ charter/console.py,sha256=SzKkizjhhOzj7X0xtuJQEcpPsKpfClrSfvlH6uw1qPI,1168
7
+ charter/notify.py,sha256=ohgRz3x7dhg6P2JMXBJux6Y0szM8elZywRUWsA-_SAY,6215
8
+ charter/policy.py,sha256=nT4M9fglmOOm-SDn0qnGisTVRmasTpfV2f1JjNYUlrM,8179
9
+ charter/trace.py,sha256=fCnUBDk7_jFzErtB0iP0UNHT867MIEyPFnE8Kndp8Rk,2224
10
+ charter/ui.py,sha256=05WzlqEV9FJV7nUQt86mPgAoNF2pvxSRHhco8t55CFI,6097
11
+ charter/worker.py,sha256=hz6PZfgujqNCC2iMTzkT8EEP-KvMkzYFVzIUtTTdnIc,14557
12
+ charter/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ charter/config/agent.py,sha256=3aYHfyJcOsHo6tSpZ0gTfRk-sacZJrYHUxVFiG6dJ_A,30005
14
+ charter/config/lifecycle.py,sha256=RuuvlwUKURZYmQIv9SOlZCani-hDurVIhdD76QmSrhQ,4106
15
+ charter/config/loader.py,sha256=mDpKkYsERT4TBtUwfUI5P_-Dq-8O5_CUJSl70NFYMmQ,10784
16
+ charter/config/runtime.py,sha256=6v2nxosG3FkbxijrRX0KGLlH3xgXu-iEiU_lvzoYTwU,12115
17
+ charter/config/worker.py,sha256=zWBm67GBe1Q1KgA2p1YhwNcpsufv5wATawAs3adi4K4,11050
18
+ charter/harness/__init__.py,sha256=iXivL9F2lIoWGHuEt4qknfN5xtDT_QAIREQJkE3gZuw,1235
19
+ charter/harness/callbacks.py,sha256=m5vT6j3jm1BruWX2lYdMBmC7sI6oHZ7FiXckiu8tnXY,4847
20
+ charter/harness/capabilities.py,sha256=B7KaZid5iJeXitza6QkKL-1QaokJvIznGcYHDmWdrHE,4418
21
+ charter/harness/durable.py,sha256=KOe0OpvmBeEK3yBFj5sRSY1hFkePScQKx2ogd2nI9XI,12555
22
+ charter/harness/gates.py,sha256=2WCyVoHhl1IGESleYK_04WpuZR-hLEH-r295xBCbQHI,3612
23
+ charter/harness/metering.py,sha256=FbUYtZywMWeNq01Z3-KVj2O7FugK8DZJW4pe0TzCTgc,6219
24
+ charter/harness/middleware.py,sha256=RdRRix-PvCzJ6ezPQZ4b6gQMOgvxBLzU6FY8dbWd7V4,9418
25
+ charter/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ charter/mcp/client.py,sha256=cI3v2yzgzxrhojx7OiyV98SoJt4DWxDzWiaWW1OQIUU,18077
27
+ charter/provisioning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ charter/provisioning/apply.py,sha256=LUDaX5rOxlcOF3VacZTn6Z2Fwu2FwnpWprIDQ2t0LKc,9006
29
+ charter/workflows/loop.py,sha256=fGcBBWqKbtKz_NWbZ2L-UaaGXAlukX_YdjmTGjllbwM,36580
30
+ charter/workflows/spawning.py,sha256=eW9YWu1qPEVTaTTVM1oUcZ3lOP1FHVE0HEAeMYVDO6o,14796
31
+ charter/workflows/subagents.py,sha256=ZsI50jdWLB4kwfdk_tOWcF75h1hZS2JwQX4yW8Pf1m8,4692
32
+ boundflow_charter-0.1.0.dev122.dist-info/METADATA,sha256=kloFIF5Rff20azvrbk77Y2dKeiGB-KBlTtcbuUDZXvE,17251
33
+ boundflow_charter-0.1.0.dev122.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
34
+ boundflow_charter-0.1.0.dev122.dist-info/entry_points.txt,sha256=8g8aQYCsIpvBH8rDKYBPNRb0G2SyRyzBvtURo5XN8uA,45
35
+ boundflow_charter-0.1.0.dev122.dist-info/top_level.txt,sha256=GlYBj0fCO6RnSAwzcuDX9SnO-lMBEXJeiPDKl_lAN5k,8
36
+ boundflow_charter-0.1.0.dev122.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ charter = charter.cli:main