pinakes lint
Scans the creative layers of your project, parses chapter frontmatter, resolves names against the codex registry, and checks for timeline or co-presence violations.
pinakes lint --root .Diagnostic output example
Section titled “Diagnostic output example”======================================================================PINAKES CONTINUITY CHECK======================================================================
📁 stories/book1/chapters/ch11_the_empty_stall.md: :18 [unresolved-entities] 🔴 ERROR: Unresolved reference to character 'Paolo Ferrante' in field 'characters_referenced'
📁 stories/book1/chapters/ch17_sharpening_the_knives.md: [co-presence-conflict] 🟡 WARNING: Co-presence conflict: Character 'Emma' is present in Chapter 17 (Distributed) and Chapter 14 (Emma's Apartment) at the same time.
FAIL — pinakes found errors.Built-in checks
Section titled “Built-in checks”- Entity Resolution: Verifies that every character, location, and item mentioned in chapter frontmatter exists in
entities.yamlor is explicitly ignored innon_entities.yaml. - Sequential Timelines: Ensures every chapter has a date, and that start dates do not retrogress across sequential chapters. The two are separate rules (
missing-dateandnon-sequential-dates), so relaxing the ordering check leaves undated chapters reported. - Co-Presence Conflicts: Flags physical impossibilities, such as a character being marked as present in two distinct locations at the same time.
- Custody Resolution: Verifies that every item and holder named in a chapter’s
custody:block resolves, so a hand-off is never silently dropped. - Stretch Horizon: Verifies that a character stretch cites only records that have ended by its
asOfdate, so a character never draws on what hasn’t happened yet. - Affect Declarations: Every
affect:label in a chapter or stretch must be in the affect vocabulary (the core labels plusaffect.labelsinpinakes.yaml), and every numeric value an integer in [−100, 100]. An unknown label is never scored as neutral: the chapter emits no affect event for it (affect-label-unresolved, a warning) and the stretch compiles with no coordinates (stretch-affect-unresolved, an error). A chapter’s affect is a transition or a numeric delta, a stretch’s one label or triple (affect-malformed), and a chapter declaring affect for a character with noregisters:entry there is a warning (affect-declared-no-register). CodexaffectBaselineandaffectHalfLifeScaleare checked too. Withaffect.dynamics.discontinuityset, a declaration that disagrees with the replayed state is a warning (affect-discontinuity). See Affect. - Frontmatter Integrity: A chapter whose frontmatter is not valid YAML is an error, and a file in
chapters/with nochapterkey is a warning. Either would otherwise drop out of every check. - Unique Chapters: Two chapter files in one story with the same
chapternumber are an error, since chapter numbers become record ids. - Registry Conflicts: One alias claimed by two entities of the same type is an error, and the alias resolves to neither until one entry drops it. A character and a place may share a name. An id registered twice is also an error.
- Character Accounts: A character’s
didandhandlelive on itsentities.yamlentry. A DID atproto would reject (any method butdid:plcanddid:web, or a malformed one) is an error, and so is a handle that is not one DNS label (emmacooks, notemmacooks.example.com). So is one DID or handle on two characters, either one on a place or item, or either one left in codex frontmatter. Only syntax is checked;lintnever resolves anything, so it stays offline.compilereports all of these too. - Registry Validity: An
entities.yamlentry that is missingid,typeordisplayName, or has a field of the wrong type, is an error. It is left out of the registry, andlintwould otherwise pass with the entity silently missing.
Severities are set per rule under rules: in pinakes.yaml, and a rules: block only needs the rules you change: the rest keep their defaults. The full table is in Continuity and drift.
Custom YAML rules
Section titled “Custom YAML rules”Authors can write custom rules in the rules/ directory to enforce style guidelines or state transitions:
paths.rules is a glob, not a directory — use rules/*.yaml. A bare
rules matches the directory itself and fails lint. So does a glob that
matches no files, and any rule file that cannot be loaded: invalid YAML, the
wrong shape, a pattern that is not a valid regex, or a rule that could never
check anything. A rule that silently stopped running would be worse than none.
name: "voice-register-transitions"description: "Verify that character registers only transition to valid states"severity: errorselector: "stateEvent"validate: field: "register" pattern: "^(public|private|under-pressure)$"