Skip to content

Repository files navigation

Chitral

Chitral is a local semantic-layer + synthetic-data workbench: connect a database, import tables onto a canvas, design relationships, and generate privacy-preserving synthetic data from statistical profiles.

Chitral supports two complementary workflows:

  • Relational synthesis — generate deterministic, relationship-valid snapshots from existing tables.
  • Temporal and journey synthesis — optionally describe how table rows represent events, constrain their timestamps, and model probabilistic customer journeys without requiring Kafka or a separate event store.

Feature highlights

AreaWhat Chitral provides
Visual semantic canvasImport or create datasets, inspect fields, draw relationships, edit metadata, search, filter by source, auto-layout the graph, and focus on upstream/downstream lineage.
Database profilingLearn aggregate column distributions, null and distinct counts, quantiles, string patterns, boolean rates, JSON structure, uniqueness, and relationship fan-out.
Deterministic synthesisA fixed seed produces reproducible output. Generation streams in bounded batches and does not train a model or retain all output in memory.
Relationship integrityPreserve primary keys, unique values, foreign keys, child-per-parent fan-out, childless-parent rates, and constraint columns copied from the selected parent row.
Fidelity controlsConfigure ordering rules, composite unique keys, discriminator-based distributions, correlated fan-out, cross-table conditioning, and optional LLM-assisted JSON templates.
Quality gatesEvaluate schema, row counts, distributions, null rates, uniqueness, foreign keys, ordering, temporal rules, transitions, delays, correlation, and privacy before accepting output.
Temporal datasetsMap events to tables or discriminator values and enforce constraints such as within, not-before, not-after, and same-or-after.
Customer journeysDefine actor mappings, occurrence bounds, transition probabilities, exclusive branches, termination, bounded repeats, delays, and correlation behavior.
Versioned generation plansCreate mutable drafts, validate them, publish immutable versions, preview bounded samples, and execute the exact compiled version.
Durable job controlSubmit asynchronous work, monitor stages, inspect privacy-safe events, cancel cooperatively, enforce deadlines and capacity, and retry deterministically.
Portable and Lakehouse outputDownload CSV or Parquet. Optionally write supported database sinks or publish to Apache Iceberg on S3 through a registered REST catalog.

How the pieces fit together

Connect source
-> Import tables and fields
-> Review or design relationships on the canvas
-> Configure synthesis fidelity rules
-> Profile aggregate statistics
-> Generate deterministic relational data
-> Apply optional temporal and journey rules
-> Run quality gates
-> Download or publish accepted output

Security posture — read this first

Chitral is a local, single-user developer tool. There is no authentication. The API trusts whoever can reach it. Do not expose the backend to the public internet without putting it behind your own auth/gateway.

Saved data-source credentials are encrypted at rest (Fernet) in backend/chitral.db. List/read APIs never return passwords or raw config— only a non-secret config_summary. Protect DATASOURCE_ENCRYPTION_KEY (or backend/.datasource_key); anyone with both the DB file and the key can decrypt. Treat the machine as a trusted workstation.

If you don't set DATASOURCE_ENCRYPTION_KEY, a key is auto-generated at backend/.datasource_key. Saved datasource credentials are not portable across machines or fresh clones unless you pin that env var (or copy the key file along with the database).


Prerequisites

ToolVersion
Python≥ 3.12
uvlatest
Node.js≥ 18
npm≥ 9
Docker (optional)for connector integration-test DBs
curl -LsSf https://astral.sh/uv/install.sh | sh

Quick start

# Install dependencies
make install
# equivalent to:# cd backend && uv sync --extra connectors# cd frontend && npm ci# Terminal 1 — API (http://localhost:8000)cd backend
uv run run.py
# Terminal 2 — UI (http://localhost:5173)cd frontend
npm run dev

Open http://localhost:5173. Interactive API docs: http://localhost:8000/docs.

ServiceDefault URL
Frontend (Vite)http://localhost:5173
Backend APIhttp://localhost:8000
Health checkhttp://localhost:8000/health

End-user guide: generate a relational snapshot

The relational workflow is the default and does not require any temporal or journey feature flags.

1. Connect and import a source

  1. Select Connect Source in the canvas toolbar.
  2. Choose SQLite, PostgreSQL, MySQL, MongoDB, or Snowflake.
  3. Enter the connection information and test or browse the source.
  4. Select the tables or collections to import.
  5. Import them onto the canvas.
  6. Save the connection with the Source role when prompted. Generation from the UI uses a saved source so credentials stay server-side.

Imported tables become dataset nodes with their fields and source identity. Relational imports are atomic: if a required part of the import fails, Chitral rolls the import back instead of leaving a partial canvas.

2. Review the semantic model

Use the canvas to verify the imported model before generating data:

  • Drag from one dataset to another to create a relationship.
  • Select the relationship type and map one or more column pairs.
  • Mark a pair as a join key to preserve FK integrity or as a constraint to copy the value from the exact selected parent row.
  • Open a relationship to enable correlated fan-out or select a parent conditioning column.
  • Open a dataset's Edit metadata action to configure ordering rules, composite unique keys, or a discriminator column.
  • Use Show Lineage to inspect upstream and downstream dependencies.
  • Use search, source filters, and auto-layout when working with a larger canvas.

Chitral generates related tables in dependency order. Unsupported cycles are rejected by the strict workflow; the compatibility workflow can retain its legacy input-order behavior.

3. Configure generation

  1. Select Generate Synthetic Data.
  2. Choose the saved source that contains the imported tables.
  3. Select the tables to generate. The server-advertised table limit is shown in the panel.
  4. Optionally enter an exact output row count for each table. If omitted, Chitral uses the profiled row count multiplied by the scale factor.
  5. Review the readiness summary for relationships, constraints, conditioning, and boundary warnings.
  6. Choose Download only or a supported saved Sink connection.
  7. Open Advanced to set the scale factor, deterministic seed, relationship preservation, and optional JSON-template settings.
  8. Select Generate Data.

If only one side of a relationship is selected, Chitral warns about the boundary. A missing referenced parent falls back to value generation for that FK rather than silently pretending the relationship was preserved.

4. Monitor and download

The generation panel reports the current job stage and any warnings. When the job succeeds, download the result as:

  • Parquet ZIP for efficient typed data exchange; or
  • CSV ZIP for broad tool compatibility.

Downloads are assembled from disk-backed Parquet batches and remain available until the local artifact TTL expires. When a database sink is selected, Chitral also writes the generated tables after generation; a sink warning does not remove the downloadable result.


End-user guide: temporal datasets and customer journeys

Temporal and journey synthesis are implemented but disabled by default. They are server-controlled capabilities intended for an explicitly enabled local or isolated deployment.

Generation modes

ModeUse it when
Relational snapshotYou need statistically similar tables with keys and relationships preserved.
Temporal datasetRelated rows must obey timestamp constraints, such as an order occurring after account creation.
Journey scenarioPhysical tables or discriminator rows represent logical events connected by probabilities, delays, occurrence rules, and actor identity.

Journey modeling is an overlay on the relational canvas. Relational edges continue to represent physical data integrity; journey edges separately represent event transitions. A journey can therefore produce ordinary database or Lakehouse tables—Kafka is not required.

Enable the advanced workspace locally

Set only the capabilities you intend to evaluate in backend/.env, then restart the backend:

GENERATION_SPECS_ENABLED=trueTEMPORAL_GENERATION_ENABLED=trueJOURNEY_GENERATION_ENABLED=trueGENERATION_PREVIEW_ENABLED=true# Keep disabled unless a registered Iceberg REST/S3 destination has passed# the deployment-specific atomicity and security gates.LAKEHOUSE_PUBLICATION_ENABLED=false

The frontend reads the server's /api/capabilities response. Hiding or showing a UI control is not the security boundary; the backend independently enforces every capability.

Build and execute a versioned scenario

  1. Import the physical tables and verify their PK/FK relationships.
  2. Open Journey and create a specification from the current canvas.
  3. Choose Relational snapshot, Temporal dataset, or Journey scenario.
  4. For temporal or journey modes, define logical events:
    • map an event to a dedicated table or a discriminator value;
    • select its timestamp column;
    • map actor keys through exactly one directed relational path;
    • optionally select correlation columns and occurrence bounds.
  5. Add temporal rules and choose the null behavior for missing anchors.
  6. For a journey, add transitions, probabilities, delays, exclusive groups, termination behavior, and bounded repeats.
  7. Save the draft and resolve any revision conflict explicitly.
  8. Select Validate and fix every blocking diagnostic.
  9. Select Publish exact revision. Published versions are immutable.
  10. Generate a bounded preview and review samples, UTC histograms, resource projections, diagnostics, and the quality report.
  11. Select a saved source and start the job.
  12. Monitor its stage, cancel if necessary, and download only when publication is accepted.

Preview and full execution use the same immutable compiled plan. Seeds, logical IDs, transition choices, occurrence counts, delays, and temporal values are independent of batch boundaries and scheduling, making retries reproducible.

For the focused workflow and operating limits, see Journey and Temporal Generation User Guide.


Synthesis behavior and fidelity controls

Profile-driven generation

Chitral's current engine is profile-driven. It queries aggregate statistics and generates new values from those profiles; it does not train a generative model or simply resample complete source rows.

The engine supports:

  • deterministic numeric, categorical, boolean, date/time, string, UUID, and JSON generation;
  • collision-free primary and unique values by construction;
  • exact or quantile-based relationship fan-out, including childless parents;
  • top-level JSON key presence, type mixtures, and value distributions;
  • optional bounded LLM template pools for selected JSON columns;
  • per-table discriminator groups for row-coherent conditional distributions;
  • cross-table conditioning based on one declared parent attribute;
  • ordering constraints such as created_at <= completed_at;
  • composite unique tuples generated without retaining an unbounded seen-set; and
  • independent quality collectors that verify the generated result rather than trusting the generator.

Current modeling limits

  • Columns without an explicit discriminator, ordering, conditioning, or relationship rule are generated independently.
  • Cross-table conditioning uses one declared parent attribute rather than the parent's entire row jointly.
  • Composite keys across tables and multiple discriminator columns are not modeled.
  • JSON fidelity is strongest at the top level; nested values preserve discovered structure and type but not full nested distributions.
  • Empty tables can be imported, but generation requires at least one source row for every generated table.

Outputs and publication

DestinationSupportBehavior
CSV ZIPSupportedGenerated from the accepted disk-backed Parquet artifact.
Parquet ZIPSupportedDefault typed, portable output; supports bounded multipart generation.
SQLite sinkSupportedSame-named tables are replaced after generation.
Snowflake sinkSupportedUses batched INSERT; staged bulk copy is not yet implemented.
PostgreSQL/MySQL/MongoDB sinkNot yetUse downloadable output instead.
Iceberg REST catalog + S3Implemented, disabled by defaultSupports atomic append and replace-snapshot bundles for existing tables through one catalog transaction.

Accepted Parquet publication uses private staging, schema and checksum validation, a signed quality attestation, an immutable manifest, and atomic promotion. Retries resolve to the same deterministic manifest instead of creating duplicate output.

Iceberg table creation remains disabled unless the exact registered catalog and version proves atomic multi-table creation. Chitral never falls back to sequential per-table creation because that could expose a partial journey bundle. See Iceberg REST/S3 Output Architecture.


Connector support

ConnectorSource (profile / import)Sink (write synthetic tables)Automated tests
SQLiteSupportedSupportedStrong unit tests
SnowflakeSupportedSupported (batched INSERT; no staged COPY yet)Unit / mocked only — no live integration suite in CI
PostgreSQLSupportedNot yet (download-only; 422 if selected as sink)Unit + Docker integration
MySQLSupportedNot yetUnit + Docker integration
MongoDBSupported (collections; no FK inference)Not yetUnit + Docker integration

Empty tables/collections can be imported but generation requires ≥ 1 source row.

Integration-test databases

make test-db-up # Postgres :5433, MySQL :3307, MongoDB :27018
python scripts/seed_e2e_dbs.py
make test-postgres # or test-mysql / test-mongodb
make test-db-down

Default URLs (also in .env.test.example):

  • postgresql://chitral:chitral@localhost:5433/chitral_test
  • mysql://chitral:chitral@localhost:3307/chitral_test
  • mongodb://chitral:chitral@localhost:27018/?authSource=admin

Without these env vars, make test skips ~88 integration tests on purpose.


Operational boundaries

  • Chitral currently runs generation in one API process with a bounded thread executor. Do not add web workers to scale generation; the repository does not yet provide an external queue/worker runtime.
  • Default admission limits are 50 tables, 100 million logical rows, approximately 50 GiB, eight active jobs, and a one-hour deadline. Deployments can reduce these limits.
  • A process restart fails interrupted embedded-worker jobs closed. Resubmit the immutable version with the same seed for a deterministic replay.
  • Local artifacts expire after one hour by default; durable job metadata and events expire after 24 hours.
  • Job events and diagnostics are designed to exclude credentials, connector URIs, and source values. Do not add sensitive samples to logs or bug reports.
  • The project does not provide Kafka publication, arbitrary user scripting, public self-service, built-in RBAC, or a multi-tenant identity boundary.

Operators should read the Generation Operations Runbook before enabling advanced capabilities outside a developer workstation.


CORS (local by default)

By default the API allows only localhost frontends:

  • http://localhost:5173 / http://127.0.0.1:5173
  • http://localhost:3000 / http://127.0.0.1:3000

To allow other origins, set in backend/.env:

CORS_ORIGINS=["http://localhost:5173","https://your-frontend.example"]

Do not set ["*"] on a networked deployment without auth.


Common commands

CommandPurpose
make installBackend + frontend deps
make testBackend unit tests (uv run pytest)
make lintBackend ruff + frontend ESLint
make buildFrontend production build
make test:e2ePlaywright browser tests
make test-db-upStart Docker test DBs

More detail: developers.md, AGENTS.md, backend/ARCHITECTURE.md.

Additional documentation

DocumentPurpose
Journey and Temporal Generation User GuideConcise workflow for versioned relational, temporal, and journey generation.
Generation Operations RunbookAdmission, observability, cancellation, restart, cleanup, and escalation procedures.
Backend ArchitectureDetailed APIs, contracts, synthesis pipeline, quality, jobs, and output architecture.
Iceberg REST/S3 Output ArchitectureLakehouse registration, atomicity, recovery, and approval requirements.
Temporal/Journey Product RequirementsComplete phased product and engineering requirements.
Production Readiness PlanDeferred hardening work and release gates.

License

MIT

About

Synthetic Data Generation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages