YYYYMMDDHHMMSS_name.sql: a 14-digit UTC prefix and lowercase descriptive name. Read ohmyhost init --dry-run --json for the exact source contract.
Ordinary schema migrations are expand-only. Admitted statements create tables, types, domains, sequences, views/materialized views, triggers, indexes or SQL/PLpgSQL functions (SECURITY DEFINER requires SET search_path); ALTER TABLE … ADD, COMMENT ON, CREATE SCHEMA IF NOT EXISTS auth|extensions|private, CREATE EXTENSION IF NOT EXISTS pgcrypto|btree_gist|unaccent, and SET check_function_bodies=false are the other allowed forms. Ordinary DROP/TRUNCATE, row changes, CREATE OR REPLACE, other schema ALTER, GRANT, DO and transaction control are refused. Supabase/storage dependencies, unsupported auth references and provider-role authority remain unsupported. Init reports migration_sql_not_admitted with the refused file/reason.
The coordinated 0.1.30 or later release adds a bounded RLS policy lifecycle: CREATE POLICY, ALTER POLICY conditions, atomic DROP POLICY/recreation and single ENABLE/FORCE statements on explicitly named, migrator-owned ordinary tables in public or private. Use TO PUBLIC or omit the role. Every touched table must finish enabled and forced. Only the provided ohmyhost.user_id() and ohmyhost.claims() helper calls are allowed within the reserved schema; platform objects remain protected. DISABLE/NO FORCE, CASCADE, role/grant changes and destructive schema changes are still refused.
Existing tables gain only nullable columns without defaults and non-unique indexes. Constraints, foreign keys, triggers and unique indexes may attach only to tables created within the same pending migration run. All pending files apply atomically with a thirty-second statement and five-second lock timeout; CREATE INDEX CONCURRENTLY therefore fails. Applied files are immutable: never edit, rename or remove one; every new timestamp follows the applied catalog. Maximum 128 files,256 KiB each,2 MiB total, UTF-8/LF without BOM.
Source planning checks canonical filenames, not complete SQL admission. Run init before paying for a build; execution/catalog validation may still fail as database_migration_failed, with none of the new files applied. Read DATABASE_MIGRATION_FAILED’s file and reason: MIGRATION_CHANGED_EXISTING_SCHEMA, MIGRATION_EXECUTION_FAILED, APPLIED_MIGRATION_CHANGED or MIGRATION_SQL_NOT_ADMITTED. Fix the cause and plan the new commit; never reset to repair a failed migration.