KURAL

Architecture

System overview — the pipeline, tiers, data model, and sync design

System Overview

Kural is a five-stage pipeline that transforms source code into structural health scores:

Parse — Walk the filesystem, extract functions, types, and descriptions from the AST

Embed — Produce identity and leaf vectors via 7-facet embedding
Score — Compute fit, uniqueness, and subtree health for every node
Store — Persist units, scores, and metadata to a snapshot database
Query — Read snapshots for scoring, auditing, and comparison

The system is split into two tiers:

  • CLI — scan, score, local snapshots
  • Dashboard (web UI) — reactive views over snapshot data

Tech Stack

LayerToolRole
CLI frameworkGunshiCommand routing, plugin system
AIMultiple providers (Vercel, OpenAI, OpenRouter, Ollama)Embeddings, advise
Local persistenceTanStack DB + node-sqlite-persistenceSnapshot storage
Cloud backendTurso (database-per-project)active.db + history.db per project
DashboardTanStack DB (React)Reactive UI over collections

Data Model

KuralUnit (base for all)

Every parsed unit carries:

  • name, path, description
  • identityEmbedding — name + description vector
  • leafEmbedding — name + description + structural signature vector
  • facetHash — SHA256 for cache invalidation

Unit Types

  • KuralFile — source files with functions, types, imports
  • KuralType — interfaces, classes, type aliases with fields and references
  • KuralFunction — functions with params, return types, purity, call graph
  • KuralDirectory — directory hierarchy with children, descriptions from KURAL.md

Scores

Every node (types, functions, files, directories) gets a ScoreCard:

  • fit — how well the node's content matches its parent's identity
  • uniqueness — mean distance to siblings (2.0 = N/A)
  • score — harmonic mean of fit and uniqueness
  • childrenFit / childrenUniqueness / childrenScore — direct children quality (containers only)
  • subtreeFit / subtreeUniqueness / subtreeScore — aggregate descendant health (containers only)
  • overallScore — leaf: score. Container: harmonic mean of score and subtreeScore
  • worstPair — the most similar child pair
  • bestUncle — the uncle node where this unit would fit better (name + score)

Snapshot System

Snapshot = Isolated SQLite Database

Each snapshot is a self-contained SQLite database file. This enables clone-and-mutate workflows — copy a snapshot, run analysis/simulation on the clone, discard when done. The original stays untouched.

Snapshot ID

Format: <timestamp>-<short-commit-hash>

1711700400-a3f8b2c
  • Sortable by time for history ordering
  • Tied to code state via commit hash
  • Deduplicable — same commit produces same hash suffix

Local Storage Layout

.kural-db/
  <branch>/
    active.db       # current snapshot, clone-able
    advise.db       # ephemeral clone for AI simulation
    history/        # rotated snapshots (max 10)
      <snapshot-id>.db

Server Storage Layout

Turso (<user-id>.kural.io):
  <project>/
    <branch>/active.db    # live, clone-able snapshot
    history.db            # consolidated, all branches + timestamps

Snapshot Lifecycle

  1. CLI generates a snapshot for the current branch
  2. Active snapshot is rotated to history/<snapshot-id>.db; a fresh active.db is created
  3. Oldest unpinned history snapshots are evicted when count exceeds 10
  4. On the server, only CI writes (via API); developers keep snapshots locally

Schema Design

Database Tables

TablePurpose
filesSource files with embeddings, imports, descriptions
typesType/interface/class declarations with fields, refs
functionsFunctions with params, return types, purity, call graph
directoriesDirectory hierarchy with children, descriptions
scoresStructural health metrics per file/directory
metadataKey-value store (created_at, model_id, schema_version, axes)

Schema Versioning

  • schema_version is stored in every snapshot's metadata from day one
  • Additive-only evolution is the default — new nullable columns only, no removals or renames
  • Old snapshots have NULLs for new columns; dashboard handles gracefully
  • For rare breaking changes, a one-time migration is applied to history.db

Embedding Model Versioning

  • model_id is stored in snapshot metadata for context
  • Scores are precomputed numbers — no cross-snapshot vector comparison needed
  • If the model changes and scores shift, the dashboard shows the shift; model_id explains why

Sync Architecture

Write Path (CI Only)

CI pipeline -> POST <user-id>.kural.io/api/snapshots
                  |
                  v
              API validates, deduplicates, writes to Turso:
                - active.db (replace if newer commit)
                - history.db (append)
  • Developers never push to the server — local only
  • CI is the sole writer via authenticated API
  • API is the single writer to Turso — no direct client access

Concurrency Handling

  • Parallel CI runs for different branches: no conflict
  • Parallel CI runs for same branch, same commit: idempotent (skip duplicate)
  • Parallel CI runs for same branch, different commits: latest commit wins, stale rejected (409)

CI Failure Policy

Fail silently with a warning in CI logs. The snapshot exists locally; next CI run generates a fresh one. No retries or queuing — simplicity over completeness.

Dashboard

Branch-Aware Views

The dashboard supports multi-branch, multi-project views:

ViewValue
Single branchCurrent structural health
Branch comparisonHealth diff between branches (e.g., alpha vs release)
Branch timelineTrend over history snapshots
Pre-merge gateFeature branch health vs main

Data Flow

  • TanStack DB (@tanstack/react-db) provides reactive live queries over collections
  • Collections are backed by Turso via QueryCollection
  • Live queries update the UI when new snapshots arrive

On this page