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
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
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:
- open model calls are charged;
- orphaned turns are killed and recorded;
- uncollected turns are collected;
- pending pushes and merges are reconciled;
- its own rollouts are finished.
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