import { Callout } from "zudoku/ui/Callout";

# CLI (`albuild`)

The **`albuild` CLI** is a thin, cross-platform command-line face for the ALbuild toolchain: provision (or warm-reuse) a Business Central container, resolve dependencies from your feeds, build, publish and test apps, measure [code coverage &amp; test quality](../concepts/code-coverage), and host/operate the [MCP server](../mcp-server/index), all from one stable verb surface.

<Callout type="info" title="One engine, no drift">
The CLI does **not** re-implement container/artifact/coverage logic. It runs everything through the [`businessdev.ALbuild` PowerShell module](../powershell-module/index), the same engine behind the [Azure DevOps tasks](../devops-extension/index), the [VS Code extension](../vscode-extension) and the [MCP server](../mcp-server/index). One code path, no second wrapper.
</Callout>

---

## What it's for

- A **stable, discoverable** command vocabulary so humans, CI and shell-only AI agents don't hand-write `pwsh` one-liners.
- The **Mac/Linux** developer's entry point, talk to a remote Windows MCP host that runs the containers.
- **MCP lifecycle** tooling: install, host (HTTP / Windows service), configure clients, list/call tools.
- Uniform **`--json` / `--ndjson`** structured output for CI and agents.
- **Answering a question about AL without a container**: [`albuild probe`](./probe) runs one procedure or expression locally in a fraction of a second.

---

## Backends

The CLI is **not** MCP-only. Each command runs through one of two backends:

| Selection | Backend |
| --- | --- |
| _(default, local)_ | **Direct**: the `businessdev.ALbuild` module via `pwsh`. No MCP server, no Node. The right path on a local Windows host that can run BC Docker containers. |
| `--backend mcp` | A local stdio MCP server (`@365businessdev/albuild-mcp`), when you want the server's job model / agent scoping locally. |
| `--server https://host:5020/mcp` | A **remote** MCP host over Streamable HTTP (token from `ALBUILD_MCP_TOKEN`), e.g. a Mac driving a Windows MCP host. |
| `--server <profile>` | A saved server profile in `~/.albuild/config.json`. |
| `--server local` | Force the local direct backend for one command, even when a default server is configured. |

When you **omit** `--server`, the backend is resolved in precedence order: explicit `--server` → the `ALBUILD_SERVER` environment variable → the configured **default server** (`albuild mcp default`) → local. So a Mac that can't run BC containers locally sets a default once and every command goes remote; a Windows box leaves it unset and runs local by default. See [setting a default host](get-started#make-the-remote-host-the-default).

<Callout type="info" title="Compilation is always local">
`app build` (and the build step of `run pipeline`) **always compile on the client**, regardless of `--server` or a configured default, your AL source and compiler stay on your machine. Only container ops (publish, test, unpublish) follow the server; the locally-built `.app`s travel to a remote host as base64 uploads. This is the macOS flow: compile here, run there.
</Callout>

The direct backend keeps the credentials of containers it creates in `~/.albuild/containers.json` (the local equivalent of the server's pool), so a later `app test` can authenticate. Jobs (`job get/cancel`) and `mcp call` require an MCP backend.

---

## Output modes (two audiences)

| `--output` | For | stdout | stderr |
| --- | --- | --- | --- |
| `text` (default) | humans | the result (colored) | an AL-themed **work-in-progress spinner** + log lines + `✓`/`✗` |
| `json` | agents / CI | one envelope `{ ok, command, data, warnings, error, schemaVersion }` | logs only with `--verbose` |
| `ndjson` | agents / streaming | one JSON event per line (`step` / `progress` / `result` / `error`) |  |

In `text` mode every command shows a spinner (a braille spinner + the `albuild` wordmark + elapsed time + the live step) so long operations always show activity. It degrades safely: no animation when stderr isn't a TTY, in **CI**, or with `--no-color` / `NO_COLOR`. `json` / `ndjson` never emit decoration, **stdout carries only the result**, so you can pipe it straight into a parser.

---

## Next steps

- **[Get started](get-started)**: install the tool and run your first commands.
- **[Command reference](commands)**: every command, global options and exit codes.
