/wbDeploy — Expert
What /wbDeploy architecturally is
A target-routing deploy command for apps. Reads per-app deploy.md config, runs the production build, and pushes output to the configured target (default: GitHub Pages). Gated on /wbTest passing and /wbAudit having no BLOCKERS.
The design choice worth naming: target-routing rather than target-specialization. One command, multiple possible targets, config-driven. The alternative (dedicated /wbDeployGHPages, /wbDeployNetlify, etc.) proliferates commands for no gain — the deploy workflow is identical; only the last step differs.
The separation from /wbPublish
The architectural intuition: things that go to a registry (npm) and things that go to a URL (hosting) are different enough to need different commands, but not so different that they need unrelated abstractions.
- Both: build + push.
/wbPublish: push isnpm publishto a registry./wbDeploy: push isgit push(or similar) to a host.
Shared: gate-check phase, build phase, post-push reporting. Different: what the push does, what success looks like, what recovery looks like.
Keeping them separate allows each to enforce target-specific gates (npm version conflicts vs. GitHub Pages base-url mismatches) without cross-contamination.
Three design decisions worth naming
1. --target=local as a first-class mode
Production build + local server is functionally a staging environment. Most deploy tools expect a separate "preview deploy" URL for this. /wbDeploy folds staging into the same command by parameterizing the target. Cheaper + safer than a real preview host for the solo-dev case.
The tradeoff: local can't catch CORS / DNS / GitHub-caching bugs. For those, you still need a scratch-repo deploy. But local catches 80% of prod-specific bugs at 0% of the cost.
2. deploy.md as the per-app config
Not inferred from package.json, not hard-coded, not in the command invocation. A separate dedicated config file per app. This lets the command stay stateless (no memory across apps) and makes deploy targets auditable (the config is a file you can read).
3. Gated on reports, not on fresh checks
/wbDeploy reads recent /wbTest and /wbAudit reports to gate the deploy. It doesn't re-run them. Trade-off: faster deploys + trust in the report corpus. If reports are stale (>24h), the AI warns; very stale (>7d), it refuses until a fresh check.
How the default target actually publishes
GitHub Pages serves from a single branch, so the push step is a branch replacement rather than a commit:
- Build to
dist/. - Create a throwaway git worktree at a temp location.
- Copy
dist/contents in as the branch root — not nested underdist/. - Force-push to
gh-pages. - Remove the temp worktree.
The consequence worth internalizing: gh-pages is always "whatever the latest dist was," with no history of dev commits. Deploy history lives in reports/.../deployments/, not in the branch. This is also why rollback is another deploy rather than an undo — there is no prior state on the branch to return to.
When GitHub Pages is the wrong target
It is a static-file host: point it at a branch and it serves whatever HTML/JS/CSS is there. It is not a build server (Actions can build; Pages itself cannot), not a server-side runtime, and not a CDN with arbitrary routing. So it is the wrong target when the app needs server-side rendering, API routes, redirects or rewrites beyond the SPA fallback, or is larger than roughly 1 GB. Any of those means switching target: in deploy.md to a real host — Vercel, Netlify, Cloudflare — which is exactly the extension path that leaks 3 and 4 below make awkward.
Where the command leaks
Post-deploy verification is manual. The AI tells you the URL; it can't load it. Broken deploys are caught by the user clicking the link, not by the command. Possible mitigation:
--verifyflag that does a headless load + screenshot. Not implemented.Rollback is manual. There's no "redeploy the previous version" command. You'd have to git checkout the previous
gh-pagescommit and force-push. Users under pressure do risky rollbacks.Target-specific gates live in the AI's prompt, not in schema. Adding a new target (e.g., Netlify) requires updating
wbDeploy_template.mdwith Netlify-specific gates. No formal extension mechanism.SPA fallback handling is GitHub-Pages-specific, embedded in the command. If you deploy to a host that doesn't need the fallback (or needs a different mechanism), the logic is in the wrong place. Should be per-target plugin, isn't.
No cross-deploy consistency check. Deploy wb-dataviewer to
/wbdataviewer2/, deploy wb-press to/wb-press/. If the base-urls are inconsistent (e.g., one ends in/, the other doesn't), nothing detects it. Users discover the inconsistency by clicking between apps.
What wb-flow-docs's playbook gets wrong about /wbDeploy: treating it as app deployment only, when the actual scope includes the 3-tier build matrix (dev/free/pro) with WBC_PRO gating — which means deploy is as much about licensing enforcement as about pushing files to a server.
One-paragraph verdict
A target-routing deploy command whose architectural contribution is correctly separating from /wbPublish (registry vs. URL), folding local-staging into the same command via --target=local, and trusting the report-corpus for gates. Weakest in post-deploy verification (manual), rollback mechanics (manual), and target-extension formality (prompt-level, not schema-level). The SPA-fallback coupling to GitHub Pages is the most concerning leak — adding a new target means modifying command logic, not just config. Correct for solo monorepo work with a small number of deploy targets; would need a plugin architecture and rollback tooling to scale to multiple hosts.
