Skip to content

Why noorm ​

I stopped using ORMs and needed something to run the SQL. Every other part of noorm answers a question I hit after that.

Which questions grew the tool? ​

Each row is a question I hit.

QuestionWhat it became
How do I run SQL?A folder of files, run in path order
How do I undo one?Forward and revert pairs
How do I test against it?A real database behind a requireTest guard
How do I write painful DDL and seed data?Templates that render SQL from YAML, and transfer
Where does connection configuration live?Configs you export to a teammate
How do I onboard someone onto four environments?Stages with required secrets
Where do team secrets live?A vault table inside the database
What ran, who ran it, and why did it break?History with the operator and the error
How do I re-run objects meant to be re-run?.txt manifests that run db/sql/ files

Why is the interface split in two? ​

noorm is the fifth attempt. I replaced each of the first three because I needed something more robust, one a new teammate could use without a manual. Then I moved to citty and @clack/prompts, and tried Ink.

Library, in the order I used itWhat it isIn noorm today
minimistargument parserno
cmd-tstype-driven argument parserno
oclifCLI frameworkno
cittyCLI builderthe commands in src/cli/
@clack/promptsinteractive promptsnoorm init, noorm change add
InkReact for the terminalthe TUI in src/tui/

Running commands means remembering commands. A screen that shows configs, pending changes, and schema while you decide beats typing a verb and hoping the flags are right.

noorm ui opens the TUI. The other commands take flags, so they run in scripts and CI (CLI reference).

Why templates? ​

Templates let seed data be written and iterated on, and let YAML become DDL that is miserable to write by hand. SQL Server scheduled jobs are the clearest case: a schedule written semantically renders into the DDL that creates the job. A YAML list of who gets what is readable and diffable, and the GRANT statements it renders into are not.

Why does history record the operator and the error? ​

Every applied change records its status, when it ran, who ran it, and the error message when it failed. A failure you fixed and re-ran can surface days later. The recorded error shows which run to trace back to, and the operator puts a name on a pattern of failures.

changelog.md in the change folder holds the reason for the change, next to the SQL it justifies. A .txt manifest lists the views, functions, and stored procedures a change re-runs, so fixing a stored procedure is a tracked change.

How do teams share environments? ​

A config exports from the TUI encrypted to the recipient's public key, without user and password, so the recipient supplies their own. Configs covers both export paths.

A template that reads an unset secret fails with Secret "KEY" not found (searched: config-local, global-local, vault). The vault keeps team secrets encrypted in the database (noorm.vault on PostgreSQL and SQL Server, __noorm_vault__ on MySQL and SQLite) at the lowest precedence, so a local value wins.

What changed when LLMs arrived? ​

Writing SQL stopped being the slow part. Reviewing SQL that an agent wrote quickly, confidently, and sometimes wrongly became the slow part. Three additions act before the agent writes, while it writes, and before its SQL runs.

  • ignatius model: the cheapest moment to catch a bad schema is before it exists, which became a separate tool, ignatius.
  • noorm skill: the agent skill teaches an agent this project's conventions.
  • access role, dry run, typed confirmation: per-channel access roles, --dry-run, and a typed confirmation on destructive operations.

Next ​