Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Human / AI agent ──runs───► CLI / MCP / Python API ──► Gate

The config is a store, not a pipeline stage: humans and agents edit it
directly, the CLI validates and reads it, and the engine converges servers
to it. The agent operates through a stable CLI, the `cloudfall-mcp` server
to it. The agent operates through a stable CLI, the `cloudfall mcp serve` server
and a Python API instead of inventing shell commands or discovering
infrastructure over SSH. Every mutating operation goes through the engine's
explicit playbook contracts, waits behind a gate the agent does not control
Expand Down
78 changes: 76 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,81 @@ Notable changes to Cloudfall. The format follows

### Changed

- **Breaking:** argparse is gone: the last three `cloudfall` commands
move to treaty, and so do root `--help`, `--version` and `--schema`.
- `operator run` streams one envelope line per pass as it ends, with
`data.pass` (`alerts`, `drift`, `autonomy`) and `data.effect`:
`created` for a pass that wrote proposals, `updated` for one that ran
licensed proposals, `noop` otherwise. Stopping it ends the stream with a
`CANCELLED` line and exit 130 (SIGINT) or 143 (SIGTERM), so a systemd
unit needs `SuccessExitStatus=143` (the
[operator guide](docs/operator-guide.md) has it). A gateway it cannot
use (none declared, or a missing or unreadable certificate) is 4
`PRECONDITION`, an unreachable one 12 `UNAVAILABLE`. `--interval` and `--drift-interval` must be above 0. The
operating contract now lists it with the commands that change servers,
since a declared `OperatorPolicy` lets it run proposals
- `dashboard serve` streams one line once the server listens, then serves
until stopped, ending like `operator run`. Its request lines are info
log lines on stderr, shown at a terminal or with `--verbose`
- `changelog` is treaty's: it lists interface changes per release from
the packaged `schema-changelog.json`, which `treaty changelog-add
cloudfall.app:app` writes, and `--since` takes a release version
- `operator approve` reports such a gateway as 4 `PRECONDITION` (was 86
`RECORD_INVALID`) and an unreachable one as 12 `UNAVAILABLE`
- The argparse-era output contract added earlier in this release is
gone: the six-key document with a top-level `status`, `--output json`,
`--schema-version MAJOR` against that contract, the parser-built
`--schema`, the `--help` exit-code table and exit codes 0 to 3. Every
command answers treaty's envelope, and `cloudfall --schema` lists every
command's flags, output schema and exit codes. The `AGENTS.md` that
`cloudfall init` writes describes this contract
- **Breaking:** `cloudfall-mcp` is gone; the agent server is `cloudfall mcp
serve` (treaty 1.0.0rc29, from issues #239, #240, #281 and #285 filed for
it). Its tools are Cloudfall's own commands, answering with the CLI's
envelope, and tool names follow the commands (`list_operations` is
`operations_list`, `validate_config` is `config_validate`). MCP client
configs change from `cloudfall-mcp …` to `cloudfall mcp serve …`
- The server serves one fleet, chosen as before: `--project`, or
`--repository` for a team's Ansible repository. The fleet, the schema
and engine directories, and every directory a tool writes (snapshots,
receipts, artifacts, proposals, import output, the migrate plan) are
fixed for the run: they leave the tool schemas, and a call that passes
one is refused, so no call reaches another fleet or engine or writes
outside the project. So are the Render API URL `import_render-api`
sends its key file to, the env file `secrets_render` writes, and the
alert gateway `operator_approve` verifies against. Files a tool reads
as input (a blueprint, a key file, an env file) stay arguments
- On a project, `deploy`, `rollback`, `restart`, `migrate` and
`data_migrate` return their plan until called with `yes: true`, as on
the CLI; the old `confirm=true` handshake is gone. `build_artifact` and
the `converge_baseline`, `converge_services` and `converge_domains`
tools stay, the converges destructive and run only with
`confirm_destructive: true`. `operator_approve`, `backup_run` and
`backup_verify` run in one call, as their commands do (they were
confirm-gated in `cloudfall-mcp`), and `operator_watch` is gone: the
watch loop runs as a service
- On a repository, the tools are the read-only fleet commands and one
`operation_*` tool per declared operation, which runs check mode,
records a proposal and answers with the approval command in
`data.next`; a destructive operation's tool asks for
`confirm_destructive` even to preview
- Each directory has one flag name across the commands that read and
write it, so a server can fix it once and a non-default one reaches
them all: `observe --output-dir` is `--observed` (as `audit` reads it),
`services inspect --output-dir` is `--service-observed` (as `services
status` reads it), and `--receipts` is `--releases` on `deploy` and
`migrate`, `--backups` on `backup run|verify`, `--data-migrations` on
`data migrate` and `--env-receipts` on `secrets render` (as `audit`
reads it). `mcp serve` takes `--releases`, `--backups` and
`--data-migrations` too
- `init`, `operations approve`, `operator run` and `dashboard serve` are
never MCP tools (`mcp=False`), on this server or `treaty-mcp`
- A fleet that cannot be read stops the server before a client connects,
with the envelope on stderr: 79 `PROJECT_INVALID`, 80 `CONFIG_INVALID`,
85 `INVENTORY_UNREADABLE`. `--list-tools` prints the tool list
- `dashboard serve` reports a port it cannot bind as 4 `PRECONDITION`
with `dashboard_listen_failed`; an unreadable evidence file is no
longer reported as a listen failure
- **Breaking:** `cloudfall-engine` runs on [treaty](https://github.com/romamo/treaty).
Every command answers one JSON envelope on stdout (`ok`, `data`, `error`,
`warnings`, `meta`), errors included, which used to go to stderr in their
Expand Down Expand Up @@ -97,8 +172,7 @@ Notable changes to Cloudfall. The format follows
from outside. Failures that were exit 2 are 4 `PRECONDITION` with the
old code in `error.context.code`. A key a command writes only sometimes
is `null` when absent, so `inventory show` writes `data.ansible` as
`null` for a project. Still on argparse: `changelog`, `operator run`
(treaty #175) and `dashboard serve`
`null` for a project
- **Breaking:** `why` runs on treaty, `--format html` included (treaty
#179): the page is drawn from the answer's JSON document, as before. Its
verdict moves to `data.status`; a bad `--since` or `--until` is 2
Expand Down
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ uv run ansible-lint engine/ansible
Keep changes scoped to one concern. Include tests for behavior changes and
update the relevant README when a workflow changes.

## Releases

After bumping `version` in `pyproject.toml`, record the release's interface
changes, which `cloudfall changelog` serves:

```console
uv run treaty changelog-add cloudfall.app:app
```

It diffs the manifest against the snapshot beside
`sdk/src/cloudfall/schema-changelog.json` and appends one entry; commit both
files with the release.

## Licensing of contributions

Cloudfall is dual-licensed: AGPL-3.0-or-later for everyone, with commercial
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ That design is written up and not yet built; see
> with a single human approval and then autonomously under declared policy,
> a timer-driven drill proved a real backup restorable, and an alert crossed
> the public network to a second machine. The entire migration was driven by
> an AI agent through `cloudfall-mcp` alone. Full reports:
> an AI agent through the MCP server alone. Full reports:
> [proving-runs](docs/proving-runs/). The one layer not yet exercised live
> is bare-metal RAID/storage provisioning (see the [roadmap](ROADMAP.md))

Expand All @@ -52,8 +52,9 @@ That design is written up and not yet built; see
can't be undone
- **AI-agent native.** Agents operate through a stable CLI and Python API
with structured JSON results instead of inventing shell commands over SSH.
The `cloudfall-mcp` server exposes read-only evidence tools freely and
gates every server-changing tool behind an explicit confirmation handshake
`cloudfall mcp serve` exposes read-only evidence tools freely; a deploy,
rollback, restart or migration only returns its plan until called again
with `yes`, and approving a recorded operation stays a person's command
- **The bill buys computers, not margins.** A steady $1,000/mo cloud bill is
mostly margin on commodity compute and managed databases. On servers you
own, that difference becomes runway, every year
Expand Down Expand Up @@ -111,7 +112,7 @@ live on disposable Debian targets:
evidence-derived operations dashboard
- Render blueprint and live-API importers, guided data migration, and the
resumable `cloudfall migrate` orchestrator with explicit cutover steps
- The `cloudfall-mcp` agent server and the always-on operator with receipted
- The `cloudfall mcp serve` agent server and the always-on operator with receipted
proposals and policy-bounded autonomy

The one implemented layer not yet validated live is bare-metal RAID/storage
Expand Down Expand Up @@ -238,7 +239,7 @@ before the bundled roles. To move a project to a newer Cloudfall commit, bump
Humans and AI agents both edit the resources and both run the CLI, with a
human approving anything that changes a server. `cloudfall init` writes
that arrangement down as the project's `AGENTS.md`, the operating contract
an agent started in the directory (Claude Code, Codex, or `cloudfall-mcp`)
an agent started in the directory (Claude Code, Codex, or `cloudfall mcp serve`)
reads first: the canonical `uv run cloudfall` invocation and project
resolution, every command sorted by effect (changes nothing on servers,
writes project files, changes servers) with the gate each server-changing
Expand Down Expand Up @@ -351,7 +352,8 @@ and public routes on every refresh, so service health is live. Server
hardware evidence still comes from observation snapshots: schedule
`task inspect` (cron or a timer) on the management host to keep it fresh.
The server binds `127.0.0.1:8100` by default; set `DASHBOARD_HOST`,
`DASHBOARD_PORT`, and `DASHBOARD_REFRESH` to override. The projection stays
`DASHBOARD_PORT`, and `DASHBOARD_REFRESH` to override. Once it listens it
prints one JSON line with its URL, then serves until stopped. The projection stays
strictly read-only either way.

## Always-on operator
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ against a Cloudfall project first and re-rooted in M16.
row-count checks are re-expressed as verify steps
- **`cloudfall why`** — the question "why did the agent do that" answered
from the record for any host, operation or time window, in JSON and as a
page ✔ (also the `why` tool on `cloudfall-mcp --repository`)
page ✔ (also the `why` tool on `cloudfall mcp serve --repository`)

Exit: an agent drives a declared mutating operation through the MCP server
on a proving host, the client gates it from the annotation alone, the run
Expand Down
4 changes: 2 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ tasks:
cmds:
- >-
uv run cloudfall services inspect --project {{ .CONFIG_DIR }}
--schemas {{ .SCHEMA_DIR }} --output-dir {{ .SERVICE_OBSERVATION_DIR }}
--schemas {{ .SCHEMA_DIR }} --service-observed {{ .SERVICE_OBSERVATION_DIR }}

services:status:
desc: Show evidence-derived service lifecycle status
Expand Down Expand Up @@ -152,7 +152,7 @@ tasks:
uv run cloudfall deploy --project {{ .CONFIG_DIR }} {{ .COMPONENT }}
--release {{ .RELEASE }} --schemas {{ .SCHEMA_DIR }}
--artifacts {{ .ARTIFACT_DIR | default "tmp/artifacts" }}
--receipts {{ .ROOT_DIR }}/tmp/releases
--releases {{ .ROOT_DIR }}/tmp/releases
{{ if .ENV_FILE }}--env-file {{ .ENV_FILE }}{{ end }} --yes

rollback:
Expand Down
2 changes: 1 addition & 1 deletion docs/fleet-goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ acceptable if the following hold:
| 9 | Data movement verb | `data migrate` + file-storage move + receipts | Partial: databases yes, file storage no |
| 10 | Routing follows placement | Domain re-render on convergence | Partial: rendering exists, not wired to placement change |
| 11 | Drain / decommission | Evacuation procedure over 9 + 10 | Missing |
| 12 | Declared operations with verify | `Operation` catalog, MCP annotations, verify playbook | Partial: MCP tools are annotated and confirm-gated; deploys, backups and migrations verify; no catalog over arbitrary playbooks, no declared verify step |
| 12 | Declared operations with verify | `Operation` catalog, MCP annotations, verify playbook | Partial: MCP tools are annotated, server changes preview until confirmed, and approval stays a person's command; deploys, backups and migrations verify; no catalog over arbitrary playbooks, no declared verify step |
| 13 | Audit entry per decision | Receipts as the record, `cloudfall why` | Partial: operator proposals and every deploy, backup and drill write receipts; no single entry joining snapshot, diff, approver and verify; no query |
| 14 | One config, the team's | Fleet reader over their inventory, `cloudfall` key | Missing: the config is Cloudfall's own resources today (design written) |

Expand Down
8 changes: 4 additions & 4 deletions docs/landscape.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ and treats the PaaS column as the place workloads come from.
| PagerDuty, Opsgenie | Operations | Replaces at this scale | The operator remediates what its receipts prove reversible and pages you only for what it cannot undo |
| Devopness | Operations SaaS | Competes | The closest operational twin: closed SaaS, imperative dashboard; Cloudfall is AGPL with typed state the user owns |
| AI SRE agents (generic) | Operations | Alternative | Agents bolted onto imperative tools; their log says a tool was called. Cloudfall keeps the record of what the fleet looked like, what was proposed, who approved and what verify reported, and grants autonomy per operation class from it |
| Claude Code, Codex, any MCP client | Agent surface | Complements | The brain. They drive Cloudfall through `cloudfall-mcp`, gate on its tool annotations with their own permission modes, and leave the record to Cloudfall; read-only tools free, mutating tools behind a confirmation handshake |
| Claude Code, Codex, any MCP client | Agent surface | Complements | The brain. They drive Cloudfall through `cloudfall mcp serve`, gate on its tool annotations with their own permission modes, and leave the record to Cloudfall; read-only tools free, server changes previewed until confirmed |

## What Cloudfall adds and what it replaces

Expand Down Expand Up @@ -134,8 +134,8 @@ with Cloudfall on running and reacting, not on knowing what to run:
| `cloudfall operator approve` | Approval nodes in Automation Controller workflows |
| Timer-driven jobs such as restore drills | Scheduled job templates |
| Receipts | Job history and logs: a record that a job ran, not proof of its result |
| Agent surface through `cloudfall-mcp` | The AAP MCP server (jobs, inventory queries, monitoring through the controller API; a read-only mode, and a read-write mode that launches jobs; technology preview in AAP 2.6.4); the Lightspeed coding assistant and the ADT MCP server help write playbooks |
| `cloudfall-mcp` as the agent's view of the fleet | The Lightspeed intelligent assistant, a chat in the controller UI; it answers from Red Hat docs and, as a technology preview, can query live AAP data through the AAP MCP server |
| Agent surface through `cloudfall mcp serve` | The AAP MCP server (jobs, inventory queries, monitoring through the controller API; a read-only mode, and a read-write mode that launches jobs; technology preview in AAP 2.6.4); the Lightspeed coding assistant and the ADT MCP server help write playbooks |
| `cloudfall mcp serve` as the agent's view of the fleet | The Lightspeed intelligent assistant, a chat in the controller UI; it answers from Red Hat docs and, as a technology preview, can query live AAP data through the AAP MCP server |
| Read-only operations dashboard | Controller web UI, which also launches jobs |

What AAP does not provide, and a team would have to write themselves:
Expand Down Expand Up @@ -170,7 +170,7 @@ For the wedge use case, the full toolchain is:
- Cloudflare or your registrar holds DNS; Cloudfall verifies the flip, it
does not perform it
- An MCP client such as Claude Code drives the whole migration through
`cloudfall-mcp`, confirming each server-changing step
`cloudfall mcp serve`, confirming each server-changing step
- The Cloudfall operator runs afterwards on a small always-on management
host, watching alerts and audits

Expand Down
6 changes: 3 additions & 3 deletions docs/logging-service-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ records:
- **The operator**: watches that route, writes a proposal receipt per
firing alert with the alert labels as its trigger evidence, and verifies
a remediation by seeing the alert stop
- **The agent**: reads the same route through `cloudfall-mcp` and the
`operator_watch` tool; it never queries Loki or Prometheus directly, and
the gateway does not let it
- **The agent**: reads what the operator recorded from that route through
`cloudfall mcp serve` (`operator_list`, `operator_show`); it never queries
Loki or Prometheus directly, and the gateway does not let it
- **The audit**: the running units, pinned versions and listener bindings
declared here are checked by `cloudfall audit` like any other service,
so the stack that produces the evidence is itself evidence
Expand Down
2 changes: 1 addition & 1 deletion docs/neon-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The row-count check is the verify step and the receipt is the record's
entry for the migration. The restore is not done because `pg_restore`
exited zero; it is done because every table's count matches, and the
receipt is what you show when asked whether anything was lost. An agent
driving this through `cloudfall-mcp` gets the same receipt and the same
driving this through `cloudfall mcp serve` gets the same receipt and the same
refusal guards, and cannot skip either.

One database at a time; repeat per declared database. If the application
Expand Down
Loading
Loading