dist/cli.js.prorm with no arguments, or --help, prints the full flag reference.| Command | Does |
|---|---|
init [--directory <path>] | Scaffold config/, models/ and migrations/ with a zero-config SQLite setup. |
models pull [--out ./models] [--tables a,b] [--style define|class] [--lang ts|js] | Generate model files from a live database, any SQL dialect. model:create is an alias. |
migration:create -- --name <name> | New migration file. |
migration:run [-- --name <migration>] | Apply pending migrations. |
migration:revert [-- --name <m> | --steps <n>] | Roll back. |
migration:status | What has run and what has not. |
seeder:create -- --name <name> | New seeder file. |
db:seed [-- --name <s>] [--env <e>] [--force] | Run pending seeders, or one by name. |
db:seed:undo [-- --name <s>] | Undo one seeder, or the last one run. |
db:seed:undo:all | Undo every executed seeder, in reverse order. |
db:seed:status | What has been seeded. |
db:create / db:drop | Create or drop the configured database. |
prisma:import --schema ./schema.prisma | Convert a Prisma schema into prorm models plus an initial migration. |
diagram:<type> --file <spec.json> | Render one of 15 diagram types — see Diagrams below. |
packages | Pick the drivers this project uses and install only those. |
packages2 packages for what you picked:
npm install better-sqlite3 pg--run to execute it rather than print it.pg once — and picking Turso installs @libsql/client, notpg to connectpg-copy-streams only to stream a COPY, so the second is offered underCannot find module atinitProrm's own default — and reads DB_DIALECTDB_* environment variables to target something else.models pull (model:create)index that registers them andDataTypes call that recreates them; a type with no portable equivalent is--force;--dry-run prints instead of writing. See-- separator matters: flags after it go to the command rather than tonpm/npx. See Migrations for the file format and theQueryInterface you write against.db:seed runs everything pending; --name runs--force to re-run one that has already gone), --env scopes to andb:seed:undo:all walks the whole list back in reverse.prisma:importschema.prisma, writes one prorm model per Prisma model and an initialdiagram:<type>. Three of them accept a| Command | Input | Draws |
|---|---|---|
diagram:model | --file <model.json>, or --db <url> --table <t> | One table in detail: columns, types, keys |
diagram:er | --file <schema.json>, or --db <url> | Every model and the foreign keys between them |
diagram:migration | --file <migration.json> | What a migration does to a table |
diagram:class | --file <spec.json> | Models as UML classes |
diagram:relational | --file <spec.json> | A crow's-foot relational diagram |
diagram:chen | --file <spec.json> | ER in Chen notation: diamonds and ovals |
diagram:index | --file <spec.json> | Which indexes cover which columns |
diagram:schemadoc | --file <spec.json> | A data-dictionary sheet |
diagram:sequence | --file <spec.json> | The call order during a write |
diagram:state | --file <spec.json> | The states an instance moves through |
diagram:flow | --file <spec.json> | A read, from finder to instances |
diagram:tree | --file <spec.json> | A nested include, drawn as a tree |
diagram:dependency | --file <spec.json> | Create order, and its reverse for drops |
diagram:package | --file <spec.json> | How the ORM source is organised |
diagram:gantt | --file <spec.json> | A migration rollout over time |
| Flag | Does |
|---|---|
--file <path> | The JSON spec. Required for every type except when --db is given. |
--db <url> | Introspect a live database instead (diagram:model, diagram:er). |
--out <path> | Where to write the SVG. Defaults to ./diagrams/<type>.svg. |
--title <text> | Diagram title. |
--theme <light|dark> | Defaults to light. |
--color <accent> | industry (default), industry-2, blue, violet, emerald, amber, pink, sky, indigo, purple, red, teal, green, stone, or a #hex. |
--columns <n> | Grid width for diagram:er. Defaults to 3. |
--description <text> | diagram:migration only. |
schema, extension/enum/domain/sequence and maintain groups talkpsql ormysql prompt for, except they speak all 27 dialects, so the same invocation| Flag | Environment | Default |
|---|---|---|
--url | DATABASE_URL, DATABASE | — |
--dialect | DB_DIALECT, DIALECT | sqlite |
--database, -D | DB_NAME, DB_DATABASE (DB_STORAGE for SQLite) | database.sqlite |
--host | DB_HOST | localhost |
--port | DB_PORT | the dialect's default (5432, 3306, 1433, …) |
--username, -U | DB_USER, DB_USERNAME | — |
--password | DB_PASSWORD, DB_PASS | — |
--database shop_replica points an otherwise identical DATABASE_URL at a--database is the file path, andfile:./dev.db works as a URL.--dry-run--dry-run: it prints the SQL and never$ prorm maintain vacuum users --full --dialect postgres --database shop --dry-run
VACUUM (FULL) "users";maintain routine --dry-run therefore requires --tables rather than| Command | Does |
|---|---|
schema tables [--filter <substring>] | List tables. Aliased to tables. |
schema describe <table> | Columns, types, nullability, defaults, keys. Aliased to describe. |
schema indexes <table> | The table's indexes and their columns. |
schema views [--materialized] | Views, or materialized views. |
schema exists <table> | Exit 0 if present, 5 if not. Prints nothing. |
schema exists is written for scripts — it answers with its exit code, so it| Command | Does |
|---|---|
schema rename <from> <to> | Rename a table. |
schema drop <table> [--if-exists] [--cascade] | Drop a table (confirms first; --yes skips). |
schema index-add <table> <columns> [--name] [--unique] [--using] [--include] | Add an index. |
schema index-drop <table> <index> | Remove an index. |
schema comment <table> [text] [--column <c>] | Comment on a table or column; omit the text to clear it. |
QueryInterface method, so what the CLI can do here,| Command | Does |
|---|---|
extension create <name> [--schema] [--version] [--cascade] | Install an extension. |
extension drop <name> [--if-exists] [--cascade] | Remove one. |
enum create <name> <values> | Create a named enum type from a comma-separated list. |
enum add-value <name> <value> [--before | --after] | Add a member, leaving the columns using it alone. |
enum rename-value <name> <from> <to> | Rename one member. |
enum drop <name> [--if-exists] [--cascade] | Drop the type. |
domain create <name> --as <type> [--check] [--not-null] [--default] | Create a domain. |
domain drop <name> [--if-exists] [--cascade] | Drop it. |
sequence create <name> [--start] [--increment] [--cache] [--cycle] | Create a sequence. |
sequence set <name> <value> [--not-called] | Set its current value. |
sequence restart <name> [value] | Restart it. |
sequence next <name> | Take the next value, consuming it. |
sequence drop <name> [--if-exists] | Drop it. |
sequence set is the one to remember after a bulk load: rows inserted with--entry <module> (a Prorm instance, or a register(prorm)$PRORM_ENTRY. prorm_objects is the bookkeeping tableapply keeps in the database, so list and --prune know what prorm| Command | Does |
|---|---|
objects plan [--dialect <d>] [--sql] | The ordered, hashed plan for one dialect (defaults to the connection dialect); --sql prints every statement. Never connects. |
objects check --dialect <d>|a,b|all | Every refusal and warning for one dialect, several, or every engine family, at once. Never connects; exits 1 when there are errors. |
objects apply [--prune] [--dry-run] [--kind-change refuse|rename|drop] [--force] | Create and replace objects so the database matches the plan; --prune drops objects prorm created that are no longer defined; --kind-change says what to do when a model changed from a table to a view (refuse is the default; drop needs --force, the rows are lost). Uses the connection flags. |
objects list [--owner <o>] | The objects prorm created in this database, from prorm_objects; --owner is app, model:<Model>, a plugin or a pack. |
| Command | Does |
|---|---|
extensions list [--status] [--catalog] | Every extension marked installed, available, not-allowed (the service's allow-list excludes it) or unknown. |
extensions import <name…> [--schema] [--version] [--cascade] [--soname] [--dry-run] | Install: CREATE EXTENSION IF NOT EXISTS on the PostgreSQL family, INSTALL/LOAD on DuckDB, INSTALL PLUGIN/COMPONENT on MySQL/MariaDB, the driver's loadExtension on SQLite. Refused on engines without extensions. |
extensions import --from <manifest> [--source] [--latest] | Replay a manifest written by extensions export. |
extensions drop <name…> [--if-exists] [--cascade] [--dry-run] | Remove: DROP EXTENSION on the PostgreSQL family, UNINSTALL PLUGIN/COMPONENT on MySQL/MariaDB. Refused on DuckDB and SQLite, which have no statement that removes one. |
extensions export [--out] [--key] | Write name and version per database to prorm.extensions.json. |
aws, az or gcloud commanddb up runs a local database in Docker or Podman with a pinned image, generated.env, and the requested extensions installed| Command | Does |
|---|---|
db up [--dialect] [--ext] [--name] [--port] [--version] [--image] | Write docker/local-db/<name>/docker-compose.yml (plus a Dockerfile when an extension needs one) and .env, start it, install extensions. --no-start, --dry-run, --print-run. |
db down [name] [--volumes] | Stop it; --volumes deletes the data. |
db status [name] | Engine, image, port, health and redacted URL. |
db url [name] [--show-secret] | The connection URL, password masked unless --show-secret. |
| Command | Does |
|---|---|
maintain analyze [table] [--columns] | Refresh the planner's statistics. Aliased to analyze. |
maintain vacuum [table] [--full] [--analyze] [--into] | Reclaim storage. Aliased to vacuum. |
maintain reindex <target> [--scope] [--concurrently] | Rebuild indexes. Aliased to reindex. |
maintain routine [--tables] | Vacuum then analyze every table. |
maintain optimize <table> | Rebuild and defragment a table (MySQL family). |
maintain check <table> [--level] | Check for corruption; prints what the engine reports. |
maintain repair <table> [--quick] [--extended] | In-place repair (MySQL family). |
maintain checksum <table> | Checksum, for comparing two copies. |
maintain cluster <table> [--index] | Rewrite in an index's physical order (PostgreSQL). |
analyze is the one worth running on a schedule: a planner working from stalevacuum --full is the opposite — on PostgreSQL it takes an--dry-runcheck, repair, checksum) pass the--json when a script has to read it.prorm audit scans a project for patterns that weaken security, probes a| Command | Does |
|---|---|
audit code [path] | Static rules (SQL-001 … CFG-002) over TS/JS and committed .env/.klock files; --format table|json|sarif, --fail-on, --write-baseline --reason |
audit checklist [framework] | The checklists, or one checklist's items; --item <id> for one item and its crosswalk |
audit attest <item-id> | Record an attestation in .prorm/attestations/ (prompts, or --by --role --statement --expires --evidence) |
audit db | Read-only probes: TLS in use, role privileges, password hashing, RLS (--rls-tables), pgaudit, grants |
audit klock [path] | The klock checks (KLOCK-001 … KLOCK-008, and SEC-003 for .klock files) over the project, your own klock files (~/.prorm/klock/*.klock and the configured one, unless --no-home) and, signed in, the account probes; --offline, --report-days N, --fail-on |
audit run [path] | Everything, evaluated per checklist, into prorm-evidence-<slug>-<UTC>/; --db, --account (the klock account probes, signed in), --report-days, --sign-key |
audit verify <bundle> | Recompute every hash and check the ed25519 signature |
audit export <bundle> | --format evidence-json|evidence-csv for a GRC tool |
audit log | The account audit log. Bare audit still shows it for one minor release, with a deprecation note |
6 when an unsuppressed finding is at or above --fail-onhigh), 7 when nothing failed but some evidence could not beaudit klock asks the public /.well-known/klock-configuration whether the404 turns KLOCK-003, the v1-secret check, off), andGETs (/me/capabilities,/security/devices, /security/behaviour for admins, /security/access-rules).unknown, never a pass, and makes the exitaudit run --account refuses to runevidence/klock-account.json to the bundle. The checksprorm logs reads the ORM's own audit table (AuditLogs by default) over the| Command | Does |
|---|---|
logs levels [--ladder <name>] | Print a level ladder: names, ranks, syslog severities, aliases. Ladders: default, syslog, itil, sre and any you registered. |
logs presets [name] [--keyword <k>] | List the escalation presets, filtered by keyword, or print one as JSON to start your own policy from. |
logs tail [--level <filter>] | The most recent audit entries. --level warning is that level only, warning+ that level and above, info- that level and below, error..alert a range, a,b a list. |
logs escalations [--unacked] [--level <min>] | Escalated entries; with --unacked, open incidents grouped by key that nobody has acknowledged or resolved. |
logs tail and logs escalations share --table (default AuditLogs),--ladder, --limit (default 50) and --since (a duration: 24h, 7d).api.prod-orm.io — the same API the console uses. Sign| Group | Commands |
|---|---|
| Account | login, logout, whoami, status, step-up, auth token, account, account update, account emails, family, family child |
| Databases | db init, db serve, db up, db down, db status, db url, db list, db show, db create, db delete, db use, db update, db connect, db access, db env, db query, db tables, db describe, db push, db logins, db logins create, db logins rotate, db logins drop, db objects, db migrations, db migrate, db pause, db resume, db backup, db backups, db restore, db resize, db move, db replicas, db rotate-credentials, db ops, db events, db metrics, db usage, db open, engines, regions, stores, stores create, stores connect, stores delete |
| Keys | keys list, keys create, keys revoke, keys trace |
| Roles | roles list, roles create, roles show, roles update, roles delete, roles grant |
| Passwordless | passwordless issue, passwordless list, passwordless revoke, passwordless query, passwordless check, klock show |
| Transfer | transfer strategies, transfer quote, transfer create, transfer start, transfer run, transfer agent, transfer list, transfer show, transfer cancel |
| Base44 | base44 generate, base44 sync |
| Policies | policies catalog, policies show, policies assigned, policies assign, policies unassign, policies check, policies review, policies firings |
| Pools | pools list, pools create, pools update, pools close, pools buy |
| Security | security sessions (also sessions list), security revoke (also sessions revoke), sessions show, sessions rotate, sessions freeze, sessions unfreeze, devices list, devices show, devices rename, devices revoke, devices suspend, devices reinstate, devices wipe, devices pair (also devices approve), devices rotate-key, access list, access show, access allow, access block, access add, access rm, access test, behaviour list, behaviour presets, behaviour show, behaviour apply, behaviour set, behaviour rm, behaviour test, behaviour findings, lockdown, lockdown release, security audit (also audit log), security mfa enable, security mfa disable |
| Klock | klock status, klock verify, klock sync, klock rotate, klock upgrade, klock explain, klock cp, klock inbox, klock accept, klock refuse, klock receipt, klock init, klock keygen, klock agent, klock certs list (also klock certs), klock certs request, klock certs renew, klock certs revoke, klock kerberos status (also klock kerberos), klock kerberos issue, klock kerberos rotate, klock kerberos revoke (and klock show, under Passwordless) |
| Teams | teams list, teams create, teams use, teams members, teams invite, teams role, teams remove, teams accept, teams leave, teams delete, teams roles, teams projects, teams attach |
| Billing | billing plans, billing estimate, billing quote, billing subscription, billing invoices, billing checkout, billing portal |
| Config | config get, config set, config list, config unset, config path |
| System | ping, open, version, upgrade, completion (and __complete, which its scripts call), mcp, mcp clients list, mcp clients create, mcp clients revoke |
| Scaffold | new, add |
Schema, Catalog, Maintenance) are--help — but they127.0.0.1 on aConfirm code: K7QM2D (the console shows the same code — approve only if they match)~/.prorm/klock/<profile>.klock (0600, atomically), andGET /me. From then on every request is signed byprorm-cli (<host>) — is used when the API does not offer klock v2 (its/.well-known/klock-configuration answers 404, or 503klock_v2_unavailable), with --legacy, and with --token/PRORM_TOKEN.prorm login against an API that suddenly says "no v2" stops and asks for--legacy. The legacy token is kept in the OS keychain where there is one,security -i on macOS,secret-tool store on Linux), never as a command-line argument that psPRORM_NO_KEYCHAIN=1 keeps it (and the device key) in the 0600$ prorm login
Confirm code: K7QM2D (the console shows the same code — approve only if they match)
Sign in in the browser to connect this CLI:
https://app.prod-orm.io/#/cli?port=53117&state=…&host=ada-mbp&v=2&dpk=…&spk=…&sb=…&cc=K7QM2D
Waiting for the browser…
✓ Signed in as ada (ada@example.org) on this device (dev_01J9Z3K4M5N6P7Q8R9S0T1V2).
klock v2 interactive session · key in the macOS Keychain · ~/.prorm/klock/default.klock
Check in by 9/27/2026, 9:14:02 AM; the session ends 10/26/2026, 9:14:02 AM.
$ prorm whoami
ada <ada@example.org>
tier user
session interactive · device-bound · dev_01J9Z3K4M5N6P7Q8R9S0T1V2 · key in the OS keychain
check in by 9/27/2026, 9:14:02 AM (in 24h)
expires 10/26/2026, 9:14:02 AM
klock active · ~/.prorm/klock/default.klock
41 capabilities (grant); --caps lists them
API https://api.prod-orm.ioklock reads check-in-due once theexpired or idle when the~/.prorm/
config.json # API URL, default database, team, klock path; the legacy token when no keychain
config.<profile>.json # one per --profile
klock/
default.klock # the v2 session klock: device, grant, check-in (0600)
<profile>.klock
cache/
mcp-docs.json # prorm mcp's documentation-tool listing (24 h)prorm-klock when there is one, and in the klock file otherwise.PRORM_TOKEN (or prorm login --token).[!WARNING]
APRORM_TOKENis a bearer token: whoever holds it acts as you until it
expires or is revoked. Keep it in the CI system's secret store, never in
the repository, and revoke it (prorm sessions revoke <id>) when the
pipeline no longer needs it.
prorm whoami prints the tier (guest, user, team, admin), the teamcheckInBy: after it, only the public commands workprorm step-up--totp), and any command that meetsstep_up_required offers the same prompt on a terminal and retries once.prorm login does, in order (src/cli/basic/commands/auth.ts):--token <t> (or --token - to be prompted), orPRORM_TOKEN in the environment with none of --guest, --device,--pair or --legacy, stores that legacy token once GET /me accepts--pair goes straight to pairing (below). With--no-input (or $CI) anything else stops with prorm login` needs a
browser. In a non-interactive environment pass --token. (exit 2),--guest and --device --totp <code>. --legacy runs the legacyGET /.well-known/klock-configuration"v2": true means--guest and --device say the feature is coming soon (exit 1).klockV2Seen in its config)klock v2 is not available on <api> (…), and this CLI signed in
with v2 before. Refusing to fall back silently: run `prorm login --legacy`
if you mean it. (exit 3). Any other CLI says why and runs the legacy~/.prorm/klock/<profile>.klock, or beside --config/$PRORM_CONFIG)prorm-klock as pending:<thumbprint> until thestate, and the first sixbase32(sha256(state ‖ thumbprint)). The CLI printsConfirm code: K7QM2D (the console shows the same code — approve only if they match).127.0.0.1, on a port thePOST /callback, with CORS for the console's<console>/#/cli?port=…&state=…&host=<hostname>&v=2&dpk=<signPub>&spk=<sealPub>&sb=<sealBinding>&cc=<code>,&kind=device with --device and &team=<t> with --team.--no-browser only prints the link.POST /security/klock/sessions. The API recomputes the code from stateconfirm_code_mismatch, which--device session also needs a fresh step-up.{state, grant, sessionId, deviceId,
deviceCert, keyset, v: 2} to the listener. When the browser cannot reachGET /security/cli-logins/<state>, polled every 2 seconds). The state is409. After five minutes1). A parked grant is bound to this device's key,klockV2Seen refuses itklock_downgrade).seq is not below the cached/.well-known/klock-keys.json. It then checks the grant:kid, its Ed25519 signature, and that it names this device key'siss is--api-url. The keychain entries move to the device id, and the klock isversion: 2, kind, api, klock,device, and session (id, grant, grantSeq, syncSeq, syncedAtcheckInBy). The config records the klock's path and, except for aklockV2Seen: true. It forgets any legacy token.GET /me. The CLI prints who you are, the--device on a machine already signed in with v2 skips the browser. ItPOST /security/klock/sessions,--totp), then signs out the interactive session it replaces.--guest is refused on a CLI signed in to an account (prorm logout2). Otherwise it sends a device-signedPOST /security/klock/guest and stores the guest grant.--pair starts a pairing on the klock service (POST /v2/pair/start,KXQ7-M2PD, a prorm://pair?… QR link and a console link, for aprorm devices approve <code>) or the console#/pair). It polls GET /v2/pair/<id> until the pairing is approved or3 if it is not approved. The code is never stored by the service,prorm login printed and you approve it, their machine--db <id|uuid|name>; set a default once andselect, insert, update, delete--wait follows it to the end; prorm db ops --op <id> --wait follows it--cancel and --retry do what they say.prorm engines lists every engine and whether this deployment can build asqlite) and the postgres| Engine | Built on | Reached by |
|---|---|---|
postgres, mysql | Cloud SQL | a connection string (db connect) |
bigquery | BigQuery dataset | HTTPS, with an api key |
redis | Memorystore | a private VPC endpoint |
firestore | Firestore | HTTPS, with an api key |
gcs | Cloud Storage bucket | HTTPS, with an api key |
provisioning--wait is worth passing:db push runs each migration file's up() once against a recorder thatcreateTable, addColumn, addIndex and the rest — and sendsSTRING(120), BOOLEAN), and thebulkInsert is refused by name before anything is sent, because adb events --follow tails theprorm-cli is the CLI on its own: one file, no database drivers.$ npm i -g prorm-cli
$ prorm login$ pnpm add -g prorm-cli
$ prorm login$ yarn global add prorm-cli
$ prorm login$ bun add -g prorm-cli
$ prorm loginnpx prorm-cli login.schema, catalog, maintain, db push, migrations,prormts-prorm-orm installed in the current project and saysGRANT on the engine:.klock — a file.klock is the same file the outh Go tool writes and reads, and theREDIS_REST_URLREDIS_REST_TOKEN; without them each instance counts on its own and thebase44/entities/{kebab-case}.jsonc files that npx base44 entities pushbase44 generate writes exactly those files from your models; theid, created_date and updated_date. base44 sync writes them, shows what--plan to apply). It never touches an entity file your code does not define.base44 entities push is a full-folder sync: it replaces the app's entitybase44/entities/, so any entity on the app that is not aUser and anything made in thesync warns about this (and points out a missinguser entity specifically) and asks before pushing; pass --yes/-y touser.jsonc if you use Base44 auth).Base44.toBase44Entity(Model) writing throughBase44.fileBase44Client('base44/entities'), or the fullBase44.Base44Connector for the plan/apply loop; Base44.httpBase44Client--json; a list prints an array, a show/security/sessions,/security/devices, /security/access-rules, /security/behaviour and/security/lockdown routes. Against a server that does not offer one (a501, 405, a bare 404, or 503 klock_unconfigured when the API has no1.sessions, sessions list and sessions revoke are the same commands assecurity sessions and security revoke. Only a session can rotate its ownsessions rotate takes current (service sessions rotate throughprorm passwordless).device:read to list and device:manage to404, the same as one that does not--team <t> lists or revokes a team member's device, and needs a teamdevice:manage-members (owner, admin, security). Revoking--reason; the member is emailed, and therevoke ends the device's sessions first, then revokes the device andsuspend stops itreinstate undoeswipe ends its sessions, suspends it and queues an API-signedwipe command for its next sync: best effort, and only klock material is409 to a wipe.devices pair without a code starts pairing on the new device,prorm login --pair. With a code it approves: --kind device (theinteractive, which must match what the new device asked for409 pairing_kind_mismatch). Approving a device needs a fresh step-upprorm step-up first). A code works once (409 pairing_used), for ten410 pairing_expired), and an unknown code is404 pairing_not_found. Approvals are limited to 10 an hour.ip, country, asn, device,cert, principal, time, client or api-key, on the account (default),team:<t>, db:<d>, store:<s> or device:<id>. Block beats allow; themandatory) allowlists, which409 would_lock_you_out); --force--enforce-now (--report-only asks for report mode--mandatory makes an allowlist one that narrower scopes cannot--until takes a duration24h, 7d) or a date. access test exits 1 when the answer is "denied".prorm db access is the database's network firewall, a different layer.)behavior) describe what normal looks like —--mode enforce to enforce at once). Besides the access-rule scopes, asession:<id> or service:<id>.--include-services), the klock service is asked423 lockdown, even from sessions signed in afterwards, exceptLOCKDOWN (or --yes) and alockdown release needs a sign-in from the last 15 minutes plus aprorm devices reinstate. Locked out#/recover):login, whoami, sessions, devices) failsprorm klock explain prints the whole entry. klock status exits 5 whenklock verify exits 3 when the fileklock upgrade never upgrades silently: it rewrites a version 1 file asouth and--drop-secret removes the secret--no-bind only rewrites the file. When the APIPOST /provision/databases/:id/passwordless/:sid/bind, which the database'saccess:write) may call; binding makes the passwordless session aservice session held by this key (seeprorm transfer create … --local --klock-v2 gives the on-device agent its own~/.prorm/transfer-agent/<job>.klock, and prorm transfer agent then signsklock accept shows the sender, their device and every file first, then~/Downloads/prorm-klock/<id>/ by default, or--into. It refuses absolute paths, .., names over 255 bytes, symlinks--max-bytes (2 GiB by default); it never replaces an existing file without--force (and never a symlink or special file even then), checks every--keep-mode.klock inbox --sent lists what this device sent, with each transfer'sklock accept --json includes receipt, the relay's signed receipt.klock refuse <id> declines an offer (the ciphertext is deleted and therefused), and klock receipt <id> shows a transfer'sklock key: completed, refused, cancelled or expired, the bytesklock cp takes--reason (required for support:) and --max-bytes. Who may send what,503 klock_unconfigured and these commands say file transfer is coming soon,1.POST …/passwordless/enrol, or the MCP toolprorm_issue_passwordless_binding); the host redeems it:$ prorm klock keygen
✓ Created device key for ./.klock.
thumbprint …
public key …
seal key …klock keygen [file] [--rotate] writes a v2 kind: "service" klock holding./.klock, or $OUTH_KLOCK).--rotate replaces it only before2) with a pointer toprorm klock rotate. A version 1 file is refused, with a pointer toprorm klock upgrade. --json adds sealBinding andaction: created|rotated|existing.$ prorm klock init --service --ticket "$ENROL_TICKET"klock init --service [--ticket <t>] [--database <id|uuid>] [--force] [file]POST /provision/databases/:id/passwordless/redeem with the ticket and$PRORM_ENROL_TICKET, and--database defaults to the one the ticket names. It writes a v2 servicesecret, then checks the grant against the pinned keys. Without a ticketklock keygen is reused. An--force (exit 2); a refusedticket_invalid, ticket_expired, ticket_used, …) leaves no bound$ prorm klock agent ./.klockklock agent [file] [--once] [--no-channel] is the long-running daemon. The$OUTH_KLOCK, else this profile's./.klock; it must be a version 2 file with an enrolled3. It syncs on the server's nextSyncAftercheckInBy minus 10 minutes), at once oncheckInBy is within 10 minutes it checks inPOST …/security/klock/sessions/:id/refresh), renews provider credentialslogout, wipe and a revocation3. It logs one line per event to stderr[klock agent] <time> …), and SIGTERM or SIGINT stop it cleanly (exit 0).--once runs one round and exits 0 (all succeeded), 1 (something failed)3 (the session or device is gone), with the round's report under--json: that suits cron, systemd timers and CI. --no-channel syncs onExecStart=prorm klock agent /srv/app/.klock and Restart=on-failure.klock upgrade now stores the bind's answer in the file too: the servicegrantSeq and checkInBy (so klock agent can keepapi when the file had none, and the keyset beside it (soklock status verifies the grant offline). --json gains sessionId andprotocol (v1+v2 or v2). --drop-secret binds with protocol v2 first,200 rebound). If the server cannot take the session as v2 it refuses2) and keeps the secret. It cannot be combined with --no-bind.klock certs list [--file], request [--file],renew [id] [--if-due] [--file] and revoke [id] [--reason] [--file]prorm-klock,tls:<deviceId>), or in the 0600 klock for a device whose key store isfile. renew and revoke default to the installed certificate. Theyklock:sync.klock kerberos status [--file], issue [--file],rotate [--file] and revoke <id> [--reason] [--file] manage thisouth spnego opens it when a ticket is needed. They needkerberos:manage.--file points at another klock, for example a host's ./.klock;--days, default 30). It never holds an admin capability, orsession:manage, device:manage, access-rule:*, behaviour:*,billing:manage, team:manage-members, device:manage-members,session:manage-members or mcp:clients (the delegated kind mask); the*) before it asks the API. The token is shown once. How theprorm mcp runs the local MCP server on a narrowed child token holdingprorm mcp --full runs on--full with --caps is a usage error. Details inprorm mcp --caps a,b [--hours 1–24] runs the local MCP server on aprorm mcp (<host>)), serves every call through it,--hours (default 12), and revokes theprorm mcp: --caps needs your own session, not an MCP client token. Not started.delegated mask asmcp clients create, which also refuses device:manage-members,session:manage-members, access-rule:team and behaviour:team. Detailsprorm adminprorm: prorm admin <command>. Theyprorm-admin; a namespace rather than bareteams, team and me already mean something in prorm.--help, "did you mean" suggestions and completion, andprorm admin users answers exactly as a command that was never registeredprorm help admin … too). An admin sees them in --help, groupedAdmin: …, and prorm admin alone lists the ones they may use.admin:<scope> — one per adminadmin:users, admin:billing, admin:email, …; the table issrc/cli/core/command-needs.ts) — and the API enforces it on every request,admin users is refusedadmin me lists the ones it holds.grant-admin, which only the generalprorm step-up first).assume scope (the support and general presets carry it), anassume hands back a token that is the customer's. Give it to prorm forPRORM_TOKEN, or with --save as a profile:billing,resources, the profile, teams and family only withusers — never more than the admin could touch anyway, narrowed to one/admin answers to an assumed token, so assuming an admingrant-admin) borrows none of its powers. The customerprorm-admin and prorm-teamprorm:| Old | Now | Notice |
|---|---|---|
prorm-admin users | prorm admin users (every staff command gains admin; login, logout, whoami, status, ping and version pass through, and prorm-admin login still opens the staff console) | prorm-admin is now `prorm admin`; this alias is removed in 4.10 |
prorm-team teams members | prorm teams members (argv unchanged: its commands were always teams …) | prorm-team is now `prorm` (its commands are `prorm teams …`); this alias is removed in 4.10 |
PRORM_ALIAS andbin/prorm.js. prorm-admin can is prorm admin can for now; prorm
whoami --caps is its replacement.src/capabilities.ts (the map is src/cli/core/command-needs.ts). Localconfig,init/migration:*/db:*/diagram:* — needlocal:use, which everyone has: they never ask you to sign in and never waitresource:read, key:write, team:manage-members, …), and before one runs/me/capabilities, cached for an hour; signed| The view says | What happens |
|---|---|
| allowed | It runs. |
| sign in (you are signed out) | Sign in to use `prorm db list`: prorm login, exit 3. |
| step up (an admin capability is dormant) | On a terminal, it asks for an authenticator code and carries on; with --no-input or no terminal, prorm <cmd>` needs a fresh step-up. Run `prorm step-up` first., exit 3. |
| sync (the grant is past its check-in time) | It syncs with the klock service and looks again; if the sync fails (offline), it runs and the API decides. |
| denied | Exit 3 with what would unlock it: a plan upgrade (prorm billing plans), another team role, or nothing the CLI can offer. |
--json the refusal is JSON on stdout: {"error", "needs", "unlock"}unlock is login, upgrade, team-role, step-up, sync or none).step_up_required gets the step-upcapability_missing prints its unlock hint, and any otherWhat to do (<code>) with the fix and a link toprorm --help lists what you may use. A group you can use none of gets oneTeams — sign
in to unlock (prorm login)); staff groups get nothing.--json, and the framework supports table, json,csv and tsv, so they compose with jq and friends:--json, prose (progress, hints, warnings) goes to stderr and only the$ prorm teams members --json # signed out
{
"error": "Sign in to use `prorm teams members`: prorm login",
"needs": "team:read",
"unlock": "login"
}
$ echo $?
3| Flag | Does |
|---|---|
--json | Raw JSON on stdout. |
--output, -o <fmt> | table (default), json, csv, tsv. |
--quiet, -q | Suppress everything but errors and the actual answer. |
--verbose | Debug output, including every HTTP request and the SQL the live-database commands run. |
--color / --no-color | Force colour on or off; auto-detected otherwise. |
--api-url <url> | Override the API base URL for one run. |
--team <id> | Team context for one run. |
--yes, -y | Pre-confirm prompts (db delete, roles delete, …). |
--no-input | Never prompt; a prompt resolves to its default. Implied by $CI. |
--profile <name> | Use a named config profile (~/.prorm/config.<name>.json). |
--config <path> | Use an alternate config file. |
--no-truncate, --wide | Do not trim wide table columns to the terminal. |
--timeout <sec> | HTTP timeout. |
0 ok,1 error, 2 usage (bad flag or missing argument), 3 auth, 4 network,5 not found, 6 findings (prorm audit), 7 inconclusive evidenceprorm audit), 124 timeout. schema exists uses 5 deliberately.<command> --help prints that command's own arguments, flags, defaults,prorm --help lists every command by group.databases, keys,roles, policies, sessions, audit, query, trace, pq (forpasswordless query), me, and tables, describe, analyze, vacuum,reindex for their schema/maintain forms.$ prorm completion zsh >> ~/.zshrc # or: > "${fpath[1]}/_prorm"$ prorm completion bash >> ~/.bashrc$ prorm completion fish > ~/.config/fish/completions/prorm.fishprorm __complete -- <words…>, whichprorm completion again forsrc/cli.ts as a direct dispatch. Everything else is asrc/cli/basic/commands, each exporting a commands: Command[] arraysrc/cli/core/framework.ts. The live-databasesrc/cli/core/connect.ts, which resolves the--dry-run by capturing the statements a query-interface call would have run. An unknownsrc/cli/admin/commands.ts, are registered in the sameprorm admin …. src/cli/admin/program.ts andsrc/cli/team/program.ts are only the one-release aliases: src/admin-cli.ts andsrc/team-cli.ts (the ORM's bins) and the standalone package's PRORM_ALIASprorm. resolveCommand matches the longestadmin inbox addresses add).src/cli/core/command-needs.ts, applied byregister() when a command does not set needs itself, so command modulesrunRegistered (src/cli/core/framework.ts); the views it readssrc/cli/core/capability-view.ts, which both entry points install.Command declares its name (which may be namespaced with a space, likedb add), description, group, aliases, positionals, flags — with types,required — examples, and a run function. Adding asrc/cli/basic/commands/index.ts; there is no central switch to edit.export const commands: Command[] = [{
name: 'db list',
group: 'Databases',
description: 'Your databases.',
examples: ['prorm db list --json'],
async run() {
const { databases } = await api<{ databases: Database[] }>('/provision/databases');
out.table(databases.map((d) => ({ id: d.id, name: d.name, engine: d.type })));
return 0;
},
}];src/cli/core/cloud.ts: the config file and keychain,resolveDatabase(), which turns an id, uuid or