Architecture¶
GraveTrail is a single local Streamlit application with Python feature services. Presentation never parses source or executes imported statements. DuckDB persists facts; NetworkX derives bounded graphs; a local SVG/JavaScript component links graph interactions to source evidence.
flowchart LR
Inputs[ZIP / browser folder / allowed host root] --> Inventory[Bounded inventory and original blobs]
Inventory --> SQL[SQLGlot AST scopes]
Inventory --> SAS[SAS static rule blocks]
Inventory --> CSV[Streaming CSV metadata]
SQL & SAS & CSV --> Facts[Transactional DuckDB facts]
Facts --> Graph[Focused NetworkX graph]
Facts --> Columns[Direct column reports]
Graph & Columns --> UI[Streamlit workspace]
UI --> Exports[Offline HTML / JSON / CSV / original ZIP]
Facts --> AI[Optional privacy-gated grounded assistance]
AI --> Validation[Schema and source validation]
Validation --> Facts
models.py defines parser contracts. ingestion.py validates inputs and persists inventory.
parsers/ returns facts and diagnostics without DB/UI access. services.py snapshots input,
uses hash/config/path caches, parses with 1–8 workers, and atomically materializes facts.
store.py serializes connection access and applies versioned transactional schema migrations.
maintenance.py previews bounded unreferenced history, archives with a transactional recovery
journal plus local JSON copy, and restores missing records without changing materialized facts.
cleanup.py owns broader dependency-aware category plans and guarded apply; the specialized
history/staging recovery services remain separate. database_maintenance.py owns integrity
inspection, checkpointed whole-home snapshots and validated restore into a new home.
graph.py derives traversal, SCC cycles, path views and temporary contraction.
llm.py implements HTTP adapters, privacy, strict grounding, quarantine and inferred merges.
connections.py supplies session-scoped RuntimeConnections via a context variable. Adapters
resolve a credential from that scope, then the explicitly named read-only launch variable.
No per-session credential is placed in the process environment or persisted profile.
assistance_queue.py derives bounded current diagnostics and statement/context suggestions;
explicit review requests pin the preview hash through task routing before network transmission.
The queue has no separate persisted job state or automatic worker. AI results use existing
retained records, and UI session state holds result IDs rather than copied source claims.
exports.py serves UI components and offline exports from the same renderer.
Original bytes are immutable SHA-256-addressed blobs. Statements pin their source hash, so reimporting the same path cannot substitute new code for old evidence. Newer files stay pending if imported during analysis. Only one analysis runs at a time per Store, while immutable input snapshots allow import activity without cache poisoning. Graph cache revisions use completed runs.
No graph database, message broker or external service is required. The intended deployment is a single local user/process. Multi-user/authenticated hosting requires additional deployment work.
Agent and automation interfaces¶
dataforge.cli (Typer) and dataforge.agent.mcp_server (official MCP SDK) call
AgentService, which applies permissions/output policy and delegates to the existing
Importer, analyze, Store, LineageGraph, column_report and export helpers. Streamlit
remains the primary UI; Automation & access adds setup/control/test presentation only. No parser,
source execution or LLM logic is added to adapters. Managed jobs/results/audit/revocation
snapshots live beneath the runtime home's agent/ directory; no database migration is
needed. See MCP_INTEGRATION.md and CLI_GUIDE.md.
Maintenance boundary¶
Category plans list actual rows/files, logical JSON row size estimates and a revision token. Apply recomputes the plan under the maintenance guard, verifies typed scope confirmation and rejects active jobs, analysis and provider requests. Database mutations are transactional; managed filesystem deletion is checked within the home. A failed filesystem action can leave an incomplete cleanup; the result must be reviewed rather than assuming cross-resource atomicity. General destructive cleanup is not recoverable without a backup.
Source and AI cleanup remove the complete dependent workspace graph and analysis history, avoiding stale inferred edges or missing statement references. Lineage reset preserves imported inventory and configuration; workspace reset also removes generated AI/history. Parser cache is shared and has its own operation. Immutable originals remain until unreferenced blob collection; retained snapshots protect content, and recovery archives conservatively prevent collection. Application reset targets a fixed managed allowlist and preserves backups, unrecognized files, installed code and maintained documentation. No schema tables are dropped.
Whole-home backups use DuckDB COPY FROM DATABASE to a checkpointed snapshot, then archive
managed runtime files with a SHA-256 manifest. Restore validates bounded archive contents and
schema, opens the staged database read-only and renames staging into a new destination. This
is distinct from the bounded history/staging recovery journals. Schema versions are additive through 5;
maintenance adds no destructive upgrade. See setup and deployment.
Distribution boundary¶
launcher.py finds the source app or packaged _app directory and launches the same
Streamlit pages. Wheels include UI/component assets, prompt resources and default Streamlit
configuration. Frozen bundles use the same launcher and expose CLI/MCP via --cli.
Installed/frozen launchers default to platform user-data locations; source launchers default
to .dataforge/ relative to the working directory unless explicitly configured. CLI/MCP
uses the same home resolver. Installed theme configuration
is copied once into the writable home instead of changing packaged assets.
build.py provides Python, Docker and host executable targets, reading the project version,
launching build tools with an allowlisted environment and recording artifact hashes/metadata.
Checksums prove file integrity, not publisher authenticity or runtime correctness. Native
artifacts need native runner smoke tests. Docker runs the installed wheel as a non-root user
with persistent /data. UI and MCP are alternative owners of a home, not concurrent services
against one DuckDB file. See build verification.