fundaia 0.36.2

Command line for the Fundaia deployment platform: projects, services, variables, deployments, logs and metrics
# fundaia

The command line for the [Fundaia](https://infrastructure.fundaia.com) deployment platform: projects,
services, variables, deployments, logs and metrics, from a terminal. It talks to any instance of the
platform — `--url` and profiles are first-class, so one binary reaches production, staging and a
laptop.

What the platform does, and every command grouped by topic, is in the product documentation:
[infrastructure.fundaia.com/docs/cli](https://infrastructure.fundaia.com/docs/cli). This README
covers installing, scripting, updating and working on the crate.

## Install

```bash
cargo install fundaia
```

The crate is public on crates.io; that is the route that works for everybody. Each `cli-v*` release
of the repository also carries prebuilt binaries for `x86_64-unknown-linux-gnu`,
`aarch64-unknown-linux-gnu`, `x86_64-apple-darwin` and `aarch64-apple-darwin`, but the repository is
private, so they are fetched authenticated:

```bash
gh release download --repo alex28042/fundaia-apps -p '*x86_64-unknown-linux-gnu.tar.gz' -D /tmp
tar -xzf /tmp/fundaia-cli-*.tar.gz -C ~/.local/bin
```

`cli/install.sh` downloads the same assets without credentials, so it answers 404 until the
repository is public. Nothing here uses `sudo` or edits a shell profile.

## Sign in

```bash
fundaia login --url https://infrastructure.fundaia.com
```

A terminal cannot present a passkey, so the credential is minted in the browser: the command prints a
short code, opens the approval page and waits. It works over SSH (`--no-browser` prints the address).
The token lives in `~/.config/fundaia/config.toml` (directory `0700`, file `0600`). `logout` only
forgets it locally; revoke it from **Línea de comandos** in the web interface.

```bash
fundaia status                          # every project, in one screen
fundaia new shop api --repo owner/api --connect-to Postgres
fundaia deploy shop api                 # deploy, and watch the six stages
fundaia logs shop api -f

fundaia attention                       # what is broken, everywhere, worst first
fundaia diagnose shop api               # findings, each with the next step
fundaia grep shop ECONNREFUSED          # a text in every service's log
fundaia fix deployment shop api         # Claude Code fixes the newest failed deployment
```

Projects and services are named by id, slug or display name; an ambiguous name is an error, not a
guess.

## Scripting and AI agents

- `--json` (or `FUNDAIA_JSON=1`) prints one compact JSON value on stdout — the server's own DTOs.
  `logs -f` and `watch` print one object per line; `deploy --json` waits and prints one result.
  The diagnosis commands (`attention`, `health`, `diagnose`, `grep`, `deps`, `compare`, `probe`,
  `security`…) print the same object the matching MCP tool returns.
- A failure is one object on stderr: `{"error":{"code","message","exit","retryable",…}}`, with the
  server's error code. Colour is off in JSON mode.
- The exit code is the class, and the numbers never move:

  | Exit | Meaning | Retryable |
  |---|---|---|
  | 0 | success | — |
  | 1 | a bug in the CLI | yes |
  | 2 | bad arguments (clap) | no |
  | 3 | `not_found` | no |
  | 4 | `validation_failed` | no |
  | 5 | `unauthorized` — run `fundaia login` | no |
  | 6 | `forbidden` | no |
  | 7 | `conflict` | no |
  | 8 | `rate_limited` | yes |
  | 9 | `external_service_failed` | yes |
  | 10 | the instance is unreachable | yes |
  | 11 | the deployment failed | no |

- `fundaia schema --json` describes every command, argument and exit code, and whether a command
  `reads`, `writes`, `starts`, `destroys` or is `local`. `fundaia guide` prints the platform's
  briefing for agents (`AGENT.md`, the same truths the instance serves at `/agent.md`). Both work
  offline.
- Completions: `fundaia completions bash|zsh|fish`.

### A Claude Code skill

`fundaia skill install` writes `~/.claude/skills/fundaia/SKILL.md` (`--project` writes it into
`.claude/skills/` of the current directory). It is generated from this binary's own commands and
the guide, so it lists exactly what the installed version can do; run it again after an upgrade.
`fundaia skill` prints it without writing anything.

## CI and profiles

Every global option reads an environment variable (`FUNDAIA_URL`, `FUNDAIA_TOKEN`, `FUNDAIA_PROFILE`):

```yaml
env:
  FUNDAIA_URL: https://infrastructure.fundaia.com
  FUNDAIA_TOKEN: ${{ secrets.FUNDAIA_TOKEN }}
run: fundaia deploy shop api
```

```bash
fundaia login --url https://staging.example.com --as-profile staging
fundaia --profile staging status
```

A saved token never travels to another host: `--url` pointing elsewhere than the profile needs
`--token` too. Plain `http://` is refused except on loopback (`FUNDAIA_INSECURE_HTTP=1` overrides).

## Updates

The tool updates itself. Once a day it asks crates.io for a newer release (alongside the command,
never before it), and installs it: the release binary when it can be downloaded — its `sha256` is
mandatory — and `cargo install` otherwise, which is what happens today because the assets are
private. The swap is a `rename`, so the running command finishes on the version it started with.
Notices go to stderr; nothing here can make a command that worked exit non-zero.

| | |
|---|---|
| Inside CI (`CI` set) | Notice only, never installs |
| `FUNDAIA_NO_SELF_UPDATE=1` | Notice only — your package manager owns the binary |
| `FUNDAIA_NO_UPDATE_CHECK=1` | No check at all |
| `fundaia upgrade [--check]` | Update now, ignoring the daily cache |
| `fundaia changelog [<version>\|--since <v>\|--all]` | What each version brought, compiled into the binary |
| `fundaia changelog --history` | Which versions have run on this machine (`~/.config/fundaia/versions.toml`) |

## Working on it

```bash
cd cli
cargo build --release
cargo test
cargo clippy --all-targets -- -D warnings
FUNDAIA_PERF_BUDGET_MS=150 cargo test --release -- --include-ignored   # startup and hot-path budgets
```

`cli.yml` runs formatting, clippy and the tests on every change under `cli/`; the performance
budgets and the 8 MiB release-binary ceiling run on `main`, before anything is published.

A new command is finished when it has its `--json` shape and its row in `EFFECT_OF`
(`src/commands/schema.rs`); the platform side — service, REST route, MCP tool — is described in
`.claude/rules/surfaces.md`.

## Releasing

Nobody edits the version by hand. The repository's `post-commit` hook raises `Cargo.toml` from the
commit type when a commit touches `cli/` (`feat` minor, `!` or `BREAKING CHANGE` major, anything else
a patch) and stamps `CHANGELOG.md`, whose entries are written by a person.

A push to `main` that touches `cli/**` runs `.github/workflows/cli.yml`: if the tag
`cli-v<version>` does not exist yet, it tags, creates the GitHub release, builds the four binaries
with their checksums and publishes the crate. A version already on crates.io is skipped, so a run can
be repeated safely; `gh workflow run cli.yml --ref cli-v<version>` rebuilds a release from its tag.

Publishing uses `CARGO_REGISTRY_TOKEN`, scoped to `publish-new` and `publish-update` on this crate,
with no expiry. If it is missing the publish step says so and ends green; mint a replacement under
**Account settings → API tokens** on crates.io and add it to the repository under **Settings →
Secrets and variables → Actions**. When GitHub Actions cannot
run at all, `bun run ship` publishes the crate from a laptop (see `deploy/README.md`).

## Licence

MIT.