Datasets, structured. An open-source, local-first, single-application workspace for importing, exploring, cleaning, labeling, versioning, augmenting, and exporting AI datasets — without stitching together Roboflow, CVAT, Label Studio, FiftyOne, pandas, DVC, and a dozen bash scripts.
Built by ArminNX. Licensed under MIT — see LICENSE.
- The problem
- What DataLith actually is
- Status at a glance
- Getting started
- Architecture
- The 15 modules
- Dataset Sourcing (Module 15)
- BYOK AI
- Desktop app (Tauri)
- PWA / offline
- Accessibility
- Roadmap: building the modules that need real infrastructure
- Contributing
- License
Training AI today means fighting a different tool at every stage:
Roboflow · CVAT · Label Studio · FiftyOne · pandas · Python scripts
FFmpeg · Hugging Face · DVC · Git · Bash scripts · Custom augmentation code
Every stage has its own tool, its own file formats, its own mental model. DataLith's goal is to unify the entire dataset workflow into one application — the Figma / Photoshop / VS Code of AI datasets — supporting every data type a real project touches: images, video, audio, text, PDFs, CSV, JSON, medical, 3D, point clouds, time series, and synthetic data.
The long-term goal is not to replace Label Studio or CVAT. The goal is to become the default operating system for AI data — the same way VS Code became the default editor for software.
DataLith ships in two honest halves, and this README doesn't blur them:
- What's real and running today — every module marked
AvailableorBYOK AIbelow does exactly what it says, with no simulated output. Import really unzips your archive in-browser. Clean really runs a SHA-256 hash over every sample. Augment really pushes pixels through a live Canvas 2D pipeline. Nothing here is a mockup wired to fake data. - What's architected but not implemented — Training, Synthetic Data Generation, Model Evaluation, and the Marketplace need a real backend (compute, storage, moderation) that a browser tab fundamentally can't provide. Rather than fake those with placeholder buttons, they're left off — and the last major section below is a real technical guide to building them properly.
That distinction is the whole design philosophy. A dataset tool that lies about what it just did to your data is worse than no tool at all.
| # | Module | Status | Notes |
|---|---|---|---|
| 1 | Universal Importer | ✅ Available | Drag/drop, folder picker, full client-side .zip extraction |
| 2 | Visual Dataset Explorer | ✅ Available | Search, filter, inspector panel |
| 3 | AI Dataset Understanding | 🔷 BYOK AI | Rule-based free; open-ended → your connected model |
| 4 | Automatic Cleaning | ✅ Available | Real SHA-256 dedupe, corrupt/empty detection, renaming |
| 5 | Dataset Version Control | ✅ Available | Linear commits, diffs, rollback (in-session) |
| 6 | AI-Assisted Labeling | 🔷 BYOK AI | Manual labeling free; AI-suggest needs a vision provider |
| 7 | Dataset Analytics | ✅ Available | Live stat cards + Chart.js visualizations |
| 8 | Visual Data Augmentation | ✅ Available | Real Canvas 2D pipeline: rotate, flip, brightness, contrast, blur, noise |
| 9 | Synthetic Data Generation | 🛣️ Roadmap | Needs a generative model backend |
| 10 | Training Integration | 🛣️ Roadmap | Needs a real compute backend / GPUs |
| 11 | Model Evaluation | 🛣️ Roadmap | Depends on #10 existing first |
| 12 | Dataset Marketplace | 🛣️ Roadmap | Needs hosted infrastructure + moderation |
| 13 | AI Dataset Agent | 🔷 BYOK AI | Same engine as #3 |
| 14 | Visual Workflow Builder | ✅ Available | Chains the real steps above into a runnable pipeline |
| 15 | Dataset Sourcing | 🔷 BYOK AI | Real Wikipedia + Hugging Face fetches (web build); real arbitrary-URL scraping (desktop build); every candidate gated by review before it reaches the dataset |
The in-app Roadmap page (/studio/roadmap) mirrors this table and will
never drift from it — both are generated from the same
src/lib/roadmap.ts.
npm install
npm run dev # http://localhost:3000npm run build # static export → out/
npm run lintNo environment variables, no server, no database. DataLith is 100% client-side — everything lives in memory for the tab's lifetime. Reload and you start fresh, on purpose (see Roadmap → persistence for how that changes going forward).
src/
├── app/
│ ├── page.tsx # Landing page (vision, module grid, stack)
│ └── studio/
│ ├── layout.tsx # Sidebar + Topbar shell
│ └── <module>/page.tsx # One route per module
├── components/ # Sidebar, Topbar, Mark, EmptyState, ToastHost…
└── lib/
├── types.ts # Sample, Commit, ScanResult, RoadmapEntry
├── store/
│ ├── dataset.ts # Zustand — THE single source of truth for samples
│ ├── version.ts # Zustand — commit history
│ └── toast.ts # Zustand — notifications
├── importer.ts # Module 1 logic (JSZip)
├── clean.ts # Module 4 logic (SHA-256, decode checks)
├── exporter.ts # Mirror of importer.ts
├── agent.ts # Module 3/13 rule engine + BYOK prompt builder
├── ai/providers.ts # Module 3/6/13's BYOK layer (8 providers)
├── workflow.ts # Module 14's runnable step registry
└── roadmap.ts # Canonical module list (drives 2 UIs)
One discipline holds the whole app together: every module talks to the
dataset only through useDatasetStore (Zustand). No module reaches into
another module's state directly. That's what lets Explorer, Clean,
Analytics, and the Agent all agree on "what a sample is" without knowing
anything about each other — and it's exactly the seam a future persistence
layer (see Roadmap) will slot into.
Stack, as actually built (per the original vision's "suggested stack"):
| Layer | Vision suggested | What's here |
|---|---|---|
| Frontend | React, Next.js, Tailwind CSS | React 19, Next.js 16 (App Router), Tailwind CSS v4 |
| Desktop | Tauri | Tauri 2 config scaffolded (src-tauri/) |
| State | — | Zustand |
| Processing | OpenCV, FFmpeg, Polars, Arrow | Canvas 2D (Augment), JSZip (Import/Export), Chart.js (Analytics) |
| Plugin SDK | Rust, Python, TypeScript | Not yet — see Roadmap |
| Backend / ML workers | Rust, Python, PyTorch, ONNX | Not yet — see Roadmap |
| Vector DB | Qdrant, LanceDB | Not yet — see Roadmap |
Full per-module descriptions live in src/lib/roadmap.ts
and render on both the landing page and /studio/roadmap. Short version:
- Import — drop files or a
.zip; parsed entirely client-side. - Explore — searchable/filterable grid with a live inspector.
- Understand — ask questions in plain English; rules answer instantly, an LLM answers the rest.
- Clean — real dedupe (SHA-256), corrupt/empty detection, filename normalization.
- Version — commit snapshots, see diffs, roll back.
- Label — manual classification, plus AI-suggest via your own vision model.
- Analytics — live stat cards and charts computed off the real dataset.
- Augment — a real Canvas 2D transform pipeline with a live preview.
- Synthetic — roadmap, needs a generative backend.
- Train — roadmap, needs real compute.
- Evaluate — roadmap, depends on Train.
- Marketplace — roadmap, needs hosting + moderation.
- Agent — the same rule/LLM engine as Understand, as a chat.
- Workflow — chain the real steps above and run them as a pipeline.
- Source — pull candidate content from a URL, Wikipedia, or a Hugging Face dataset; screen and (optionally) AI-curate every candidate; commit only what's approved. See Dataset Sourcing below.
Turning "research the internet" into a dataset without a human ever touching raw scraped junk is a two-part problem — getting the content, and deciding what's worth keeping — and this module keeps that split honest instead of blurring it into one "AI does everything" button.
Getting the content — three real, working sources:
- Hugging Face (
datasets-server.huggingface.co) — search the public dataset hub, pick a dataset, pull a page of rows. CORS-open, works directly from the web build. - Wikipedia (REST
page/summary+ article API) — search, fetch an article's full text. Also CORS-open, also works on the web build. - Any URL — the browser tries a direct fetch first (works for the
minority of sites with permissive CORS), and on the desktop app,
falls back to a native fetch via a
#[tauri::command]insrc-tauri/src/main.rs— a real Rust HTTP client has no CORS restriction, because CORS is a browser policy, not a network one. On the web build, if a site blocks direct requests, DataLith says so plainly and points you at the desktop app or the Paste text/HTML tab, rather than routing through a third-party CORS-relay that would just move the trust problem to someone else's server.
Deciding what's worth keeping — the AI review gate, before anything touches your dataset:
- Every fetched candidate lands in a separate review queue
(
src/lib/store/source.ts), not the dataset store. There's no code path that lets a fetch skip review. - A free heuristic screen runs first — word count, boilerplate-line ratio, repetition — and rejects obvious junk (nav dumps, cookie notices, near-empty pages) at zero cost, same instinct as Clean's SHA-256 pass running before anything else touches a sample.
- With a BYOK provider connected, an optional AI review pass
(
src/lib/source/curate.ts) reads the raw text and returns approve/reject plus a cleaned version and a stated reason — capped at 15 candidates per click, same discipline as Label's AI-suggest. - Every candidate — its raw text, curated text, verdict, and the AI's reason — stays visible and editable in the Source page. You can manually approve or reject anything regardless of what the AI said.
- Only clicking "Commit approved to dataset" calls
useDatasetStore.add(). Nothing is silent, nothing is automatic.
This module has no server component of its own — Wikipedia/Hugging Face calls go straight from your tab to their APIs, and the desktop-only URL fetch goes straight from the Tauri process to the target site, the same local-first shape as everything else in DataLith.
DataLith is local-first: there is no DataLith server, so there's nothing
for a dataset — or an API key — to leak to. When you connect a provider in
AI Settings, the key is written to your browser's localStorage
only, and every request goes straight from your tab to that provider's own
API.
Supported today: OpenAI, Anthropic, Google Gemini, Groq, OpenRouter, Mistral, DeepSeek, xAI (Grok). Vision-capable ones (used by Label's AI-suggest) are flagged in the AI Settings UI.
One honest caveat: a few providers don't send CORS headers permitting
direct browser calls, precisely because a key sitting in browser JS is
less protected than one behind your own server. Where that happens,
DataLith surfaces the real error instead of hiding it — see
fetchWithReason in src/lib/ai/providers.ts.
cd src-tauri
cargo tauri dev # requires the Rust toolchain + Tauri CLI locally
cargo tauri buildnext.config.ts is set to output: "export", so npm run build produces
a static out/ directory that tauri.conf.json points to directly
(frontendDist: "../out"). The Rust side (src-tauri/src/main.rs) stays
minimal on purpose — almost all app logic lives in the frontend, exactly as
it does on the web — but it's no longer a pure passthrough: it exposes one
real native command, fetch_url, that Module 15 (Source) uses to fetch
arbitrary URLs without the CORS restriction a browser tab is bound by (see
Dataset Sourcing). That's the pattern for
adding more native-only capability here — real filesystem access instead of
the browser file picker, or a local SQLite-backed Version Control store,
are natural next additions, each as its own #[tauri::command] function
called from the frontend via @tauri-apps/api, same as fetch_url.
This repo doesn't include a compiled binary — building one requires the Rust toolchain, which isn't assumed to be on your machine. The config is real and will build as-is once you have
cargo+ the Tauri CLI installed.
public/manifest.webmanifest— installable, standalone display, generated 192/512 + maskable icons.public/sw.js— a stale-while-revalidate service worker that caches the app shell (not dataset content — that's intentionally out of scope for a browser cache).- Registered from
src/components/ServiceWorkerRegistrar.tsx, production builds only.
Install it like any PWA: open the deployed app, use your browser's "Install app" prompt. Once installed, the shell keeps opening (and the UI keeps working) even offline — your in-memory dataset for that session still won't survive a full reload, by the same design as the rest of the app (see Roadmap for persistence).
- Skip-to-content link on every page.
- Semantic landmarks:
<nav aria-label="Studio modules">,aria-current="page"on the active route. - Toggle buttons expose
aria-pressed(kind filters, class chips, flip controls). - The Agent's conversation is an
aria-live="polite"log; the global toast isrole="status". - All icon-only buttons and canvas previews carry
aria-label; all inputs have associated<label>elements (visually hidden where the placeholder already communicates purpose). - Respects
prefers-reduced-motion. - Not yet audited with a screen reader end-to-end — treat this as a strong baseline, not a certification.
This is the part of the vision that a static, client-only app genuinely cannot deliver honestly. Here's what each one actually needs, concretely, if you want to build it next.
Needs: a generation backend (hosted diffusion/LLM API, or a self-hosted
model server). How to slot it in: add a new file under src/lib/
(e.g. synthetic.ts) that calls out to a generation API the same way
ai/providers.ts calls chat APIs — BYOK works here too (Stability, Replicate,
fal.ai, or a local ComfyUI/Automatic1111 instance with CORS enabled). Output
comes back as blobs → wrap them as Sample objects → useDatasetStore.add().
No architecture change needed; this is a new module using the existing seam.
Needs: real compute — GPUs, a job runner, and a place for checkpoints to live. This is the one module that can't be BYOK'd from a static site the way chat APIs can, because training jobs run for minutes-to-hours, not milliseconds. How to build it:
- Stand up a minimal backend (FastAPI/Python is the natural fit given the vision's own suggested stack — PyTorch, HF Transformers, YOLO, Detectron2).
- Expose a job API:
POST /train(dataset export + hyperparameters) →GET /train/:id(status/logs) →GET /train/:id/artifact(checkpoint). - From DataLith, Export already produces a clean
.zip+manifest.json— that's your training payload format for free. - Poll job status into a new
src/lib/training.ts+store/training.ts(same Zustand pattern asstore/version.ts), and a/studio/trainpage that mirrors the DesignLanguage of/studio/workflow. - For local-only training without a hosted backend,
llama.cpp/MLX-style local inference servers with an HTTP API are a lighter-weight starting point than full training — worth doing before full training if you want an incremental win.
Needs: #10 to exist first, since evaluation reads a trained model's
outputs. Once you have a checkpoint, this becomes: run inference over a held
-out split of the current dataset, diff predictions against sample.label,
and surface per-class precision/recall the same way analytics/page.tsx
already surfaces per-class counts — this module is mostly UI once the
inference call exists.
Needs: real backend infrastructure (auth, storage, a database, and — non-negotiably — moderation before anything about hosting user-uploaded datasets publicly). This is the module furthest from "just add a file" — treat it as its own project (a Next.js API layer + Postgres + object storage like S3/R2, likely deployed separately from the local-first studio) rather than something to bolt onto this client-only app.
Every module above — and honestly the whole app — currently resets on reload because there's no backend. The single highest-leverage next step, before any of #9–#12, is probably: give Version Control (Module 5) a real on-disk store. Two reasonable paths:
- Browser-only: swap the in-memory Zustand store for IndexedDB
(e.g. via
idbor Dexie) so a reload doesn't lose your dataset. No backend needed, works on the web build as-is. - Desktop-only: now that Tauri is scaffolded, add
#[tauri::command]functions backed by SQLite (rusqlite) for a real content-addressed commit store — the closest thing to "Git for datasets" the vision describes.
Issues and PRs welcome. If you're picking up one of the roadmap modules
above, please keep the project's one hard rule: never simulate output.
If a feature needs infrastructure that isn't there yet, it stays off the
roadmap-as-Available list until it's real.
MIT — see LICENSE. Copyright © ArminNX.