Skip to content

Day-2 operations

Everything blogwright needs for day-2 work already lives in the environment’s S3 bucket: the topology state, one manifest per build, and every source zip. The commands on this page read that record — check for drift, audit what deployed when, replay an earlier build, empty the site, or remove the stack entirely. Each command takes the environment positionally or via --env, defaulting to production (see Environments).

blogwright status [env] walks the environment’s resource graph — the same nodes bootstrap reconciles — and reads each one against the live AWS account.

Terminal window
bw status staging

On a TTY you get a drift tree: present, missing, read error, with each resource’s recorded outputs dimmed alongside. When output is piped, in CI, or with --plain, each resource becomes one stable present / missing line instead, and read failures become warnings.

A missing resource means the account has drifted from the plan. bootstrap is a reconciler — re-run it to create what’s missing and update what exists.

Every build the builder MicroVM runs — deploy or rollback, success or failure — writes a manifest to build/manifests/<hash>.json recording the revision hash, source key, status, start and finish times, duration, and the MicroVM id. blogwright history lists them, newest first.

Terminal window
bw history

On a TTY the table shows a status mark, a relative finish time (3h ago), the build duration, and a ← live marker on the newest success. The plain form prints fixed columns — hash status finished duration — with ISO timestamps.

One corrupt manifest never takes down the whole listing: it’s skipped with a skipping unreadable manifest warning and the rest still render. An environment with no builds yet prints no deployments yet.

blogwright logs <hash> shows the CloudWatch logs for one build. It reads that build’s manifest and filters the builder MicroVM log group to the build’s time window — from a minute before it started to a minute after it finished — printing each event with an ISO timestamp. Get hashes from history.

Terminal window
bw logs 4f3a2b1c9d0e

If the manifest for that hash is unreadable, the command warns and shows the unfiltered log window instead. An empty result prints no log events for <hash> — which also happens once log retention has expired the events (the history listing is unaffected; manifests live in S3, not CloudWatch).

blogwright rollback <hash> re-runs the builder MicroVM against the source zip already archived at build/<hash>.zip — the same build-and-sync pipeline as a deploy, but fed from the archive instead of your working tree. Your checkout is untouched. If the artifact is gone, the command fails immediately:

Terminal window
bw rollback 4f3a2b1c9d0e
# Error: no build artifact at build/4f3a2b1c9d0e.zip; cannot roll back to 4f3a2b1c9d0e

As with a deploy, only the CloudFront paths whose content actually changed are invalidated, and --refresh is accepted to force every file to re-upload.

blogwright delete [env] removes every object under the site/ prefix — nothing else — and then requests a full /* CloudFront invalidation so cached copies fall out of the edge.

Terminal window
bw delete staging

Infrastructure, state, source zips, and build manifests all stay intact, so recovery is just bw deploy or bw rollback <hash>.

blogwright destroy [env] --yes destroys the environment’s entire resource graph and deletes the recorded state. The bucket is emptied and removed too, which takes the build artifacts and deployment history with it. The command refuses to run without --yes.

Terminal window
bw destroy staging --yes

A running builder MicroVM pins its image — the image delete fails while any are alive — so destroy first lists active MicroVMs launched from this environment’s builder image (a sibling environment’s VMs are never touched) and offers to terminate them, default yes. Declining leaves them running and cancels the destroy; non-interactive runs take the default so automation isn’t blocked. After terminating, it waits up to three minutes for them to clear; if they don’t, it errors and asks you to re-run once they have.

Every AWS resource blogwright creates carries two tags:

  • environment — the environment name.
  • app — the explicit "app" config value, falling back to the domain, then the repo directory name — always something you can trace back to the project from a billing or resource listing.

Site files get the same values as S3 object tags on upload, and preview deploys stamp the PR into them (environment: preview-pr-42), so per-PR cost and cleanup queries work.

config/production.jsonc
{
"region": "us-east-1",
"siteName": "example",
"app": "example-blog", // the app tag; defaults to the domain, then the repo dir name
}

Each environment gets two CloudWatch log groups at bootstrap, with independently configurable retention:

Log group Config key Default
MicroVM build logs retention.microvmDays 365 days
CloudFront access logs retention.cloudfrontDays 90 days

The CloudFront log group always lives in us-east-1, regardless of the stack’s primary region, because CloudFront’s vended log delivery only exists there.

config/production.jsonc
{
"retention": { "microvmDays": 90, "cloudfrontDays": 30 },
}

Both values must be at least 1. To apply a change, re-run bootstrap — reconciling an existing log group re-applies its retention policy. See the configuration reference for the full option list.

Output is pretty on a TTY (stdin and stdout must both be TTYs): live build progress, the deploy summary card, the status drift tree, spinners.

Everywhere else the CLI switches to stable, line-oriented text — and the plain formats are a compatibility contract, safe for scripts, CI logs, and agents to parse:

  • Piped output or CI automatically gets the plain line-oriented format.
  • --plain forces it explicitly, even when a TTY is attached.
  • NO_COLOR disables colour only, per the no-color.org convention — the layout is unchanged.

However it’s triggered, plain mode strips all colour codes and disables prompts — confirmations take their default (destructive commands still require --yes). For scripts that parse the output, pass --plain so the plain format is guaranteed regardless of how the command is invoked. The full flag list is in the CLI reference.