vekna¶
Run coding agents as rituals: ordinary Python programs whose steps you control and whose agent calls happen inside those steps. Agents run permissively within a step; determinism lives at the step boundaries.
An agent left to plan its own work is impressive right up to the point where it decides the failing test was the problem. A ritual is the other arrangement: you write the loop, the branches and the stopping condition yourself, and hand the agent one bounded piece of work at a time.
The one below fits on a screen because it is an introduction; a ritual in daily use is a package with a test suite. What stays true at any size is that the control flow is yours to read.
Install¶
Python 3.11 or newer. The coding medium reaches an agent through the
Claude Code CLI, which
installs separately — everything else works without it.
Your first ritual¶
Put a rituals.py in your project:
from typing import Annotated
from pydantic import BaseModel, Field
from vekna.folio.coding import coding
from vekna.folio.shell import shell
from vekna.lexicon import Transition, done, goto, ritual, step
class FixTests(BaseModel):
# A retry budget counts down to zero, so the CLI rejects a negative one
# rather than letting `--bound -1` run until the step backstop.
bound: Annotated[int, Field(ge=0)] = 3
class Attempt(BaseModel):
left: int
class Verdict(BaseModel):
outcome: str
@step
async def fix(state: Attempt) -> Transition:
result = await shell("pytest")
if result.exit_code == 0:
return done(Verdict(outcome="green"))
if state.left <= 0:
return done(Verdict(outcome="gave up"))
await coding(f"The test suite fails:\n{result.stdout}\nFix it.")
return goto(fix, Attempt(left=state.left - 1))
# `def`, not `async def`: naming the first step has nothing to await. A step or
# entrypoint is written whichever way its body needs.
@ritual("fix_tests")
def fix_tests(components: FixTests) -> Transition:
return goto(fix, Attempt(left=components.bound))
Then cast it:
Output streams live as a tree of rites — one node per step, one nested under it per medium call, with the agent's own output indented beneath. The last line is the cast's result, as JSON:
The retry budget is a number you wrote, the stopping condition is an if you
can read, and the agent is called once per attempt with exactly what you chose
to tell it.
Where to go next¶
- Rituals — steps, transitions, components, and how a ritual is found.
- Mediums —
coding,shellanddecide, and how to configure the agent behind them. - Testing rituals — run a ritual with every medium answering from a script.
- Examples — the rituals this project runs on itself.
- Safety — what vekna does not sandbox. Worth reading before your first cast.
If you use Claude Code, this repository ships a
ritual-scribe skill
— drop it in your own .claude/skills/ and the agent writes rituals against
the real surface rather than inventing an API that reads plausibly.