Cloud Deployment
- Added the public site (
@skybolt/site) as a fourth container in the production stack (ADR-0049 follow-up): the edge Caddy now terminates TLS forskybolt.ai+www.skybolt.ai(www → apex) and reverse-proxies to asitecontainer serving the static Astro build. The site ships as its own GHCR image (ghcr.io/txmerc/skybolt/site), built/pushed bydeploy.ymland tag-pinned / rolled-back beside the api (SKYBOLT_SITE_TAG). - Validation:
bash -non deploy/rollback, YAML parse of compose + workflow, and a localpnpm --filter @skybolt/site build(4 pages incl. the build-time changelog). The image build runs in CI;docker compose configruns implicitly on the droplet at deploy. - Operator action for go-live: apex +
wwwA records (Namecheap) → droplet, alongsideapi.
Desktop App
- Marketing-site consolidation: deleted the React
apps/web/src/marketing/MarketingSite.tsx(the public marketing site now lives solely in the Astroapps/site).apps/web/src/App.tsxno longer branches on path/runtime to serve a marketing page — it always rendersSkyboltApp. UpdatedAppRouting.test.tsxaccordingly and dropped the now-unusedthree,@types/three, andgsapdependencies fromapps/web(smaller renderer bundle). -
scripts/dev.ps1/scripts/dev.shdefault runs now also start the public Astro site (apps/site) onhttp://localhost:50030alongside the desktop app, and stop it when the desktop process exits (incl. Ctrl-C). New-Site(--site) switch runs only the site.
Encrypted Project Sync
- Locked/ciphertext
project.db→ clean 423 on every per-project route. The A4 convert route added an auth-first pre-flight that sniffs the header and returns 422 before opening, but that guard protected onlysync/convert; every other per-project route (cards, terminals, agents, workspace, project detail, …) still opened the project via_open_project, whose per-project ATTACH raised a rawsqlite3.DatabaseError→ opaque HTTP 500 when the on-diskproject.dbwas git-crypt ciphertext (\x00GITCRYPT), a sealed artifact (SBSEALv1), or otherwise not SQLite.- Engine:
store/project_store.pyaddsProjectDatabaseLockedError+ a header classifier_project_db_locked_detail(mirrorsservices/sync_ops.inspect_project_db)._ensure_project_dbsniffs the header on EVERY open — not gated by the_UPGRADED_PROJECT_DBSupgrade cache, so a re-locked checkout (a pull/checkout brings ciphertext after a prior successful open) is still caught — and raises the typed error;_open_projectkeeps a tightly-scoped ATTACH safety net for a residual non-SQLite body and always closes the global connection on failure.app.pyregisters an exception handler mapping it to 423 Locked with an actionable detail (git-crypt → "Unlock Encrypted Data"; sealed → "Unseal (Sync & Resume)"; generic → "Unlock or unseal"), mirroring the engine-lockrequire_unlockedmiddleware. Additive only: the convert pre-flight (still 422) and the graceful/projectslisting fallback (_read_project_settings_row) are unchanged; background callers (scheduler) already wrap per-project opens inexcept Exception. - Tests (
tests/test_project_db_lock.py, 5): detail + listing routes return 423 (never 500) for all three ciphertext kinds with actionable details; the lock still fires after a prior successful open (cache bypass); the global/projectsindex still lists a locked project.
- Engine:
Public Site
- Marketing consolidation: migrated the richer single-page design/content of the former React marketing site (
apps/web/src/marketing/MarketingSite.tsx) into this Astro landing, keeping theHeroSwarmagent animation as the hero. New/sections: a command-center hero with a three-step strip, Platform (#platform, six product cards), Machines (#machines, capability chips + a command-window mock), and Privacy (#privacy, three trust groups) — replacing the previous "Control the chaos" grid, principles terminal, and pricing teaser. Nav now targets the section anchors plus Pricing. The React site's Tailwind was translated to the Astro site's CSS-variable system; the mobile nav was resized so all four links fit a phone width. The old ReactMarketingSite.tsxwas deleted,apps/web/src/App.tsxnow always renders the Skybolt app (itsAppRoutingtest updated), and the unusedthree/gsapdeps were removed fromapps/web.scripts/dev.ps1/dev.shdefault runs now start the desktop app + this site on:50030together (new-Site/--siteflag runs the site alone). - Animated hero swarm (
src/components/HeroSwarm.astro): a live "agents working a board" layer — an ORCH node routes five named agents (claude-code, codex-01, vllm-local, expert:docs, expert:security, reference colors) to task cards with progress bars; agents fly over, dock, pulse and fill the bar, pair up over a green collaboration link, and completed cards flash green with a ✓ before respawning with the next task title; packets travel the work links. Dependency-free (no three.js/gsap): runtime DOM + one SVG line pool driven by a single rAF loop, paused offscreen via IntersectionObserver. The build-time constellation remains as the no-JS fallback;prefers-reduced-motiongets a static composed scene. Mobile runs a smaller 3-agent/3-card config. The technical-design hero section was rewritten accordingly (the three.js island is no longer the planned upgrade path). - Hero visibility fix: the upper hero rendered as a near-black void — the readability scrim (0.35–0.55 black) sat over the whole starfield and flattened the Atmosphere gradient and constellation below perception. The scrim is now light at the top (0.05 → 0.22 @ 42%) and dark only in the lower text zone; the hero background gained a faint
#0077e4radial halo; stars are brighter/larger (opacity 0.35–0.9, r 0.6–1.9); the constellation stroke went 0.25 → 0.4 and agent nodes gained translucent halo rings. The starfield is also 28px taller than the hero so the drift animation never exposes an unpainted strip. - Content refresh to match the shipped product (Waves A+B): landing panels now feature the gated full Git surface (M4) and repo import/readiness audits (P-M2) — "Kanban cards" merged into the orchestration panel and "Local by default" ceded to the principles terminal directly below.
/featuresgrew matching "Git operations, gated" and "Project import & readiness" cards (eight total), the orchestration card swapped the unshipped overlap-radar/artifact-registry claim for lease-backed scheduling + file-scope conflict prevention and the live agent board, and the cloud identity card now mentions device-session list/revoke. Pricing Free tier lists repo import with readiness audits. - Mobile nav: page links (Features/Changelog/Pricing) stay visible under 720px (smaller type); the waitlist CTA pill hides instead — previously the links vanished entirely, leaving subpages unreachable except via the footer.
- Font loading: preload
<link>s for the five above-the-fold latin woff2 faces (Space Grotesk 500/600, Inter 400/500/600) to suppress the fallback-font flash on first paint. - Containerized production deployment (ADR-0049 follow-up, rides ADR-0043):
apps/site/Dockerfile(multi-stage — pnpm workspace build mirroring thesiteCI job →caddy:2-alpinestatic file-server on:8080),apps/site/Dockerfile.dockerignore(keepsdocuments/in the build context so the build-time changelog resolves — the root.dockerignoredrops it), andapps/site/site.Caddyfile(internal static server). - Added the
siteservice todeploy/production/docker-compose.prod.yml(own GHCR imageghcr.io/txmerc/skybolt/site, edge network, healthcheck) andskybolt.ai+www.skybolt.aiblocks toCaddyfile.prod(edge Caddy terminates TLS; www → apex redirect). - Extended the deploy pipeline to two images:
deploy.ymlbuilds/pushes the site image beside the api;deploy.sh/rollback.shpin and roll back both tags (SKYBOLT_SITE_TAG).