# The contract for this example vault, and a starting point for your own.
#
# Copy it to System/schemas/vault-schema.toml inside your vault, then adapt
# every directory, enum, privacy boundary and transition deliberately: each one
# is a decision about your notes. yomihon reads this file and never writes it.
schema_version = "1"
[enums]
type = ["note", "lesson", "study-path", "moc", "concept", "inbox"]
# A domain is what a note is about. Keep the list short enough that every value
# is one you would really file under.
domain = ["yomihon", "japanese", "go"]
# Where a note's words came from, when they came from somewhere else.
source_kind = ["book"]
source_provider = ["personal"]
# How much a lesson assumes of its reader.
level = ["fundamental", "intermediate"]
# What a map groups by.
map_kind = ["topic"]
# published is declared for notes. yomihon never sets it — see the lifecycle
# row below — but a note that carries it is legal and renders like any other.
[enums.status]
note = ["draft", "ready", "published", "archived"]
lesson = ["draft", "ready", "archived"]
[fields]
required = ["title", "type", "status", "domain"]
# A capture has not been filed yet, so it is not asked what it is about.
required_inbox = ["title", "type", "status"]
# A course and a map span subjects rather than sitting inside one.
domain_exempt_types = ["study-path", "moc"]
known = [
"title", "aliases", "type", "domain", "topics", "tags", "status",
"created", "updated", "lang", "map_kind",
"source_kind", "source_provider", "based_on", "replaces",
]
lesson_only = ["slug", "level", "supersedes", "superseded_by"]
# lang declares one note's own BCP 47 language tag, e.g. "zh-Hant" or "ja". A
# note that leaves it out has its content inherit the page's language; writing
# it marks that note's content on its own, whichever language the interface is
# speaking around it.
# A type not named here is read against enums.status.note. Every contract has
# to declare that group.
[fields.status_group]
lesson = ["lesson"]
[rules]
# A note filed under Concepts/<domain>/ has to agree with the folder it is in.
domain_equals_folder_under = ["Concepts"]
# A distilled idea says where it came from.
concept_requires_provenance = ["based_on"]
slug_pattern = "^[a-z0-9]+(-[a-z0-9]+)*$"
# A tag carrying a slash is a property written in the wrong place.
forbid_tag_with_slash = true
[scan]
knowledge_dirs = ["Concepts", "Inbox", "Lessons", "Maps", "Notes"]
skip_basenames = ["README.md"]
no_frontmatter_is_legal = true
[navigation]
path_types = ["study-path"]
map_types = ["moc"]
journal_dir = "Diary"
# The existing note type used for a reader's own source-linked thoughts.
answer_type = "note"
[artifacts]
non_instance_dirs = ["System/templates"]
[privacy]
# Nothing under a directory named here reaches yomihon's agent-facing output:
# check, coverage and exists leave those notes out of what they report. It does
# not bind the reading pages — a reader on this machine opens a note under
# Diary the way they open any other — so what it declares is what a program is
# told about the vault, not what the person at the keyboard can see. A
# directory left off the list is one that output may draw from, so naming it
# here is the whole protection.
never_egress_dirs = ["Diary"]
[supersession]
# The fields a note writes to say which note it replaced, and which replaced
# it. yomihon reports on the pair and moves nothing: the ledger is how a vault
# keeps the relationship after the maps have stopped listing the old note.
#
# The three names have to differ, and the first two have to be lesson-only, so
# a lesson keeps both sides of its own history and any other note keeps the
# single field naming what it replaced.
predecessor_field = "supersedes"
successor_field = "superseded_by"
general_link_field = "replaces"
archived_status = "archived"
# Every stage says outright whether a note can start there. Writing "initial" on
# one row means writing it on all of them: a lifecycle where some rows declare
# it and others leave it to be worked out is refused, because the rows that
# stayed silent are the ones a reader would have to guess about.
#
# Owner lists are declarative data. They gate nothing and any name works; they
# record, for your own tooling's doctrine, whose step a status's onward move is.
#
# A row may also say settled = true: the status is where a finished note rests.
# A surface that prints each note's status leaves a settled one unmarked and
# marks only the notes not there yet, so a vault of finished notes is not
# covered in labels. A status is settled when any row naming it says so, and a
# contract that writes the key on no row settles nothing: every status is
# marked.
[[lifecycle]]
status = "draft"
applies_to = ["*"]
initial = true
# A note pressed to ready by mistake comes back here; without this edge the
# only way back is an editor, and the page can offer nothing.
from = ["ready"]
owner = ["author"]
[[lifecycle]]
status = "ready"
applies_to = ["*"]
initial = false
from = ["draft"]
owner = ["author"]
settled = true
[[lifecycle]]
status = "archived"
applies_to = ["*"]
initial = false
from = ["*"]
owner = ["author"]
# The schema allows this transition and yomihon still refuses to make it. The
# value records a publication that happened outside the vault, and nothing here
# can attest to one, so the control is never offered and a request for it is
# refused with that reason. A note carrying the value renders like any other.
# The refusal is yomihon's own, which is why the row is written out rather than
# left absent: an absent row would say the vault never allowed it.
[[lifecycle]]
status = "published"
# In this starting-point contract, name only types whose status list carries
# the value. A lesson's list does not, so naming it here would be a row for
# a status that type cannot hold.
applies_to = ["note", "study-path", "moc", "concept", "inbox"]
initial = false
from = ["ready"]
owner = ["author"]
settled = true