<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Muhammed Rasin O M</title>
    <description>The latest articles on Forem by Muhammed Rasin O M (@rasinmuhammed).</description>
    <link>https://forem.com/rasinmuhammed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3649283%2F280874f9-48bd-4283-838c-ab37ca897bda.jpeg</url>
      <title>Forem: Muhammed Rasin O M</title>
      <link>https://forem.com/rasinmuhammed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rasinmuhammed"/>
    <language>en</language>
    <item>
      <title>The Best Python Library for Generating Quick Synthetic Data in 2026</title>
      <dc:creator>Muhammed Rasin O M</dc:creator>
      <pubDate>Sat, 11 Apr 2026 14:22:09 +0000</pubDate>
      <link>https://forem.com/rasinmuhammed/the-best-python-library-for-generating-quick-synthetic-data-in-2026-5681</link>
      <guid>https://forem.com/rasinmuhammed/the-best-python-library-for-generating-quick-synthetic-data-in-2026-5681</guid>
      <description>&lt;h3&gt;
  
  
  Misata: Generate Realistic Synthetic Datasets From Plain English Descriptions
&lt;/h3&gt;

&lt;p&gt;Generating synthetic data in Python used to mean one of three things: write &lt;code&gt;random.uniform()&lt;/code&gt; loops by hand, use Faker for fake names and emails, or spend a week configuring SDV on top of real data you might not even have. But we have got LLMs now. Still maintaining the logics and the referential integrity is a nightmare.&lt;/p&gt;

&lt;p&gt;Misata is none of those things.&lt;/p&gt;

&lt;p&gt;One sentence in. Multiple related tables out. Distributions calibrated to real-world statistics. Foreign key integrity guaranteed. Monthly revenue targets hit to the cent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;misata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;

&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A SaaS company with 2000 users. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MRR rises from 80k in January to 320k in June, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drops to 180k in August due to churn, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;then recovers to 400k in December.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That generates two linked tables with 21,000+ rows. Here is what the monthly MRR looks like when you sum the rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Jan    $80,000   ✓
Feb   $128,000   ✓
Mar   $176,000   ✓
Apr   $224,000   ✓
May   $272,000   ✓
Jun   $320,000   ✓
Jul   $250,000   ✓
Aug   $180,000   ✓   &amp;lt;- churn dip, as described
Sep   $235,000   ✓
Oct   $290,000   ✓
Nov   $345,000   ✓
Dec   $400,000   ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every target exact. Not approximate. The individual rows still follow a log-normal distribution (median MRR $126, mean $150, p90 $291) because that is what real SaaS revenue looks like. But the monthly totals are pinned to whatever story you gave it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The core problem: why most synthetic data is useless
&lt;/h2&gt;

&lt;p&gt;There's a gap between what synthetic data generators produce and what you actually need to build, test, or demo a data system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uniform distributions lie.&lt;/strong&gt; Real revenue data is log-normal. Real fraud rates hover around 2%, not 50%. Real product category distributions follow Zipf's law - one category dominates, the others trail off. When your fake data looks nothing like the real thing, your model trains on lies, your dashboards tell wrong stories, and your tests pass cases that would fail in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referential integrity breaks things.&lt;/strong&gt; If you're testing a JOIN across customers and transactions, orphan foreign keys will silently ruin your results. Most data generators either skip relational structure entirely or produce it inconsistently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business targets get ignored.&lt;/strong&gt; You don't just want data that looks roughly right. You want a dataset where Q3 revenue dips 22% due to a simulated product recall, or where churn spikes in August because your description says so. No general-purpose generator can do this.&lt;/p&gt;

&lt;p&gt;Misata was built specifically to close this gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why distributions matter more than people think
&lt;/h2&gt;

&lt;p&gt;Most fake data generators produce values that are uniformly distributed. When you plot them, everything looks flat. Real business data is never flat.&lt;/p&gt;

&lt;p&gt;Misata ships calibrated distribution priors for seven domains. Here is what that means in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fintech: fraud rates, credit scores, and account balances
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A fintech company with 2000 customers and banking transactions.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fraud rate: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_fraud&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fraud rate: 2.00%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;400 fraudulent transactions out of 20,000. The calibrated real-world baseline for card fraud is around 2%. That is what you get. Not a random number. A calibrated one.&lt;/p&gt;

&lt;p&gt;Credit scores follow the actual US distribution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mean:   679   (real US average: 680-720)
std:     80   (real range: 70-90)
min:    328
max:    850
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Account balances follow log-normal because real bank balances do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;median     $1,976
mean       $6,128
p90       $14,260
p99       $62,565
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most customers have under two thousand dollars. A few have tens of thousands. The tail is real. This matters enormously if you're building fraud detection models, credit scoring pipelines, or stress-testing payment infrastructure — a flat distribution would make every one of those models overfit to a distribution that doesn't exist in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Healthcare: blood type frequencies, age distributions, and appointment patterns
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A hospital with 500 patients and doctors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;patients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patients&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blood type    Generated    Real-world
O+               37.9%        38.0%   ✓
A+               33.9%        34.0%   ✓
B+                9.6%         9.0%   ✓
AB+               3.0%         3.0%   ✓
O-                6.5%         7.0%   ✓
A-                6.1%         6.0%   ✓
B-                2.0%         2.0%   ✓
AB-               0.9%         1.0%   ✓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All eight blood types within 0.6% of the actual ABO/Rh frequency distribution. Patient ages center on 45 with a standard deviation of 18, matching a chronic-care hospital population. Nobody configured any of this. It is what the healthcare domain prior knows.&lt;/p&gt;

&lt;p&gt;This level of epidemiological accuracy is essential when you're training triage models, testing EHR systems, or building health analytics pipelines that will eventually run on real patient data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ecommerce: Zipf categories, seasonal peaks, and return rates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An ecommerce store with 5000 customers and orders. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Revenue grows from 100k in January to 300k in November &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;then 350k in December.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_from_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Product categories follow Zipf's law because that is how real shopping behavior works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;electronics      47.1%
clothing         20.0%
home &amp;amp; garden    12.3%
sports            8.7%
books             6.5%
beauty            5.5%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One category dominates. The rest trail off. Uniform would give you ~17% each. Real shopping does not look like that.&lt;/p&gt;

&lt;p&gt;Order statuses come with realistic rates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;completed    71.5%
shipped      12.4%
pending       8.2%
returned      5.0%
cancelled     3.0%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real e-commerce return rates are 8–10%. That is what gets generated. If you're building a returns processing pipeline, this means your test data will actually stress the right code paths.&lt;/p&gt;




&lt;h2&gt;
  
  
  Referential integrity across all tables
&lt;/h2&gt;

&lt;p&gt;Every child table samples foreign key values from the actual parent pool. This means zero orphan rows by construction, not by luck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A fintech company with 2000 customers and banking transactions.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;customers&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# 2,000 rows
&lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;      &lt;span class="c1"&gt;# 2,600 rows
&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# 20,000 rows
&lt;/span&gt;
&lt;span class="c1"&gt;# Both FK edges hold
&lt;/span&gt;&lt;span class="n"&gt;orphan_accounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;orphan_txns&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orphan_accounts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 0
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orphan_txns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# 0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tables are generated in topological dependency order. Parents first. Children sample from the completed parent pool. It cannot produce orphans.&lt;/p&gt;

&lt;p&gt;This matters for any workflow that involves JOINs. Referential integrity errors in test data produce false negatives — your pipeline looks like it works until it meets real data.&lt;/p&gt;




&lt;h2&gt;
  
  
  The two-step flow for more control
&lt;/h2&gt;

&lt;p&gt;When you want to inspect or modify the schema before committing to generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A hospital with 500 patients and doctors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Schema: Healthcare Dataset
Domain: healthcare
Tables (3)
  doctors         25 rows    [doctor_id, first_name, last_name, specialty, years_experience]
  patients       500 rows    [patient_id, name, age, gender, blood_type, registered_at]
  appointments  1500 rows    [appointment_id, patient_id, doctor_id, type, duration_minutes]

Relationships (2)
  patients.patient_id  -&amp;gt; appointments.patient_id
  doctors.doctor_id    -&amp;gt; appointments.doctor_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adjust the seed, add columns, change row counts. Then generate. The two-step flow is useful for teams where a data engineer defines the schema and a developer generates data against it — the schema becomes a shared artifact you can version control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-world use cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use case 1: Training ML models without access to production data
&lt;/h3&gt;

&lt;p&gt;Privacy regulations — GDPR, HIPAA, CCPA — make it difficult or impossible to use real user data for model training in many industries. The usual workaround is anonymization, but anonymized data often loses the statistical properties that make it useful for training.&lt;/p&gt;

&lt;p&gt;Misata generates statistically calibrated data with no PII at all. A fraud detection team can produce 500,000 transactions with a realistic 2% fraud rate, a plausible credit score distribution, and calibrated account balance tails — without touching a single real customer record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A fintech company with 50000 customers and banking transactions. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fraud rate is 2%. High-value accounts above 50k balance are 3x more likely to be targeted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model trains on data that behaves like production data. The privacy risk is zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 2: Seeding development and staging databases
&lt;/h3&gt;

&lt;p&gt;Every new developer joining a product team hits the same wall: the development database is empty or has three test rows from 2019. You can't build features that depend on realistic data patterns without realistic data.&lt;/p&gt;

&lt;p&gt;Misata can seed a full development database in seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;seed_database&lt;/span&gt;

&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A SaaS company with 1000 users.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;seed_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql://user:pass@localhost/mydb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 12,400
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from the CLI, which makes it easy to add to a &lt;code&gt;Makefile&lt;/code&gt; or &lt;code&gt;docker-compose&lt;/code&gt; setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;misata generate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--story&lt;/span&gt; &lt;span class="s2"&gt;"A SaaS company with 1000 users"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--db-url&lt;/span&gt; postgresql://user:pass@localhost/mydb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--db-create&lt;/span&gt; &lt;span class="nt"&gt;--db-truncate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SQLite works too for local-only development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;misata generate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--story&lt;/span&gt; &lt;span class="s2"&gt;"A SaaS company with 1000 users"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--db-url&lt;/span&gt; sqlite:///./dev.db &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--db-create&lt;/span&gt; &lt;span class="nt"&gt;--db-truncate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new developer can run &lt;code&gt;make seed-db&lt;/code&gt; and have a working dataset in their environment in under 10 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 3: Building product demos without real customer data
&lt;/h3&gt;

&lt;p&gt;Sales engineering teams routinely need to demo analytics dashboards, CRM systems, and data products to prospects. Using real customer data for demos is a legal and ethical non-starter. Using hand-crafted fake data means someone spends two days building a CSV in Excel.&lt;/p&gt;

&lt;p&gt;Misata lets you generate a compelling, internally consistent demo dataset for any domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A B2B SaaS company with 800 enterprise customers. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ARR grows from 2M in Q1 to 5M in Q4. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Average contract value is 6000. Churn rate is 8%.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a dataset where every KPI in the demo dashboard reflects a plausible business trajectory — not a random scatter of numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 4: Testing data pipelines and ETL systems
&lt;/h3&gt;

&lt;p&gt;Data pipeline tests are only as good as the data they run on. Edge cases like NULL foreign keys, skewed distributions, and outlier values are exactly what break pipelines in production — and exactly what hand-crafted test data tends to miss.&lt;/p&gt;

&lt;p&gt;Misata's calibrated distributions naturally produce the tail values that stress-test pipelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A logistics company with 10000 shipments. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Include delayed deliveries at a 12% rate. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;International shipments are 30% of total volume.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The p99 values in account balances, the occasional NULL in optional fields, the rare blood type AB- at 1% frequency — these are the values that reveal pipeline brittleness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 5: Generating benchmark datasets for academic and research use
&lt;/h3&gt;

&lt;p&gt;Researchers publishing papers on data systems, query optimizers, or ML benchmarks need datasets that are reproducible, realistic, and free of privacy concerns. Misata's &lt;code&gt;seed&lt;/code&gt; parameter makes generation fully deterministic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A marketplace with 5000 buyers and sellers, orders, and product listings.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Anyone running this gets the exact same dataset
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Share the &lt;code&gt;seed&lt;/code&gt; and description in your paper. Readers can reproduce your exact dataset with a single Python call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 6: Prototyping data products and BI dashboards
&lt;/h3&gt;

&lt;p&gt;Before you connect a BI tool to production data, you need something to build against. Misata gives you a structurally correct, statistically plausible dataset to prototype on — so you can validate your data model, build your first dashboard, and demo your schema to stakeholders before a single production row exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  LLM-powered generation for custom domains
&lt;/h2&gt;

&lt;p&gt;The rule-based parser covers SaaS, ecommerce, fintech, healthcare, marketplace, logistics, and pharma. For anything outside those domains, the LLM backend handles arbitrary schema generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLMSchemaGenerator&lt;/span&gt;

&lt;span class="n"&gt;gen&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLMSchemaGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;groq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# or openai, ollama
&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_from_story&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A B2B marketplace with vendor tiers, SLA contracts, and quarterly invoices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;misata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_from_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works with any LLM provider that supports the OpenAI-compatible API format. Requires &lt;code&gt;GROQ_API_KEY&lt;/code&gt; or &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;. Retries automatically on rate limits.&lt;/p&gt;

&lt;p&gt;The LLM path is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Industry-specific schemas with unusual entities (clinical trials, commodity trading, fleet management)&lt;/li&gt;
&lt;li&gt;Multi-tenant SaaS with complex permission hierarchies&lt;/li&gt;
&lt;li&gt;Any domain where the rule-based parser doesn't have calibrated priors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM infers a reasonable schema, column types, and row count ratios from your description. You get back the same DataFrames as the rule-based path — just with the schema derived from a language model instead of hard-coded priors.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it compares to Faker and SDV
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Faker&lt;/strong&gt; generates individual fake values. One row at a time. It has no concept of tables that reference each other and no domain-specific distributions. Wiring foreign keys and getting log-normal amounts is your job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SDV (Synthetic Data Vault)&lt;/strong&gt; learns patterns from real data and generates synthetic copies. It requires actual training data, pulls in heavy ML dependencies, and cannot pin specific business targets like "fraud rate must be 2%." If you don't have real data to train on, SDV is a dead end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Misata&lt;/strong&gt; generates from a description. No real data required. No ML training. Distributions are calibrated to domain knowledge. Business targets are exact.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Faker&lt;/th&gt;
&lt;th&gt;SDV&lt;/th&gt;
&lt;th&gt;Misata&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multi-table FK integrity&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No real data needed&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Calibrated domain distributions&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Learned&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exact monthly aggregate targets&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plain-English story input&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database seeding&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM-powered custom domains&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reproducible with seed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key distinction: SDV is a synthetic data &lt;em&gt;replication&lt;/em&gt; tool. Misata is a synthetic data &lt;em&gt;generation&lt;/em&gt; tool. They solve different problems. SDV needs real data to learn from. Misata generates from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation and quick start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;misata pandas numpy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these produce full verified output in under 3 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python examples/saas_revenue_curve.py
python examples/fintech_fraud_detection.py
python examples/healthcare_multi_table.py
python examples/ecommerce_seasonal.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or open the &lt;a href="https://colab.research.google.com/github/rasinmuhammed/misata/blob/main/notebooks/quickstart.ipynb" rel="noopener noreferrer"&gt;Colab notebook&lt;/a&gt; and run it without installing anything. No signup, no API key, no configuration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design principles
&lt;/h2&gt;

&lt;p&gt;A few constraints Misata holds to that are worth understanding:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Determinism over randomness.&lt;/strong&gt; Given the same description and seed, you always get the same dataset. This is non-negotiable for reproducible research and CI pipelines where test data needs to be stable across runs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Statistical realism over convenience.&lt;/strong&gt; It would be simpler to generate uniformly distributed values. Misata does not do this because uniform distributions produce data that behaves nothing like real data. The extra calibration work is the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggregate targets are constraints, not approximations.&lt;/strong&gt; When you say MRR should be $320k in June, the generated data will sum to exactly $320k in June. Not $318k. Not $322k. The individual rows remain statistically realistic while the aggregates are treated as hard constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referential integrity is structural, not checked.&lt;/strong&gt; Misata does not generate data and then validate foreign keys. It generates in dependency order so invalid keys cannot occur. This is a stronger guarantee than post-hoc validation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Can I add custom columns to a generated schema?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. The two-step &lt;code&gt;parse&lt;/code&gt; → &lt;code&gt;generate_from_schema&lt;/code&gt; flow lets you inspect and modify the schema object before generating. You can add columns, change data types, adjust row counts, and modify relationship cardinality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How large can generated datasets be?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Misata is DataFrame-based, so the practical limit is your available RAM. For datasets larger than a few million rows, you can generate in chunks and write directly to a database using &lt;code&gt;seed_database&lt;/code&gt;. Benchmarks on a standard laptop show ~500k rows/second for most schemas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it support databases other than PostgreSQL and SQLite?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;seed_database&lt;/code&gt; accepts any SQLAlchemy connection string, which covers PostgreSQL, MySQL, SQLite, MS SQL Server, Oracle, and others. If SQLAlchemy can connect to it, Misata can seed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a way to generate time-series data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Temporal columns are supported. The &lt;code&gt;registered_at&lt;/code&gt;, &lt;code&gt;transaction_date&lt;/code&gt;, and similar timestamp fields follow realistic distributions relative to one another — a customer's first transaction always comes after their account creation date, for example. You can specify date ranges in your description: "transactions between January 2023 and December 2024."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if I need data that follows my company's specific distribution?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The LLM path lets you describe distribution constraints in natural language: "30% of accounts are enterprise tier with balances above $50k." For highly specific requirements, the schema object exposes column-level distribution parameters you can override directly.&lt;/p&gt;




&lt;p&gt;Misata is open source, MIT licensed, and available now.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/rasinmuhammed/misata" rel="noopener noreferrer"&gt;github.com/rasinmuhammed/misata&lt;/a&gt;&lt;br&gt;
PyPI: &lt;a href="https://pypi.org/project/misata/" rel="noopener noreferrer"&gt;pypi.org/project/misata&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://github.com/rasinmuhammed/misata/blob/main/QUICKSTART.md" rel="noopener noreferrer"&gt;QUICKSTART.md&lt;/a&gt;&lt;br&gt;
Colab: &lt;a href="https://colab.research.google.com/github/rasinmuhammed/misata/blob/main/notebooks/quickstart.ipynb" rel="noopener noreferrer"&gt;Run the quickstart notebook&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How I Built a "Story-to-Data" Engine in Python (Because Faker Wasn't Enough)</title>
      <dc:creator>Muhammed Rasin O M</dc:creator>
      <pubDate>Tue, 16 Dec 2025 16:01:49 +0000</pubDate>
      <link>https://forem.com/rasinmuhammed/how-i-built-a-story-to-data-engine-in-python-because-faker-wasnt-enough-3oi0</link>
      <guid>https://forem.com/rasinmuhammed/how-i-built-a-story-to-data-engine-in-python-because-faker-wasnt-enough-3oi0</guid>
      <description>&lt;p&gt;&lt;strong&gt;The "2 Months of Pain" Origin Story&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An year ago, I was working as a Data Science Engineer at a consultancy firm. We needed to build a Tableau dashboard to demonstrate a new business model. The consultants didn't want "random" data; they wanted a specific story:&lt;/p&gt;

&lt;p&gt;"Show a _____ failing in Phase 2, causing a 40% revenue dip in Q3, followed by a recovery in Q4 due to a new ____ launch."&lt;/p&gt;

&lt;p&gt;I tried at first using standard libraries like Faker and Mimesis. They are fantastic for generating random names and emails, but they failed hard on Business Logic. Then I used python scripting to generate the data, using for loops and all kind of loops.&lt;/p&gt;

&lt;p&gt;I ended up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time Travel Bugs: Timesheets dated before an employee's hire date.&lt;/li&gt;
&lt;li&gt;Orphaned Rows: Orders linked to non-existent Users.&lt;/li&gt;
&lt;li&gt;Flat Curves: Revenue that looked like static noise, not a "Q3 Dip."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I spent 2 months manually hacking Python scripts, hard-coding probabilities, and stitching CSVs together to make the demo look real. It was a nightmare.&lt;/p&gt;

&lt;p&gt;I realized: We don't need more random data generators. We need Narrative Data Engines.&lt;/p&gt;

&lt;p&gt;So, I built &lt;strong&gt;Misata&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Misata?&lt;/strong&gt;&lt;br&gt;
Misata is an open-source Python engine that turns a natural language story into a multi-table, referentially intact dataset.&lt;/p&gt;

&lt;p&gt;Instead of writing 500 lines of schema config, you just type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;misata generate --story "A SaaS platform with 50k users, 20% churn in Q3, and usage-based billing" --use-llm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it generates SQL-ready CSVs where the math actually works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Under the Hood: The Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Misata isn't just a wrapper around Faker. It uses a Neuro-Symbolic approach to solve the consistency problem.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Brain (LLM Parser)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First, it uses an LLM (I optimized it for Llama 3.3 via Groq) to parse your story into a strict JSON schema. It extracts:&lt;/p&gt;

&lt;p&gt;Entities: Users, Subscriptions, Invoices.&lt;/p&gt;

&lt;p&gt;Distributions: "20% churn" becomes a probability weight.&lt;/p&gt;

&lt;p&gt;Relationships: "Invoices belong to Subscriptions."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Logic (Topological Sort)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To prevent "Orphaned Rows," Misata builds a Directed Acyclic Graph (DAG) of your tables. It uses Topological Sorting to ensure parent tables (e.g., Users) are generated before child tables (e.g., Orders).&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Simplified logic from misata/simulator.py
def topological_sort(self):
    graph = defaultdict(list)
    in_degree = {table.name: 0 for table in self.config.tables}

    for rel in self.config.relationships:
        graph[rel.parent_table].append(rel.child_table)
        in_degree[rel.child_table] += 1

    # Standard Kahn's Algorithm...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The Muscle (Vectorized NumPy)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The biggest bottleneck with Python data generation is looping. Generating 10 million rows in a loop is too slow.&lt;/p&gt;

&lt;p&gt;Misata uses Vectorized Operations (via NumPy and Pandas) to generate data in blocks. This allows it to hit speeds of ~250,000 rows/second on a standard laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features for Data Engineers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built this to solve the specific pains I faced in consulting:&lt;/p&gt;

&lt;p&gt;Relational Integrity: It automatically maps Primary Keys to Foreign Keys. No more broken joins in SQL/Tableau.&lt;/p&gt;

&lt;p&gt;No "Time Travel": Child tables (like Timesheets) automatically look up their parent's Start Date to ensure events happen chronologically.&lt;/p&gt;

&lt;p&gt;Business Constraints: You can define rules like "Employees cannot log &amp;gt; 8 hours/day."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out&lt;/strong&gt;&lt;br&gt;
It's &lt;strong&gt;open source&lt;/strong&gt; and available on PyPI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install misata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate a dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Needs GROQ_API_KEY (free tier works great)
misata generate --story "E-commerce store with seasonal spikes in December" --use-llm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why I Open Sourced It&lt;/strong&gt;&lt;br&gt;
I know there are enterprise tools out there that cost $10k+/year. But for individual consultants, students, and indie hackers, there was no good "middle ground" between Faker and Enterprise Privacy tools.&lt;/p&gt;

&lt;p&gt;I want Misata to be that middle ground.&lt;/p&gt;

&lt;p&gt;I'm currently working on adding Curve Fitting (so you can draw a chart and get data that matches it). If you're into Data Engineering or Python optimization, I'd love your feedback on the architecture!&lt;/p&gt;

&lt;p&gt;Repo: github.com/rasinmuhammed/misata&lt;/p&gt;

&lt;p&gt;P.S. If you are a consultant stuck in "Demo Data Hell" right now and need a specific scenario generated, drop a comment or DM me. I'm looking for complex edge cases to stress-test the engine.&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>opensource</category>
      <category>database</category>
    </item>
    <item>
      <title>I Built a TUI to Visualize RAG Chunking because chunk_size=1000 is a Lie 📉</title>
      <dc:creator>Muhammed Rasin O M</dc:creator>
      <pubDate>Wed, 10 Dec 2025 15:38:26 +0000</pubDate>
      <link>https://forem.com/rasinmuhammed/i-built-a-tui-to-visualize-rag-chunking-because-chunksize1000-is-a-lie-1dg0</link>
      <guid>https://forem.com/rasinmuhammed/i-built-a-tui-to-visualize-rag-chunking-because-chunksize1000-is-a-lie-1dg0</guid>
      <description>&lt;p&gt;Let’s be honest for a second. When you are building a RAG (Retrieval-Augmented Generation) pipeline, how do you pick your &lt;code&gt;chunk_size&lt;/code&gt; and &lt;code&gt;overlap&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;If you are like 90% of us, you copy-paste &lt;code&gt;1000&lt;/code&gt; and &lt;code&gt;200&lt;/code&gt; from a tutorial, run it, and hope the LLM doesn't hallucinate.&lt;/p&gt;

&lt;p&gt;I realized I was doing "vibes-based engineering". I had no idea if my chunks were cutting sentences in half, if my overlap was actually preserving context, or if my retrieval was failing because of the embedding model or the chunking strategy.&lt;/p&gt;

&lt;p&gt;So, I spent my nights and weekends building a tool to fix it.&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;RAG-TUI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is an open-source, terminal-based visual debugger for RAG pipelines. It helps you &lt;strong&gt;see&lt;/strong&gt; what your splitters are doing before you index millions of documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: "The Black Box"
&lt;/h2&gt;

&lt;p&gt;We treat text splitters like black boxes. You feed in a PDF, and out comes a list of strings. But what do those strings look like?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did you just cut a critical definition in half?&lt;/li&gt;
&lt;li&gt;Is your 10% overlap actually capturing the previous sentence?&lt;/li&gt;
&lt;li&gt;Are you feeding your embedding model garbage?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I got tired of printing chunks to the console to debug this. I wanted a UI, but I didn't want to leave my terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: RAG-TUI
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RAG-TUI&lt;/strong&gt; is a lightweight CLI tool built in Python. You point it at a file, and it gives you an interactive dashboard to tune your indexing strategy in real-time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykfvfxujdmv3u2uk80gz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykfvfxujdmv3u2uk80gz.gif" alt=" " width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features (Why you might want this)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Real-time Visualization&lt;/strong&gt; 🎨&lt;br&gt;
Drag a slider to change the &lt;code&gt;chunk_size&lt;/code&gt;. Watch the text re-chunk instantly.&lt;br&gt;
The UI uses color-coded cards to show you exactly where one chunk ends and the next begins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Quality Indicators&lt;/strong&gt; 🚦&lt;br&gt;
I added visual "linters" for your chunks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🟢 &lt;strong&gt;Green:&lt;/strong&gt; Clean break (ends with &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;🟡 &lt;strong&gt;Yellow:&lt;/strong&gt; Mid-phrase break (ends with &lt;code&gt;,&lt;/code&gt;, &lt;code&gt;:&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;🔴 &lt;strong&gt;Red:&lt;/strong&gt; Hard cut (ends with a character).&lt;/li&gt;
&lt;li&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; Chunk is too small (&amp;lt;50 tokens) or too large.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. "Scientific" Batch Testing&lt;/strong&gt; &lt;br&gt;
Stop guessing. Enter 20 test queries ("What is the refund policy?", "How do I reset my password?"). RAG-TUI runs them against your current settings using local vector search and calculates a &lt;strong&gt;Hit Rate&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Hit Rate &amp;gt; 80%?&lt;/em&gt; Ship it.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Hit Rate &amp;lt; 60%?&lt;/em&gt; Your chunks are wrong. Change the strategy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Privacy First (Ollama Support)&lt;/strong&gt; 🔒&lt;br&gt;
You don't need to send your private docs to OpenAI just to debug a splitter. RAG-TUI has native support for &lt;strong&gt;Ollama&lt;/strong&gt;. You can run the entire debugging loop offline on your laptop.&lt;/p&gt;
&lt;h2&gt;
  
  
  💻 Under the Hood
&lt;/h2&gt;

&lt;p&gt;For the Python nerds (like me), here is the stack that makes this possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UI:&lt;/strong&gt; &lt;a href="https://github.com/Textualize/textual" rel="noopener noreferrer"&gt;Textual&lt;/a&gt; (The best TUI framework, period).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking:&lt;/strong&gt; &lt;a href="https://github.com/chonkie-ai/chonkie" rel="noopener noreferrer"&gt;Chonkie&lt;/a&gt; (Blazing fast token splitting).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector DB:&lt;/strong&gt; &lt;a href="https://github.com/unum-cloud/usearch" rel="noopener noreferrer"&gt;Usearch&lt;/a&gt; (Lightweight, in-memory vector search).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM:&lt;/strong&gt; Async wrapper for Ollama/OpenAI.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  🚀 How to Try It
&lt;/h2&gt;

&lt;p&gt;I tried to make the onboarding as painless as possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;rag-tui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rag-tui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Make sure you have &lt;code&gt;ollama serve&lt;/code&gt; running if you want to test embeddings!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤝 I Need Your Feedback!
&lt;/h2&gt;

&lt;p&gt;This is currently in &lt;strong&gt;v0.0.2 Beta&lt;/strong&gt;. It works, but I know there are edge cases I haven't found yet.&lt;/p&gt;

&lt;p&gt;I am building this in public because I believe RAG tooling needs to get better. If you are learning RAG or building a production pipeline, please give this a spin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it support your weird PDF format?&lt;/li&gt;
&lt;li&gt;Do you need a specific splitter I haven't added?&lt;/li&gt;
&lt;li&gt;Is the TUI crashing on Windows? (It shouldn't, but you know... Windows).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Star the repo if you think this is useful. It motivates me to keep shipping updates!&lt;/strong&gt; ⭐️&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/rasinmuhammed/rag-tui" rel="noopener noreferrer"&gt;https://github.com/rasinmuhammed/rag-tui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy Chunking! ✂️&lt;/p&gt;

</description>
      <category>rag</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a FastAPI admin panel that doesn't suck (and here's why it's different)</title>
      <dc:creator>Muhammed Rasin O M</dc:creator>
      <pubDate>Sat, 06 Dec 2025 13:56:15 +0000</pubDate>
      <link>https://forem.com/rasinmuhammed/i-built-a-fastapi-admin-panel-that-doesnt-suck-and-heres-why-its-different-57ej</link>
      <guid>https://forem.com/rasinmuhammed/i-built-a-fastapi-admin-panel-that-doesnt-suck-and-heres-why-its-different-57ej</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; FastAPI Matrix Admin combines one-line auto-discovery, async-first architecture, and production-grade security in a package that requires &lt;strong&gt;zero Node.js&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🟢 &lt;strong&gt;&lt;a href="https://fastapi-matrix-admin-demo.onrender.com/admin/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; (Read-only)&lt;br&gt;
💻 &lt;strong&gt;&lt;a href="https://github.com/rasinmuhammed/fastapi-matrix-admin" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The admin panel problem nobody talks about
&lt;/h2&gt;

&lt;p&gt;Every FastAPI project follows the same arc:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; You build a great API.&lt;/li&gt;
&lt;li&gt; Product wants to "just update a few records manually."&lt;/li&gt;
&lt;li&gt; You reluctantly install Django admin (now you have two frameworks).&lt;/li&gt;
&lt;li&gt; Or you build a custom React dashboard (6 weeks later...).&lt;/li&gt;
&lt;li&gt; Or you use a generic admin and spend days configuring it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've done all three. They all sucked for different reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's wrong with existing FastAPI admin solutions?
&lt;/h2&gt;

&lt;p&gt;I evaluated every major option before building this. Here's what I found:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FastAPI-Admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires Tortoise ORM (can't use SQLAlchemy).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLAdmin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Good, but sync-only. No async support in 2024?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Starlette-Admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Heavy Starlette dependency, limited FastAPI integration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admin-One&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires Vue.js build step, defeats FastAPI's simplicity.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The pattern:&lt;/strong&gt; They either force you into specific ORMs, ignore async, or add frontend build complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built Instead
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FastAPI Matrix Admin&lt;/strong&gt; focuses on three non-negotiables:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. One-Line Auto-Discovery (Because Your Time Matters)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_matrix_admin&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MatrixAdmin&lt;/span&gt;

&lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MatrixAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auto_discover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Done. All models registered.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Under the hood:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introspects SQLAlchemy models using &lt;code&gt;inspect()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Analyzes column types to generate appropriate form fields.&lt;/li&gt;
&lt;li&gt;Detects text columns for search.&lt;/li&gt;
&lt;li&gt;Finds timestamp columns for default ordering.&lt;/li&gt;
&lt;li&gt;Creates a sensible list display based on column types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Customization when you need it:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;list_display&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;searchable_fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;ordering&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-created_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Obviously
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Zero Node.js (Seriously)
&lt;/h3&gt;

&lt;p&gt;No npm. No webpack. No &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; Tailwind CSS via CDN, HTMX for dynamic updates, Alpine.js (3KB), and Jinja2 templates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why this matters:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pip install fastapi-matrix-admin&lt;/code&gt; → you're done.&lt;/li&gt;
&lt;li&gt;No build step in CI/CD.&lt;/li&gt;
&lt;li&gt;No frontend/backend version mismatches.&lt;/li&gt;
&lt;li&gt;Deploys anywhere Python runs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Production-Grade Security (Not an Afterthought)
&lt;/h3&gt;

&lt;p&gt;Most admin libraries treat security as optional. Here is what is built-in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content Security Policy (CSP):&lt;/strong&gt; Prevents XSS by strictly controlling script sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSRF Protection:&lt;/strong&gt; Every form gets a signed token automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL Signing:&lt;/strong&gt; All admin URLs are cryptographically signed to prevent ID enumeration/tampering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety with Pydantic v2:&lt;/strong&gt; Input validation happens automatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security Comparison:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;FastAPI Matrix Admin&lt;/th&gt;
&lt;th&gt;SQLAdmin&lt;/th&gt;
&lt;th&gt;FastAPI-Admin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSP Headers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Built-in&lt;/td&gt;
&lt;td&gt;❌ Manual&lt;/td&gt;
&lt;td&gt;❌ Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSRF Protection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Automatic&lt;/td&gt;
&lt;td&gt;⚠️ Optional&lt;/td&gt;
&lt;td&gt;❌ None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;URL Signing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pydantic v2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;⚠️ v1&lt;/td&gt;
&lt;td&gt;❌ No validation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Performance: Async All The Way Down
&lt;/h2&gt;

&lt;p&gt;Full async support isn't optional in 2024.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Async SQLAlchemy 2.0
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.ext.asyncio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;

&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql+asyncpg://...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MatrixAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Simple benchmark (100 concurrent list view requests):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI Matrix Admin (async):&lt;/strong&gt; ~50ms avg&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLAdmin (sync):&lt;/strong&gt; ~180ms avg (blocks other requests)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Matrix UI (Yeah, It's Different)
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend the cyberpunk aesthetic is for everyone. But here's why it exists:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Every admin panel looks the same. Generic Bootstrap tables. Boring gray sidebars. No personality.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Terminal-style green/black theme with neon accents.&lt;/p&gt;

&lt;p&gt;It makes internal tools feel less corporate, and stakeholders actually remember seeing "that Matrix admin thing." (If you hate it, the CSS variables are customizable).&lt;/p&gt;


&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install fastapi-matrix-admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Boolean&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.ext.asyncio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_async_engine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;declarative_base&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi_matrix_admin&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MatrixAdmin&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;declarative_base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;is_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sqlite+aiosqlite:///./database.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# That's it
&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MatrixAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-secret-key-min-32-chars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auto_discover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvicorn app:app
# Visit http://localhost:8000/admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Current roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] File/image upload support&lt;/li&gt;
&lt;li&gt;[ ] Advanced filters (date ranges, multi-select)&lt;/li&gt;
&lt;li&gt;[ ] Export to CSV/Excel&lt;/li&gt;
&lt;li&gt;[ ] Custom dashboard widgets&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toMaybe"&gt; &lt;/a&gt; light theme for the Matrix-haters&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I built this because I kept rebuilding the same admin panel over and over. Auto-discovery saves me hours per project. Zero Node.js means simple deploys. The security features mean I can actually use this in production.&lt;/p&gt;

&lt;p&gt;If you try it, let me know what breaks. Or what you wish it did differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions I'd love feedback on:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Is auto-discovery too magical, or genuinely useful?&lt;/li&gt;
&lt;li&gt; What security features am I missing?&lt;/li&gt;
&lt;li&gt; Would you actually use this in production?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Drop a comment or open an issue. First-time contributors welcome!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/rasinmuhammed/fastapi-matrix-admin" rel="noopener noreferrer"&gt;Github: fastapi-matrix-admin&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>fastapi</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
