Your first plan
Assume your desired schema begins with:
CREATE SCHEMA app;
CREATE TABLE app.accounts ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, display_name text NOT NULL);Establish replayable history
Section titled “Establish replayable history”onwardpg config checkonwardpg initinit creates and clone-verifies the first content-addressed history entry. It does not apply anything to your development or production database.
Evolve desired DDL
Section titled “Evolve desired DDL”Add a nullable status to the authoritative schema:
ALTER TABLE app.accounts ADD COLUMN status text;In a declarative schema file, write the resulting complete CREATE TABLE shape instead of the ALTER above. Then plan one feature:
onwardpg plan add-account-statusThe durable bundle appears under the configured bundle_root:
migrations/onward/app/add-account-status/├── manifest.json├── decisions.json├── plan.json├── phases/│ ├── expand.sql│ └── contract.sql└── verify.sqlReview every statement and hazard. Continue editing your models or DDL and rerun onwardpg plan; the same active feature bundle is recalculated rather than stacked into a trail of local fixups.
Prove the bundle
Section titled “Prove the bundle”onwardpg verify add-account-statusVerification independently replays the chosen checkpoint and its continuation, runs boolean assertions, compares the final graph fingerprint, and requires an empty residual diff.
Use the read-only CI form after the bundle is reviewed:
onwardpg verify --checkIf onwardpg exits with needs_decisions or needs_sql_edits, the bundle is intentionally incomplete. Follow the printed fingerprinted hint, replace any phase-local ONWARDPG TODO, and verify again.