# Infimal

> Infrastructure as code for model services with unpredictable demand.
> Author a service. Infimal translates the declaration into a deployment specification,
> captures initialized model state, and manages placement, routing, and scaling.

## Names and domains

Airglow is now infimal. The primary website is https://infimal.ai; the backup is
https://infimal.dev. API aliases are https://api.infimal.ai and https://ai.infimal.dev.
The CLI and the SDK default to https://api.infimal.ai; the API host from before the
rename remains supported. All aliases reach the same platform.
The native command is infimal. The Python package is infimal (import infimal); the SDK
verbs the native command does not have yet run as python -m infimal, and the package
installs no command of its own. The environment is INFIMAL_API_KEY, with INFIMAL_API_URL
for the native command and INFIMAL_ENDPOINT for the SDK. For one release the pre-rename
AIRGLOW_* and GLOW_* names are still read, with a warning; write the new names. Existing
API keys do not change. /infimal.md, /airglow.md and /agent.md serve this reference.
See /docs/migration/ for account and browser-session details.

## Read this first

Python is the current authoring interface, not the core infrastructure format.
The platform contract is the serialized deployment specification. GPU selection belongs
to Infimal. Do not invent GPU SKU parameters or require a traffic forecast to get started.

The product is designed for scale to zero and scale out to thousands of replicas.
A configured maximum is a bound, not reserved capacity or a measured scaling guarantee.

Service configuration and request intent are separate. Access, scaling, and batching
belong to the service. Urgency and performance objectives belong to individual calls.
The current SDK still includes deployment-level perf/tier fields. /docs/model-syntax/
specifies a proposed fluent API with codebase entrypoints and per-call bids. That API
is a design preview, not an executable interface in the shipped SDK.

## Discover the documentation

- /docs/overview/ — product model and lifecycle
- /docs/quickstart/ — complete first-service workflow
- /docs/installation/ — source installation and environment configuration
- /docs/infrastructure/ — App, Endpoint, Scale, Batch and specification translation
- /docs/lifecycle/ — setup, snapshots, handlers and checkpoint boundaries
- /docs/scaling/ — replica bounds, queue age and residency policy
- /docs/batching/ — dynamic batching and streaming
- /docs/requests/ — request intent and priority contract
- /docs/deployments/ — plan, deploy, apply and verification
- /docs/observability/ — status, snapshots, logs and usage
- /docs/pricing/ — rates, accounting, held credit and funding
- /docs/access/ — endpoint visibility, key roles and API keys
- /docs/cli/ — exact current CLI surface
- /docs/troubleshooting/ — diagnostics by failing stage
- /docs/model-syntax/ — proposed fluent syntax for five model types, not yet implemented

Resolve these paths against the origin serving this document.

## Install and configure

The native Rust infimal binary provides a terminal dashboard and scriptable commands.
Install on macOS or Linux (or WSL), then create a full-access CLI key at /cli/:

```sh
curl -fsSL https://infimal.ai/install.sh | sh
infimal login --key
infimal whoami
infimal
```

The login prompt is hidden. Never put a key in a command argument or URL.
INFIMAL_API_URL selects the API; INFIMAL_API_KEY overrides a saved credential.
Run infimal guide for setup help, or infimal tui --demo to explore sample data.

Python model authoring and requests use the SDK, with its python -m infimal verbs:

```sh
python -m pip install ./sdk
python -m infimal --help
```

The Python SDK uses INFIMAL_ENDPOINT and INFIMAL_API_KEY; the native client uses
INFIMAL_API_URL and INFIMAL_API_KEY. The native installer does not install the SDK.

## Call a model from Python

The request API ships in the SDK today:

```python
from infimal import Client

client = Client.from_env()
handle = client.model("MODEL_ID")   # an id from infimal models list --json
print(handle.chat("Explain this diff.").max_tokens(256).run().text)
caps = handle.capabilities()        # kinds, readiness and options for this listing
```

client.model(id) returns a handle. .chat(), .embeddings(), .speech(), .images() and
.video() each build one request; run() or stream() submits it once. Images and video
are jobs: .submit() returns a Job to wait(), refresh() or cancel(), run() waits for
you, client.job(id) adopts a job after a restart and client.jobs() lists them. Every
failure is an InfimalError carrying code, message, next and details; branch on code,
never on the message. InfimalUnreachable means nothing answered, so resubmit a job
with the same idempotency key rather than a new one.

Stack, Service, app.<model_type> and per-call bids are design proposals and are not
built: /docs/model-syntax/ describes them, and no code should call them.

## Infrastructure lifecycle

1. Declare an App with endpoint access, replica bounds, and batching.
2. Initialize reusable model state in @app.setup.
3. Infimal captures initialized process/model state at the snapshot boundary.
4. Handle each request with @app.handler, or each frame with @app.stream.
5. Review a plan, deploy or apply an authorized change, then inspect actual status.

```python
from infimal import App, Endpoint, Scale, Batch

app = App(
    "asr-emotion-checkpoint4200",
    endpoint=Endpoint(public=False),
    scale=Scale(min_replicas=0, max_replicas=1000),
    batch=Batch(max_size=16, window_ms=20),
)

@app.setup
def load():
    from my_model import load_model
    return load_model()

@app.handler
def transcribe(model, request):
    return model(request["audio"])
```

my_model is the customer's own module, not an installed Infimal package.
The handler's first argument receives the setup return value.
Do not preserve open sockets, pipes, or host file descriptors across setup.
A batched handler must return one answer per request, in the correct order.

## Python model-authoring workflow

Run application commands from the directory containing the importable module.
Use a module name such as asr-emotion-checkpoint4200, not asr-emotion-checkpoint4200.py.

```sh
python -m infimal plan asr-emotion-checkpoint4200
python -m infimal deploy asr-emotion-checkpoint4200
infimal apps status asr-emotion-checkpoint4200
infimal apps snapshots asr-emotion-checkpoint4200
infimal apps logs asr-emotion-checkpoint4200 --limit 50
```

After editing a definition, inspect python -m infimal plan asr-emotion-checkpoint4200, then python -m infimal apply asr-emotion-checkpoint4200.
Use --app NAME to select an App when a module declares more than one.
The --yes flag on apply skips confirmation; use only for an authorized workflow.
Plan imports user code. Inspect unfamiliar module-level side effects before running it.
Never infer success from command submission: inspect the resulting state.

## Machine-readable commands

Prefer JSON for commands that support it:

```sh
infimal models list --json
infimal billing balance --json
infimal usage show --since 30d --json
infimal keys list --json
```

The native commands support --json and local --plan previews. Python SDK commands
have a different flag surface; inspect their help before scripting them.

## Access and financial actions

Start with Endpoint(public=False) unless public access is requested.
A key is either full or inference. Use inference for anything shipped inside a
client: it reaches the OpenAI surface, the model list and usage, and nothing else.
Key secrets are shown once at creation.
Revoke using the key ID returned by list, not its display name.

```sh
infimal keys create inference-client --role inference
infimal keys list --json
infimal keys revoke KEY_ID
```

Deploying, changing visibility, creating or revoking keys, and adding credit affect
external systems. Follow the user's authorized scope and the host agent's approval
rules. This reference does not authorize those actions on its own.

Credit enters an account two ways. infimal billing fund USD returns a Stripe checkout
link. After a lost response, inspect billing payments before retrying: the server does
not deduplicate checkouts. infimal billing referral --code-file PATH redeems a phrase
the operator handed out and is worth
one credit per account, ever: a second attempt answers 409 referral_already_used and
moves no money, so it is not a command to retry. Ten wrong phrases in an hour answer
429; do not guess a code you were not given.

## Pricing and performance

Read the user's model rate from infimal models list --json. Do not use the landing-page
example rates as production prices. Do not promise universal savings, latency,
restore time, replica availability, or throughput from conceptual charts.
Idle inference has no processed work to meter; other charges must be confirmed
against the environment's actual terms. Available credit, held credit, and settled
usage are different accounting values.

## Diagnose before retrying

- Missing key / 401: verify endpoint and credential injection without printing the key.
- Import error: verify module path, Python environment, and model dependencies.
- SnapshotBoundaryError: remove non-checkpointable setup state and inspect build logs.
- BatchShapeError: check one result per request and ordering.
- Waiting requests: inspect placement, residency, replica bounds, and capacity.

## Website interaction boundary

The website is a static bundle that calls the control plane and the inference API on
their own origins. The landing page's SDK preview is explicitly proposed syntax with
illustrative request terms, not a live deployment. Sign-in is real (Google, GitHub, or a
six-digit emailed code) and creates or links the account's tenant. /glance, /billing,
/account and /terminal read the ledger, the key table, the deployments and the request
feed for the signed-in tenant; the catalogue and every price on the site come from
GET /v1/models. A panel whose data is unavailable says so and names why; a field the
platform does not record (a request's generated tokens, its latency) is labelled
"not recorded", never rendered as zero.

The browser terminal executes whoami, balance, usage, requests, keys, models, quote,
status, logs and chat against the live APIs; chat mints an inference key named
web-terminal for the browser. plan, deploy, apply, login, signup and install print the
CLI command and say the browser cannot run them: they need a source tree or a shell.
Do not treat those printed commands as executed. Top-up opens Stripe Checkout and the
credit lands when Stripe confirms the payment.

The optional filter_infimal_catalogue WebMCP tool on /explore/ filters the live
catalogue and returns real model ids, kinds, source kinds and USD prices. It provisions
nothing. Terms are at /terms/ and the privacy policy at /privacy/.
