Valor Engels

Durability

Every model call, turn, effect, question, correction and stop is a row in one append-only table. The kernel is the deterministic code that runs every task. Everything it knows about a task is computed from those rows, so a crash at any instant leaves nothing to reconcile.

Data model

The data model

The kernel's database role can only insert and select, so the system can't edit its own record. A trigger refuses edits even from the table's owner.

Documents, such as a task's Brief, are written once; anything that changes later is a new event.

In place of foreign keys, partial unique indexes make whole classes of double-write impossible: a call charged twice, a task stopped twice, two outcomes for one effect.

Source: core/schema.sql · docs/data.md, The tables

eventsthe ledgeridthe order every reader usestask_ida task, or a named streamtypenoun.verb: turn.startedpayloadthe event's fields, JSONBatwall time, for peopleinsert and select only; edits refuseddocumentswritten oncekindtask or transcriptidits id within the kindbodyJSONB: the Brief as it startedA task's statefolded from its rows, never stored

Effects

How effects are recorded

An effect is an action outside the kernel, such as a push, merge or send. Its intent is committed to the ledger, the append-only table above, before the effect runs, and its outcome is committed after.

If the process is killed between the two, the ledger shows an intent with no outcome, so no effect goes unrecorded.

On restart the kernel asks the target what happened (for example, whether the branch holds the commit) and writes the answer. If the target doesn't answer, nothing is written.

Source: docs/data.md, Intent before outcome · core/broker.py

1. effect.intent committedthe action, written before it runs2. The performer runsa push, a merge, or a send3. effect.outcomecommitted afterKilled before 3intent, no outcomeOn restartask the targetdonetarget has itfailedtarget lacks itin flightno answer yet

The resident kernel

Recovery after a crash

Each machine runs one kernel process, kept alive by launchd, the macOS service manager. When it starts, it settles whatever a dead kernel left:

After that, it wakes each time a new row lands in the ledger.

Retries
A failed step is retried after a minute, then after twice as long each time; four failures in a row end the task with a report.
Turn slots
Two turns run at a time by default, which keeps memory use in bounds.
Tom's answers
A turn uses up an answer from Tom, who built Valor and runs Yudame, only if the turn finishes, so a failed turn can't lose it.
Backups
The newest 30 database dumps are kept, and each is checked by restoring it into a scratch cluster.

Source: core/README.md · core/serve.py · core/backup.py

Harnesses

Harnesses and bridges

Harnesses

The kernel never knows which agent it runs. A harness, the agent program that does a turn's work (Claude Code, Pi or Codex), hands the kernel the command for one turn, normally claude -p, and a gateway meters every model call that turn makes.

A turn talks back only through files it leaves under .valor/.

Bridges

Each channel (Telegram, Slack, email and the local chat) has a bridge, a process that records inbound messages and performs the sends the broker releases. The kernel's loop drives all the work.

Source: docs/harnesses.md · harnesses/ · docs/bridges/

Memory

Memory

What goes in
After each turn, the new rows: instructions, Tom's answers and feedback, corrections, and turn transcripts, stored raw.
What comes out
A later task's prompt gets up to ten matching records from its own project, plus any record from any client that Valor has judged a standard of working. All are quoted as data.
What it can't do
Memory has its own database role with no access to the ledger, and nothing it returns can change a ceiling.

Source: docs/memory.md · core/memory.py

Previous← Overview NextIn the chat →