§01|Install & setup

the binary, the path, the variables.


Three things that go wrong on the first run: a stale PATH after the global install, an unsupported Node version, and confusion about which commands need credentials.

  • question
    satus: command not found

    The CLI was installed to a directory not on your PATH. Run `npm prefix -g` to find npm's global bin directory and add it to your shell's PATH, or reinstall with `npm i -g @passkeybridge/satus` after fixing your npm prefix.

  • question
    Which Node versions are supported?

    Node 18, 20, and 22 on macOS and Linux. Windows is supported via WSL2. Older Node versions are not tested and will likely fail at install or first run.

  • question
    Do I need any environment variables to run `satus init`?

    No. `init` only writes files into ./satus/ and needs neither DATABASE_URL nor OPENAI_API_KEY. The two variables become required at `satus plan` and `satus generate`.

§02|Schema errors

the planner refused to write.


The planner reads pg_catalog before any insert. When it sees something it can’t resolve safely it exits with a named code and writes nothing. Every error below is recoverable without database surgery.

  • question
    E_FK_CYCLE: foreign-key cycle could not be broken automatically

    Your schema has a cycle in its foreign keys, and every column on the cycle is NOT NULL with no DEFAULT and is not declared DEFERRABLE. satus refuses to guess which constraint to violate. Fix one of three ways: mark one side of the cycle nullable, add a column DEFAULT, or declare the constraint DEFERRABLE INITIALLY DEFERRED. The /docs/how-it-works page explains why each option works.

  • question
    E_DB_NOT_EMPTY: database has more than 10,000 user rows

    Safety guard. satus refuses to write into a database that already holds more than 10,000 user-table rows, because that's almost always a sign DATABASE_URL points at production by accident. If you really do mean to append seed data, re-run with --force. Better: point at a fresh Supabase/Neon branch or a Docker container.

  • question
    E_PROFILE_NOT_FOUND: profile name doesn't match

    The --profile value must match either one of the three bundled profiles (medical-booking, e-commerce, saas-subscriptions) or a Markdown file in ./satus/profiles/. Check spelling, check the directory you're running from, and check that `satus init --profile <name>` actually wrote the file.

  • question
    satus generated rows that violate a CHECK constraint I didn't think to declare in the profile

    The whole transaction will have rolled back, so your database is fine. File an issue with the CREATE TABLE statement and the CHECK constraint—the planner reads NOT NULL, FK, and unique constraints from pg_catalog, but CHECK predicates are out of scope for the 0.1.x line.

§03|LLM provider

your key. your bill. your retries.


satus calls OpenAI directly from your machine. Authentication and rate-limit errors come straight from the provider; we map them to stable exit codes so CI can branch on them.

  • question
    E_LLM_AUTH: OPENAI_API_KEY missing, malformed, or rejected

    Either the variable isn't set, doesn't start with `sk-`, or OpenAI rejected it (revoked, billing problem, wrong organisation). Check `echo $OPENAI_API_KEY` returns a value, and verify the key in the OpenAI dashboard. satus never proxies your key—the call goes from your machine directly to OpenAI.

  • question
    E_LLM_RATE_LIMIT: provider rate-limited the run

    satus retries with exponential backoff up to 5 attempts before giving up. If you hit a hard tier ceiling, drop --batch-size below the default of 50 (try 20), wait a minute, or upgrade your OpenAI tier. We never resell tokens—the bill is on your provider's dashboard.

  • question
    The run cost more than I expected.

    Use --max-cost <usd> to cap the spend; by default the planner refuses to proceed if the estimated cost exceeds $1.00. Always preview with `satus generate --profile <name> --dry` first—the planner prints `✓ estimated cost · $X.XX` before any LLM calls actually fire.

  • question
    Can I use Anthropic or Gemini instead of OpenAI?

    Not yet. OpenAI is the only supported provider at launch. Anthropic (ANTHROPIC_API_KEY) and Google (GOOGLE_API_KEY) are planned for 0.2; until then, the CLI will only read OPENAI_API_KEY.

§04|Runtime & rollback

what happens when a run dies mid-flight.


satus generate runs inside a single Postgres transaction. Most “is my database corrupted?” questions have the same answer: no, the transaction rolled back. The mechanics are covered in how it works.

  • question
    satus generate failed halfway. Is my database half-seeded?

    No. The entire run executes inside a single Postgres transaction. A failure—any failure, including Ctrl-C—rolls back to the state your database was in before you ran the command. There is nothing to clean up.

  • question
    Can I run satus generate twice in a row?

    Yes, against a fresh or empty database. If the first run committed successfully you'll trip the 10,000-row safety guard on the second; pass --force or truncate first. For CI loops, point at a database branch and reset between runs.

  • question
    How do I produce the same data twice for snapshot tests?

    Pass --seed <n>. Identical seed + identical schema + identical profile + same model version = identical rows. Across model versions reproducibility is best-effort; OpenAI does not guarantee deterministic output at a given temperature.

  • question
    Does satus need superuser access on Postgres?

    No. It needs SELECT on the catalog (pg_catalog, information_schema—both world-readable by default) and INSERT/UPDATE on the user tables you're seeding. A standard application role is enough.

§05|License & billing

activation, seats, refunds.


Free runs uncapped time-wise but caps each run at 25 rows per table across 5 tables; license-keyed activation lifts those caps and applies to Pro and Team. The CLI verifies once, caches for 24 hours, and works offline within that window.

  • question
    I bought Pro. How do I activate it on the CLI?

    Run `satus activate` and paste the license key from your purchase email. The CLI verifies the key against satus.sh once, caches the result for 24 hours, and works fully offline within that window.

  • question
    How do I check what tier I'm on?

    Run `satus whoami`. It prints the current license tier, the verification cache expiry, and the email the key is registered to.

  • question
    My team needs more than one seat.

    Team tier is on the waitlist—email support@satus.sh with how many seats you need and we'll prioritise. In the meantime, every developer can self-serve a Pro seat.

  • question
    Can I get a refund?

    Yes—within 14 days of purchase, no questions. Email support@satus.sh from the address on the order.

§06|Still stuck

open an issue. include the schema.


If nothing above matches, the fastest path to a fix is a GitHub issue with three things: the full stack trace (or the named exit code), the offending CREATE TABLE statement(s), and the satus version (satus --version). Schema reproduction is the single thing we triage hardest—the more faithful your repro, the faster the fix.

For private questions (procurement, security disclosures, anything you don’t want on a public tracker), email support@satus.sh. Humans answer; we aim to acknowledge within two business days.