Releases: frankenpress/fp
0.9.0
What's Changed
- feat: fp list + fp delete learn about pulled snapshots (fp pull Phase 4) by @MatthewKennedy in #20
Full Changelog: v0.8.0...v0.9.0
0.8.0
What's Changed
- feat: fp pull — download prod snapshots from per-tenant S3 (fp pull Phase 3) by @MatthewKennedy in #19
Full Changelog: v0.7.1...v0.8.0
0.7.1
What's Changed
- feat: fp up / down / restart / logs — docker-compose verb wrappers by @MatthewKennedy in #18
Full Changelog: v0.7.0...v0.7.1
0.7.0
What's Changed
- docs(claude): internal/repo/ no longer feeds the slug cascade by @MatthewKennedy in #11
- chore: tidy v0.5.0 surface (hide validate, shelve aidoc, fix links) by @MatthewKennedy in #12
- feat: fp list — host-side snapshot table + summary.Walk helper by @MatthewKennedy in #16
- feat: fp delete + fp prune — companions to the accumulation model by @MatthewKennedy in #14
- feat: fp doctor — read-only health check of the local stack by @MatthewKennedy in #15
- feat: fp wp passthrough + fp release --draft by @MatthewKennedy in #17
Full Changelog: v0.6.0...v0.7.0
0.6.0
fp init — one command, fresh clone to ready-to-design
git clone git@github.com:<your-org>/<your-site>.git
cd <your-site>
fp initThat's it. Designer is in the WP admin a couple of minutes later, with the previous designer's snapshot already applied — assets, templates, options, the lot.
Re-running fp init after docker compose down -v is the canonical recovery flow: same command, brings volumes back from empty to the state captured by the latest snapshot, MinIO assets and all.
What it does
Six idempotent steps:
- Scaffold
.envfrom.env.exampleif missing - Run
composer installvia docker (no PHP needed on host) - Write
FP_S3_DISABLED=0to.envso uploads land in MinIO (designer mental model matches prod) — unless operator already setFP_S3_DISABLEDexplicitly, in which case their choice wins docker compose up -d --wait— gates on healthcheckswp core installif WP isn't installed yet (defaultsadmin / admin / admin@example.test, override via[init]infrankenpress.toml)- Apply the latest snapshot by
manifest.created— same logic the chart's install Job uses on cluster deploy, so local + in-cluster apply target the same source of truth
Every step is independently idempotent: .env scaffold no-ops if .env exists, composer install no-ops if vendor/ exists, the FP_S3_DISABLED line is appended only if absent, wp core install no-ops if WP is already installed, apply hits the mu-plugin's idempotency markers. Re-running is safe and cheap.
Flags
| Flag | Effect |
|---|---|
--slug <s> |
Override the most-recent-snapshot pick. |
--skip-setup |
Skip ALL env-mutating steps (.env scaffold + composer + FP_S3_DISABLED line). For CI / scripted setups. |
--no-apply |
Bring stack up + install WP, skip apply. |
--reinstall-wp |
Drop existing WP install (default off). |
--service / --project |
Standard compose overrides. |
Config
New [init] section in frankenpress.toml (all optional):
[init]
site_title = "FrankenPress site"
admin_user = "admin"
admin_password = "admin"
admin_email = "admin@example.test"
disable_s3 = false # true to keep FP_S3_DISABLED=1 locallyTradeoff
Designer-mode S3 (FP_S3_DISABLED=0) means wp-admin's "Install plugin / theme from zip" buttons don't work — the s3:// stream wrapper doesn't support every ZipArchive op. Designers rarely need that path; if you do, set FP_S3_DISABLED=1 in .env and re-run fp init (operator-choice preservation makes this stick), or use composer require wpackagist-plugin/<slug> (the FrankenPress canonical install path).
Under the hood
docker.Runnergrows three methods:ComposeUp,ComposeBuild,ComposerInstall. Each has a recorded-call Fake for unit tests.apply.PickLatest()(shipped in v0.5.0) is reused for the snapshot pick —fp initandfp apply(no arg) share semantics so they can't drift.- New
internal/setup/package: pure file-IO helpers (ScaffoldEnvFromExample,EnsureEnvKey,ReadEnvKey) + the orchestrator. - 91 unit tests across 17 packages; vet + lint clean.
Upgrading
brew upgrade fp
fp version # → v0.6.0
fp init --helpDocs PR: frankenpress/docs#45. Full design rationale: workspace .aidocs/fp-init.md.
Full diff
0.5.0
Snapshots are timestamped; fp apply knows what "latest" means
Two coupled changes that retire the single-named-slug-per-release convention in favour of accumulating timestamped snapshots that the chart picks latest from at deploy time.
fp snapshot — timestamp default
fp snapshot with no --slug now produces a UTC timestamp dir:
$ fp snapshot
# → web/imports/2026-05-14T10-56-09Z/The pre-existing cascade (state.LastSlug → git branch → composer name → timestamp) is removed. --slug=<name> is still the explicit override for milestone markers (e.g. --slug=pre-2026-rebrand).
New sub-second collision guard: firing fp snapshot && fp snapshot within the same UTC second refuses with wait a moment and re-run, or pass --slug=<name> — pre-clean no longer silently wipes the prior capture. Only fires for the timestamp-default path; explicit --slug=foo keeps its iterate-on-named-slug overwrite behaviour.
fp apply — pick latest with no arg
fp apply # NEW: picks latest by manifest.created
fp apply 2026-05-14T10-56-09Z # explicit slug (unchanged)
fp apply web/imports/sts-launch # path (unchanged)Walks [snapshot].output_dir, reads each manifest.yaml, applies the snapshot whose created is highest — same logic the charts install Job uses at deploy time, so local apply and in-cluster apply target the same snapshot from the same source of truth.
Helper exported as apply.PickLatest() for future fp init reuse.
Why this matters
The old convention required designers to git rm the previous snapshot dir on each release (otherwise the chart's install Job hard-failed on >1 manifest.json). That destroyed history at the filesystem layer — only the git log carried "what did the design look like 3 iterations ago". Timestamps let snapshots accumulate; git log + commit messages carry the human-readable "what changed".
Breaking
- Scripts that grep for
snapshot-YYYYMMDD-HHMMSSin captured dir names need updating toYYYY-MM-DDTHH-MM-SSZ. - Requires
charts≥ v0.12.0 once tenants accumulate multiple snapshots — pre-v0.12.0 install Jobs still hard-fail on >1.
Cross-repo
See workspace .aidocs/timestamp-snapshot-slugs.md for the full plan. The matching docs sweep (site-template README, docs designer-flow) is in flight.
Upgrading
brew upgrade fp
fp version # → v0.5.0Full diff
0.4.0
Changelog
Verification
Every release artefact is signed via cosign keyless OIDC. To verify:
cosign verify-blob \
--certificate-identity-regexp "https://github.com/frankenpress/fp/.github/workflows/release.yaml@.*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--cert checksums.txt.pem \
--signature checksums.txt.sig \
checksums.txt0.3.0
Changelog
Verification
Every release artefact is signed via cosign keyless OIDC. To verify:
cosign verify-blob \
--certificate-identity-regexp "https://github.com/frankenpress/fp/.github/workflows/release.yaml@.*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--cert checksums.txt.pem \
--signature checksums.txt.sig \
checksums.txt0.2.0
Changelog
Verification
Every release artefact is signed via cosign keyless OIDC. To verify:
cosign verify-blob \
--certificate-identity-regexp "https://github.com/frankenpress/fp/.github/workflows/release.yaml@.*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--cert checksums.txt.pem \
--signature checksums.txt.sig \
checksums.txt0.1.1
Changelog
- b9d4d1b feat: phase-1 — fp snapshot end-to-end
Verification
Every release artefact is signed via cosign keyless OIDC. To verify:
cosign verify-blob \
--certificate-identity-regexp "https://github.com/frankenpress/fp/.github/workflows/release.yaml@.*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--cert checksums.txt.pem \
--signature checksums.txt.sig \
checksums.txt