On this page
- Start from what you have
- A first dataset
- What it is for
- What the evidence supports
- Use it from an AI agent
- Questions
- Does Misata need real data?
- Is the output of mimic anonymous or privacy-safe?
- Can it fill a Postgres database directly?
- Will the same seed give the same rows after an upgrade?
- How is this different from Faker?
Misata
Misata generates relational synthetic data from a declaration of what must be true, and proves afterwards that it is.
You say what the data has to satisfy: the tables and keys, the CHECK rules, a monthly revenue curve, a refund rate, a 50/35/15 channel split, the legal order of a subscription's states. Misata generates rows that satisfy all of it, refuses before generating when two declarations contradict each other, and writes an attestation that anyone can rerun with DuckDB to confirm every declared number on the files themselves.
It is an open-source Python library (MIT), a CLI and an MCP server. It needs no real data, no trained model and no API key, and within one Misata version the same schema and seed give the same rows on every machine.
pip install misata schema.sql · misata.yaml · a sentence · a live database
│
▼
misata explain ──────▶ planned rows, which declaration writes which column,
every conflict and its remedy (exit 3: nothing written)
│
▼
misata generate ─────▶ CSV · JSON Lines · Parquet · DuckDB · Postgres · SQLite
│
▼
--attest ────────────▶ attestation.intoto.json every file pinned by SHA-256,
verify.py every invariant as DuckDB SQL
│
┌──────────────┼──────────────────┬───────────────────┐
▼ ▼ ▼ ▼
python verify.py misata publish misata evalpack misata solve
(anyone, no (Hugging Face, (questions with (make a dbt or
Misata needed) verified first) known answers) SQL pipeline hit
its targets)Start from what you have#
| You have | Call | Read |
|---|---|---|
SQL DDL (CREATE TABLE ...) | misata generate -c schema.sql, or misata.from_ddl(ddl) | Seed a dev database from its DDL |
| A live Postgres or SQLite database | misata seed postgresql://..., or schema_from_db(url) then seed_database(schema, url) | Seed a live database |
| A YAML or dict schema | misata generate -c misata.yaml, or misata.generate_from_schema(schema) | YAML schema |
| A sentence | misata.generate("A SaaS company with 1,000 customers", seed=42) | Plain English |
| Django models | misata.from_django(app_labels=[...]) | Django |
| More rows than fit in memory | misata generate --format parquet, or misata.generate_stream(...) | Streaming |
| A number a dbt or SQL pipeline must produce | misata solve -c solve.yaml | Solve for a pipeline's output |
| Real rows to imitate | misata.mimic(df_or_csv) | Mimic. Fitted to real rows, so not anonymous |
Always pass a seed (--seed, seed: in YAML, __seed__ in a dict) so the
result can be reproduced.
A first dataset#
import misata
tables = misata.generate(
"A SaaS company with 5k users, monthly subscriptions, and 20% churn",
seed=42,
)
for name, df in tables.items():
print(name, len(df))The same data as a file you can commit and review:
# misata.yaml
name: my-app
seed: 42
tables:
users:
rows: 1000
columns:
user_id: {type: int, unique: true}
email: {type: email, unique: true}
plan: {type: categorical, choices: [free, pro, enterprise]}
orders:
rows: 5000
columns:
order_id: {type: int, unique: true}
user_id: {type: foreign_key}
amount: {type: float, min: 5, max: 500}
ordered_at: {type: date, start: "2025-01-01", end: "2025-06-30"}
relationships:
- users.user_id -> orders.user_idmisata explain misata.yaml
misata generate -c misata.yaml -o out --attest
python out/verify.pyThe quickstart walks through both, and the use cases are complete recipes for specific jobs.
What it is for#
- Seeding development, CI and preview databases whose schemas have foreign keys, CHECK rules, unique and composite keys, and self-references.
- Testing pipelines and dbt models against data whose correct output is known before it exists.
- Demos and dashboards that need believable shapes: skewed money, a few large customers, weekday rhythms, histories that hold up to questions.
- Evaluating text-to-SQL models and data agents against answer keys that are checked on several databases at once.
- Volume: ten million rows across fourteen tables stream to Parquet in 36 seconds on an Apple M1, at 0.78 GB peak.
What the evidence supports#
- Valid by construction. On five DDL schemas, zero violations of keys, CHECK rules, UNIQUE, NOT NULL and self-reference trees, against 15,014 to 50,416 per schema for a per-column Faker script, and 3,055 to 5,557 for SDV's multi-table model trained on valid data, which refuses two of the five schemas. See the validity benchmark.
- Realistic without data, within limits. Blind e-commerce data is harder to tell from real orders than a Faker script or SDV trained on the real data (detection AUC 0.629 against 0.783 and 0.711 on Olist, mean of five seeds; 0.5 means a classifier cannot tell them apart). On taxi trips it beats the script (0.750 against 0.788) but not SDV trained on the trips (0.675). See the realism benchmark.
- Honest about the rest. The limitations page lists what the checks do not cover, and When Misata refuses explains every refusal and warning.
What Misata does not claim: that mimic output is private or anonymous,
that any data is indistinguishable from a particular production table, or
that rows are byte-identical across Misata versions (they are within one
version; see the stability policy).
Use it from an AI agent#
pip install "misata[mcp]"
claude mcp add misata misata-mcpThe MCP server gives Claude, Cursor and other agents tools
to explain, generate, audit, attest, solve and seed. Agents writing code
against the library should read
AGENTS.md,
and every page here is also served as Markdown at its URL plus .md.
Questions#
Does Misata need real data?#
No. Declared generation starts from a schema, DDL, a database's structure
or a sentence, and no real row is read. The one exception is
misata.mimic, which you point at a real file on
purpose.
Is the output of mimic anonymous or privacy-safe?#
No. A twin is fitted to the real rows, reuses their category values and quantiles, and can reproduce a rare record. When the data must be private, use a differentially private synthesizer with a stated epsilon, or declare the data instead of fitting it.
Can it fill a Postgres database directly?#
Yes. misata seed postgresql://... reads the live schema and inserts rows
parents first in one transaction; misata generate -c schema.sql --db-url ... --db-create does the same from DDL. Neither empties a table unless
you ask (--truncate for seed, --db-truncate for generate). See Seed a live database.
Will the same seed give the same rows after an upgrade?#
Within one Misata version, yes, on Linux, macOS and Windows. Across versions,
declared totals, rates, shares and integrity hold, but individual rows may
change; each release lists them under Output changes. Pin the version for
byte-identical fixtures and record misata.fingerprint(tables)["__all__"].
See the stability policy.
How is this different from Faker?#
Faker produces one value at a time and leaves keys, CHECK rules and totals to the script around it. Misata generates whole tables together, so keys resolve, rules hold and declared numbers come out exact. On five DDL schemas a per-column Faker script broke 15,014 to 50,416 rules per schema where Misata broke none. See Faker vs SDV vs Misata.
Prefer generating data visually?
Misata Studio lets you turn natural language prompts into relational schemas with exact outcome invariants, live preview tables, and one-click database seeding without writing code.

