| name | cpk-author |
| description | Build a `.cpk/` container package, declare a host
that runs it, and bind that host to a machine in the
fleet inventory. Trigger when the user wants to
package a service for deployment, set up a new
host on a machine in the inventory, or learn the
container / hosts / machines separation.
|
cpk-author skill
(Renamed from infra-author per FEAT-319 + FEAT-323. The
sibling cpk-operator skill
covers the fleet-operation journey; this skill stays
focused on authoring.)
1. Design principles
- Educational. Each substrate is a separate verb on
cpk; reading libexec/cpk/{machines,hosts,container}
teaches one substrate end-to-end.
- Functional. No service registry, no central
control plane. The fleet inventory is a flat
parameter tree; deployments are explicit.
- Decentralized. The machine inventory and host
declarations live in this collection, not in a
cloud-vendor console.
- Simple.
cpk calls account, config,
repo, msync, and the underlying container
runtime (podman). Nothing else.
2. The model
| Substrate | What it is | Where it lives |
|---|
| container | a self-contained .cpk/ package | cpk container / .cpk/ |
| host | a named role bound to one or more machines | cpk hosts |
| machine | a substrate the fleet can reach via SSH | cpk machines |
A host's deployment plan is the container packages it
runs (plus optional cluster-plugin enrolment). Per
FEAT-087, the host's config lives in a git repo
(repo) managed by the host owner; the host's data
rolls via msync so a swap-out preserves state.
The cpk-base layer (FEAT-321) ships a minimal Alpine
rootfs with runit as PID 1 so services operates
uniformly inside the container.
3. Workflow recipes
-
Add a machine to the inventory.
cpk machines add web-01 ssh://admin@198.51.100.5
-
Author a cpk package.
cd /path/to/my-service
cpk container init # scaffolds .cpk/{config,files,hooks,tasks}
echo "80/tcp" > .cpk/config/expose
# ...add Dockerfile fragments under .cpk/, files/ overlays
cpk container build
-
Declare a host that runs that package on a machine.
cpk hosts create acme web # → web.acme
cpk hosts add web.acme web-01
cpk hosts master web.acme web-01
-
Push and run.
cpk hosts update web.acme # build/push to every bound machine
cpk hosts start web.acme # runs on the master
-
Inspect the fleet.
cpk machines list
cpk hosts list
cpk hosts list web-01 # hosts on that machine
4. The .cpk/ author surface
A cpk author writes the package by editing files under .cpk/:
4.1. Dockerfile fragments + files
.cpk/<num>-<name> — numbered Dockerfile fragments
concatenated onto the base image's Dockerfile.in. Use the
numeric prefix to control ordering.
.cpk/files/<path> — files laid into the image at <path>.
.cpk/base — rpk packages to install on top of the base layer
(FEAT-133).
4.2. .cpk/config/* — declarative per-host config
Each file is one record per line. Comments (#) and blank lines
are tolerated everywhere.
| File | Owner | Purpose |
|---|
depends | author | bare-name service deps (FEAT-320). nextcloud resolves to nextcloud.<org>; postgres.shared keeps the cross-org name verbatim. |
expose | author | exposed ports (80/tcp). |
volumes | author | volume mounts (/var/lib/foo). |
auth | author | per-route basic auth rules for the edge cpk (FEAT-318 slice 6). Format: <path-pattern> <user> <bcrypt-hash>. Hashes generated out-of-band (caddy hash-password). |
l4 | author | TCP/UDP forwards for the edge cpk (FEAT-318 slice 7). Format: <port>[/<proto>] <upstream>:<port>. Default proto = tcp. |
retention | author | snapshot retention (FEAT-327 slice 3). A single positive integer; the snapshot proxy pushes it to the remote's max-backups before each backup. |
secrets | author | declared secret names for seed-secrets (FEAT-326 slice 11). One name per line; the operator's choice of --inherit-secrets is what triggers the copy. |
machine-type | clone-org | instance-size hint; cpk hosts up uses it as the default --type (FEAT-326 slice 9). Plain cx11 or a cx22=cx11 mapping. |
ephemeral | clone-org | ISO-8601 expiry timestamp; honoured by destroy-org (FEAT-326 slice 6). |
inherit-secrets | clone-org | empty marker; seed-secrets honours its intent. |
cloned-from | clone-org | source-host fqdn for seed-data and seed-secrets. |
schema-only | clone-org | empty marker; seed-data --handler=postgres passes --schema-only to pg_dump. |
Authoring conventions: only write the "author" rows. The other
rows are written by clone-org and read by the orchestrator;
don't precreate them in your repo.
4.3. .cpk/hooks/* — lifecycle hooks
| Hook | When | Contract |
|---|
drain | cpk hosts drain, down --with-dependents, migrate --with-dependents | App-level "stop accepting traffic" signal. Run locally with $HOSTNAME exported and cwd at host repo. Exit non-zero to abort the orchestrator (FEAT-325). |
resume | inverse of drain | App-level "come back to life" signal. Same shape. |
test | cpk hosts test <host-or-org> | Smoke test. Same shape. Skipped hosts (no hook) count as silent OK, not failure (FEAT-326 slice 3). |
The vendored edge cpk at share/cpk/edge/ is a worked example:
its drain regenerates the Caddyfile in maintenance mode and
sv reload caddys; its resume regenerates the live route
table and reloads.
4.4. .cpk/check — post-build assertions
cpk container build runs check verify /etc/cpk/check against
the built image; the build aborts on assertion failure.
Authoring style:
@check "caddy installed" assert_package caddy
@check "caddy --version works" caddy version
(See FEAT-110 + FEAT-133 for the framework + base-layer hooks.)
5. Guardrails
.cpk/ is owned by the project, not by cpk.
The package spec is the contract; cpk's verbs
operate on it.
- Machines are the only stateful part. Lose the
inventory and you lose the SSH endpoint table; back
it up via
repo + account-scoped sync.
- Hosts are not VMs. A host is a logical
deployment unit. Multiple hosts can share one
machine; one host moves between machines via
cpk hosts migrate <host> <new-machine> (FEAT-314).
cpk container run is rootless by default.
podman's rootless mode is the assumed runtime; any
host needing a privileged container must be explicit.
cpk container <verb>, not cpk cpk <verb>.
The container-builder sub-verb is container
(per FEAT-319); infra cpk build is now
cpk container build. bin/infra ships as a
one-release backward-compat shim.
6. Where to read more
man cpk
cpk container help <verb> and cpk hosts help <verb> for
the actual flag surface on demand.
share/doc/cpk/standards/README.md
docs/cpk-walkthrough.md — empty repo to a
packaged cpk running on a remote host
share/cpk/edge/ — vendored Caddy edge cpk, a worked example
of the .cpk/{config,files,hooks,check} surface.
- This package's
CLAUDE.md
- The companion
cpk-operator
skill (FEAT-323) for fleet-operation journeys, and
cpk-upgrader (FEAT-323 +
FEAT-325/326/327) for the upgrade-pipeline journey.