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
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ Notable changes to Cloudfall. The format follows

### Changed

- **Breaking:** the CLI follows one name per meaning, and its output is
typed:
- Decision records have their own group: `decisions list` (was
`operations decisions`), `decisions approve` (was `operations
approve`), and a new `decisions show`. `operations` keeps the catalog:
`list`, `show`, `propose`
- `data migrate` is `data copy`, no longer read as `migrate`, and
`services inspect` is `services observe`, as `observe` collects server
evidence. Each old path answers 13 `REDIRECTED` with the new command in
`error.redirect.command`
- `migrate --release` and `--env-file` are `--component-release` and
`--component-env-file`: they take `COMPONENT=VALUE` pairs, where
`deploy`'s take one value
- `--observed` defaults to `tmp/observed` on every command, where
`observe` writes: `audit`, `services status` and `dashboard` required
it, and the operator's drift checks used `tmp/operator/observed`
- Field names in `data` are snake_case at every depth, as treaty's own
envelope keys are (`openProposals` is `open_proposals`, `wouldRun` is
`would_run`). Map keys that are data keep their spelling (resource
kinds, environment variable names, ids), and a record or resource in
`data`, anything with an `apiVersion`, keeps its stored form
- Every command's output schema gives each `data` key its JSON type, and
an optional list or object is written empty rather than `null`
(`inventory show` writes `ansible` as `{}` for a project)
- **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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ routes. Progress persists after every step, so a failed step or the DNS
pause resumes exactly where it stopped.

Managed-database contents follow the same guided path: save the source
connection URL into a local file and either run `cloudfall data migrate`
connection URL into a local file and either run `cloudfall data copy`
directly (it shows the plan until you add `--yes`) or add `--data <database>=<url-file>` to the migration plan. The
engine dumps on the target host, restores over the peer-authenticated
socket, refuses non-empty target databases, verifies per-table row counts,
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ records an explicit origin skip when origin and proxy share a host.
unmappable ✔
(blueprint files; the Render API and cron jobs are pending)
- Data migration: managed-Postgres dump and restore with verification ✔
(`cloudfall data migrate`, the `--data` step of `cloudfall migrate`, and
(`cloudfall data copy`, the `--data` step of `cloudfall migrate`, and
the confirm-gated `migrate_database` MCP tool: per-table row-count
verification, a non-empty-target refusal guard, secret-file hygiene, and
a `DataMigrationReceipt`; proven live in the
Expand Down
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ tasks:
- validate
cmds:
- >-
uv run cloudfall services inspect --project {{ .CONFIG_DIR }}
uv run cloudfall services observe --project {{ .CONFIG_DIR }}
--schemas {{ .SCHEMA_DIR }} --service-observed {{ .SERVICE_OBSERVATION_DIR }}

services:status:
Expand Down
2 changes: 1 addition & 1 deletion docs/fleet-goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ acceptable if the following hold:
| 6 | Failover on demand | `availability` block, formation mode | Designed, not implemented (demand-gated) |
| 7 | One-command node setup | Baseline over SSH from config | In place for installed Debian; provisioning (installimage, RAID) out of band |
| 8 | Resource limits | systemd resource control from declared envelopes | Missing |
| 9 | Data movement verb | `data migrate` + file-storage move + receipts | Partial: databases yes, file storage no |
| 9 | Data movement verb | `data copy` + 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, 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 |
Expand Down
6 changes: 3 additions & 3 deletions docs/neon-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ restorable, and the always-on operator watches the database with the
evidence attached to every decision. Managed PostgreSQL is mostly
insurance; this keeps the coverage and makes the proof yours.

> **Status:** the guided data migration (`cloudfall data migrate`) is
> **Status:** the guided data migration (`cloudfall data copy`) is
> proven live against an external managed PostgreSQL — dump, restore,
> per-table row-count verification, refusal guards, and a
> `DataMigrationReceipt` (see the
Expand Down Expand Up @@ -152,9 +152,9 @@ after the dump starts are lost. Put the application into maintenance
mode or stop its writers, then:

```console
uv run cloudfall data migrate postgresql-main \
uv run cloudfall data copy postgresql-main \
--database app --source-url-file tmp/neon-app-url
uv run cloudfall data migrate postgresql-main \
uv run cloudfall data copy postgresql-main \
--database app --source-url-file tmp/neon-app-url --yes
```

Expand Down
2 changes: 1 addition & 1 deletion docs/render-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Save the Render database's connection URL alone into a local file, then
either run the data migration directly or add it to the plan:

```console
uv run cloudfall data migrate acme-postgresql --database acme --source-url-file ~/.render/acme-db.url
uv run cloudfall data copy acme-postgresql --database acme --source-url-file ~/.render/acme-db.url
uv run cloudfall migrate --build acme-api=main --data acme=~/.render/acme-db.url --yes
```

Expand Down
2 changes: 1 addition & 1 deletion docs/secrets-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ uv run cloudfall secrets render crm-backend \
This writes `tmp/env/crm-backend.env` with mode `0600` and prints an
envelope carrying the key **names**, the file hash, and the resolved
references — never a value. Pass that file to `cloudfall deploy --yes
--env-file` or map it in `cloudfall migrate`; the deploy role installs it
--env-file` or map it with `cloudfall migrate --component-env-file`; the deploy role installs it
into the release owned by the application user and the systemd unit loads it
with `EnvironmentFile=`.

Expand Down
8 changes: 4 additions & 4 deletions sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ uv run cloudfall restart --project config/examples crm-backend --yes
uv run cloudfall health --project config/examples crm-backend
```

`deploy`, `rollback`, `restart`, and `data migrate` change servers only with
`deploy`, `rollback`, `restart`, and `data copy` change servers only with
`--yes`. Without it they run every controller-side check (declared component,
verified artifact, declared database, source URL file) and print a `plan`
naming the target servers, exit `0`, so a request can be reviewed before it
Expand All @@ -80,8 +80,8 @@ fleet over stdio, and its tools are Cloudfall's own commands. The fleet,
the schema and engine directories, and every directory a tool writes are
fixed when the server starts, so a tool call cannot point at another
project, schema directory or engine, or write outside the project. Read-only commands (`config_validate`, `inventory_show`, `audit`,
`services_status`, `health`, `observe`, `services_inspect`) carry read-only
annotations. `deploy`, `rollback`, `restart`, `migrate` and `data_migrate`
`services_status`, `health`, `observe`, `services_observe`) carry read-only
annotations. `deploy`, `rollback`, `restart`, `migrate` and `data_copy`
return their plan until called again with `yes: true`. Four tools have no
command of their own: `build_artifact`, and `converge_baseline`,
`converge_services` and `converge_domains`, which are destructive and run
Expand All @@ -90,7 +90,7 @@ only with `confirm_destructive: true`.
The fleet-declaring tools `add_ssh-key`, `add_server-type` and `add_server`
are `cloudfall add`: they write schema-validated resource files into the
project and never overwrite an existing resource. `cloudfall init`,
`operations approve`, `operator run` and `dashboard serve` are never tools:
`decisions approve`, `operator run` and `dashboard serve` are never tools:
the server starts inside an existing project, approving a recorded
operation is a person's command, and the loops run until stopped.

Expand Down
13 changes: 7 additions & 6 deletions sdk/src/cloudfall/agent_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
server-changing ones previewing until called with ``yes``. On a repository,
they are the read-only fleet commands and one tool per declared operation,
whose call runs check mode and records a proposal; approving it is
``cloudfall operations approve``, which no tool can stand in for.
``cloudfall decisions approve``, which no tool can stand in for.

Nothing here imports ``cloudfall.app``: ``App(mcp=...)`` needs these at
construction. The tools Cloudfall provides beside its commands, which use
Expand Down Expand Up @@ -45,7 +45,7 @@
if TYPE_CHECKING:
from cloudfall.catalog import Operation

APPROVAL_COMMAND = "cloudfall operations approve"
APPROVAL_COMMAND = "cloudfall decisions approve"
"""The command a person runs to approve a proposal; no tool stands in for it."""

ERROR_INVENTORY_UNDECLARED = "fleet_inventory_undeclared"
Expand Down Expand Up @@ -287,7 +287,7 @@ def operation_tool_description(operation: Operation) -> str:
"inventory.show",
"audit",
"services.status",
"services.inspect",
"services.observe",
"health",
"observe",
"add.ssh-key",
Expand All @@ -299,7 +299,7 @@ def operation_tool_description(operation: Operation) -> str:
"deploy",
"rollback",
"restart",
"data.migrate",
"data.copy",
"migrate",
"backup.run",
"backup.verify",
Expand All @@ -317,7 +317,8 @@ def operation_tool_description(operation: Operation) -> str:
"audit",
"operations.list",
"operations.show",
"operations.decisions",
"decisions.list",
"decisions.show",
"why",
}
)
Expand Down Expand Up @@ -427,7 +428,7 @@ def bound_arguments(args: McpServeArgs) -> dict[str, object]:
Cloudfall manages declarative infrastructure for dedicated Debian servers,
in the one project this server was started for. Read-only tools validate
the project and derive evidence. deploy, rollback, restart, migrate and
data_migrate change servers: called without yes they only return the plan;
data_copy change servers: called without yes they only return the plan;
review it, then call again with yes: true. The converge_* tools converge
every declared server and are destructive: they run only with
confirm_destructive: true. Every change writes receipts; nothing reports
Expand Down
Loading
Loading