Skip to content
Get started

CLI, import, billing, and route handoff

Operate Fugue without guessing what the route, runtime, or bill will do next.

Fugue is route-first: start on a shared managed runtime, keep the public route stable, and move the same app onto your own machine later. This page focuses on the parts that are easiest to misread from code alone: CLI defaults, import boundaries, fugue.yaml, billing activation, and the line between stateless migrate and managed failover.

Accepted upload archives.zip · .tgz · .tar.gz

Web local upload uses the multipart upload endpoint; CLI local deploy creates the archive for you.

Free managed cap500m CPU · 512 MiB · 5 GiB

This is the current default free managed envelope before paid managed capacity starts.

Calibrated reference2 vCPU · 4 GiB · 30 GiB ≈ $4 / month

The default price book is calibrated so this managed envelope lands near four dollars per month.

Read this before the first import

These are the edges users usually trip over on the first real deploy.

  1. 01CLI default runtime is shared managed.Omit --runtime and Fugue targets the shared managed runtime.
  2. 02Seed-file overrides are topology-preserving only.persistent_storage_seed_files only works when topology detection stays fully automatic.
  3. 03Move and failover are separate paths.migrate handles stateless apps and movable_rwo persistent storage; failover is for declared standby recovery.
01

CLI

CLI quick start and operator defaults

The CLI is the main operator interface. It covers deploy, import, inspect, runtime, failover, and raw HTTP diagnostics without dropping into kubectl.

For normal deploys, one tenant-scoped access key is enough. Reserve platform-admin or bootstrap keys for fugue admin ..., cross-tenant inspection, or product-layer debugging.

For self-hosted control planes, set both FUGUE_BASE_URL and FUGUE_WEB_BASE_URL. The first points CLI HTTP requests at the API, the second is needed when commands read fugue-web snapshot routes.

Secrets are intentionally redacted from fugue app overview and fugue operation show JSON output. Only add --show-secrets when you explicitly need raw values during debugging.

Shell environment

FUGUE_API_KEY
Current access keyRequired for normal deploys and tenant-scoped operations.
FUGUE_BASE_URL
Self-hosted API base URLSet this on self-hosted control planes so CLI requests hit the right API origin.
FUGUE_WEB_BASE_URL
Self-hosted web base URLNeeded by admin snapshot and fugue web diagnose commands that talk to fugue-web routes.
FUGUE_SKIP_UPDATE_CHECK
Optional quiet modeSuppresses the release-upgrade reminder in the current shell session.

High-signal commands

GoalCommandWhy it matters
Deploy current sourcefugue deploy .Uploads local source as an archive and queues an import without inventing extra scaffolding.
Inspect full app contextfugue app overview my-appShows domains, bindings, image inventory, operations, and rollout context in one snapshot.
Tail runtime logsfugue app logs runtime my-app --followFollows pod logs without leaving the CLI.
Query log-style tablesfugue app logs query my-app --table gateway_request_logs --since 1h --match status=500Useful when the useful data lives in the app database instead of stdout.
Call internal HTTP safelyfugue app request my-app GET /admin/requests --header-from-env X-Service-Key=SERVICE_KEYInjects auth headers from app env so you do not paste service secrets into the shell.
Check and apply updatesfugue version --check-latest / fugue upgradeReleased binaries can self-upgrade in place.
Released CLI quick start

Install the released CLI, export one access key, and the first deploy can happen from the current directory.

quickstart.sh
curl -fsSL https://raw.githubusercontent.com/yym68686/fugue/main/scripts/install_fugue_cli.sh | sh

export FUGUE_API_KEY=<copied-access-key>
fugue deploy .
fugue app overview my-app
Self-hosted shell environment

Self-hosted control planes also need API and web base URLs when you use admin snapshots or `web diagnose` commands.

self-hosted.sh
export FUGUE_BASE_URL=https://api.example.com
export FUGUE_WEB_BASE_URL=https://app.example.com
export FUGUE_API_KEY=<copied-access-key>

fugue app ls
fugue version --check-latest
fugue upgrade
02

Imports

Import paths, flags, and topology guardrails

Fugue supports three import surfaces today: local source, GitHub repositories, and image references. GitHub and local uploads can also fan out a topology-aware manifest into multiple apps and operations.

GitHub import is no longer limited to public static sites. The current importer supports public and private repos, tracked repository sync, and stack-aware imports from either fugue.yaml or Compose.

Image imports stay the thinnest path: point Fugue at an image reference, optionally name the app, and skip build detection entirely.

If a local archive name implies the app name clearly, upload import can derive it automatically. Accepted archive formats are .zip, .tgz, and .tar.gz.

Import guardrails

  • GitHub imports support public and private repositories, automatic build detection (auto, static-site, dockerfile, buildpacks, nixpacks), and service-specific .env overrides with --service-env-file <service>=<path>.
  • Local source on the CLI is archived automatically. In the web product layer, local upload is post-sign-in and the JSON create-and-import route deliberately rejects local-upload; that path must use the multipart upload endpoint.
  • Topology-preserving seed-file overrides only work when the importer can keep build detection fully automatic. If you set source_dir, dockerfile_path, or build_context_dir, Fugue rejects persistent_storage_seed_files.
  • When network_mode=background, Fugue clears service ports and public routes. When network_mode=internal, the service port remains, but the public route stays empty.

Flags that change behavior materially

  • --runtime defaults to the shared managed runtime when omitted.
  • --port or --service-port only matters for public or internal services.
  • --command becomes sh -lc <command> on the queued app spec and queued operation.
  • --storage-size, --mount, and --mount-file define persistent workspace state that later changes how migrate and failover behave.
  • --managed-postgres and the --postgres-* flags attach app-owned managed PostgreSQL from the start instead of treating it as an afterthought.

Import paths

PathBest forKey parametersWatch out for
Local sourcefugue deploy . or multipart upload from the web app--name, --build, --command, persistent-storage flagsWeb local upload is multipart-only and happens after sign-in.
GitHub repositoryfugue deploy github owner/repo--branch, --private, --repo-token, --service-env-filePrivate repos need explicit repo auth unless the workspace already has GitHub access wired.
Container imagefugue deploy image ghcr.io/example/app:latest--name, --runtime, --replicas, --commandNo build detection runs here, so Dockerfile/source-dir flags are irrelevant.

Network modes

Network modeRoute behaviorPort behaviorTypical use
PublicPublic route is createdService port is exposedDefault HTTP app path
InternalNo public routeInternal service remains addressableService-to-service traffic only
BackgroundNo public routeService ports are clearedWorkers, schedulers, queue consumers
GitHub, image, and local deploy entrypoints

These are the main import paths in active use today. GitHub and local source can expand topology-aware imports when `fugue.yaml` or Compose files are present.

imports.sh
fugue deploy .

fugue deploy github owner/repo --branch main
fugue deploy github owner/repo --private --repo-token $GITHUB_TOKEN

fugue deploy github owner/repo \
  --service-env-file gateway=.env.gateway \
  --service-env-file runtime=.env.runtime

fugue deploy image ghcr.io/example/app:latest --name demo
fugue deploy . --background
03

fugue.yaml

fugue.yaml topology rules and template metadata

fugue.yaml is the clearest way to tell Fugue about services, dependencies, bindings, template metadata, and backing services without relying on inference alone.

Compose import is still supported, but fugue.yaml gives you a better place to name the primary service, declare reusable template variables, and describe backing-service ownership directly.

The importer treats app services, managed Postgres declarations, backing services, and bindings as one topology. That is why fugue.yaml matters for both deploy correctness and later failover behavior.

Rules Fugue enforces

  • If more than one service is marked public, set primary_service explicitly. Fugue rejects ambiguous multi-public topologies.
  • If exactly one service is public, Fugue can infer primary_service for you.
  • Missing local files referenced from volumes become editable persistent_storage_seed_files, which is how the importer surfaces required file mounts before the first deploy.
  • persistent_storage.storage_size and storage_class_name merge with mounts inferred from volumes instead of replacing them.
  • template.variables can mark values as required, secret, and generate=password, which is useful when the repo is intended to behave like a reusable starter.

Top-level keys

Root fieldMeaningCurrent behavior
versionManifest schema versionCurrent examples use version: 1.
primary_servicePublic entrypoint for the topologyRequired when more than one service is public; otherwise Fugue can infer it if only one public service exists.
templateStarter metadataSupports template name, slug, docs/demo URLs, default runtime, and variable definitions.
servicesDeployable app and managed service topologyUsed to derive app imports, compose dependencies, bindings, and seed files.
backing_servicesShared attached services like Postgres or RedisUseful when you want explicit ownership and bindings instead of raw env strings.

Service-level fields

Service fieldScopeWhat it influences
public / portPer serviceControls public-route eligibility and the internal/public port map.
build.strategy, build.context, build.dockerfilePer servicePins build detection and file paths when auto detection is not enough.
env / environmentPer serviceStatic environment baked into the imported service spec.
depends_onPer serviceFeeds controller-side dependency ordering for topology deploys.
bindingsPer serviceConnects app services to named backing services.
volumes and persistent_storagePer serviceDrive persistent mount imports, storage class/size, and editable seed-file prompts.
Annotated `fugue.yaml` example

This shape reflects what the current importer and template inspector actually understand today.

fugue.yaml
version: 1
primary_service: web

template:
  name: Next starter
  slug: next-starter
  description: Ship a ready-made Next.js app.
  source_mode: github
  default_runtime: runtime_edge_hk
  variables:
    - key: NEXT_PUBLIC_SITE_URL
      label: Site URL
      description: Public app URL.
      default: https://example.com
      required: true
    - key: SESSION_SECRET
      label: Session secret
      description: Used to sign cookies.
      generate: password
      secret: true

services:
  web:
    public: true
    port: 3000
    build:
      strategy: dockerfile
      context: .
      dockerfile: Dockerfile
    env:
      API_BASE_URL: http://api:8000/v1
    depends_on:
      - api
    volumes:
      - ./api.yaml:/workspace/api.yaml
    persistent_storage:
      storage_size: 10Gi
      storage_class_name: fast-rwo

  api:
    port: 8000
    build:
      strategy: dockerfile
      context: apps/api
      dockerfile: Dockerfile
    bindings:
      - db

backing_services:
  db:
    type: postgres
    image: postgres:17.6-alpine
    owner_service: api
04

Billing

Billing activation, defaults, and why image inventory matters

Billing is envelope-based for managed capacity and event-based for paid public runtimes. The important distinction is that billing activation is broader than “the app is currently handling traffic.”

Live usage and committed billing are different views. The billing API can skip live managed-usage aggregation and return committed billing data only, which is useful when you care about the saved envelope and current billable posture rather than a live probe.

Managed image inventory matters. Retained managed images contribute to billing activation because managed storage is part of the envelope, even if the app itself is otherwise quiet.

Default resource baselines

Free managed cap
500m CPU · 512 MiB · 5 GiBCurrent default free managed envelope per tenant.
Default managed app
250m CPU · 512 MiB · 0 GiB extra storageDefault managed app resources before you override them.
Default managed Postgres
500m CPU · 1024 MiB · 1 GiB storageDefault app-owned managed Postgres footprint.
Default managed workspace
10 GiB storageWorkspace storage is billable storage when enabled.

What users usually underestimate

  • Billing stays inactive until managed capacity, retained managed image inventory, or paid public runtime usage becomes active.
  • Once billing is active for managed capacity, Fugue meters the saved managed envelope hourly from your balance, not just the latest instantaneous pod reading.
  • A consumer deploying onto a paid public runtime is billed hourly, while the runtime owner receives the matching credit event.
  • Your own attached servers stay free unless you publish them for other tenants as paid public runtimes.
  • The self-serve web top-up flow currently accepts whole USD amounts from 5 to 5000.

Billing status meanings

StatusMeaningTypical next action
InactiveNo managed resource, retained managed image inventory, or paid public runtime usage is currently billable.No action needed unless you are expecting managed capacity to be active.
ActiveManaged envelope or paid public runtime usage is deducting balance hourly.Check envelope size, current usage, and image inventory if the rate looks surprising.
RestrictedBalance is depleted while there is still billable managed/public runtime activity.Top up before increasing capacity or deploying onto paid public servers.
Over capCurrent live managed capacity is above the saved managed envelope.Save a higher cap before adding more managed capacity.
Billing inspection and adjustment commands

These are the current high-value billing commands on the CLI side.

billing.sh
fugue admin billing show
fugue admin billing cap --cpu 2000 --memory 4096 --storage 30
fugue admin billing topup 25 --note "manual credit"

fugue project images usage marketing
05

Continuity

Stateless migrate versus managed failover

Fugue intentionally splits stateless migrate from managed failover. Users usually confuse those two paths when a project graduates from shared runtime to attached runtime or needs stateful recovery planning.

fugue app move and /v1/apps/{id}/migrate are the active move path. They can move stateless apps and persistent storage that is explicitly migratable, such as movable_rwo.

Legacy workspace storage or dedicated PVC storage must be converted to a migratable mode before an app move.

Managed failover is controller-orchestrated. It can fence the app, wait for final workspace sync, switch runtimes, and restore replicas when failover targets have been declared.

Audit states

  • ready: no hard stateful blocker is attached and stateless posture looks reasonable.
  • caution: Fugue does not see a hard blocker, but replicas or runtime posture still need work.
  • blocked: stateless migration is intentionally blocked because managed backing services or persistent workspace state are still attached.

Migrate vs failover

PathUse whenHard boundary
MigrateYou are actively moving the app to another runtime.Blocked when persistent storage is still legacy workspace or dedicated PVC.
FailoverYou need controller-orchestrated runtime switch and state-aware recovery.Needs declared failover targets and is strongest in same-control-plane environments.
Continuity audit and failover commands

Audit first, then configure failover targets, then run failover explicitly when the topology is ready.

continuity.sh
fugue app continuity audit
fugue app continuity audit my-app

fugue app failover policy set my-app --app-to runtime-b --db-to runtime-c
fugue app failover run my-app --to runtime-b
06

Diagnose

Inspect, diagnose, and trust the contract

The shortest path to the right answer is usually an inspect or diagnose command, not an SSH session. Fugue already exposes topology, route, log, runtime, and HTTP timing probes directly in the CLI.

Use template inspection before importing unfamiliar repositories. That path shows primary_service, warnings, template metadata, and any editable persistent seed files without mutating anything.

Use fugue api request and fugue diagnose timing when you need to prove whether a problem is contract shape, control-plane latency, or an app-level behavior mismatch.

High-value details

  • fugue app fs can browse either persistent storage roots or the live container filesystem; choose --source persistent or --source live deliberately.
  • fugue app request --header-from-env is safer than pasting service secrets into your terminal history.
  • fugue runtime doctor shared folds location-specific managed-shared runtime IDs into the shared view, so the output maps to real backing nodes during debugging.
  • The control plane publishes /openapi.yaml, /openapi.json, and /docs; that contract is the HTTP source of truth.

Debugging shortcuts

CommandBest useWhy it beats guessing
fugue template inspect github owner/repoCheck a repo before importShows topology, template metadata, warnings, and seed files before the first mutation.
fugue app overview my-appRead current app posturePulls route, domains, bindings, operations, images, and rollout context together.
fugue app logs pods my-appSee current and recent pod groupsUseful after rollouts when the current runtime log tail no longer explains what changed.
fugue app logs query ...Interrogate business-log tablesAvoids writing raw SQL every time a request-log table is the real source of truth.
fugue runtime doctor sharedInspect runtime health and attachmentChecks status, endpoint, recent heartbeat, and matching nodes in one view.
fugue api request GET /v1/appsRaw control-plane API debuggingShows status, headers, body, server-timing, and transport timings directly.
fugue diagnose timing -- app overview my-appLatency attributionReports DNS, connect, TLS, TTFB, and total timing per HTTP request inside a normal CLI command.
Inspection and troubleshooting workflow

Inspect before import, then use route, logs, filesystem, runtime, and raw HTTP diagnostics without SSH.

diagnose.sh
fugue template inspect github owner/repo
fugue deploy inspect github owner/repo

fugue app logs pods my-app
fugue app logs query my-app --table gateway_request_logs --since 1h --match status=500
fugue app request my-app GET /admin/requests --header-from-env X-Service-Key=SERVICE_KEY

fugue app fs ls my-app / --source live
fugue runtime doctor shared
fugue api request GET /v1/apps
fugue diagnose timing -- app overview my-app