Metadata-Version: 2.4
Name: skogi
Version: 0.3.2
Summary: Thin API-contract CLI for syn-data-gen — generate synthetic data and seed it into a live database
Keywords: synthetic-data,test-data,database,postgres,seed,cli,fixtures
Author: Yashmeet Singh
Author-email: Yashmeet Singh <yashmeet.singh@outlook.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Testing
Requires-Dist: httpx>=0.28
Requires-Dist: psycopg[binary]>=3.2.0
Requires-Dist: pydantic>=2.13.4
Requires-Python: >=3.12
Project-URL: Homepage, https://skogi.io
Description-Content-Type: text/markdown

<!--
  This file is the *published* package description: pyproject.toml's `readme` points here, and
  pypi.org renders it verbatim. README.md is the contributor front door and stays that way — this
  one is written for people installing skogi, not building it.

  Two rules, enforced by tests/test_pypi_readme.py:
    1. Every link is an absolute https:// URL. PyPI does not rewrite relative links to the source
       repo, so `docs/usage.md` resolves against pypi.org and dead-ends.
    2. No internal vocabulary — no repo file paths, no phase/track codes, no issue numbers, no CI
       badge (the repo is private, so the image 404s for everyone but a collaborator).

  It is deliberately short: the subset a user needs, not a mirror of README.md. It only reaches
  pypi.org when a version is released.
-->

# skogi

You have a database schema — a `CREATE TABLE` script — but no data to put in it. **skogi** makes up
realistic-looking fake data that fits your schema (names that look like names, prices that look like
prices, orders that actually point at customers that exist) and puts it in your database, in one
command:

```bash
skogi run --ddl schema.sql --dsn postgresql://user@localhost:5432/dbname
```

**PostgreSQL today.** MySQL, SQLite and Oracle are planned.

## Install

```bash
uv tool install skogi
skogi --version
```

Requires **Python 3.12+**. [uv](https://docs.astral.sh/uv/) fetches a suitable interpreter itself, so
this works even if your system Python is older — which is why it is the instruction to lead with.

With [pipx](https://pipx.pypa.io/) instead, note that it uses your *system* Python, so you need a
3.12 one already installed:

```bash
pipx install skogi
```

## Get a token

Generation runs on Skogi's servers, so the tool needs to know it's you and which plan you're on. Sign
up at [skogi.io](https://skogi.io), then **Settings → CLI tokens** → create one. It is shown once:

```bash
export SKOGI_TOKEN=…
```

**Secrets come from the environment, never a flag** — `SKOGI_TOKEN` for generating, and
`PGPASSWORD`/`DB_PASSWORD` for your database — so they don't end up in your shell history.

## The three commands

**`skogi run`** — schema in, filled database out. The one you'd type most days:

```bash
skogi run \
  --ddl schema.sql \
  --dsn postgresql://user@localhost:5432/dbname
```

Under it are two halves, usable on their own:

```bash
skogi generate --ddl schema.sql --out ./out
skogi seed --run-dir ./out --dsn postgresql://user@localhost:5432/dbname
```

**`skogi generate`** asks the service for a dataset and writes a folder: your schema copied through
unchanged, the generated rows as `INSERT` statements, and a small run summary.

**`skogi seed`** materializes that folder into a real database — creating any tables that aren't
there yet and leaving alone the ones that are, then inserting every row in **one transaction**, so a
failure partway leaves the database exactly as it was. It prints a summary of tables created, rows
per table and time taken. Useful switches: `--dry-run` (print the plan, touch nothing),
`--on-conflict` (stop on duplicates, skip them, or empty the tables first), and `--record run.json`
to keep a record of what it did.

**Undo.** Hand that record back and it removes exactly what it added — its rows deleted, its tables
dropped, anything that was already in the database left completely untouched:

```bash
skogi seed --teardown --record run.json --dsn postgresql://user@localhost:5432/dbname
```

## Templates: pinned, or live?

Tune a schema on [skogi.io](https://skogi.io) and save it as a **Template**, then drive it from the
command line two ways — and the difference only shows up later:

- **`--template-id <id>`** runs the Template **as it is right now**. A teammate's edit reaches your
  next run with nothing to re-download.
- **Its downloaded settings file** (`--config skogi.config.json`) is a **copy, frozen at download**.
  Later edits don't reach it, and it lives next to your code where a change is reviewable.

For your own machine, naming the Template is usually nicer. **For CI, prefer the downloaded file** —
otherwise an edit on the website quietly changes what your tests run against.

## Destructive work names its target

Two things are destructive: emptying tables before loading (`--on-conflict truncate`) and undoing a
previous load (`--teardown`). On a database on your own machine, they ask you to confirm. On a
database that is **not on this machine**, they refuse until you name it:

```
Refusing to destroy data on a database that is not on this machine.
Pass --confirm-target app_staging to proceed.
```

`--yes` is deliberately not enough. "Yes" travels — it does the same thing wherever you paste it,
including at a database you didn't mean — while a command that names `app_staging` *fails* when it is
pointed at `app_prod`.

## Worth knowing

- **Generating needs a network and a token; seeding does not.** The engine that invents the data
  lives on Skogi's servers, and your plan's limits apply the same from the website or the command
  line. `skogi seed` talks to your database and nothing else, fully offline.
- **A seed makes output repeatable within a calendar day.** Run it twice this afternoon with the same
  settings and you get identical data. Tomorrow, most of it is still identical — but date and
  timestamp columns shift, because they are generated relative to today. So assert on row counts and
  relationships, not on date values you hard-coded last week.
- **SQL output is a paid feature, and it is the command line's default** — the command line exists to
  load a database, and that needs SQL. On the free plan your first run is refused, and the message
  says so.
- **If a run times out it is not cancelled** — it may still finish on the server and count against
  your monthly allowance. Check your recent runs on the website before running it again.
- **If the loading half of `skogi run` fails**, the generated files are still in the folder: fix the
  problem and load *those* with `skogi seed --run-dir`, rather than paying for the data twice.

Full documentation, plans and support: [skogi.io](https://skogi.io).
