Command Reference
This page documents every command group available in the Foir CLI. Commands follow a consistent foir <group> <action> pattern. All commands support the global --json, --jsonl, --quiet, and --project flags described in the CLI Overview.
Authentication & Setup
login
Authenticate the CLI via browser-based OAuth. Opens your default browser to sign in and writes a session token to ~/.foir/credentials.json once you complete the flow. Run this first on any new machine.
foir login [options]| Option | Description |
|---|---|
--device | Use the device flow: approve on any device with a short code (for SSH, containers, CI). Auto-selected when no local browser is detected. |
--no-browser | Authenticate without a local browser callback by pasting a one-time code back into the terminal. |
The default login flow:
- Opens your default browser at the Foir sign-in page.
- You sign in (or pick an existing session).
- The browser hands a short-lived authorization code back to the CLI listening on a local port.
- The CLI exchanges the code for a session token and saves it to
~/.foir/credentials.json.
When no local browser is detected (SSH, containers, CI), foir login automatically falls back to the device flow — it prints a short code and a URL to approve on any other device, then waits for approval. Pass --device to force this, or --no-browser to paste a one-time code back into the terminal instead.
Examples
# Default: opens a local browser
foir login
# Headless: approve a short code on any device (SSH / containers / CI)
foir login --device
# Out-of-band: paste a one-time code back into the terminal
foir login --no-browserlogout
Clear stored credentials. Removes ~/.foir/credentials.json and any cached session state.
foir logoutwhoami
Show the current authentication status — which user is signed in, which tenant + project are active, and which credentials file is in use.
foir whoamiUseful for confirming you’re operating on the project you think you are before running a destructive command. Combine with --json to script against the output.
select-project
Pick the active project for subsequent CLI calls. Lists every project your session has access to, provisions a scoped API key, and writes the selection to .foir/project.json at your repository root so later commands don’t need a --project flag.
foir select-project [options]| Option | Description |
|---|---|
--project-id <id> | Skip the interactive picker and select a project directly. |
--save-as <name> | Save the selection as a named profile (see foir profiles). |
Examples
# Interactive picker
foir select-project
# Switch without the prompt
foir select-project --project-id prj_abc123
# Save the selection as a profile so you can switch back later
foir select-project --project-id prj_abc123 --save-as stagingprofiles
Manage named project profiles — bookmarks for tenant/project combinations so you can switch between environments (dev, staging, prod) without re-running select-project each time. Each profile is just a saved { tenantId, projectId } pair pinned to a name.
| Command | Description |
|---|---|
foir profiles list | List all saved profiles |
foir profiles show [name] | Show details of a profile (or the active one if no name) |
foir profiles default [name] | Show or set the default profile |
foir profiles delete <name> | Delete a named profile |
| Option | Applies to | Description |
|---|---|---|
--confirm | delete | Skip confirmation prompt. |
Activate a saved profile with the global --project <name> flag (see CLI Overview).
Examples
# List profiles
foir profiles list
# Inspect the active profile
foir profiles show
# Set the default profile so naked CLI calls use staging
foir profiles default staging
# Remove a profile
foir profiles delete old-tenant --confirmworkspaces create
Create a workspace from the terminal. You become its owner, it starts on the free plan, and it comes with a default project — the same atomic flow as the dashboard’s New workspace. While public sign-ups are closed, workspace creation is declined server-side (your account and any workspaces you’ve been invited to are unaffected).
foir workspaces create --name <name> [options]| Option | Description |
|---|---|
--name <name> | Workspace name (required). |
--project-name <name> | Name for the default project. Defaults to "<name> Project". |
--select | Make the new workspace’s default project the active CLI context (same save path as select-project). |
Examples
# Create a workspace and start pushing immediately
foir workspaces create --name "Acme Studio" --select
foir push
# Scripting-friendly output
foir workspaces create --name "Acme Studio" --jsonprojects create
Create a project in a workspace you own. Requires the projects:write permission in that workspace (owners have it).
foir projects create --name <name> [options]| Option | Description |
|---|---|
--name <name> | Project name (required). |
--tenant <id> | Workspace to create the project in. Defaults to your active session workspace; with several workspaces and no default, an interactive picker opens. |
--select | Make the new project the active CLI context. |
Examples
# Create in the active workspace and switch to it
foir projects create --name "Marketing Site" --select
# Target a specific workspace
foir projects create --name "Marketing Site" --tenant ten_abc123Content Management
records
Manage content records within a model.
| Command | Description |
|---|---|
foir records list <modelKey> | List records for a model |
foir records get <modelKey> <idOrKey> | Get a record by ID or natural key |
foir records create <modelKey> | Create a record |
foir records update <modelKey> <id> | Update a record’s data column directly (bypasses versioning) |
foir records save <modelKey> <id> | Atomic draft save (data + new version + currentVersionId bump) |
foir records delete <modelKey> <id> | Delete a record |
foir records publish <versionId> | Publish a record version |
foir records unpublish <id> | Unpublish a record |
foir records duplicate <modelKey> <id> | Duplicate a record |
foir records versions <recordId> | List versions for a record |
foir records variants <recordId> | List variants for a record |
foir records create-version <parentId> | Low-level: create a version row without touching the parent |
foir records create-variant <recordId> | Create a variant |
| Option | Applies to | Description |
|---|---|---|
--filter <expr> | list | Filter expression (e.g. status=active). See Filtering. |
--first <n> | list, versions | Page size. Default: 20. |
--after <cursor> | list | Cursor for the next page (from prior pageInfo). |
--resolved | get | Include resolved content (published version). |
--preview | get | Resolve the latest draft instead of the published version. |
--locale <locale> | get | Locale for field translations. |
-d, --data <json> | create, update, save, create-version | Data as a JSON string. |
-f, --file <path> | create, update, save, create-version | Read data from a file. |
-m, --message <msg> | save, create-version | Change description. |
--variant <key> | save | Save into a specific variant. |
--natural-key <key> | duplicate | Natural key for the duplicate. |
--key <variantKey> | create-variant | Variant key (required). |
--confirm | delete | Skip confirmation prompt. |
updatevssave:records updatewrites the record’sdatacolumn directly and does not create a version or movecurrentVersionId— preview/storefront won’t see the change.records saveis the admin “Save Draft” equivalent: it replaces data, writes an immutable version row, and advancescurrentVersionIdin one atomic step.
Examples
# List published records, page size 10
foir records list blog-post --filter "status=published" --first 10
# Get a record by natural key (model key is positional)
foir records get page hello-world
# Get the resolved published content
foir records get page hello-world --resolved
# Create a record from a JSON file
foir records create page --file page.json
# Atomic draft save (data + version + currentVersionId)
foir records save page clx123 --file page.json --message "Update hero copy"
# Publish a version by its version ID
foir records publish ver_abc123
# List all versions of a record
foir records versions clx1234567890models
Manage content models (schemas).
| Command | Description |
|---|---|
foir models list | List all models |
foir models get <key> | Get a model by key |
foir models create | Create a model |
foir models update <key> | Update a model |
foir models delete <key> | Delete a model |
foir models versions <key> | List schema versions for a model |
| Option | Applies to | Description |
|---|---|---|
--category <cat> | list | Filter by category. |
--search <term> | list | Search by name. |
--first <n> | list, versions | Max results. Default: 50 for list, 20 for versions. |
--after <cursor> | list | Opaque cursor from a previous page. |
-d, --data <json> | create, update | Model data as a JSON string. |
-f, --file <path> | create, update | Read model data from a file. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List models in a category
foir models list --category content
# Search models by name
foir models list --search blog
# Create a model from a JSON file
foir models create --file blog-post-model.json
# Update a model by key
foir models update blog-post --file blog-post-model.json
# View schema version history (by model key)
foir models versions blog-postlocales
Manage locales for content localization.
| Command | Description |
|---|---|
foir locales list | List all locales |
foir locales get <idOrCode> | Get a locale by ID or code |
foir locales default | Get the default locale |
foir locales create | Create a locale |
foir locales update <id> | Update a locale |
foir locales delete <id> | Delete a locale |
Examples
# List all locales
foir locales list
# Get a locale by code
foir locales get en-US
# Get the default locale
foir locales default
# Create a new locale
foir locales create --data '{"locale":"fr-FR","displayName":"French","nativeName":"Francais"}'media
Upload and manage media files. The media group handles file uploads via the storage service, while file metadata commands are available through the dynamic files group.
| Command | Description |
|---|---|
foir media upload <filepath> | Upload a file |
foir media list | List files |
foir media get <id> | Get file details |
foir media update <id> | Update file properties |
foir media update-metadata <id> | Update alt text, caption, description |
foir media delete <id> | Delete a file |
foir media restore <id> | Restore a deleted file |
foir media usage | Get storage usage stats |
Examples
# Upload a file to a specific folder
foir media upload ./images/hero.jpg --folder banners
# List files filtered by folder
foir media list --folder banners
# Search for files
foir media list --search "hero"
# Update file metadata
foir media update-metadata clx123 --alt-text "Hero banner image" --caption "Welcome banner"
# Check storage usage
foir media usage
# Permanently delete a file (cannot be restored)
foir media delete clx123 --confirm --permanentfiles
Inspect and manage files in the media library. For uploads use foir media upload; this group covers everything after upload — listing, renaming, tagging, moving between folders, editing alt text and captions, and reporting storage usage.
| Command | Description |
|---|---|
foir files list | List files |
foir files get <id> | Get a file by ID |
foir files usage | Storage usage statistics |
foir files update <id> | Update file properties (filename, folder, tags) |
foir files update-metadata <id> | Update alt text, caption, description |
foir files delete <id> | Delete a file |
| Option | Applies to | Description |
|---|---|---|
--folder <folder> | list, update | Filter by folder / move to folder. |
--mime-type <type> | list | Filter by MIME type. |
--search <term> | list | Search by filename. |
--first <n> | list | Max results. Default: 50. |
--after <cursor> | list | Opaque cursor from a previous page. |
--filename <name> | update | New filename. |
--tags <tags> | update | Comma-separated tags. |
--alt-text <text> | update-metadata | Alt text. |
--caption <text> | update-metadata | Caption. |
--description <text> | update-metadata | Description. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List images in the /banners folder
foir files list --folder banners --mime-type image/jpeg
# Search by filename
foir files list --search hero
# Move a file to a different folder
foir files update clx123 --folder archive
# Tag a file
foir files update clx123 --tags "homepage,launch,q2"
# Add alt text + caption for accessibility / SEO
foir files update-metadata clx123 \
--alt-text "A woman walking through a field of barley at sunrise" \
--caption "Spring '26 campaign"
# Storage usage summary
foir files usage --jsonsearch
Search across all records globally.
foir search <query> [options]| Option | Description |
|---|---|
--models <keys> | Filter to specific model keys (comma-separated) |
--first <n> | Maximum number of results (default: 20) |
Examples
# Search across all content
foir search "getting started"
# Search within specific models
foir search "pricing" --models page,blog-post --first 5
# Output as JSON for scripting
foir search "hello" --jsonrollouts
Manage rollouts — bulk scheduled-publishing batches that promote a mixed set of records, models, operations, auth providers, and other publishable resources together at a chosen time. The admin equivalent is Scheduled Publishing → Rollouts; see Scheduled Publishing for the feature overview.
| Command | Description |
|---|---|
foir rollouts list | List rollouts |
foir rollouts get <id> | Get a rollout (with its items) |
foir rollouts create | Create a rollout |
foir rollouts update <id> | Update name, description, or scheduledAt |
foir rollouts delete <id> | Delete a rollout before it runs |
foir rollouts trigger <id> | Trigger a rollout immediately (ignore its scheduled time) |
foir rollouts pause <id> | Pause an in-flight rollout |
foir rollouts resume <id> | Resume a paused rollout |
foir rollouts retry <id> | Retry failed items in a rollout |
foir rollouts rollback <id> | Roll back a completed rollout |
foir rollouts add-items <id> | Add items (records / models / operations / etc.) to a rollout |
foir rollouts remove-items <id> | Remove items from a rollout |
| Option | Applies to | Description |
|---|---|---|
--status <status> | list | Filter by status. |
--first <n> | list | Page size. |
--after <cursor> | list | Opaque cursor from a previous page. |
-d, --data <json> | create, update, add-items, remove-items | Payload as a JSON string. |
--file <path> | create, update, add-items, remove-items | Payload from a JSON file. |
--preview | rollback | Preview the rollback without executing — useful for confirming scope. |
--confirm | delete, rollback | Skip confirmation prompt. |
Note on lifecycle: use
deletefor rollouts that haven’t been triggered yet,rollbackfor ones that have. The CLI rejects mixing these.
Examples
# Create a rollout scheduled for next Monday
foir rollouts create --data '{
"name": "Weekly Release",
"scheduledAt": "2026-05-19T09:00:00Z",
"items": [
{ "kind": "record", "versionId": "ver_abc123" },
{ "kind": "record", "versionId": "ver_def456" }
]
}'
# Inspect the rollout, including its items
foir rollouts get rollout_abc123 --json
# Add more items to a draft rollout
foir rollouts add-items rollout_abc123 --file ./additional-items.json
# Trigger immediately, skipping the scheduled time
foir rollouts trigger rollout_abc123
# Pause while it runs, then resume
foir rollouts pause rollout_abc123
foir rollouts resume rollout_abc123
# Retry items that failed during the run
foir rollouts retry rollout_abc123
# Preview a rollback before committing
foir rollouts rollback rollout_abc123 --preview
# Execute the rollback
foir rollouts rollback rollout_abc123 --confirm
# Delete a rollout that never ran
foir rollouts delete rollout_abc123 --confirmCustomers and Targeting
customers
Manage customer accounts.
| Command | Description |
|---|---|
foir customers list | List customers |
foir customers get <idOrEmail> | Get a customer by ID or email |
foir customers create --email <email> | Create a customer |
foir customers delete <id> | Delete a customer (hard delete for GDPR) |
| Option | Applies to | Description |
|---|---|---|
--status <status> | list | Filter by status (ACTIVE, PENDING, SUSPENDED). |
--search <term> | list | Search by email. |
--first <n> | list | Max results. Default: 20. |
--after <cursor> | list | Opaque cursor from a previous page. |
--email <email> | create | Customer email (required). |
-d, --data <json> | create | Additional customer data as a JSON string. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List active customers
foir customers list --status active
# Get a customer by email
foir customers get user@example.com
# Create a customer
foir customers create --email new@example.com
# Create a customer with extra data
foir customers create --email new@example.com --data '{"name":"New User"}'Profile schemas: A customer’s profile fields are declared in
foir.config.tsand reconciled withfoir push— there is no standalone CLI command for editing the profile schema. Use the admin app or your config file to change profile fields.
customer-roles
Manage customer RBAC roles — the scope sets attached to customer access tokens. A customer token’s scopes are the union of the customer’s role permissions; a role marked default grants its permissions to every customer with no explicit assignment. The declarative equivalent is the customerRoles block in foir.config.ts, reconciled by foir push; this group is for one-off CRUD and assignment management.
| Command | Description |
|---|---|
foir customer-roles list | List customer roles in the current project |
foir customer-roles create | Create a customer role |
foir customer-roles update <id> | Update a role’s name, permissions, or default flag |
foir customer-roles disable <id> | Disable a customer role |
foir customer-roles assign | Assign a role to a specific customer |
foir customer-roles revoke <assignmentId> | Revoke a role assignment |
foir customer-roles assignments | List role assignments for a customer or a role |
| Option | Applies to | Description |
|---|---|---|
--first <n> | list | Max results. Default: 100. |
--key <key> | create | Stable role key (e.g. default). Required. |
--name <name> | create, update | Display name. Required for create. |
--permissions <scopes> | create, update | Comma-separated scopes (e.g. self:*,operations:execute). Required for create; replaces scopes on update. |
--default | create, update | Make this the project default role (all customers inherit it). |
--no-default | update | Clear the project-default flag. |
--customer <id> | assign, assignments | Customer ID (required for assign). |
--role <id> | assign, assignments | Role ID (required for assign). |
--confirm | disable, revoke | Skip confirmation prompt. |
For
assignments, pass at least one of--customer <id>or--role <id>. Customers must log in again to pick up newly assigned or changed scopes.
Examples
# List customer roles
foir customer-roles list
# Create a default role granting self-access to customer-writable records
foir customer-roles create --key default --name "Default" --permissions "self:*" --default
# Add operation execution to a role
foir customer-roles update clx_role_123 --permissions "self:*,operations:execute"
# Assign a role to a specific customer
foir customer-roles assign --customer clx_cust_456 --role clx_role_123
# List a customer's role assignments
foir customer-roles assignments --customer clx_cust_456
# Revoke an assignment
foir customer-roles revoke clx_assign_789 --confirmcontext-dimensions
Manage context dimensions — the home of segments (sourceType: 'segment', a
rule evaluated into segment.<key>) and customer-context sources
(sourceType: 'model'). Prefer declaring them in your config (see
Defining Context Dimensions); this command is for one-off
inspection and edits. Aliased as foir context-dims.
foir push auto-publishes context dimensions on create, so use
foir context-dimensions publish <id> to promote a subsequent edit to the
published channel.
| Command | Description |
|---|---|
foir context-dimensions list | List context dimensions |
foir context-dimensions get <idOrKey> | Get a dimension by ID or key |
foir context-dimensions create | Create a dimension (--data <json> / --file <path>) |
foir context-dimensions update <id> | Update a dimension |
foir context-dimensions publish <id> | Promote a dimension draft to the published channel |
foir context-dimensions delete <id> | Delete a dimension |
Examples
# List context dimensions (segments + model sources)
foir context-dimensions list
# Create a segment from JSON
foir context-dimensions create --data '{
"key": "gold",
"name": "Gold",
"sourceType": "segment",
"evaluationRules": { "type": "group", "logicalOperator": "AND", "conditions": [] }
}'variant-catalog
Manage the variant catalog for content personalization.
| Command | Description |
|---|---|
foir variant-catalog list | List variant catalog entries |
foir variant-catalog get <idOrKey> | Get an entry by ID or key |
foir variant-catalog create | Create a variant catalog entry |
foir variant-catalog update <id> | Update a variant catalog entry |
foir variant-catalog delete <id> | Delete a variant catalog entry |
Examples
# List all variant catalog entries
foir variant-catalog list
# Get a variant by key
foir variant-catalog get premium-users
# Create a new variant catalog entry
foir variant-catalog create --data '{"key":"mobile","name":"Mobile Users","isActive":true}'context
Inspect and switch the CLI’s session context — the tenant and project subsequent commands run against. This is session/project management, not targeting data; the active project is persisted in .foir/project.json (see the CLI Overview).
| Command | Description |
|---|---|
foir context projects | List projects your session can access (the active one is marked) |
foir context switch <projectId> | Switch the active project |
foir context tenants | List tenants your session can access |
Examples
# See which projects you can use and which is active
foir context projects
# Switch to a different project
foir context switch prj_abc123
# List available tenants
foir context tenantsAfter
context switch, runfoir select-projectto provision a scoped API key for the newly selected project.
Automation
operations
Run and inspect server-side operations. Operations themselves are declared in foir.config.ts and reconciled with foir push — this group executes them and manages their dead-letter queue.
| Command | Description |
|---|---|
foir operations list | List operations |
foir operations get <key> | Get an operation by key |
foir operations execute <key> | Execute an operation |
foir operations dead-letters | List failed operations in the dead letter queue |
foir operations retry-dead-letter <id> | Retry a failed operation |
foir operations dismiss-dead-letter <id> | Dismiss a failed operation without retrying |
| Option | Applies to | Description |
|---|---|---|
--category <cat> | list | Filter by category. |
--active | list | Only active operations. |
--first <n> | list, dead-letters | Max results. Default: 50 for list, 20 for dead-letters. |
-d, --data <json> | execute | Input data as a JSON string. |
-f, --file <path> | execute | Read input from a file. |
--async | execute | Execute asynchronously. |
--operation <key> | dead-letters | Filter the queue by operation key. |
Examples
# List all operations
foir operations list
# Execute an operation with input data (key is positional)
foir operations execute send-welcome-email --data '{"userId":"clx123"}'
# Execute asynchronously
foir operations execute long-running-report --data '{"month":"2026-05"}' --async
# View the dead letter queue
foir operations dead-letters
# Retry a failed operation
foir operations retry-dead-letter clx_dl_456hooks
Manage lifecycle hooks — webhooks that fire on platform events (record.published, record.deleted, etc.). Hooks can also be declared in foir.config.ts and reconciled with foir push; this group is for one-off CRUD and for inspecting delivery history that lives outside the config file.
| Command | Description |
|---|---|
foir hooks list | List hooks |
foir hooks get <keyOrId> | Get a hook by key or ID |
foir hooks create | Create a hook |
foir hooks update <id> | Update a hook |
foir hooks delete <id> | Delete a hook |
foir hooks deliveries <hookId> | List recent deliveries for a hook |
foir hooks retry-delivery <deliveryId> | Retry a failed delivery |
foir hooks test <hookId> | Send a test delivery |
| Option | Applies to | Description |
|---|---|---|
--event <event> | list | Filter by event name. |
--active | list, update | List only active hooks / activate a hook. |
--inactive | list | List only inactive hooks. |
--no-active | update | Deactivate a hook. |
--first <n> | list, deliveries | Page size. |
--after <cursor> | list, deliveries | Opaque cursor from a previous page. |
--status <status> | deliveries | Filter deliveries by status (success, failed, pending). |
-d, --data <json> | create, update, test | Payload as a JSON string. |
--file <path> | create, update, test | Payload from a JSON file. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List active hooks for a specific event
foir hooks list --event record.published --active
# Create a hook from a JSON file
foir hooks create --file ./hooks/on-publish.json
# Inline create
foir hooks create --data '{"key":"on-publish","name":"On Publish","event":"record.published","url":"https://example.com/webhook"}'
# Deactivate without removing
foir hooks update hook_abc123 --no-active
# Recent failed deliveries for a hook
foir hooks deliveries hook_abc123 --status failed --first 20
# Send a synthetic delivery to verify the receiver
foir hooks test hook_abc123 --data '{"message":"test"}'
# Retry one failed delivery
foir hooks retry-delivery del_456schedules
Manage scheduled tasks with cron expressions.
| Command | Description |
|---|---|
foir schedules list | List schedules |
foir schedules get <key> | Get a schedule by key |
foir schedules create | Create a schedule |
foir schedules update <key> | Update a schedule |
foir schedules trigger <key> | Trigger a schedule immediately |
foir schedules pause <key> | Pause a schedule |
foir schedules resume <key> | Resume a paused schedule |
foir schedules delete <key> | Delete a schedule |
Examples
# List all schedules
foir schedules list
# Create a scheduled task
foir schedules create --file daily-sync.json
# Trigger a schedule immediately (outside its cron)
foir schedules trigger daily-sync
# Pause a schedule
foir schedules pause daily-syncAdministration
settings
Manage project settings.
| Command | Description |
|---|---|
foir settings list | List all settings |
foir settings get <key> | Get a setting by key |
foir settings set <key> <value> | Set a setting value |
foir settings reset <key> | Delete a setting (reset to default) |
| Option | Applies to | Description |
|---|---|---|
--category <cat> | list, set | Filter by category / category for the setting (required for new settings). |
--data-type <type> | set | Data type: STRING, NUMBER, BOOLEAN, or JSON. Inferred from the value if omitted. |
Examples
# List all settings
foir settings list
# Get a specific setting
foir settings get site.name
# Set a setting value (key and value are positional)
foir settings set site.name "My Site" --category general
# Reset a setting back to its default
foir settings reset site.namedesign-tokens
Manage the project’s design tokens document.
| Command | Description |
|---|---|
foir design-tokens get | Print the current document |
foir design-tokens apply <path> | Apply a W3C-formatted JSON document from disk |
foir design-tokens publish | Promote draft → published |
foir design-tokens unpublish | Remove the published snapshot |
foir design-tokens status | Show draft / published version status |
| Option | Applies to | Description |
|---|---|---|
--channel <draft|published> | get | Channel to read. Default: draft. |
--resolved | get | Print the server-resolved view (typed arrays, references expanded) instead of the raw W3C document. |
--publish | apply | Also publish after applying. |
Examples
# Print the draft document as JSON
foir design-tokens get
# Print the resolved view (groups expanded into flat arrays)
foir design-tokens get --resolved
# Diff what the storefront is serving against the draft
foir design-tokens get --channel published > published.json
foir design-tokens get --channel draft > draft.json
diff published.json draft.json
# Apply a hand-authored or generated tokens document
foir design-tokens apply ./tokens.json
# Apply and publish in one step
foir design-tokens apply ./tokens.json --publish
# Promote the current draft to published
foir design-tokens publish
# Check whether draft and published are in sync
foir design-tokens statusTip: For projects that track tokens in
foir.config.ts, usefoir push --publishinstead — it applies models, operations, and design tokens (and publishes them) in one step.
secrets
Manage vault secrets — opaque references your app code resolves to plaintext at runtime. Plaintext values never leave your machine; the CLI stores only encrypted blobs on the platform.
| Command | Description |
|---|---|
foir secrets put | Store a new secret and print its ref |
foir secrets list | List secret metadata (no plaintext) |
foir secrets rotate <ref> | Replace plaintext for an existing ref; returns a new ref |
foir secrets delete <ref> | Soft-delete a secret (recoverable until purged) |
foir secrets restore <ref> | Undo a soft-delete (only valid before the purge window passes) |
foir secrets push | Reconcile a foir.secrets.ts declaration file with the vault |
foir secrets purge | Drop every soft-deleted secret past its TTL |
| Option | Applies to | Description |
|---|---|---|
--label <label> | put | Optional human-readable label. |
--app <name> | put, list | Owner: app name. Default: project-owned. |
--file <path> | put, rotate | Read plaintext from file (binary-safe). |
--value <plaintext> | put, rotate | Plaintext value (string only; prefer --file for binary). |
--include-soft-deleted | list | Include soft-deleted entries. |
--config <path> | push | Path to foir.secrets.ts (default: auto-discover). |
--plaintext <path> | push | Path to local.foir.secrets.ts (default: auto-discover). |
--rotate | push | Rotate plaintext for secrets that already exist. |
--dry-run | push | Show what would change without writing. |
--confirm | rotate, delete, purge | Skip confirmation prompt. |
Examples
# Store a new secret from a file (binary-safe)
foir secrets put --file ./stripe.key --label "Stripe API key"
# Store a string value
foir secrets put --value "sk_test_..." --label "Stripe (test)"
# List project-owned secrets
foir secrets list
# Reconcile a declarative secrets file
foir secrets push --config foir.secrets.ts --plaintext local.foir.secrets.ts
# Rotate (returns a new ref — update your app code)
foir secrets rotate vault:abc123 --file ./new-stripe.key
# Soft-delete and undo
foir secrets delete vault:abc123 --confirm
foir secrets restore vault:abc123api-keys
Manage API keys for programmatic access.
| Command | Description |
|---|---|
foir api-keys list | List API keys |
foir api-keys create | Create an API key |
foir api-keys rotate <id> | Rotate an API key |
foir api-keys revoke <id> | Revoke an API key |
Examples
# List all API keys
foir api-keys list
# Create a new API key
foir api-keys create --data '{"name":"CI Pipeline"}'
# Rotate an existing key (requires confirmation)
foir api-keys rotate clx123 --confirm
# Revoke a key
foir api-keys revoke clx123 --confirmauth-providers
Manage customer authentication providers (OAuth, SAML, etc.).
| Command | Description |
|---|---|
foir auth-providers list | List customer auth providers |
foir auth-providers get <id> | Get an auth provider |
foir auth-providers create | Create an auth provider |
foir auth-providers update <id> | Update an auth provider |
foir auth-providers delete <id> | Delete an auth provider |
| Option | Applies to | Description |
|---|---|---|
--enabled-only | list | Show only enabled providers. |
--key <key> | create | Unique provider key. Required. |
--name <name> | create, update | Display name. Required for create. |
--type <type> | create | Provider type: OAUTH2, TOKEN_SSO, SAML, OTP_VERIFY, OIDC, or EXTERNAL. Required. |
-d, --data <json> | create, update | Provider config as a JSON string. |
--file <path> | create, update | Provider config from a JSON file. |
--enabled / --no-enabled | create, update | Enable / disable the provider (--no-enabled on update). |
--is-default | create, update | Set as the default provider. |
--priority <n> | create, update | Display priority (higher = first). |
--verify-external-customer | create, update | Verify the customer exists in an external system. |
--capture-metadata | create, update | Capture metadata from the provider during auth. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List configured auth providers
foir auth-providers list
# Create a Google OAuth provider (key, name, and type are required)
foir auth-providers create \
--key google \
--name "Google" \
--type OAUTH2 \
--enabled \
--file google-auth.jsonnotifications
Manage platform notifications.
| Command | Description |
|---|---|
foir notifications list | List notifications |
foir notifications read <id> | Mark a notification as read |
foir notifications read-all | Mark all notifications as read |
Examples
# List unread notifications
foir notifications list --unread
# Mark all as read
foir notifications read-allpush-credentials
Manage per-project push credentials (APNs for iOS, FCM for Android) used to deliver push notifications. Alias: push-creds.
| Command | Description |
|---|---|
foir push-credentials list | List push credentials for the current project |
foir push-credentials upload-ios | Upload an APNs .p8 credential for iOS |
foir push-credentials upload-android | Upload an FCM service-account JSON for Android |
foir push-credentials delete <id> | Delete a push credential by ID |
| Option | Applies to | Description |
|---|---|---|
--p8 <path> | upload-ios | Path to the APNs .p8 private key. Required. |
--bundle-id <id> | upload-ios | iOS app bundle identifier. Required. |
--team-id <id> | upload-ios | Apple Developer Team ID (10 chars). Required. |
--key-id <id> | upload-ios | APNs Key ID (10 chars). Required. |
--production | upload-ios | Use the production APNs endpoint (default: sandbox). |
--service-account <path> | upload-android | Path to the Firebase service-account JSON. Required. |
Examples
# List configured push credentials
foir push-credentials list
# Upload an APNs key for iOS (sandbox by default)
foir push-credentials upload-ios \
--p8 ./AuthKey_ABC123.p8 \
--bundle-id com.example.app \
--team-id A1B2C3D4E5 \
--key-id F6G7H8I9J0
# Upload the same key for production
foir push-creds upload-ios --p8 ./AuthKey_ABC123.p8 --bundle-id com.example.app \
--team-id A1B2C3D4E5 --key-id F6G7H8I9J0 --production
# Upload an FCM service-account for Android
foir push-credentials upload-android --service-account ./firebase-service-account.json
# Delete a credential
foir push-credentials delete cred_abc123notes
Manage notes attached to entities (records, models, etc.).
| Command | Description |
|---|---|
foir notes list | List notes for an entity |
foir notes get <id> | Get a note by ID |
foir notes create | Create a note |
foir notes resolve <id> | Resolve a note |
foir notes delete <id> | Delete a note |
| Option | Applies to | Description |
|---|---|---|
--entity-type <type> | list, create | Entity type (e.g. record, model). Required. |
--entity-id <id> | list, create | Entity ID. Required. |
--include-resolved | list | Include resolved notes (default: unresolved only). |
--first <n> | list | Max results. Default: 20. |
--body <text> | create | Note body text. Required. |
--parent-note-id <id> | create | Reply to an existing note. |
--resolution <text> | resolve | Resolution message. |
--confirm | delete | Skip confirmation prompt. |
Examples
# List unresolved notes on a record
foir notes list --entity-type record --entity-id clx123
# Create a note on a record
foir notes create --entity-type record --entity-id clx123 --body "Needs review before publishing"
# Resolve a note
foir notes resolve clx_note_456 --resolution "Reviewed and approved"
# Delete a note
foir notes delete clx_note_456 --confirmApps
apps
Install and manage apps — pluggable units delivered by manifest URL.
| Command | Description |
|---|---|
foir apps list | List installed apps |
foir apps get <name> | Get an installed app by name |
foir apps install <manifestUrl> | Install an app from a manifest URL |
foir apps update <name> | Check for updates and apply if no rejected changes |
foir apps uninstall <name> | Uninstall (runs __uninstall first if declared) |
foir apps trigger <appName> <operationKey> | Trigger an app-owned operation |
foir apps validate <manifestUrl> | Dry-run validation of a manifest URL |
foir apps dev | Open a public tunnel to a local app dev server so foir admin can iframe it |
| Option | Applies to | Description |
|---|---|---|
--source-map <json> | install | Inline source mappings (ad-hoc, instead of foir.config.ts). |
--dry-run | update | Show the diff without applying. |
--force | uninstall | Skip the middleware __uninstall call; remove platform state regardless. |
-d, --data <json> | trigger | Input data as a JSON string. |
-p, --port <port> | dev | Local port serving the app. Default: 8787 (wrangler default). |
--host <host> | dev | Local host to forward to. Default: localhost. |
-t, --tunnel <kind> | dev | Tunnel provider: cloudflared (default), ngrok, or none (use --url). |
--url <url> | dev | BYO tunnel URL; pairs with --tunnel none. |
--push | dev | Run foir push once after the tunnel comes up, with FOIR_APPS_HOST set. |
--watch | dev | Re-run foir push on foir.config.* changes (implies --push). |
Examples
# List installed apps
foir apps list
# Install with inline mappings (ad-hoc)
foir apps install https://shopify.apps.foir.io/manifest.json \
--source-map '{"product":{"toModel":"product","naturalKey":"handle","fields":{"title":"title","handle":"handle"}}}'
# Install via foir.config.ts (golden path) — declare apps.<name> and run:
foir push
# Check for updates with a diff
foir apps update redirector --dry-run
# Apply updates (only safe-auto changes apply automatically; rejected changes block)
foir apps update redirector
# Trigger a specific operation on an installed app
foir apps trigger redirector deploy-worker --data '{"force":true}'
# Force-uninstall (skip middleware __uninstall, remove platform state regardless)
foir apps uninstall redirector --force
# Validate a manifest before installing
foir apps validate https://my-app.example.com/manifest.json
# Tunnel a local app dev server (on :5173) and re-push on config changes
foir apps dev --port 5173 --watch
# Use a BYO tunnel URL instead of cloudflared
foir apps dev --tunnel none --url https://my-tunnel.example.com --pushThe CLI namespaces app-owned operation keys as <appName>/<operationKey> when storing them, but foir apps trigger accepts the bare key form too.
Scaffolding
create-config
Scaffold a new app or extension project — a Vite UI + Hono API monorepo wired up for Foir’s scoped-token verification.
npx @foir/cli create-config <name> [options]| Option | Description |
|---|---|
--type <type> | Project type: custom-editor, workflow, or widget |
Examples
# Custom editor placement (UI + middleware)
npx @foir/cli create-config my-editor --type custom-editor
# Pure backend operation (no UI)
npx @foir/cli create-config my-summarizer --type workflow
# Static iframe (no middleware)
npx @foir/cli create-config color-picker --type widgetSee Building an App and Building Operations for end-to-end walkthroughs.
init
Generate starter files for a project — a single model definition, or a tree of seed records for existing models. Run from inside a project that already has a foir.config.ts. To scaffold a brand-new project, use create-config.
| Command | Description |
|---|---|
foir init model <key> | Generate a starter model definition file |
foir init records | Generate seed files for one or more existing models (interactive picker) |
| Option | Applies to | Description |
|---|---|---|
-o, --output <dir> | model, records | Output directory. Default: models for model, seed for records. |
--ts | model, records | Emit TypeScript (.ts) instead of JSON. |
Examples
# Create a starter model file at ./models/blog-post.ts
foir init model blog-post --ts
# Generate seed records into ./seed/ for models you pick interactively
foir init records --tsConfig Management
configs
Manage platform configs (apps, webhooks). For the config-as-code workflow built around foir.config.ts, use push / pull / remove instead.
| Command | Description |
|---|---|
foir configs list | List configs |
foir configs get <idOrKey> | Get a config by ID or key |
foir configs create | Create a new config |
foir configs sync <id> | Trigger a data sync for a config |
| Option | Applies to | Description |
|---|---|---|
--type <type> | list | Filter by config type. |
--enabled | list | Only enabled configs. |
--first <n> | list | Max results. Default: 50. |
-d, --data <json> | create | Config data as a JSON string. |
-f, --file <path> | create | Read config data from a file. |
Examples
# List all configs
foir configs list
# Get a config by key
foir configs get my-blog-config
# Create a config
foir configs create --file config.json
# Trigger a sync
foir configs sync clx123pull
Export the current platform state of a config back into a local foir.config.ts file. Inverse of push — useful when an admin edited models or operations in the dashboard and you want those changes back in source control.
foir pull [options]| Option | Description |
|---|---|
--key <configKey> | Config key to export (default: auto-discover from the current foir.config.ts) |
--out <path> | Output file (default: foir.config.ts next to the current one) |
--force | Overwrite an existing file without prompting |
Examples
# Pull the current project's config into ./foir.config.ts
foir pull
# Pull a named config and write to a different file
foir pull --key my-blog-config --out ./configs/blog.config.ts
# Overwrite without prompt (useful in CI / pre-commit hooks)
foir pull --forcepush
Push a local foir.config.ts file to the platform. This registers or updates a config and all its associated resources.
foir push [options]| Option | Description |
|---|---|
--config <path> | Path to config file (default: auto-discovers foir.config.ts) |
--force | Overwrite platform state on three-way-merge conflicts with admin-UI edits |
--publish | Promote ALL updated resources — including breaking model changes — to the published channel after the push. New resources and additive model updates auto-publish; breaking model changes and updated operations / auth providers / profile schema are otherwise left as drafts, and this flag releases them too. |
--rebuild | Accept lookup renames. A lookup with the same keyBy but a changed name rebuilds its projection rows (old rows dropped, new rows re-emitted). Without this flag the server rejects renames. Pure add/remove of lookups does not need it. |
--rotate-keys | Rotate existing API keys and rewrite their values in .env |
--dry-run | Print what the push would create / update / delete and exit without changing anything. |
--allow-delete | Skip the interactive confirmation when the push deletes resources (for CI). Without this flag, deletions prompt on a TTY and abort when there’s no TTY. |
--env <path> | Path to .env file (default: .env) |
Examples
# Push the config file in the current directory
foir push
# Push a specific config file
foir push --config ./configs/blog.config.ts
# Apply and publish in one step — including design tokens
foir push --publish
# Overwrite admin-UI edits when the three-way merge reports conflicts
foir push --force
# Preview the create / update / delete plan without changing anything
foir push --dry-run
# In CI: allow deletions to proceed without an interactive prompt
foir push --allow-deleteremove
Remove a config and all its provisioned resources (models, operations, hooks, schedules).
foir remove <key> [options]| Option | Description |
|---|---|
--force | Skip the confirmation prompt |
Examples
# Remove a config (with confirmation prompt)
foir remove my-blog-config
# Remove without confirmation
foir remove my-blog-config --forceData Portability
export
Export the project as a restorable Postgres database — typed tables, real foreign keys, your media, and your access rules as row-level security. See the Export to Postgres guide for the full walkthrough, and Your Data Is Portable for what the commitment is.
You must be the owner of the workspace: exporting reads the whole project at once.
| Command | Description |
|---|---|
foir export postgres | Export the project as a restorable Postgres bundle |
| Option | Description |
|---|---|
-o, --out <path> | Write the archive to this path (default: foir-export-<date>.tar.gz). |
--target <dsn> | Apply the bundle directly into this Postgres. Requires psql. The connection string never leaves your machine — the bundle is applied from here, so your database password is never sent to Foir. |
--postgis | Export location fields as PostGIS geography(Point,4326) rather than JSON. Your database needs the postgis extension. |
--include-raw | Also emit a full-fidelity JSON mirror of every record, drafts and versions and variants included. |
--include-credentials | Also include your customers’ password hashes (portable argon2id, so nobody resets). Prompts for your password to confirm, and records the export in your audit log. |
Examples
# Write an archive you can restore later
foir export postgres
# …somewhere specific
foir export postgres --out ./backups/myproject.tar.gz
# Restore straight into a database you own (never leaves your machine)
foir export postgres --target "postgresql://user:pass@localhost:5432/myproject"
# With PostGIS geometry and the full-fidelity mirror
foir export postgres --postgis --include-raw --target "$DATABASE_URL"The command prints what it could not carry — a reference pointing at something already deleted, a value that wouldn’t fit its column — before it prints success. Nothing is dropped silently.
Embeddings and AI
embeddings
Manage vector embeddings for semantic search and similarity. Pairs with the AI & Search feature; the embedding pipeline runs on the platform but the CLI is how you trigger writes, deletes, and ad-hoc searches outside the admin app.
| Command | Description |
|---|---|
foir embeddings write | Write an embedding vector for a record |
foir embeddings delete <recordId> | Delete the embedding for a record |
foir embeddings search | Search by vector similarity |
foir embeddings list <recordId> | List embeddings stored for a record |
foir embeddings stats [modelKey] | Embedding statistics, optionally scoped to a model |
foir embeddings similar <recordId> | Find records similar to the given record |
| Option | Applies to | Description |
|---|---|---|
-d, --data <json> | write, search | Input payload as a JSON string. search requires --data. |
--file <path> | write | Input payload from a JSON file. |
--confirm | delete | Skip confirmation prompt. |
--model-key <key> | similar | Limit matches to a specific model. |
--first <n> | similar | Page size. |
The write payload is {"recordId":"…","vector":[…]} (with optional dimensions, provider, modelName). The search payload is {"queryVector":[…],"modelKey":"…","first":N} — queryVector is required.
Examples
# Write an embedding from a file
foir embeddings write --file embeddings.json
# Semantic search by vector similarity
foir embeddings search --data '{"queryVector":[0.12,0.04,-0.31],"modelKey":"article","first":10}'
# Find similar records, scoped to a model
foir embeddings similar clx123 --model-key article --first 5
# Embedding statistics for a single model
foir embeddings stats article --json
# Project-wide stats (no model key)
foir embeddings stats --json
# Delete the embedding attached to a record
foir embeddings delete clx123 --confirm