@frontera-sdk/cli
v1.50.19
Published
The frontera CLI — scaffold, pull, save and deploy Frontera apps and automations.
Readme
@frontera-sdk/cli
frontera — scaffold, pull, save and deploy Frontera apps and automations.
bunx @frontera-sdk/cli --helpfrontera auth add acme-prod --api-url https://api.frontera.example --from -
frontera auth use acme-prod
frontera app init shipments-console
cd shipments-console && bun install
frontera app devNew Apps are Next.js static exports by default. frontera app dev starts Next
on loopback and a separate authenticated session broker. The stored workspace
key never enters browser JavaScript or .env.local; the browser receives only
a short-lived, App-scoped token. Existing Vite Apps remain supported with
--framework react and their legacy dev-host.html flow.
One machine, many customers
A credential is a profile, and the working directory selects which profile is in play. Two keys for the same deployment coexist under different names, and a command run in a customer's directory uses that customer's key with no flag.
frontera auth add acme-prod --api-url https://api.frontera.example --from -
frontera auth add globex-dev --api-url https://api.frontera.example --from -
cd ~/Customers/acme && frontera auth use acme-prod
cd ~/Customers/globex && frontera auth use globex-dev
frontera auth current --json # which profile, which origin, which scopeauth use writes a gitignored .frontera/context.json holding a profile
name — never a token and never an origin. Resolution walks up from the
working directory and the nearest binding wins, so a nested customer project
safely overrides its parent.
Precedence is explicit over inferred: --profile beats FRONTERA_PROFILE,
which beats the directory. --api-url must agree with the selected profile's
origin — a profile's key is never sent to another deployment. FRONTERA_TOKEN
still works for CI and the Computer, and requires an explicit origin alongside
it for the same reason.
Keys live in the OS credential store addressed by profile; config.json holds
metadata and a short fingerprint, never key bytes. A version-1 configuration
migrates on first use, verifying every copied secret before the old plaintext
is dropped. frontera login remains as a deprecated alias that manages the
default profile.
| | |
|---|---|
| frontera auth add <profile> | verify a key and store it (stdin or no-echo prompt only) |
| frontera auth use <profile> | bind this directory tree — no initialization needed |
| frontera auth current | the resolved profile, origin, scope and provenance |
| frontera auth list / verify / remove | what exists, is it still valid, delete it |
Agent harness
frontera setup # every coding host installed here
frontera setup codex
frontera setup claudeCodex and Claude Code both install plugins from a marketplace, and both accept a
local directory as one. The CLI carries the Frontera skills pinned at build
time, so setup materializes a marketplace under
~/.local/share/frontera/harness and points the host at it — nothing published,
nothing hosted, no network. Upgrading the CLI upgrades the plugin.
Nothing needs to be written into a repository. For teams that want the
instructions versioned with the code — or for Windows checkouts, archives and
cloud sandboxes — frontera kit vendor writes both host projections
(.agents/skills and .claude/skills), a bounded managed block in AGENTS.md,
a CLAUDE.md importing @AGENTS.md, and a committable
frontera.kit.lock.json. kit status, kit sync and kit doctor report
drift, update generated files without discarding local edits, and diagnose a
skill reachable from two sources at once.
The commands
frontera <noun> <verb>. Note that frontera init (prepare an existing
project) and frontera app init (scaffold a new app) are different commands.
| | |
|---|---|
| frontera app init <name> | scaffold a Next.js static App |
| frontera app init <name> --framework react | scaffold a legacy Vite App |
| frontera app dev | run locally with authenticated Blueprint access |
| frontera app pull <slug> | fetch an existing app's source |
| frontera app save | package the working tree to storage |
| frontera app deploy | build output → an immutable version |
| frontera app list / versions | what exists, what is live |
| frontera blueprint list / get | what data an app can read |
| frontera blueprint generate-types | generate committed App-local types from that data contract |
frontera help --json returns the whole table as data.
Exit codes are a contract
0 success · 1 transient · 2 usage · 3 conflict · 4 auth. Branch on
them rather than on message text.
Project configuration
package.json remains standard package metadata: package identity, scripts,
dependencies, development dependencies, and package-manager metadata.
Frontera's artifact contract lives in frontera.config.json:
{
"displayName": "shipments-console",
"outputDirectory": "out",
"routing": "filesystem",
"connectDomains": [],
"resourceDomains": []
}runtime is always static; routing describes the artifact rather than the
framework that produced it. The environment-specific App binding is written to
gitignored .frontera/state.json. Existing projects that already use
package.json#frontera remain readable, but new scaffolds do not add it.
Next Apps consume the published @frontera-sdk/core and
@frontera-sdk/blueprint packages. Existing Vite Apps retain vendored SDK
source; frontera app sdk sync refreshes only that generated tree.
What app init does
It refuses before it writes, then finishes the job:
- Rejects a name
package.jsonwould reject — with the name that would have worked — and refuses to scaffold over a directory that already holds work. - Writes the project, its
AGENTS.md, and its pattern skills. - Runs
bun install. A machine with no network gets a reported skip and abun installline in the next steps, never a failed command. - Adds the baseline shadcn components —
button,input,table,skeleton,card,alert— which the reference feature imports. - Creates a repository and an initial commit, unless it is already inside one. A repository that cannot be committed to is removed rather than left half made.
--no-install, --no-components and --no-git opt out of the last three.
Progress goes to stderr, so --json still returns nothing but the result
document.
Components come from shadcn
Apps do not carry a component library this repository maintains. components.json
is configured for the project as scaffolded — Tailwind v4, src/app/globals.css,
the @/ aliases, cn from @/lib/utils — so anything upstream publishes drops
in unmodified:
bunx --bun shadcn@latest add dialog dropdown-menu tabsTwo details make that work and are asserted by the scaffold tests. Every item in
the shadcn registry declares no npm dependencies, so the scaffold declares
what they import — class-variance-authority, radix-ui, lucide-react,
tw-animate-css. And the platform stylesheet already defines every token
upstream references, so add leaves it untouched; shadcn init would replace
it with the vanilla palette, which is why nothing runs it.
frontera app add remains for Frontera-specific compositions — app-page,
page-header, stat-tile, filter-bar, data-table — that upstream has no
equivalent for.
What a new App contains
frontera app init writes a project that already demonstrates the patterns its
skills describe, because an agent copies the nearest file rather than the
nearest paragraph:
src/app/ route adapters: layout, providers, one thin page
src/ui/app-shell/ the frame, aware of embedded vs standalone
src/ui/object-explorer/ reference feature — entry, components/, hooks/, utils, types
src/lib/blueprint/ the data layer, with tests over its pure helpers
src/lib/copy.ts user-visible strings
src/components/ui/ shadcn primitives, fetched at init
components.json shadcn CLI configuration for this project
AGENTS.md / CLAUDE.md the entry point that routes an agent to the skills
.agents/skills/ thirteen pattern skills, dispatcher firstThe reference feature reads any object type by name, so it works before a data model is known: search debounced into a server-side filter, paged reads, a total from a separate aggregate over the same object set, a content-shaped skeleton, dimmed background refetches, and distinct empty and error states.
bun run check — typecheck, then bun test, then next build — is the gate a
scaffolded project ships with, and the one its skills tell an agent to run
before claiming a change works.
Blueprint types
From an authenticated App project, generate the active workspace-granted Blueprint contract:
bun run blueprint:types
git add src/generated/frontera-blueprint.tsThe generated file is deterministic and contains API names and TypeScript types, never server IDs, credentials, origins, or timestamps. Commit it so ordinary installs and builds remain offline and reproducible. An authenticated CI job may check freshness without writing:
bun run blueprint:types:checkGeneration is intentionally not part of install, build, local development, or
deployment. Use --output <relative.ts> for a different committed location.
Build and release
Build on the FDE laptop or in customer CI, then upload the immutable result:
bun run typecheck
bun run build
frontera app deploy --no-promote
frontera app versions
frontera app promote 0.1.0The CLI packages the configured output directory and records packaging provenance. The service independently computes the authoritative artifact digest, file count, byte count, and uploader.
It runs on Bun, not Node
bin points at src/main.ts and the package ships TypeScript source, so:
bunx --bun @frontera-sdk/cli app init # works
npm i -g @frontera-sdk/cli && frontera # does NOT — Node cannot run the .ts entryengines.bun says so in the manifest. Publishing source rather than a bundle is
deliberate — every consumer is Bun or a bundler, and a build step would emit
output the consumer immediately re-transpiles — but it does mean a global
npm i -g is not a supported install.
License
Apache-2.0. See LICENSE.
