Skip to content
🚧 Early alpha — building the foundation. See the roadmap →

System architecture — components, tiers, and data flow

Updated

This page is the canonical entry point for understanding how Crosswalker’s pieces fit together. It consolidates information that was previously scattered across the ETL concept, the embedded substrates concept, the v0.1 schema spec, and per-milestone pages.

If you’re new here, read this first.

Crosswalker has three storage tiers and six logical layers that move data between them.

                  CROSSWALKER IN ONE DIAGRAM

                     ┌─ Tier 0 — your source data ─┐
                     │  CSV, JSON, JSONL, XLSX     │
                     │  (your raw spreadsheets,    │
                     │   exports, etc.)            │
                     └────────────┬────────────────┘

                          (1) IMPORT layer


   ┌─────────────────────────────────────────────────────────┐
   │   Tier 1 — canonical Markdown vault                     │
   │   ──────────────────────────────────────────            │
   │   .md files with YAML frontmatter                       │
   │   conforming to spec/tier1.schema.json                  │
   │                                                         │
   │   THIS IS THE TRUTH. git-tracked. Obsidian reads        │
   │   this. Bases queries this. Exports come from this.     │
   └─────────────────────────────────────────────────────────┘

                          (3) PROJECTION layer


   ┌─────────────────────────────────────────────────────────┐
   │   Tier 2 — SQLite sidecar (derived; deletable)          │
   │   ──────────────────────────────────────────            │
   │   .crosswalker.sqlite at vault root                     │
   │   tables: ontologies, concepts, mappings,               │
   │           junction_notes, closure_cache                 │
   │                                                         │
   │   PURELY A CACHE. Delete it → reprojects from Tier 1.   │
   │   Exists because SQL queries over crosswalk closures    │
   │   are 100× faster than walking .md files every time.    │
   └─────────────────────────────────────────────────────────┘

Three tiers, simply:

  • Tier 0 = your source data (whatever shape it arrives in)
  • Tier 1 = the canonical Markdown vault (what Obsidian sees, what git tracks, what survives plugin uninstall) — the source of truth
  • Tier 2 = a deletable SQLite cache derived from Tier 1 — convenience for fast queries

Six logical layers, simply:

#LayerWhat it doesWhere it operates
1ImportRead source → write canonical MarkdownT0 → T1
2StorageHold canonical state on diskT1 (also T2 once projected)
3ProjectionRead T1 → write T2 (the projector)T1 → T2
4QueryAnswer user questions over T1 + T2T1, T2 → user
5ExportRead T1 (or T2) → write external formatsT1, T2 → external
6AuditTrack who-changed-what + integritygit, signed manifests

The rest of this page expands each layer with diagrams, components, and code references.

Three rules that make the whole architecture tractable:

  1. Tier 1 is canonical. Every other tier (T0, T2, exports) is either upstream of T1 or derived from T1. Nothing important lives only in T2.
  2. Tier 2 is deletable. If .crosswalker.sqlite is missing, corrupted, or stale, the projector rebuilds it from T1 on next vault load. This is what makes Tier 2 risk-free to bundle (Ch 24 §2).
  3. The contract is the schema, not the engine. Anyone who can write valid Tier 1 frontmatter is a first-class producer (schema-as-primitive commitment).

These three rules together mean: you can lose, replace, or reimplement everything except the Tier 1 schema and the canonical Markdown vault. That property is what makes the architecture portable, modular, and resilient.

TierWhat it isLifetimeAuthoritative?Spec
Tier 0Source data in whatever shape it ships (CSV, JSON, JSONL, XLSX, OSCAL, etc.)Whenever the user has itNo — it’s the inputn/a (any structured format)
Tier 1Canonical Markdown vault — .md files with YAML frontmatterPermanent (git-tracked)Yes — the source of truthspec/tier1.schema.json
Tier 2.crosswalker.sqlite sidecar — a SQL projection of Tier 1Recreatable on demandNo — derived from T1v0.1 schema spec §7

What “canonical” means: every field in Tier 2 has to be derivable from Tier 1 frontmatter. Every queryable Tier 1 frontmatter field has to be a flat scalar or wikilink (no nested objects, no inline expressions) so it’s Bases-queryable directly without going through T2.

What’s NOT a tier:

  • ParsedData (the bundled engine’s in-memory iteration shape) is not a tier — it’s an implementation detail of the import layer (see ETL concept “What ParsedData is”)
  • The recipe (spec/recipe.schema.json) is not a tier — it’s a transformation declaration consumed by the import layer
  • The closure cache (rows in closure_cache table) is not a separate tier — it’s a materialized view inside Tier 2

One-liner: take a source ontology + a recipe, produce Tier 1 Markdown files.

                       IMPORT LAYER

  Source data            ┌─ Recipe ──────────────┐
  (T0)                   │ spec/recipe.schema.   │
   │                     │ json — declares HOW   │
   ▼                     │ to project source     │
  Parser                 │ rows into vault       │
  (PapaParse,            │ primitives            │
   xlsx, JSON)           └───────────┬───────────┘
   │                                 │
   ▼                                 │
  ParsedData                         │
  (in-memory iter or                 │
   AsyncIterable for                 │
   streaming sources)                │
   │                                 │
   └──────────┬──────────────────────┘

              ▼  per row
   ┌─────────────────────────────────────────┐
   │  ConceptIdentity {curie, scope}         │
   │  + Recipe                               │
   │              │                          │
   │              ▼                          │
   │  render() ◄── pure function (Ch 22)     │
   │              │                          │
   │              ▼                          │
   │  Address (path + frontmatter +          │
   │           tags + aliases +              │
   │           wikilinkTarget)               │
   │              │                          │
   │              ▼                          │
   │  + buildProvenance() (_crosswalker)     │
   │              │                          │
   │              ▼                          │
   │  validateTier1Frontmatter() ◄── PRE-    │
   │              │           WRITE GATE     │
   │              ▼                          │
   │  mergeFrontmatter() if existing file    │
   │              │  (managed/user_preserve) │
   │              ▼                          │
   │  app.vault.create() / .modify()         │
   └──────────────┬──────────────────────────┘


              Tier 1 file
ComponentCodeWhat it does
Source parserssrc/import/parsers/csv-parser.ts (+ JSONL + JSON-with-iterator-path planned for v0.2)T0 file → ParsedData (eager array OR AsyncIterable<Row>)
Streaming foundationsrc/import/parsers/csv-parser.ts:parseCSVFileStreamPapaParse step callback → AsyncIterable with backpressure (v0.1.4.5)
render()src/render/index.tsPure function (Recipe, ConceptIdentity) → Address (v0.1.2)
Template enginesrc/render/template.tsR2RML-style {var|filter} interpolation; closed 7-filter set; JSONata sub-language reserved for v0.3+
Mechanismssrc/render/mechanisms/{folder,file,heading,tag,wikilink}.tsThe 5 closed hierarchy primitives — folder/file/heading wired in v0.1; tag/wikilink reserved for v0.2
Kind dispatchsrc/render/index.ts (Tier1Kind)kind: concept | junction-note | crosswalk-edge discriminator (v0.1.4)
Generation enginesrc/generation/generation-engine.ts:generateNotes / generateFromRecipePer-row loop calling render() + provenance + validation + merge → vault.create/modify
Frontmatter mergesrc/generation/frontmatter-merge.tsmanaged (recipe-owned, overwritten) vs user_preserve (recipe-untouched) per Ch 22 §8.4
Provenance writersrc/generation/provenance.ts_crosswalker block per Tier 1 schema $defs/provenance_block
Validator (pre-write gate)src/validation/validator.ts:validateTier1FrontmatterAJV against spec/tier1.schema.json. Strict mode rejects bad rows pre-write — STRM predicate enforcement happens here
Legacy-recipe shimsrc/generation/legacy-recipe-shim.tsTranslates v0.1.0 column-role configs → Ch 22 layout Recipe (Phase-0 compat per Ch 22 §10.7)

The import layer supports two architectural modes (decided 2026-05-05):

  • Mode 1 — bundled projector: external producer (or wizard) hands the bundled engine structured rows + recipe → engine emits Tier 1
  • Mode 2 — direct emission: external producer (AI agent, MCP server, marketplace bundle) writes Tier 1 Markdown directly, bypassing the bundled engine

Both are first-class. ChunkyCSV / JSONaut / dbt are natural Mode 1 feeders. AI agents are natural Mode 2 emitters. See ETL concept “two-mode architecture” for the full picture.

v0.1.1 (validation), v0.1.2 (render), v0.1.3 (engine), v0.1.4 (kind dispatch + STRM), v0.1.4.5 (streaming foundation).

One-liner: hold the truth as Markdown files on disk.

                       STORAGE LAYER

  vault root/
  ├── Frameworks/                         ◄── concept-note files
  │   ├── NIST 800-53 r5/
  │   │   ├── AC/
  │   │   │   ├── AC-2.md            ─┐
  │   │   │   └── AU-1.md            │ kind: concept (default)
  │   ├── NIST CSF 2.0/              │ frontmatter: curie, title,
  │   │   ├── PR.AC-01.md           ─┘ parent, _crosswalker, ...

  ├── Crosswalks/                         ◄── crosswalk-edge files
  │   ├── CSF-to-800-53/
  │   │   ├── cw-pr-ac-01-ac-2.md   ─┐
  │   │   └── cw-id-am-01-cm-8.md   ─┘ kind: crosswalk-edge
  │                                    frontmatter: subject_id,
  │                                                 predicate_id,
  │                                                 object_id, ...
  ├── Evidence/
  │   └── Junctions/                      ◄── junction-note files
  │       └── jn-ac-2-mfa-policy.md   ─── kind: junction-note
  │                                       frontmatter: subject,
  │                                                    predicate,
  │                                                    object, ...

  ├── .crosswalker.sqlite                 ◄── Tier 2 sidecar
  │                                          (derived; deletable)

  └── _crosswalker_manifest.json          ◄── Audit (Tier 1
                                              floor, v0.1.8)
  • File-based: every concept, evidence link, and crosswalk is its own .md file
  • YAML frontmatter is the data: per Ch 22 §1.3, frontmatter is flat-scalar / wikilink only, not nested objects
  • git-tracked: every change is a commit (v0.1.8 audit trail)
  • Obsidian-native: files appear in the file explorer, search, graph view, Bases queries, etc., natively
  • Survives plugin uninstall: even with no plugins enabled, the vault is still readable Markdown
  • Three Tier 1 shapes discriminated by kind field — concept / junction-note / crosswalk-edge (Tier 1 schema)

See concepts/file-based-graph-database for the full philosophical case. Short version: files are diffable, mergeable, exportable, archivable, attestable, and survive every tool/plugin in the stack getting replaced.

One-liner: read Tier 1 Markdown frontmatter, write rows into the SQLite sidecar.

                     PROJECTION LAYER

  Tier 1                                      Tier 2
  ─────────────────                           ───────────────────
  Frameworks/                                 ┌─ ontologies ────┐
  NIST/AC-2.md            ─────►              │ id │name │ver  │
   curie: nist:AC-2                           └─────────────────┘
   title: ...
   parent: nist:AC                            ┌─ concepts ──────┐
   _crosswalker: {...}                        │ ontology│curie│ │
                                              │ ─path───┼──── │
                                              │ vault_path:    │
  Crosswalks/                                 │ Frameworks/... │
  cw-csf-pr-ac-01-                            └─────────────────┘
  nist-ac-2.md            ─────►
   kind: crosswalk-edge                       ┌─ mappings ──────┐
   subject_id: csf:PR.AC-01                   │ subj│pred│obj │ │
   predicate_id: is_eq...                     │ id  │ id │ id │ │
   object_id: nist:AC-2                       └─────────────────┘
   match_type: ...
                                              ┌─ junction_notes ─┐
  Evidence/                                   │ vault_path│curie│ │
  jn-ac-2-mfa.md          ─────►              │ subject│pred│obj│ │
   kind: junction-note                        └──────────────────┘
   subject: AC-2
   predicate: covers                          ┌─ closure_cache ──┐
   object: MFA-Policy                         │ subj│pred│obj │  │
                                              │ shortest_depth│  │  ◄── populated lazily
                                              └──────────────────┘     on first transitive
                                                                       query
                                              ┌─ schema_meta ────┐
                                              │ key │ value     │
                                              │ schema_version:  │
                                              │ tier2-sqlite-v1  │
                                              └──────────────────┘
ComponentCodeWhat it does
Sidecar lifecyclesrc/tier2/sidecar.ts:openSidecar/clearSidecarInit sqlite-wasm; OPFS sahpool VFS; open .crosswalker.sqlite
Schema migrationssrc/tier2/migrations.tsdrop-and-recreate on version mismatch (correct because T2 is purely a T1 projection)
Schema DDLsrc/tier2/schema.sqlThe full Tier 2 SQL schema per spec §7
Projectorsrc/tier2/projector.ts (Phase 2 of v0.1.5)Walk vault .md files via streaming foundation; dispatch by kind; idempotent upsert
Closure cachesrc/tier2/queries.ts (Phase 3 of v0.1.5)Recursive-CTE materialization on first transitive query; mtime-based invalidation

If .crosswalker.sqlite is missing, corrupted, or stale, the projector reprojects from canonical Tier 1 on next vault load. This is what makes Tier 2 risk-free to bundle. Per Ch 24 §2 — the modularity rule that lets us swap substrates (libSQL/Limbo/server) without data migration.

@sqlite.org/sqlite-wasm (canonical, foundation-governed). sqlite-vec deferred — see the WASM-A path notes in v0.1.5 and the calendar-anchored 2026-11-06 revisit checkpoint in Ch 24 §5 Q4.

v0.1.5 (the entire projection layer).

One-liner: let users ask questions over their vault — flat lookups via Bases over T1, transitive/joined queries via SQL over T2.

                        QUERY LAYER

   User question                  Routing decision
   ─────────────                  ────────────────
   "Show me all NIST          ─►  Bases over Tier 1 frontmatter
    AC-family controls"           (file.hasTag('framework/nist/ac'))

   "What evidence covers      ─►  Bases over Tier 1 frontmatter
    AC-2?"                        (junction-note where subject == AC-2)

   "Which CSF                 ─►  Bases (simple case) OR SQL (cross-
    subcategories map to          ontology join)
    NIST AC-family?"

   "Show all controls         ─►  SQL recursive CTE over mappings
    NIST CSF Identify             table (Tier 2; closure_cache
    maps to via any chain         materialized on first call)
    of crosswalks"

   "Coverage matrix:          ─►  SQL join over concepts ×
    every control × every         mappings × junction_notes
    framework that maps           (Tier 2)
    to it × evidence count"
ComponentCodeWhat it does
Bases (upstream Obsidian)n/a (built-in to Obsidian)Flat YAML-frontmatter queries directly over Tier 1 — no plugin needed
SQL query helperssrc/tier2/queries.ts (v0.1.5 Phase 3)Typed getControlsByOntology, findCoverageGaps, crosswalkBetween, closureFromConcept
Bases query templates emitted in concept-note bodiessrc/generation/templates/ (v0.1.6)Recipe-author authors a body template; engine emits a working Bases query in each concept note
Question shapeTierWhy
Flat key/value over a single note kindTier 1 via BasesNative; no plugin; survives Tier 2 corruption
Tag-prefix or single-frontmatter-field filterTier 1 via BasesSame
Multi-ontology joinsTier 2 via SQLBases doesn’t do joins; SQL does
Transitive closure (chain of crosswalks)Tier 2 via SQL recursive CTEClosure cache materialized once; subsequent queries hit the cache
Coverage matrix (controls × evidence × frameworks)Tier 2 via SQLMulti-table join; awkward in Bases
Vector / semantic similarityTier 2 via sqlite-vecDeferred to a future milestone (see Ch 24 §5 Q4)

The choice is the recipe author’s (or query author’s). Tier 1 is the default for simple queries because it survives Tier 2 corruption. Tier 2 is for when SQL’s expressivity is needed.

The query layer separates concerns across three orthogonal layers (settled 2026-05-08; see synthesis log):

LayerVocabularyConcept page
A — Query primitivesfilter / project / traversal / closure / anti-join / pivot / aggregatequery-primitives
B — View shapestable / list / pivot / graph / hierarchy / timelineview-shapes
C — Recipes / reports”Coverage Matrix”, “Crosswalk Density”, “Ontology Overlap”, etc.recipe registry
PrimitiveBases-nativeTier 2 SQL helpersCodeblock processor (v0.1.7)Materialized snapshot (v0.1.8)
filter✅ defaultWHERE✅ pre-resolved
project✅ default✅ projection
traversalpartial (single-hop via file.hasLink)✅ via mappings table + crosswalkBetween
closure❌ no recursion✅ recursive CTE via closureFromConcept (already shipped v0.1.5 P3)
anti-join✅ via EXCEPT / LEFT JOIN ... NULL
pivot❌ summaries are 1-Dcomposes filter + traversal + aggregate✅ pre-rendered
aggregate✅ summaries (1-D)✅ multi-D aggregates

Crosswalker recipes (Layer C) name a primitive composition + a view shape. The engine picks the right mechanism for each primitive based on what’s expressible at that layer. v0.1.6 ships the crosswalkerPivot custom Bases view (registerBasesView) for the pivot shape; v0.1.7 ships the crosswalker-query codeblock processor; v0.1.8 ships materialized snapshot output.

v0.1.6 (Bases templates + crosswalkerPivot custom view + recipe loader); v0.1.7 (codeblock processor); v0.1.8 (materialized snapshot output).

Layer 5 — Export (T1 → external; or T2 → external)

Section titled “Layer 5 — Export (T1 → external; or T2 → external)”

One-liner: serialize Tier 1 (or Tier 2) data into external interop formats.

                        EXPORT LAYER

   Tier 1 / Tier 2  ──►  Exporter  ──►  External format
   ────────────────      ────────       ────────────────

   crosswalk-edge        STRM          NIST IR 8278A r1
   notes (T1)            TSV           OLIR template
   OR mappings (T2)      exporter      (Excel-friendly TSV)
                                        round-trip determ.

   junction-note         OSCAL JSON    NIST OSCAL
   notes (T1)            profile       Control Mapping Model
   OR junction_notes     exporter      (.json profile)
   (T2)

   crosswalk-edge        SSSOM TSV     SSSOM (Mapping Commons)
   notes (T1)            exporter      academic interop
   OR mappings (T2)      (opt-in)      (TSV with metadata
                                        header; off by default
                                        per Ch 19 — zero GRC
                                        adoption)
ComponentCodeWhat it does
STRM TSV exportersrc/export/strm-tsv.ts (v0.1.7)Reads T2 mappings; emits NIST IR 8278A r1 OLIR template format
OSCAL JSON exportersrc/export/oscal-profile.ts (v0.1.7)Reads T1 junction notes (or T2 junction_notes); emits OSCAL Control Mapping profile
SSSOM TSV exportersrc/export/sssom-tsv.ts (v0.1.7)Reads T2 mappings; emits SSSOM-shaped TSV; opt-in toggle

The export layer commits to byte-identical round-trip: import a STRM TSV → export the resulting Tier 1 vault → STRM TSV bytes match. This is enforced by tests in v0.1.7. Importing your own export and re-exporting must be a fixed point.

v0.1.7 (the entire export layer).

One-liner: track who-changed-what, when, with what integrity guarantees.

                         AUDIT LAYER

   Tier 1 = git commits (T1 audit floor)
            ─────────────────────────
            Every generation pass produces one commit
            Commit message includes recipe id + recipe hash +
            concept count + summary diff
            git log + git blame are the audit trail

                   +
            ────────────────────────────────────────────
            Optional Ed25519-signed release manifests
            for shared mapping bundles
            (per Ch 13 attestation primitives)

                   +
            ────────────────────────────────────────────
            On-demand FRE 902(13) certification PDF
            (US litigation evidence-submission template)

   Tier 2/Tier 3 audit profiles (deferred to v1.0+):
            ─────────────────────────────────────────
            T2: OpenTimestamps / RFC 3161 trusted timestamps,
                S3 Object Lock WORM mirror
            T3: Sigstore Rekor v2 + in-toto attestations,
                eIDAS QTSA + W3C VC
            All opt-in compliance-export mode (per Ch 13/15)
ComponentCodeWhat it does
git commit hooksrc/audit/git-commit.ts (v0.1.8)One commit per generation pass; deterministic message
Ed25519 sign helpersrc/audit/sign.ts (v0.1.8)@noble/curves; signs release manifests
Release manifest writersrc/audit/manifest.ts (v0.1.8)_crosswalker_manifest.json at vault root
FRE 902(13) PDF templatesrc/audit/fre-902.ts (v0.1.8)pdf-lib-rendered certification template

v0.1.8 (Tier 1 audit floor: git + Ed25519 + FRE 902(13)).

A single table of every load-bearing logical component, where it lives, and what it reads/writes:

ComponentLayerReadsWritesCode
Source parserImportT0 fileParsedData (in-memory iter)src/import/parsers/*.ts
render()ImportRecipe + ConceptIdentityAddress (in-memory)src/render/index.ts
Generation engineImportParsedData + RecipeTier 1 .md filessrc/generation/generation-engine.ts
ValidatorImportFrontmatter object(returns valid/invalid)src/validation/validator.ts
Frontmatter mergeImportExisting frontmatter + new managedMerged frontmattersrc/generation/frontmatter-merge.ts
Provenance writerImportsource ref + recipe id_crosswalker blocksrc/generation/provenance.ts
Tier 1 vaultStorage(passive)(held on disk)n/a — files
Sidecar lifecycleProjection(init only)Opens .crosswalker.sqlite; applies migrationssrc/tier2/sidecar.ts
ProjectorProjectionTier 1 .md frontmatterontologies, concepts, mappings, junction_notes rowssrc/tier2/projector.ts (v0.1.5 Phase 2)
Closure cache populatorProjectionmappings tableclosure_cache tablesrc/tier2/queries.ts:closureFromConcept
Bases queriesQueryTier 1 frontmatter(returns user data)n/a (upstream Obsidian)
SQL query helpersQueryTier 2 tables(returns user data)src/tier2/queries.ts
Body-query templatesQueryRecipe templateTier 1 note body (Bases query string)src/generation/templates/ (v0.1.6)
STRM TSV exporterExportT2 mappings (or T1 crosswalk-edge notes).tsv filesrc/export/strm-tsv.ts (v0.1.7)
OSCAL JSON exporterExportT1 junction notes (or T2).json filesrc/export/oscal-profile.ts (v0.1.7)
SSSOM TSV exporterExportT2 mappings.tsv filesrc/export/sssom-tsv.ts (v0.1.7)
git commit hookAudit(write event)git commitsrc/audit/git-commit.ts (v0.1.8)
Ed25519 signerAuditRelease bundleSignature on _crosswalker_manifest.jsonsrc/audit/sign.ts (v0.1.8)
FRE 902(13) PDFAuditVault hash + signed manifest.pdf filesrc/audit/fre-902.ts (v0.1.8)

Which components read/write which storage tier:

TierWritten byRead by
T0 (source)the user (or external producer)Source parser
T1 (canonical Markdown)Generation engine; external Mode 2 producersBases queries; projector; exporters; git audit
T2 (SQLite sidecar)Sidecar lifecycle (open + migrations); projector; closure cache populatorSQL query helpers; exporters (when joining over T2 tables)
External (TSV / JSON / PDF)Exporters; FRE 902(13) PDF generator(downstream tools — Excel, OSCAL validators, courts)

Notice that everything ultimately traces back to Tier 1: T0 produces T1, T2 derives from T1, exports come from T1 (or T2 which derives from T1), audit hashes T1. No data lives only in T2.

src/
├── main.ts                        ── Plugin entry point. Wires everything.

├── render/                        ── render() — Layer 1 single coupling point
│   ├── index.ts                      Pure (Recipe, ConceptIdentity) → Address
│   ├── template.ts                   {var|filter} interpolation engine
│   ├── types.ts                      Address, ConceptIdentity, SourceScope
│   └── mechanisms/                   The 5 closed primitives
│       ├── folder.ts                 wired
│       ├── file.ts                   wired
│       ├── heading.ts                wired
│       ├── tag.ts                    deferred to v0.2 (stub)
│       └── wikilink.ts               deferred to v0.2 (stub)

├── import/                        ── Layer 1 (source → render input)
│   ├── parsers/
│   │   └── csv-parser.ts             PapaParse + streaming (v0.1.4.5)
│   └── import-wizard.ts              The wizard UI (column-role mapping)

├── generation/                    ── Layer 1 (render output → Tier 1)
│   ├── generation-engine.ts          Per-row loop; calls render(); writes vault
│   ├── frontmatter-merge.ts          managed/user_preserve semantics
│   ├── provenance.ts                 _crosswalker block writer
│   └── legacy-recipe-shim.ts         v0.1.0 column-role → Ch 22 layout

├── validation/                    ── Layer 1 pre-write gate
│   └── validator.ts                  AJV against spec/tier1.schema.json

├── tier2/                         ── Layer 3 (projection)
│   ├── sidecar.ts                    sqlite-wasm lifecycle; OPFS sahpool VFS
│   ├── schema.sql                    Tier 2 DDL (canonical .sql doc)
│   ├── migrations.ts                 schema_version + drop-and-recreate
│   ├── projector.ts                  Tier 1 → Tier 2 (v0.1.5 Phase 2)
│   └── queries.ts                    Typed query API + closure cache (v0.1.5 Phase 3)

├── export/                        ── Layer 5 (T1/T2 → external)
│   ├── strm-tsv.ts                   v0.1.7
│   ├── oscal-profile.ts              v0.1.7
│   └── sssom-tsv.ts                  v0.1.7

├── audit/                         ── Layer 6 (cross-cutting)
│   ├── git-commit.ts                 v0.1.8
│   ├── sign.ts                       v0.1.8
│   ├── manifest.ts                   v0.1.8
│   └── fre-902.ts                    v0.1.8

├── settings/                      ── Plugin settings (cross-layer)
└── types/
    └── config.ts                     ParsedData, ImportRecipe, etc.

spec/
├── tier1.schema.json              ── Tier 1 frontmatter contract
└── recipe.schema.json             ── Recipe shape contract

recipes/starter/                   ── Mode 1 starter recipes
├── nist-csf-to-800-53-crosswalk.json
├── iso27001-to-800-53-crosswalk.json
├── evidence-junction-notes.json
└── README.md                         multi-framework recipe-pattern story
If you want…Read this
Quickest way to grasp the systemThis page (TL;DR section)
The truth about what Tier 1 must look likev0.1 schema spec
The recipe shape (transformation declaration)spec/recipe.schema.json + Ch 22 synthesis
Why the architecture is shaped this way (the philosophy)What makes Crosswalker unique + Vision
Why Tier 1 is files (not a database)File-based graph database concept
Why Tier 2 is sqlite-wasm (and not Turso/libSQL/Limbo)Ch 24 substrate synthesis
The closed 5-mechanism recipe grammarHierarchy primitives concept + Ch 22 synthesis
The two-mode architecture (bundled vs direct)ETL two-mode section + decision log
Definitions of every term used hereTerminology
The full implementation roadmapMilestones hub
The 6 architectural commitments locked 2026-05-04v0.1 import-engine design log
Why no JSONaut/ChunkyCSV port + GUI scope lineTransform-engine-depth log

How v0.1 implementation maps to this architecture

Section titled “How v0.1 implementation maps to this architecture”
v0.1.1 ── Import layer types + validation foundation
            └── AJV + spec/*.schema.json wired into runtime

v0.1.2 ── Import layer: render() v1
            └── (Recipe, ConceptIdentity) → Address (folder/file/heading)

v0.1.3 ── Import layer: generation engine integration
            └── render() wired through engine; provenance + merge

v0.1.4 ── Import layer: kind dispatch (3 Tier 1 shapes)
            └── concept / junction-note / crosswalk-edge + STRM gate

v0.1.4.5 ─ Import layer: streaming refactor
            └── ParsedData.rows accepts AsyncIterable<Row>
            └── Engine iterates via for-await; no full-vault-in-RAM

────── Layer 1 + 2 (storage) complete ──────

v0.1.5 ── Projection layer: Tier 2 sqlite-wasm sidecar     ◄── WE ARE HERE
            ├── Phase 1 (DONE): substrate scaffolding
            ├── Phase 2: projector (Tier 1 → Tier 2 tables)
            ├── Phase 3: query API + closure cache
            ├── Phase 4: plugin integration
            ├── Phase 5: tests
            └── Phase 6: delivery log + status flip

v0.1.6 ── Query layer: Bases templates + SQL helpers
            └── Concept-note bodies emit working Bases queries

v0.1.7 ── Export layer: STRM TSV + OSCAL + SSSOM
            └── Round-trip determinism enforced

v0.1.8 ── Audit layer: git + Ed25519 + FRE 902(13)
            └── Tier 1 audit floor

v0.1-RC ── Ship: bundle size, mobile, community plugin submission

Phase 2 of v0.1.5 (the projector) is the next unit of work — it’s the bridge between “Tier 1 exists” and “fast queries are possible.”

Concept pages (this page links to and from):

Agent context:

Foundation decisions (synthesis logs — six load-bearing commitments settled 2026-05-04):

Recent design decisions (2026-05-05):

Implementation milestones:

Spec files:

Registry references (frameworks the architecture is generic over):