Skip to content

fix(init-qm): only write a Dockerfile where one can actually run - #67

Merged
shekharkadyan merged 2 commits into
mainfrom
fix/init-qm-skip-unusable-dockerfile
Aug 15, 2026
Merged

fix(init-qm): only write a Dockerfile where one can actually run#67
shekharkadyan merged 2 commits into
mainfrom
fix/init-qm-skip-unusable-dockerfile

Conversation

@shekharkadyan

Copy link
Copy Markdown
Contributor

Stacked on #64 — the diff below includes that PR's commits until it merges. Review the top commit.

The problem

pipeshub init-qm wrote a sandbox/Dockerfile into every deployment. On Fly Sprites and AWS MicroVM sandboxes that file never runs — Sprites boot the stock image and ignore a published one (qm#272), and AWS MicroVM has no way to install a binary at all (qm#350).

A Dockerfile that cannot run is worse than no Dockerfile. It reads as the install path, so when someone's agent reports pipeshub: command not found, they open the Dockerfile and start debugging a file that was never used.

There's a deadline on this too: two upstream PRs (qm#427, qm#379) turn that file from useless into a hard validation failure. Today our scaffold produces a deployment that limps; after those land it produces one that won't pass qm check — and the error names our files, not the reason.

What changed

init-qm now reads target and sandbox.backend from the operator's existing qm.config.jsonc and writes the Dockerfile only where a custom image actually boots.

Deployment Dockerfile
Sprites / target: fly skipped, with the reason
AWS skipped, plus a note that the binary can't be installed there at all
local docker written, as before
no config, or one we can't parse written, as before

That last row is deliberate. Guessing wrong in that direction deletes a file someone needs, so anything we can't classify keeps the old behaviour.

What the operator now sees on Sprites:

No sandbox/Dockerfile was written: Fly Sprites cannot boot a custom
image, so one would look like the install path while never running.
The skill installs the CLI on first use instead — that is the line
that actually executes, and it needs nothing from you.

What did NOT change, on purpose

tool.json is still written everywhere, including AWS.

Both upstream PRs reject custom tools, not just Dockerfiles — so a literal reading says we should stop writing it. I didn't, because a tool descriptor carries more than install:

  • egress — the only hostname the agent may reach
  • auth.check / auth.reauth — how QM tests whether someone's credential still works
  • approvalsdeny on the two subcommands that could take a credential on a command line, and require_approval before pulling a full document into the transcript

None of those need anything materialized, all of them are enforced today, and none has a skill-side equivalent — I checked the contract types. Dropping them now would trade working security controls for tidiness against a change that hasn't merged and that we've asked upstream to narrow (comment).

If upstream keeps the wholesale rejection, that's the point to revisit — and the answer then is to find those fields a new home, not to ship without them.

A small thing worth mentioning

Reading the config needed JSONC comment-stripping. The naive version eats the second slash of "https://..." and turns a valid config into a parse error — in a file the operator doesn't know we read. There's a test for exactly that.

Docs

  • bundle README: the Dockerfile is no longer listed as unconditional; the file table says when it applies
  • operator guide: explains why Sprites skips it
  • air-gapped section: now covers the first-run install too, since on Sprites that's the step that actually reaches npm

Checked

  • 89 tests pass (7 new), lint and build clean
  • scaffolded into three real configs — our own target: docker + backend: sprites deployment, a plain docker one, and an empty directory — and confirmed the right files appear in each

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a41233c-c128-4ad1-95ab-47a127a71724


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@shekharkadyan
shekharkadyan force-pushed the fix/init-qm-skip-unusable-dockerfile branch from a2b13b0 to 9715b51 Compare August 15, 2026 01:52
@shekharkadyan

Copy link
Copy Markdown
Contributor Author

All three are right — fixed in 9715b51. Also rebased onto the current #64, so this now includes 16ee0fb.

1. target: aws is not MicroVM. Confirmed against the installed CLI: config.js:1106 requires "backend": "aws" to have target: "aws", but not the reverse — and the error at :1112 explicitly offers "sandbox.backend": "sprites" as the alternative on an AWS target. So an AWS control plane with Sprites sandboxes is a real, different deployment, and telling that operator the CLI can never be installed is simply false.

Rather than re-key one string, the skip now returns a reason instead of a boolean, so the message is derived from the same value that made the decision and can't drift from it again:

target aws + backend aws      → "AWS Lambda MicroVM sandboxes have no way to install a binary"
target aws + backend sprites  → "Fly Sprites boot the stock image and ignore a published one"

Verified both end to end.

2. Re-run doesn't clean up. Right, and this is the case that actually bites — everyone who already ran 2.3.1 has that file. Re-running now prints an ACTION NEEDED block naming it and saying qm check will fail. It does not delete: it's their file and may carry their own build steps. Also covered in the bundle README for people who don't re-run.

3. Tests only covered helpers. Added the shapes that ship — target: docker + backend: sprites (what our own guide documents), target: aws + backend: sprites, and real MicroVM.

On trailing commas I went further than documenting it. Fail-open there writes the exact file we're trying to avoid, so a stray comma would have silently defeated the change on a Sprites deployment. dropTrailingCommas now handles them, string-aware, with a test. Fail-open remains for configs that are genuinely unreadable.

Framing. Fair point — the README now says this reflects current QM and that qm#272 being fixed reverses it, and the code comment says the same.

95 tests pass, build and lint clean.

On merge order — agreed, and to be explicit: #64 first, then this, then rebase #66 so 2.3.2 pins this code. Publishing #66 first would put 2.3.2 on npm with 2.3.1's init-qm, which is the one outcome worth avoiding.

rish664
rish664 previously approved these changes Aug 15, 2026
@shekharkadyan
shekharkadyan dismissed abhishekgml1991’s stale review August 15, 2026 08:51

The merge-base changed after approval.

shekharkadyan and others added 2 commits August 15, 2026 01:53
Scaffolding wrote sandbox/Dockerfile unconditionally. On Fly Sprites and AWS
MicroVM sandboxes that file never executes — Sprites boot the stock image and
ignore a published one (yc-software/qm#272), and AWS MicroVM has no install
mechanism at all (#350).

A Dockerfile that cannot run is worse than none. It reads as the supported
install path, so when the binary turns out to be missing the operator debugs
the file rather than learning the image was never used. Two upstream PRs
(qm#427, qm#379) would turn this from useless into a hard validation failure,
so a scaffold emitting the rejected file would fail its own `qm check`.

init-qm now reads target and sandbox.backend from the operator's existing
qm.config.jsonc and writes the Dockerfile only where a custom image boots. An
absent or unparseable config scaffolds exactly as before: guessing wrong in
that direction removes a file someone needs.

tool.json is still written everywhere. Beyond `install`, it carries `egress`,
`auth`, and `approvals` — none of which need anything materialized, all of
which are enforced today, and which have no skill-side equivalent. Dropping
those preemptively would trade working security controls for tidiness against
an upstream change that has not merged and that we have asked to narrow.

Comes with a JSONC comment stripper rather than a regex, because the naive
version eats the second slash of "https://" and turns a valid config into a
parse error in a file the operator did not know we read.

Docs updated to match: the bundle README no longer lists the Dockerfile as
unconditional, the operator guide explains why Sprites skips it, and the
air-gapped section now covers the first-run install, which is the path that
actually reaches npm on Sprites.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PnyXXBMwhMj5CtcZRJoJ2
… file

Three corrections from review.

An AWS control plane running Sprites sandboxes was described as Lambda
MicroVM, which told the operator the CLI could never be installed there.
That is false — Sprites install it on first use. `backend` decides where
sandboxes run, not `target`: the CLI requires `"backend": "aws"` to have
`target: "aws"` but not the reverse (config.js:1106-1112), so the two are
different deployments. The skip now carries a reason rather than a boolean,
so the message cannot describe a deployment as something it is not.

Skipping the file does nothing for anyone who already ran the previous
version: they still have a Dockerfile that upcoming QM validation rejects.
Re-running now says so and what to do. It is not deleted for them — it is
their file and may carry their own build steps.

Trailing commas made the config unparseable, which fell open and wrote the
Dockerfile we were trying not to write. JSONC allows them and hand-edited
files collect them, so they are now handled rather than documented as a
hole. Fail-open remains for genuinely unreadable configs.

Tests now cover the shapes that ship rather than only the helpers: target
docker with the sprites backend (what our own guide documents), an AWS
target with Sprites sandboxes, and real MicroVM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PnyXXBMwhMj5CtcZRJoJ2
@shekharkadyan
shekharkadyan dismissed abhishekgml1991’s stale review August 15, 2026 08:54

The merge-base changed after approval.

@shekharkadyan
shekharkadyan force-pushed the fix/init-qm-skip-unusable-dockerfile branch from ad10639 to d65c2df Compare August 15, 2026 08:54
@shekharkadyan
shekharkadyan merged commit 08c420b into main Aug 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants