Substrate — how satelle stores and validates its configuration
satelle's process is configuration, not code: workflows, skills, and principles are authored markdown. This topic explains where that substrate lives, the format it follows, and how it is validated.
Three planes (authored / defaults / runtime)
| Plane | Where | Holds |
|---|---|---|
| Authored | <repo>/.satelle/ (git-optional) | satelle.toml, constitution, edited workflows (incl. workflows/agents.toml) / skills / principles, documents, tasks |
| Defaults | embedded in the binary | sparse repo-agnostic workflows/skills/principles (resolved virtually; see virtual-defaults work) |
| Runtime | ~/.satelle/<repo-key>/ | satelle.db (+wal/shm), logs/, backups/, stories attachment cache |
satelle runtime path prints the resolved runtime dir and whether this repo is
still on the legacy in-repo layout. satelle runtime migrate copies a legacy
DB + runtime dirs to the home key (explicit; never silent). One repo-key maps to
one isolated DB — never a flat multi-repo bag.
Authored substrate under .satelle/
satelle init lays a self-documenting skeleton under .satelle/:
satelle.tomlandworkflows/agents.toml(both documented, both optional to edit);- a dir per authored kind —
documents/ workflows/ principles/ skills/ tasks/— each with aREADME.mddescribing what it should contain (READMEs are dir descriptors; the indexer and OKF normaliser skip them); - the complete default solution, materialised on disk so the default
substrate is visible and editable: the order-zero baseline workflow (the
minimal repo-agnostic lifecycle — edit it in place to layer your own gates),
the parent/epic container workflow, the task-execution workflow, and every
gate skill they reference. A workflow whose
applies_tocategory is already claimed by an authored workflow is skipped (no same-precedence duplicate); the embedded copy still backstops the order-zero fallback either way.
The binary still ships embedded canonical defaults; a repo file with the same
(kind, name) overrides its default. init materialises the defaults so you never
have to reason about invisible substrate — and never clobbers an authored file
(an existing workflow set is respected wholesale). satelle restore re-installs
the embedded skills/principles over drifted copies; satelle rebase goes
further — it backs up workflows/ skills/ principles/ to a timestamped dir under
the runtime backups/, wipes them, and redeploys the complete default solution
(the "start clean" recovery).
Pre-mutation backup
Before init/restore/rebase overwrites an existing file under .satelle/,
satelle writes a local copy under the runtime backups/ tree (kinds:
pre-mutation/, diverged/, restore/, or a timestamped dir for rebase). Local
floor always — heal paths never block for backup. Online/personal push of
pre-images into the bound project's documents partition is opt-in
([backup] hosted = true) and requires satelle login + project bind;
offline/auth failure degrades to local with a notice. Default is local-only so
init never poisons the documents partition that satelle sync pulls (backups/
is a restore exclusion). Set [backup] local_only = true (prefer
satelle.local.toml) to suppress the advisory that points at the online option.
Format: Open Knowledge Format (OKF)
Every authored doc carries YAML frontmatter with a required type key (OKF):
type: workflow | principle | skill, and type: <category> for free-form
documents. The directory is authoritative for the kind; type mirrors it. A
legacy kind: key is migrated to type: automatically at ingest. Bodies are
ordinary markdown — a route half carries its declaration of done or its step
catalogue, a skill its rubric.
Validation is deterministic code
The per-noun satelle <noun> validate (and the reindex pass) check each doc with a deterministic
structure check (internal/structure) — frontmatter keys, kebab name matching
the file, a usable definition, a non-stub body, and for a workflow the graph
(connected, terminal done, backlog start, resolvable executor skills). These
are CODE, not LLM rubrics: harness-independent and never flaky. A swapped agent
(claude, codex, …) cannot change what "valid" means. satelle <noun> validate needs no
agent CLI.
satelle-repo-agnostic (only satelle's OWN embedded scope: system substrate
must avoid repo-specifics) is a satelle-dev concern — never a runtime gate. Your
project substrate is meant to be opinionated; satelle never judges it for that.
Authoring
Drop a markdown file under the right .satelle/<kind>/ dir and run satelle reindex — or use satelle skill|workflow|principle create --from <file>, which
writes through the deterministic structure check and refuses a non-conforming
artifact. List with satelle doc list; read one with satelle doc get <kind> <name>.
See also: satelle help reviewer-checks, satelle help principles.
Mirrored from satelle’s built-in help. Read it in the binary with
satelle help substrate, or see the canonical source in the
satelle repo.