Dev.to AI 🤖 Ai 👁 0 📖 5 min read

Your framework should deploy four apps with one command

This one covers two and a half weeks, September 8 to 24. I was out of town for part of it, and the work that landed was shipping work: eight point releases of the workflow kit, an OMEGA release, two releases of the strea

This one covers two and a half weeks, September 8 to 24. I was out of town for part of it, and the work that landed was shipping work: eight point releases of the workflow kit, an OMEGA release, two releases of the stream panel, and two engines that still live only on my disk. The theme, if there is one, is that every "run this by hand" step got a verb.

OMEGA: one deploy lane for web, backend, desktop, and extension

OMEGA 0.51.0 shipped on September 15, and the seven @omega.js packages (client, backend, mcp-router, extension, desktop, web, manager) are public on npm for the first time. A fresh install resolves from the registry instead of a linked checkout.

The headline change is the deploy lane. omega deploy at a brand root now scaffolds every selected target in-process, packs any linked framework into a tarball, snapshots the brand folder to one branch (omega-deploy, the only branch CI ever builds), and dispatches one workflow per target. Then it follows every run, streaming each job's log with the job's name in front, and exits on the run's conclusion. Backend goes first alone; web, desktop, and extension go together.

The part I use most is --dry-run. It runs the real precheck on all four targets and sends nothing: the plan names the secret keys it would publish, the derived signing lines, and any refusal. A deploy can be previewed end to end without publishing a byte. Beside it, omega bump patch|minor|major writes one version into the root and every target, never commits, and every framework's deploy refuses a target whose version drifted from the root.

Config grew an environment layer to match .env: every omega.json5 takes an optional omega.<environment>.json5 beside it, overrides only.

Switchboard: stream keys stored nowhere

Switchboard is the stream panel I have been building on the same framework (private for now, so no link). Two releases landed, 0.6.0 and 0.7.0, and the panel is multi-user: each signed-in account connects its own channels and streams to its own platforms through a shared relay. Kick joined Twitch and YouTube as a full peer: one browser approval to connect, chat replies from the same send box, title and category from the same form.

The design decision I am happiest with: your stream keys are stored nowhere. The panel asks each platform for your key at the moment it pushes, so a key you reset works straight away with no reconnect.

Streams can repeat (daily, weekly, monthly, every N of them). A weekly stream becomes one recurring entry on your Twitch schedule; every other rule is a single entry the panel rolls forward each time you go live. Eight in the evening stays eight across a daylight saving change. Going live after a panel restart asks YouTube which broadcast is on air before trusting the one written down, which fixed a bug where a restart moved a live stream onto next week's broadcast.

Hosting is one command too: npm run deploy builds the image here, sends it over SSH, and brings up MediaMTX, the panel, and Caddy as one stack, with the relay answering at relay.<your host>. The end-to-end suite drives the pages in a real browser against a real emulator and a real relay. One lesson from making it pass unattended: waits check on a timer, not on animation frames, because a sleeping display starves frames.

Windows: a colon in a filename opened a hidden stream

Both the workflow kit and my dotfiles now run on Windows under Git Bash, next to macOS and Linux. workkit went from 0.50.5 to 0.57.1 in the window, and most of that is one platform seam: every jq read in the engine, the jobs, and the hooks goes through one CRLF-safe wrapper (118 sites in 33 files), every marker and cache key is named through the seam, and the Node test suites spawn the shell and spell PATH per platform.

The bug I will remember: a test fixture was named after a label, agent:working. On NTFS the colon is syntax. file:stream opens an alternate data stream, so bash wrote the fixture into a hidden stream and read back an empty file, and six cases failed only on Windows. Never put a colon in a filename you expect to see there.

Three gates also hardened. A Proof: line on an issue is now a hard requirement to flip it complete or close it, checked by a hook and by the board's own move. A suite-guard hook bounces a bare npm test from every class of agent, so the commit gate is the one place the full suite gets paid for. And a release-taken hook bounces a release commit or an npm publish whose version a registry already has.

On the dotfiles side, setup.sh provisions a Windows machine the way it provisions a Mac, through fnm where the Mac uses nvm. A win command drives the Windows machine from the Mac over SSH: it mirrors the working tree as one tar stream and runs the command in the mirror.

Merchforge: background is whatever touches the border

Merchforge is a new engine for Amazon Merch on Demand (private, no link yet). Same shape as the ad engine from the last post: one AI call writes the plan, scripts do everything else.

merchforge research <seed> expands seeds into keywords through Amazon's own endpoints, measures each one, checks the trademark register, and writes a ranked research.json. merchforge plan is the one model call, validated against the products, the formats, and the listing limits. generate draws each design with gpt-image-2 on a transparent background, and finish snaps the palette, strips the background, traces to SVG, and composes the print file at the product canvas.

The clean step is the interesting code. Background is defined as what touches the border: a flood fill from the image edge over transparent and near-white pixels. An alpha hole the model punched inside a shape keeps its fill, because it never touched the edge. Palette buckets that read the same to the eye merge (four near-identical reds became one), and a 5x5 majority filter over the snapped pixels removes one-pixel noise before the trace.

Small but satisfying

  • The cover on this post was rendered this afternoon by a new tool: an HTML and CSS template, a theme, a plan JSON, and a Playwright screenshot. No stock photo, no image model. The ad engine taught me that the AI should write the plan and the scripts should make the pixels; covers get the same rule.
  • Notifly, a small desktop notifier my Claude Code hooks fire, now installs from a public releases feed on both platforms, sha512-verified, only when the version differs. The app has no auto-updater, so setup is it.

Next: the first real ad batch against an ad account, and a gallery of cover templates so the next post picks from more than one. If your deploy spans more than one target, I would like to know what your one command looks like. Comments open.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.