vekna 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. vekna-0.5.0/LICENSE +28 -0
  2. vekna-0.5.0/PKG-INFO +139 -0
  3. vekna-0.5.0/README.md +105 -0
  4. vekna-0.5.0/pyproject.toml +631 -0
  5. vekna-0.5.0/src/vekna/__init__.py +0 -0
  6. vekna-0.5.0/src/vekna/edges/__init__.py +0 -0
  7. vekna-0.5.0/src/vekna/edges/pytest_plugin.py +25 -0
  8. vekna-0.5.0/src/vekna/folio/__init__.py +0 -0
  9. vekna-0.5.0/src/vekna/folio/coding/__init__.py +21 -0
  10. vekna-0.5.0/src/vekna/folio/coding/_inits.py +11 -0
  11. vekna-0.5.0/src/vekna/folio/coding/_mills.py +218 -0
  12. vekna-0.5.0/src/vekna/folio/coding/_pacts.py +109 -0
  13. vekna-0.5.0/src/vekna/folio/coding_claude/__init__.py +5 -0
  14. vekna-0.5.0/src/vekna/folio/coding_claude/_inits.py +10 -0
  15. vekna-0.5.0/src/vekna/folio/coding_claude/_links.py +248 -0
  16. vekna-0.5.0/src/vekna/folio/coding_claude/_pacts.py +15 -0
  17. vekna-0.5.0/src/vekna/folio/flow/__init__.py +3 -0
  18. vekna-0.5.0/src/vekna/folio/flow/_mills.py +30 -0
  19. vekna-0.5.0/src/vekna/folio/shell/__init__.py +4 -0
  20. vekna-0.5.0/src/vekna/folio/shell/_links.py +119 -0
  21. vekna-0.5.0/src/vekna/folio/shell/_pacts.py +7 -0
  22. vekna-0.5.0/src/vekna/gates/__init__.py +0 -0
  23. vekna-0.5.0/src/vekna/inits/__init__.py +0 -0
  24. vekna-0.5.0/src/vekna/inits/cli.py +77 -0
  25. vekna-0.5.0/src/vekna/lexicon/__init__.py +96 -0
  26. vekna-0.5.0/src/vekna/lexicon/_edges.py +0 -0
  27. vekna-0.5.0/src/vekna/lexicon/_gates.py +0 -0
  28. vekna-0.5.0/src/vekna/lexicon/_inits.py +389 -0
  29. vekna-0.5.0/src/vekna/lexicon/_links/__init__.py +0 -0
  30. vekna-0.5.0/src/vekna/lexicon/_links/loader.py +156 -0
  31. vekna-0.5.0/src/vekna/lexicon/_links/standalone.py +186 -0
  32. vekna-0.5.0/src/vekna/lexicon/_mills/__init__.py +0 -0
  33. vekna-0.5.0/src/vekna/lexicon/_mills/_annotations.py +121 -0
  34. vekna-0.5.0/src/vekna/lexicon/_mills/dispatch.py +156 -0
  35. vekna-0.5.0/src/vekna/lexicon/_mills/engine.py +392 -0
  36. vekna-0.5.0/src/vekna/lexicon/_mills/graph.py +75 -0
  37. vekna-0.5.0/src/vekna/lexicon/_pacts.py +287 -0
  38. vekna-0.5.0/src/vekna/lexicon/_specs.py +1 -0
  39. vekna-0.5.0/src/vekna/links/__init__.py +0 -0
  40. vekna-0.5.0/src/vekna/mills/__init__.py +0 -0
  41. vekna-0.5.0/src/vekna/pacts/__init__.py +0 -0
  42. vekna-0.5.0/src/vekna/py.typed +0 -0
  43. vekna-0.5.0/src/vekna/specs/__init__.py +0 -0
  44. vekna-0.5.0/src/vekna/trial/__init__.py +28 -0
  45. vekna-0.5.0/src/vekna/trial/_inits.py +135 -0
  46. vekna-0.5.0/src/vekna/trial/_links.py +208 -0
  47. vekna-0.5.0/src/vekna/trial/_mills.py +70 -0
  48. vekna-0.5.0/src/vekna/trial/_pacts.py +55 -0
  49. vekna-0.5.0/src/vekna/wire/__init__.py +39 -0
  50. vekna-0.5.0/src/vekna/wire/_links.py +10 -0
  51. vekna-0.5.0/src/vekna/wire/_pacts.py +150 -0
vekna-0.5.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Radosław Ganczarek
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
vekna-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: vekna
3
+ Version: 0.5.0
4
+ Summary: Run coding agents as rituals: ordinary Python programs whose steps you control
5
+ License-Expression: BSD-3-Clause
6
+ License-File: LICENSE
7
+ Keywords: agents,claude,llm,orchestration,workflow
8
+ Author: Radosław Ganczarek
9
+ Author-email: radoslaw@ganczarek.in
10
+ Requires-Python: >=3.11,<4
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Build Tools
21
+ Classifier: Typing :: Typed
22
+ Provides-Extra: trial
23
+ Requires-Dist: claude-agent-sdk (>=0.2,<1.0)
24
+ Requires-Dist: click (>=8.3.2,<9.0.0)
25
+ Requires-Dist: pydantic (>=2.12.5,<3.0.0)
26
+ Requires-Dist: pytest (>=8.0,<10.0) ; extra == "trial"
27
+ Project-URL: Changelog, https://github.com/fancysnake/vekna/blob/main/CHANGELOG.md
28
+ Project-URL: Documentation, https://vekna.fancysnake.dev
29
+ Project-URL: Homepage, https://vekna.fancysnake.dev
30
+ Project-URL: Issues, https://github.com/fancysnake/vekna/issues
31
+ Project-URL: Repository, https://github.com/fancysnake/vekna
32
+ Description-Content-Type: text/markdown
33
+
34
+ # vekna
35
+
36
+ Run coding agents as **rituals**: ordinary Python programs whose steps you
37
+ control and whose agent calls happen inside those steps. Agents run
38
+ permissively *within* a step; determinism lives at the step boundaries.
39
+
40
+ Documentation is at [vekna.fancysnake.dev](https://vekna.fancysnake.dev).
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install vekna
46
+ ```
47
+
48
+ Python 3.11+. Testing your rituals needs the `trial` extra:
49
+ `pip install 'vekna[trial]'` — quoted, because zsh globs the brackets.
50
+
51
+ ## A ritual
52
+
53
+ Put a `rituals.py` in your project — or a `rituals/` package, split however you
54
+ like, once one file stops being enough:
55
+
56
+ ```python
57
+ from typing import Annotated
58
+
59
+ from pydantic import BaseModel, Field
60
+
61
+ from vekna.folio.coding import coding
62
+ from vekna.folio.shell import shell
63
+ from vekna.lexicon import Transition, done, goto, ritual, step
64
+
65
+
66
+ class FixTests(BaseModel):
67
+ # A retry budget counts down to zero, so the CLI rejects a negative one
68
+ # rather than letting `--bound -1` run until the step backstop.
69
+ bound: Annotated[int, Field(ge=0)] = 3
70
+
71
+
72
+ class Attempt(BaseModel):
73
+ left: int
74
+
75
+
76
+ class Verdict(BaseModel):
77
+ outcome: str
78
+
79
+
80
+ @step
81
+ async def fix(state: Attempt) -> Transition:
82
+ result = await shell("mise run test:py")
83
+ if result.exit_code == 0:
84
+ return done(Verdict(outcome="green"))
85
+ if state.left <= 0:
86
+ return done(Verdict(outcome="gave up"))
87
+ await coding(f"The test suite fails:\n{result.stdout}\nFix it.")
88
+ return goto(fix, Attempt(left=state.left - 1))
89
+
90
+
91
+ # `def`, not `async def`: naming the first step has nothing to await. A step or
92
+ # entrypoint is written whichever way its body needs.
93
+ @ritual("fix_tests")
94
+ def fix_tests(components: FixTests) -> Transition:
95
+ return goto(fix, Attempt(left=components.bound))
96
+ ```
97
+
98
+ Then cast it:
99
+
100
+ ```bash
101
+ vekna cast fix_tests --bound 5
102
+ ```
103
+
104
+ Output streams live as a tree of rites — one node per step, one nested under
105
+ it per medium call, with the agent's own output indented beneath. The last
106
+ line is the cast's result, as JSON:
107
+
108
+ ```text
109
+ result: {"outcome":"green"}
110
+ ```
111
+
112
+ ## Commands
113
+
114
+ | Command | What it does |
115
+ | --- | --- |
116
+ | `vekna cast <ritual> [--<component> value …]` | Run a ritual from `rituals.py` |
117
+ | `vekna cast --prompt "<text>"` | One-shot cast on the coding medium, no `rituals.py` needed |
118
+ | `vekna rituals list` | Every ritual and the options it takes |
119
+ | `vekna rituals show <ritual>` | A ritual's components and its step graph |
120
+
121
+ ## Architecture
122
+
123
+ [GLIMPSE](https://glimpse.fancysnake.dev/) layering, enforced by
124
+ [`import-linter`](https://import-linter.readthedocs.io/). See
125
+ [`docs/architecture.md`](docs/architecture.md) and
126
+ [`docs/reborn/`](docs/reborn/) for the release-by-release plan.
127
+
128
+ ## Development
129
+
130
+ ```bash
131
+ mise run test:py # all tests
132
+ mise run check:py # the loop while you work: format, lint, tests
133
+ mise run fullcheck # the gate before you push: adds diff-coverage and tingle
134
+ ```
135
+
136
+ ## Licence
137
+
138
+ BSD-3-Clause.
139
+
vekna-0.5.0/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # vekna
2
+
3
+ Run coding agents as **rituals**: ordinary Python programs whose steps you
4
+ control and whose agent calls happen inside those steps. Agents run
5
+ permissively *within* a step; determinism lives at the step boundaries.
6
+
7
+ Documentation is at [vekna.fancysnake.dev](https://vekna.fancysnake.dev).
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install vekna
13
+ ```
14
+
15
+ Python 3.11+. Testing your rituals needs the `trial` extra:
16
+ `pip install 'vekna[trial]'` — quoted, because zsh globs the brackets.
17
+
18
+ ## A ritual
19
+
20
+ Put a `rituals.py` in your project — or a `rituals/` package, split however you
21
+ like, once one file stops being enough:
22
+
23
+ ```python
24
+ from typing import Annotated
25
+
26
+ from pydantic import BaseModel, Field
27
+
28
+ from vekna.folio.coding import coding
29
+ from vekna.folio.shell import shell
30
+ from vekna.lexicon import Transition, done, goto, ritual, step
31
+
32
+
33
+ class FixTests(BaseModel):
34
+ # A retry budget counts down to zero, so the CLI rejects a negative one
35
+ # rather than letting `--bound -1` run until the step backstop.
36
+ bound: Annotated[int, Field(ge=0)] = 3
37
+
38
+
39
+ class Attempt(BaseModel):
40
+ left: int
41
+
42
+
43
+ class Verdict(BaseModel):
44
+ outcome: str
45
+
46
+
47
+ @step
48
+ async def fix(state: Attempt) -> Transition:
49
+ result = await shell("mise run test:py")
50
+ if result.exit_code == 0:
51
+ return done(Verdict(outcome="green"))
52
+ if state.left <= 0:
53
+ return done(Verdict(outcome="gave up"))
54
+ await coding(f"The test suite fails:\n{result.stdout}\nFix it.")
55
+ return goto(fix, Attempt(left=state.left - 1))
56
+
57
+
58
+ # `def`, not `async def`: naming the first step has nothing to await. A step or
59
+ # entrypoint is written whichever way its body needs.
60
+ @ritual("fix_tests")
61
+ def fix_tests(components: FixTests) -> Transition:
62
+ return goto(fix, Attempt(left=components.bound))
63
+ ```
64
+
65
+ Then cast it:
66
+
67
+ ```bash
68
+ vekna cast fix_tests --bound 5
69
+ ```
70
+
71
+ Output streams live as a tree of rites — one node per step, one nested under
72
+ it per medium call, with the agent's own output indented beneath. The last
73
+ line is the cast's result, as JSON:
74
+
75
+ ```text
76
+ result: {"outcome":"green"}
77
+ ```
78
+
79
+ ## Commands
80
+
81
+ | Command | What it does |
82
+ | --- | --- |
83
+ | `vekna cast <ritual> [--<component> value …]` | Run a ritual from `rituals.py` |
84
+ | `vekna cast --prompt "<text>"` | One-shot cast on the coding medium, no `rituals.py` needed |
85
+ | `vekna rituals list` | Every ritual and the options it takes |
86
+ | `vekna rituals show <ritual>` | A ritual's components and its step graph |
87
+
88
+ ## Architecture
89
+
90
+ [GLIMPSE](https://glimpse.fancysnake.dev/) layering, enforced by
91
+ [`import-linter`](https://import-linter.readthedocs.io/). See
92
+ [`docs/architecture.md`](docs/architecture.md) and
93
+ [`docs/reborn/`](docs/reborn/) for the release-by-release plan.
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ mise run test:py # all tests
99
+ mise run check:py # the loop while you work: format, lint, tests
100
+ mise run fullcheck # the gate before you push: adds diff-coverage and tingle
101
+ ```
102
+
103
+ ## Licence
104
+
105
+ BSD-3-Clause.