The official command-line interface for the Frontal platform.
Every API call goes through @frontal-labs/sdk;
the CLI adds a project model (frontal.jsonc), a local dev loop and deployment workflows on top.
frontal init --name my-app
cd my-app && frontal dev # local server, no API key needed
frontal deploy --preview # shareable preview URLAll seven project commands are available: init, dev, types, env, deploy
(+ promote/rollback), logs and policy check.
The
bashblocks in this README are executed in CI (bun run test:readme). Blocks taggedskipneed a real account or an interactive terminal.
npm install -g frontal-cli # Node ≥ 18
# or
brew tap frontal-labs/cli && brew install frontal-cli
# or download a single binary from the GitHub releases pageCheck the install:
frontal version # Frontal CLI v0.1.2 + runtime (bun/node, platform)
frontal --help # grouped command overview with examplesinit creates a minimal project. It never overwrites existing files unless you pass --force.
frontal init --name my-app
cd my-app
cat frontal.jsonctypes turns frontal.jsonc into typings for your app — FrontalEnv (vars + secrets),
FrontalServices (the SDK client for every enabled service) and FrontalProject:
cd my-app
frontal types
head -3 src/frontal-configuration.d.tsThe generated file starts with // Generated by frontal types — do not edit. and is
regenerated in place; commit it or add it to your build.
dev runs a local Frontal API for the project — no API key required. Every service
listed in frontal.jsonc is served from SDK-compatible fixtures persisted under
.frontal/state/ (gitignored), so your app can use @frontal-labs/sdk unchanged:
cd my-app
frontal dev --port 8788 --no-watch > dev.log 2>&1 &
DEV_PID=$!
sleep 1
curl -s localhost:8788/health
curl -s -X POST localhost:8788/v1/agents -H 'content-type: application/json' \
-d '{"name":"triage","triggers":[{"event":"ticket.created"}]}'
kill $DEV_PIDPoint the SDK at it with baseUrl: "http://localhost:8787/v1" (any frt_… key works locally).
| Flag | Effect |
|---|---|
--port 8787, --host 127.0.0.1 |
Where to listen (--port 0 picks a free port) |
--scenario <name> |
Load .frontal/scenarios/<name>.json — { "routes": [{ "method", "path", "status", "body", "headers", "times" }] }, same shape as MockRoute in @frontal-labs/testing. Scenario routes win over built-ins |
--remote ai,graph |
Proxy those services to the real API through the SDK (needs credentials); the rest stay local. The startup line shows [local] agents [remote] ai and proxied requests carry X-Frontal-Dev-Proxy |
--persist-to <dir> |
State directory (default .frontal/state) |
--no-watch |
Disable live reload of frontal*.jsonc, .env.local and scenario files |
--json |
NDJSON lifecycle + request log (`{"type":"ready" |
Built-in local services: agents (CRUD, versions, rollback, runs, SSE run stream),
graph (entities, relationships, query with filter operators, neighborhood, path),
datasets, blob (upload/download/list/copy/move), observability (logs query +
live logs/stream fed by the server's own request log), governance (policies,
access/check, compliance score). GET /health is always local and unauthenticated;
every response carries an X-Request-Id. Ctrl+C shuts down cleanly.
env pull writes .env.local from frontal.jsonc (vars, secrets.required, apiUrl)
and your active credential — never overwriting an existing file without --force, and
never printing secret values. logs and policy check work against the local dev server
too, so the whole loop runs without an account:
cd my-app
frontal dev --port 8789 --no-watch > dev.log 2>&1 &
DEV_PID=$!
sleep 1
frontal env pull
frontal logs --since 5m --api-url http://localhost:8789/v1
frontal policy check --api-url http://localhost:8789/v1
kill $DEV_PIDfrontal env pull --env staging --force # merge staging vars, keep existing secrets
frontal env push # upload vars to the current deployment
frontal logs --follow --level error # tail (SSE), reconnects on drops
frontal logs --follow --json | jq -r .requestId
frontal policy check --strict --env prod # warnings become errors; exit 1 on denydeploy bundles the project's entry (default src/index.ts, via bun build) into a
single ESM file and uploads it as a worker: <name>-preview for --preview (the default),
<name> for --prod (confirmation required unless --yes). The URL is
<apiUrl>/workers/<name>. Every deployment is recorded under .frontal/state/deploys/
with an immutable copy of the artifact, so promote and rollback re-send exactly what
was deployed — no rebuild. --dry-run bundles and writes a manifest (the local state
schema only, never row data) without touching the network:
cd my-app
printf 'export default { fetch: () => new Response("hi") };\n' > src/index.ts
frontal deploy --dry-run --outdir dist/frontal
cat dist/frontal/manifest.jsonfrontal deploy --preview # prints https://api.frontal.dev/v1/workers/my-app-preview
frontal promote https://api.frontal.dev/v1/workers/my-app-preview
frontal deploy --prod --yes
frontal rollback # previous production artifact (+ agents listed in frontal.jsonc)- Comments and trailing commas are allowed. The
$schemaURL gives editors validation and completions; the schema is generated from the CLI's own validator (schemas/frontal.json,bun run generate:schema). - Unknown service keys fail validation with the list of valid services
(
agents, ai, audit, auth, billing, blob, connectors, data, datasets, events, governance, graph, integrations, lineage, observability, ontology, pipelines, sandbox, schedules, webhooks, workers, workflows). - Per-environment overlays:
frontal.staging.jsoncis deep-merged overfrontal.jsoncwhen you pass--env staging(or whenenvis set tostaging). - Connection rules (
apiUrl, optionalsdk.timeout/maxRetries/retryDelay/headers) are validated with the SDK's own schema.
Credentials resolve in this order: --api-key → FRONTAL_API_KEY → .env.local in the
project → the active profile in ~/.frontal/config.json (API key, then OAuth session).
frontal auth login # browser OAuth (PKCE)
frontal auth login --method api-key
frontal auth whoami # local status + account profile
frontal auth whoami --local # no API callSet FRONTAL_CONFIG_DIR to relocate the profile store (CI, tests).
| Command | Purpose |
|---|---|
frontal init [--name <dir>] [--force] |
Create frontal.jsonc, .env.example, .gitignore entries, src/ |
frontal dev [--port] [--scenario] [--remote] [--persist-to] |
Local Frontal API backed by .frontal/state |
frontal types [--out <file>] |
Generate FrontalEnv / FrontalServices / FrontalProject typings |
frontal deploy [--preview|--prod] [--yes] [--dry-run --outdir <dir>] |
Bundle + upload a worker; print its URL |
frontal promote <url> / frontal rollback [url] |
Re-point production at a recorded artifact (no rebuild) |
frontal env pull [file] [--force] / frontal env push [file] |
.env.local from frontal.jsonc + credentials / upload vars to the current deployment |
frontal logs [--follow] [--filter <q>] [--since 15m] [--level <l>] |
Query or tail platform logs (SSE) |
frontal policy check [--strict] [--user] [--role] |
Dry-run governance: policy files, deploy access per service, compliance |
frontal auth <login|password-login|signup|logout|whoami|token|refresh|mfa> |
Sessions, API keys, MFA |
frontal config <set|get|list|reset|profiles|use|telemetry> |
Profiles in ~/.frontal |
frontal workflows <list|create|search|batch|run get|run summary|run timeline> |
Workflows and executions (SSE timeline) |
frontal runs <list|create> |
Runs |
frontal invocations create |
Submit an invocation |
frontal events <list|get|query|usage|reprocess> |
Events |
frontal completion <bash|zsh|fish> |
Shell completions |
frontal migrate-legacy |
v1 → current command mapping |
See llms.txt for a machine-readable summary of every command.
Every command has an Examples: section in --help:
frontal workflows list --help| Flag | Effect |
|---|---|
--json / --yaml |
Machine-readable output (secrets are always redacted) |
--env <dev|staging|prod> |
Select the environment overlay and X-Frontal-Environment |
--api-key <key>, --api-url <url> |
Override credentials / base URL for one call |
-p, --profile <name> |
Use a named profile |
-q, --quiet, -v, --verbose, --debug |
Output verbosity (--verbose logs every request) |
-y, --yes |
Skip confirmation prompts (CI) |
--watch [seconds], --until field=value |
Re-run a read command until a condition holds |
frontal workflows list --limit 10 --json | jq '.data[].name'
frontal workflows run timeline wf_123 run_456 --json | jq .data
frontal events query --body '{"type":"agent.run.completed"}'Every failure prints a stable code, a fix hint, a docs link and the request id, and exits
with a stable code — the same fields are in --json output on stderr:
cd my-app
frontal workflows list --api-url http://127.0.0.1:9/v1 --json || echo "exit code: $?"
# stderr: {"error":{"code":"NETWORK_ERROR","message":"Could not reach the Frontal API.","fix":"…","docs":"…"}}
# stdout: exit code: 10| Exit | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Validation error (bad input / payload) |
| 3 | Authentication error (NO_CREDENTIALS, UNAUTHORIZED, TOKEN_EXPIRED) |
| 4 | Permission denied |
| 5 | Not found |
| 6 | Configuration error (CONFIG_INVALID, NO_PROJECT) |
| 10 / 11 / 12 | Network / timeout / rate limited |
| Variable | Purpose |
|---|---|
FRONTAL_API_KEY |
API key (frt_…) |
FRONTAL_API_URL |
API base URL (default https://api.frontal.dev/v1) |
FRONTAL_ENV |
development / test / production for the SDK; the CLI maps --env dev|staging|prod |
FRONTAL_DEBUG |
1 to log every request (same as --verbose) |
FRONTAL_PROFILE |
Profile name (same as --profile) |
FRONTAL_CONFIG_DIR |
Location of the profile store (default ~/.frontal) |
bun install
bun run dev -- --help # run from source
bun run build # dist/index.js (npm bin, Node ≥ 18)
bun run build:binary # dist/frontal single executable (bun build --compile)
bun run type-check && bun run test && bun run lint
bun run test:readme # execute the bash blocks in this READMESee docs/DEVELOPERS.md for the architecture and CONTRIBUTING.md for the workflow.
Apache License 2.0 - see LICENSE.md and NOTICE.md.
- Documentation: docs.frontal.dev
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: support@frontal.dev
See CHANGELOG.md for version history and changes.

{ "$schema": "https://frontal.dev/schemas/frontal.json", "name": "my-app", "env": "dev", // dev | staging | prod "apiUrl": "https://api.frontal.dev/v1", "services": { "ai": { "remote": false }, // remote: true proxies to the API in `frontal dev` "agents": { "remote": false }, "graph": { "remote": false } }, "entry": "src/index.ts", // bundled by `frontal deploy` "vars": { "LOG_LEVEL": "info" }, // written to .env.local by `frontal env pull` "secrets": { "required": ["FRONTAL_API_KEY"] } }