# Alf > Alf deploys apps (containers and docker-compose stacks), databases (Postgres, MySQL, Redis, MongoDB) and Linux computers for people and their coding agents, and runs them on servers Alf operates in several regions (shared by default; an organization can have private ones). Every public service gets an HTTPS address; idle services sleep (paused, never stopped) and wake on the next request; busy ones scale out. Coding agents work with it through MCP. ## Facts - Name: Alf, formerly smartalfred (the command-line tool still answers to both names). Site, docs and dashboard: https://runalf.com. Apps are served at addresses under smartalfred.com. - What it is: a hosting platform (a PaaS) for apps, databases, Linux computers, static sites and S3-compatible buckets, built to be driven by coding agents (Claude Code, Codex, Cursor, opencode) over MCP as well as by people, from the dashboard, the `alf` command line or the REST API. - Where it runs: on servers Alf operates, in Europe for now (https://runalf.com/regions). - Prices, in US dollars: Hobby $5 a month and Business $50, each covering that much usage; beyond it, a service costs $6 per GB of its size (its memory) a month awake, billed by the hour (from $1.50 a month for xs), and nothing asleep; a volume is $0.10 per GB of its size a month, awake, asleep or stopped. The first $5 are free. https://runalf.com/pricing - Project file: `alf.toml` beside the code (`smartalfred.toml`, its first name, still works). https://runalf.com/docs/alf-toml - How it compares with Fly.io and Railway: https://runalf.com/compare. Security: https://runalf.com/security. Docs for people: https://runalf.com/docs. Every page in one file: https://runalf.com/llms-full.txt. Each page as Markdown: https://runalf.com/docs/.md (for example https://runalf.com/docs/quickstart.md). ## Connect an agent (MCP) - Endpoint: https://api.runalf.com/mcp (Streamable HTTP, JSON responses). - Sign in with the browser (OAuth 2.1 + PKCE, dynamic client registration; metadata at https://api.runalf.com/.well-known/oauth-authorization-server), or send `Authorization: Bearer sat_…` with a token made under Agents in the dashboard (https://runalf.com/app/agents). - Claude Code: `claude mcp add --transport http alf https://api.runalf.com/mcp`, then `/mcp` → Authenticate. - Codex: `codex mcp add alf --url https://api.runalf.com/mcp` and `codex mcp login alf`. - opencode: a `remote` server with that URL in opencode.json, then `opencode mcp auth alf`. - Without MCP: POST JSON-RPC (`tools/list`, `tools/call`) to the same URL with a bearer token. ## Model - Organization → projects → services. A project's services reach each other by name on a private network (`db:5432`), encrypted between servers. - A service runs a container image, or is built on the server from code pushed to it (its Dockerfile). Code is pushed with one command, the same from a working directory and from CI; there is no GitHub connection. - Public services: `https://{service}-{project}-{organization}.smartalfred.com`, plus custom domains (one CNAME to domains.smartalfred.com). Private services have no address. - The app listens on a port: `PORT` is set; otherwise the image's EXPOSE, else 8080. - Variables are visible; secrets are encrypted and never shown again. Changes are staged until deployed. - Deploys of public services have no downtime: the new version starts beside the running one and takes over once it's ready (port, plus the service's health_path if set); if it never is, the deployment fails and the previous version keeps running. Services with a volume and private services stop the old container first. - Databases and other non-HTTP services can get a public TCP or UDP port (open_port): an address like db-shop-acme.tcp.:20431 straight at the server, open only to an allowlist of IP addresses ("anywhere" must be explicit). If a client is cut off at once, list_ports shows the addresses turned away: allow the user's. - Databases in one click: add_database (engine postgres, mysql, redis or mongodb) makes one with the official image, a generated password and a disk of its own, private and always on, with a snapshot every night and a copy off the server. connect_database gives an app its URL as a reference that follows the database: DATABASE_URL (REDIS_URL for Redis, MONGODB_URI for MongoDB). A service with a volume (a database, a computer) moves to another server with its data. - One-click deploys are ready-made stacks (an app with its database) from the public repository github.com/SmartAlfred/one-click: list_templates, then deploy_template into a project. Passwords are generated and returned once. - Candidates: deploy, upload_code or push_code with candidate true starts the new version beside the live one (same project network, same or staged config) at {address}--next.; wait_for_deployment until it's ready, test it, then promote_candidate or discard_candidate. For public services without a volume. It uses the real database. - Something wrong: get_service with diagnose true gives findings (a failed deploy with its hint, out of memory, a full volume, error rate, slowness, broken domains, staged changes), each a problem or a warning with what to do next. A failed build's failure explains the usual causes (a file not sent, a lockfile out of step, a missing script, a runtime too old, an image that doesn't exist). - Previews start with empty databases; alf.toml's [previews] seed = "…" runs once in each new preview after its app is first live. - Every deployment's result has config: whether staged variable/secret changes went live with it or are still staged. A failed deployment has failure: kind (exited, port, health, start, build), a hint (naming a missing variable when the output shows one), and the container's last output. A service's first deploy that failed only because the app listens on another port gets that port and deploys again by itself: failure.retried_as is the new deployment, and wait_for_deployment follows it (fixed_by_itself). - A computer is a Linux machine in a project, beside its services, isolated like any service (a Kata VM with its own kernel), no address of its own. Its whole filesystem is kept, so what's installed stays (the system disk holds up to 30 GB), and /workspace (HOME) is a volume that grows; sudo works, Docker runs inside when it's turned on, and people reach it with `alf ssh /`. It can run startup commands, and switches itself off after an idle time of its own (5 minutes to 24 hours, or never). Memory and cores are sized separately. create_computer makes one (system claude: Debian 12 with Node 22 and Claude Code, the default; or the stock debian, ubuntu, fedora), in the token's project or a new one; run commands in it with exec, its computer_id as service_id and live true. It runs until stopped; one an agent makes goes after a day unless asked (a week at most, extend_computer). From inside it, `alf share ` gives a port an https address. - Volumes keep data across deploys. Nobody picks a size: a volume starts at 10 GB (a database's at its engine's size) and grows by itself past 80% full, live, up to grow_up_to_gb (left out: as far as the plan allows). Its size is set aside on its server's disk, so more room by hand (resize_volume size_gb) is at most twice what it holds; before a big import, resize_volume room_for_gb makes room for it. A snapshot backs a volume up: its files as one archive on its server, taken with the container frozen for a moment (safe for databases); create_snapshot before a risky change, restore_snapshot puts one back (the volume's current contents are replaced), list_snapshots shows them and the schedule. An agent's snapshot is deleted after 7 days unless a person keeps it (expires_at), and a volume keeps the newest 10 of an agent's, the newest 10 taken by hand, and the newest scheduled ones by the schedule's count. A snapshot can have a copy off the server (create_snapshot with offsite true, or the volume's setting): it survives the server, is restored from on another server, and counts as storage. Previews are throwaway copies of a project, optionally named (pr-12) so pushes find them again. ## Tools - Look: whoami, list_projects, list_services, get_service, list_deployments, get_deployment, wait_for_deployment, get_logs, search_logs (errors: true gives each error once, with its stack trace and how often), get_metrics, list_servers, list_previews, list_computers, list_snapshots, list_groups, get_approval, check_domain, list_ports, check_port, list_templates. - Change (tokens with deploy access): create_project, create_service, update_service, add_database, connect_database, set_variables, deploy, rollback, upload_code, push_code, exec and open_session (need "may run commands"), create_computer, extend_computer, delete_computer (needs "may delete"), create_preview, extend_preview, end_preview, create_snapshot, restore_snapshot, create_group, update_group, delete_group, add_domain, open_port, close_port, deploy_template, promote_candidate, discard_candidate. - Resources: `smartalfred://guide`, `smartalfred://projects/{id}` (a project's services, addresses, connections). Prompts: deploy, debug_deployment, preview_changes. ## Deploying code `push_code` (a project) and `upload_code` (one service) return a one-time link and a command: `curl -fsSL https://runalf.com/deploy.sh | sh -s -- ""`. Run it in the code's directory. For a project it looks for a docker-compose file (docker-compose.yml, docker-compose.yaml, compose.yml, compose.yaml) and deploys every service in it (build: ones built from the code, image: ones pulled; missing services are created, existing ones get the new code and keep their settings), or else for a Dockerfile and deploys it as one service (`--service `, default the directory's name). In a git repository it sends tracked and new files (uncommitted changes included, ignored files left out), in parts, up to 8 GB compressed. It prints the plan, waits for the deployments and prints the result; on failure, why, with the container's last output, and a non-zero exit. Options: `--service`, `--compose `, `--dockerfile `, `--context `, `--preview ` (deploy to a named preview, created if missing), `--end-preview `, `--candidate`, `--keep-staged`, `--group `, `--plan` (show the plan only), `--no-wait`. CI: the same command with `SMARTALFRED_TOKEN` set to a deploy token (a `sat_` token with deploy access, ideally limited to the project) and `--project ` or `SMARTALFRED_PROJECT`. GitHub Actions: a step `run: curl -fsSL https://runalf.com/deploy.sh | sh` after `actions/checkout`. Docs: https://runalf.com/docs/deploying-code ## Static sites A service with kind `site` is a static site: built from its Dockerfile like any other, then one folder of the built image (`site_dir`, or the image's own `LABEL smartalfred.static=`) is served from Alf's edge. Nothing of it runs, so it never sleeps. A Dockerfile with that LABEL, or a compose service labelled `smartalfred.static: `, becomes a site by itself. Its variables reach the build as build args (`ARG NAME` in the Dockerfile), its secrets never: everything in a site is public. A deploy uploads only the files that changed and goes live all at once; rolling back to one of the newest 10 deploys is instant. `site_spa: true` answers paths that aren't files with index.html. Docs: https://runalf.com/docs/static-sites ## The command line People have `alf` (short for `smartalfred`), a command-line tool for macOS, Linux and Windows (`curl -fsSL https://runalf.com/cli.sh | sh`, or on Windows `powershell -c "irm https://runalf.com/cli.ps1 | iex"`, then `alf login`): `services`, `service `, `computers`, `logs [-f] [--since 2h] [--grep text]`, `shell `, `exec -- `, `connect ` (this machine in the project's private network: its services on localhost; `disconnect`, `devices`), `restart|stop|start ` (or `--all`), `launch` and `deploy` (in the code's directory; a followed deploy prints the build's lines and the app's first ones; it leaves out what `.dockerignore` does and names big files that go up), `usage` (the month's cost so far and where it's heading), `doctor [service]` (what's wrong and what to do next), `requests [service] -f --status 5xx` (the requests it answered, as they come), `top` (each service now), `cron` / `cron run `, `previews` / `previews end `, `backups` / `backups take` / `backups restore `, `env [set|unset|push|pull]` (a service's variables, from and to .env files; secrets by name only), `rollback [service]`, `db dump` / `db restore ` (a database's data as .sql, or an .archive for MongoDB, via its own container; a snapshot before a restore), `errors [service]` (what went wrong lately: each error once, with its stack trace), `requests --with-logs` (each 5xx with what the app printed meanwhile), `move ` (to another server, with its data), `ssh /`, `run -- ` (a local command with a service's variables, its project connected), `domains add `, `ci github` (GitHub Actions workflows and a deploy token), `agents` (adds this MCP server to Claude Code, Codex or Cursor, asking first), `computer create|extend|delete`, all with `--json`. In a directory with an alf.toml a command about a service may leave the name out: it's that project's app (`logs` with no name interleaves all its services). It signs in as a person (approved in the browser), so it is for people at a terminal; agents use the MCP tools. (Inside a computer, `alf` is the computer's own port tool: `ports`, `share`, `unshare`, `url`.) Docs: https://runalf.com/docs/cli ## Rules for agents - Deleting (delete_service, delete_volume, delete_snapshot, remove_domain, delete_project) needs a token that was given "may delete" (whoami: may_delete); without it, ask a person. With it: delete only what the user asked to have deleted, and snapshot a volume first if its data might still matter. Previews (end_preview), ports (close_port) and groups (delete_group) need no such permission. - Projects can require a person's approval for agents' changes: a change then returns an `approval_id`; check it with `get_approval`. - Tokens can carry limits (changes per hour, replicas, servers, services per project). - WebSockets: a public service takes them at its own address (wss://), with no setting to change; a service with an open socket stays awake until the last one closes. Anything that is not HTTP or WebSocket needs a public TCP or UDP port. - Cost, in US dollars: a service runs at a size, from xs (¼ core, 256 MB) to 5xl (32 cores, 64 GB), s by default; $6 per GB of its memory a month awake, billed by the hour it's awake (xs $1.50 a month, m $6), nothing asleep; $0.10 per GB of a volume's size per month, whether its service is awake, asleep or stopped; $0.10 per GB stored per month (snapshots, buckets, static sites' files). The first $5 are free; after that the organization's plan is charged every month (Hobby $5, Business $50), covering that much usage. A database never sleeps: give it a size that fits. GET /pricing has the numbers, GET /organizations/{id}/billing where the organization stands. A payment method has to be added (by a person, under Billing) before anything is created or deployed; a refusal with the code payment_required means that, or an unpaid invoice. A 403 saying the organization is being deleted means an owner asked for it to go: it runs nothing and changes nothing until they undo it (Settings), and a week after they asked, what's left of it is deleted for good. - A busy server takes no new services until its load is down (list_servers: takes_new_services). Creating a service, pinning one to such a server or asking for more servers is then refused with the code servers_full: choose another server, leave the choice open, or try again later. What already runs isn't affected. - Put passwords and keys in secrets (`set_variables` with `set_secrets`), never in variables or the repository. ## REST API The dashboard's REST API is documented at https://api.runalf.com/docs (OpenAPI 3.1 at https://api.runalf.com/openapi.json). Agents should prefer the MCP endpoint.