Skip to content

Add container dev mode guide and field note - #473

Open
jetm wants to merge 8 commits into
mainfrom
field-notes/container-dev-mode-vm-push
Open

Add container dev mode guide and field note#473
jetm wants to merge 8 commits into
mainfrom
field-notes/container-dev-mode-vm-push

Conversation

@jetm

@jetm jetm commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Problem

Container Dev Mode adds a new CLI surface (a container_dev config block, five
avocado container dev subcommands) and a device-side agent extension, and nothing
in the docs told a user how to use any of it. The only written material was a field
note about how the push path was validated internally, which is a QA story rather
than a how-to: a reader learned how the registry was tested, not what the feature
does for them.

Solution

Split the two jobs. A new guide under Development documents the feature for an
engineer who wants to use it, written against the implementation on the
container-dev-mode branches so the commands, config keys, ports and prerequisites
are the real ones. The field note is reframed to lead with the loop a developer
already lives in - a multi-gigabyte inference container where one iteration costs
the size of the image rather than the size of the change - and links to the guide
instead of restating it. The QEMU lab and the two bugs it caught become the
credibility half rather than the premise.

Key changes

  • docs-guides/container-dev-mode.md: new guide (prerequisites, config block, the
    loop, and reference tables for commands, env vars and default ports), plus its
    sidebars-guides.js entry next to Hardware in the loop.
  • Field note reframed around the developer's loop; drops a remote-build bullet that
    described our own build infrastructure rather than the feature.
  • Both pages share one diagram of the loop with the device in it, drawn as a text
    block using the repo's existing box-drawing and magic-comment colors rather than
    adding a Mermaid dependency.
  • Fixes a latent MDX defect: prettier rewrites the asterisks in a {/* ... */}
    comment to underscores, producing {/_ ... _/}, which MDX fails to parse
    ("Could not parse expression with acorn"). The pre-release note moved into
    frontmatter YAML comments, which prettier preserves.

Dependencies

This PR must not merge until every item below has landed. The guide documents
commands, config keys and prerequisites that do not exist in any released build
until they do, and merging early would publish documentation for a feature a reader
cannot use.

Blocks merge Provides what this PR documents
avocado-linux/avocado-cli#184 - Container Dev Mode: host CLI, embedded registry, and VM push path The avocado container dev up/sync/status/down/prune commands, the runtimes.<name>.container_dev block, the embedded registry, the engine watcher, and the AVOCADO_CONTAINER_DEV_* variables.
avocado-linux/avocado-os#46 - Add container-agent-dev: device-side agent + dev-only extension The avocado-ext-container-agent-dev extension the guide lists as a device prerequisite. Without it the device has nothing to pull the layer or restart the service.
avocado-linux/meta-avocado#246 - meta-avocado-qemu: provision the container-dev trust-store location The trust-store location the VM push path delivers the per-project CA into, behind AVOCADO_CONTAINER_DEV_VM.
An avocado-cli release containing the above A released version to pin in the guide and in the note's <TestStatus>, replacing the pre-release 1.0.0-rc.1.

All three PRs are open from their own container-dev-mode branch; #184 and #46
target main, #246 targets scarthgap. The CLI and the agent are two halves of one
protocol, so neither is optional and there is no useful ordering between them; the
release is necessarily last.

Tracked in ENG-2224, which carries the ship-day checklist for this PR.

Reviewer notes

This PR is a draft on purpose. The field note is draft: true so it is excluded
from the production build, but the guide is not: merging publishes it to
docs.peridio.com. Draft status makes an accidental merge impossible while the
dependencies above are outstanding.

Verification. Run in src/ against the container-dev-mode branches of
avocado-cli and avocado-os:

  • npx prettier --check on all three files: clean.
  • npm run lint (eslint): clean.
  • npm run build: [SUCCESS] Generated static files in "build". Confirmed
    developer-reference/container-dev-mode.html is emitted and the field note is
    absent from the build, so the draft flag does what it should.
  • Both pages reviewed on a local dev server, which renders drafts.

Unverified content, flagged. The guide was written by reading the implementation
on the branches above, not by running a released binary: the documented surface
comes from src/commands/container/{mod,dev}.rs, src/utils/container_dev/config.rs,
bootstrap.rs and the extension's avocado.yaml (CLI 1.0.0-rc.1, a pre-release
dev build). No command output is reproduced in the guide, because none of the
commands were run against a released build. Every command, config key and port needs
re-verification against the shipped CLI before this merges, and the note still
carries two [ENGINEER: ...] gaps (the <TestStatus> reference link and the
Reproduce it section) that are release-blocked.

jetm added 7 commits July 30, 2026 12:38
Capture the disposable-QEMU engine-VM lab that exercised Container Dev
Mode's authenticated push path end-to-end (single-layer sync, plus the
two bugs the lab caught: plain-HTTP write path and the 2 MiB body limit).

Kept draft: true with [ENGINEER:] gaps because the CLI and device
extension are pre-release; a reader cannot reproduce it until the feature
ships. Flip draft to false once it lands and the steps are re-verified on
a released build.

Signed-off-by: Javier Tia <javier@peridio.com>
The Container Dev Mode VM-push draft carried 14 em dashes; the sibling
field notes use at most one, so the section's house style is plain
hyphens. Convert them now so the prose matches before the draft reaches
the correctness review gate, leaving the release-blocked [ENGINEER:]
placeholders untouched.

Signed-off-by: Javier Tia <javier@peridio.com>
Docusaurus rejects `image: ''` ("does not look like a valid url"), so the
dev server refused to compile the note. The image field is optional -
omitting it renders the index placeholder box - so remove the empty
value rather than invent a path before the note has real art.

Signed-off-by: Javier Tia <javier@peridio.com>
Container Dev Mode ships a new CLI surface (a container_dev config block
and five avocado container dev subcommands) plus a device-side agent
extension, and nothing in the docs told a user how to use any of it. The
only written material was a field note about how we validated the push
path internally, which is not a how-to.

Add a guide under Development covering prerequisites, the config block,
the loop, and reference tables for the commands, environment variables,
and default ports. It sits next to hardware-in-the-loop because it is the
same iterate-against-a-live-device bargain applied to containers, and it
states the dev-only scope up front so nobody mistakes it for a production
container delivery path.

Signed-off-by: Javier Tia <javier@peridio.com>
The draft told the story from the implementer's chair: how a throwaway
QEMU lab validated the authenticated push path. A reader learned how we
tested the registry internals, not what the feature does for them or why
they would want it, so the note failed the audience it exists for.

Lead with the loop the reader already lives in - a multi-gigabyte
inference container where one iteration costs the size of the image
rather than the size of the change - and show the config block, the three
commands, and what actually moves. The QEMU lab and the two bugs it caught
become the credibility half rather than the premise, and the how-to now
lives in the guide, which the note links to instead of restating. Drops
the remote-build bullet: an NFS/SQLite detail about our own build
infrastructure that told the reader nothing about the feature.

Signed-off-by: Javier Tia <javier@peridio.com>
Both pages described the hot-reload loop in prose and a numbered list,
which made the reader assemble the shape themselves: where the layer
crosses, what runs on the host versus the device, and that the cycle
closes back to the next edit. The device's role as a live participant was
the part most easily missed.

Add the same diagram to the guide and the note, drawn as a text block with
the repo's existing box-drawing and magic-comment colors rather than a new
Mermaid dependency, since six pages already use that convention and the
prism magic comments work in blog posts too. Colors follow core-concepts:
orange for what you do, green for the CLI, blue for on-device. It also
makes explicit that a QEMU target and a physical board are the same thing
to this loop, both being SSH-reachable devices.

Signed-off-by: Javier Tia <javier@peridio.com>
The docs CI runs prettier --check, and neither file was formatted: the
reference tables in the guide were unaligned, and prettier reflowed the
note's PullQuote.

Running prettier also exposed a real defect. Prettier's markdown parser
reads the asterisks in an MDX `{/* ... */}` comment as emphasis and
rewrites them to underscores, producing `{/_ ... _/}`, which MDX then
tries to evaluate as a JS expression and fails on with "Could not parse
expression with acorn". The pre-release note therefore moves into the
frontmatter as YAML comments, which prettier preserves and which never
render, next to the existing internal-drafting comment block.

Signed-off-by: Javier Tia <javier@peridio.com>
Copilot AI review requested due to automatic review settings July 30, 2026 18:48
@jetm
jetm marked this pull request as ready for review July 30, 2026 18:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Not ready to approve

The new guide has a confirmed docs-link convention mismatch and an internally inconsistent config-key reference table that should be corrected for clarity and consistency.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Adds end-user documentation for the new “Container Dev Mode” feature by introducing a dedicated Development guide and a supporting (draft) field note, and wires the guide into the Guides sidebar.

Changes:

  • Add a new “Container dev mode” guide describing setup, workflow loop, command/env/config references, ports, and trust model.
  • Add a new draft field note reframing the feature around the developer inner loop and linking readers to the guide.
  • Update the Guides sidebar to include the new guide under Development.
File summaries
File Description
src/sidebars-guides.js Adds the new guide doc ID to the Development section navigation.
src/field-notes/2026-07-23-container-dev-mode-vm-push.mdx New draft field note describing the workflow and validation story, linking to the guide.
src/docs-guides/container-dev-mode.md New end-user guide documenting Container Dev Mode usage and reference material.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Low

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/docs-guides/container-dev-mode.md Outdated
Comment on lines +182 to +185
| `runtimes.<name>.container_dev` | yes | Presence of the block enables the feature for that runtime. |
| `container_dev.images[].ref` | yes | Image reference (`repository[:tag]`) watched on the host engine. |
| `container_dev.images[].service` | yes | Device service that consumes the image and is restarted after a pull. |
| `container_dev.registry.port` | no | Port for the bulk read listener. Defaults to `5599`. |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Row 1 is runtimes.<name>.container_dev and rows 2-4 drop the prefix (container_dev.images[].ref, .images[].service, .registry.port), so the table reads as if the later keys sit at the top level of the file rather than under the same runtime.

Fully qualifying all four is the fix. Queuing it with the other changes on this PR.

Comment thread src/docs-guides/container-dev-mode.md Outdated

@jetm jetm left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cold second read on my own PR. Six findings inline, plus both of Copilot's are valid and I am queuing fixes for them.

The one worth stopping on: the guide has no draft/unlisted and is wired into the sidebar, so merging publishes it to the live docs - while the field note in this same PR is held at draft: true with a comment saying the feature has not shipped and a reader cannot reproduce it today. That reasoning applies to the guide unchanged. container_dev is on zero files on avocado-cli origin/main and 15 on the unmerged branch, and a production build emits the guide's HTML while emitting nothing for the note.

Verified by building: npm run build exits 0. Worth noting explicitly that this is weak evidence for the note and not for the guide - Docusaurus drops draft: true posts in production, so the passing build validates the guide and says nothing at all about the note.

Also checked and clean: all 5 avocado container dev subcommands, all 6 AVOCADO_CONTAINER_DEV_* env vars, all 4 config keys, the three default ports, the sidebar id, every internal link under onBrokenLinks: 'throw', the highlight directives, the truncate marker position, authors: [jtia], and the date/filename match.

@@ -0,0 +1,216 @@
---
sidebar_position: 3

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guide publishes to production for a feature that has not shipped, while its own companion note is gated for exactly that reason.

The frontmatter here has no draft or unlisted, and src/sidebars-guides.js:34 registers it, so merging publishes it live. The field note in this same PR carries draft: true with the comment "PRE-RELEASE feature - keep on the branch until Container Dev Mode ships" and "a reader cannot reproduce this today."

That reasoning applies to the guide verbatim. Checked the CLI: git grep container_dev in avocado-cli returns 0 files on origin/main and 15 only on the unmerged origin/container-dev-mode branch. A production build confirms the asymmetry - it emits developer-reference/container-dev-mode.html containing avocado container dev up, and emits nothing at all for the note.

So a reader lands on the live page and runs a subcommand that exists on no released CLI. Gate the guide the same way the note is gated, or hold the whole PR until the CLI lands.

runtimes:
dev:
extensions:
- avocado-dev

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avocado-dev is not a real extension name, and this example does not define it.

The shipped prebuilt extension is avocado-ext-dev - 67 files under src/ use that spelling. The bare avocado-dev appears in exactly one other doc, hardware-in-the-loop.md:30, and it is legal there only because that same file defines it inline at line 43 under a top-level extensions: block.

This guide copied the usage and dropped the definition, so a reader who pastes this avocado.yaml and runs avocado build gets Extension 'avocado-dev' not found in configuration (it resolves defined: false, per config_show.rs:277-286). Confirmed it reaches the rendered page: avocado-dev appears once in the built HTML, avocado-ext-dev zero times.

Either rename it to avocado-ext-dev or add the inline definition block the way hardware-in-the-loop.md does.

avocado container dev status
```

`status` reports registry, watcher, and last-sync state. It also surfaces the case where a device presents a stale token and needs `up` to be re-run to re-bootstrap.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stale-token sentence describes behavior the CLI explicitly does not have yet.

The first half of this paragraph (registry, watcher, last-sync) is accurate. The claim that status "surfaces the case where a device presents a stale token and needs up to be re-run" is not.

avocado-cli src/commands/container/dev.rs:26-36 says so in its own words: the per-device status.devices list and the needs_rebootstrap() rotation are "NOT YET LIVE, despite being implemented and tested in bootstrap.rs", because "up writes session.json once and never updates it, so devices stays empty and needs_rebootstrap() is structurally false".

A reader with a genuinely stale token runs status, sees nothing flagged, and concludes the session is healthy while pulls fail. Drop the sentence until the path is wired.

targets={['qemux86-64']}
cli="1.0.0-rc.1"
reference={{
label: '[ENGINEER: reference link once the code is public]',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This placeholder is inside a component prop, so it renders as link text rather than sitting in prose.

It is passed as reference.label to <TestStatus>, and src/components/TestStatus/index.jsx:45-48 renders that as the anchor text. The moment draft flips to false - or on any dev-server or deploy-preview render, neither of which honors draft - the card at the top of the note shows a GitHub-iconed link reading [ENGINEER: reference link once the code is public], pointing at the bare avocado-linux/references repo root.

Every sibling note points at a real /tree/main/<reference-name> subpath. This is the only placeholder in the corpus that lands in a component prop instead of body prose, which is also why a read-through of the rendered page is less likely to catch it.


## Reproduce it

[ENGINEER: Container Dev Mode is pre-release - fill this in once the CLI and the

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole "Reproduce it" section is still an editorial placeholder.

Six lines of [ENGINEER: ...] drafting notes naming setup-lab.sh and verify-vm-write-path.sh, with no link to either, standing where the runnable instructions go.

Correctly gated today by draft: true, so this is a blocker on the un-draft rather than on the merge - flagging it so it does not get lost when the feature ships. CONTRIBUTING.md:124: "The draft only becomes 'ready' when no [ENGINEER: ...] placeholders remain."

# PRE-RELEASE NOTE (not for readers): Container Dev Mode is not shipped yet.
# The framing and the measured results are real, but the CLI and the device
# extension are pre-release, so a reader cannot reproduce this today. It stays
# draft:true on this branch until the feature ships and the [ENGINEER: ...]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This frontmatter comment will trip the pre-merge placeholder gate forever.

The comment contains the literal string [ENGINEER: ...], and the documented gate at CONTRIBUTING.md:126-128 is grep -l "\[ENGINEER:" *.mdx. So even after the two real placeholders (lines 30 and 151) are filled, this file keeps matching.

The next person either hunts for a placeholder that no longer exists, or learns to ignore the gate for every note - which is the worse outcome. Rewording to something like "the ENGINEER gaps" clears it without losing the meaning.

…nk extension

The configuration reference gave the first key as
`runtimes.<name>.container_dev` and then dropped that prefix for the three
below it. Read on its own, `container_dev.images[].ref` looks like a
top-level key - which the same page warns three sections earlier is exactly
what does not work: "the presence of a `container_dev` block under a runtime
turns it on for that runtime. A block placed anywhere else is not honored."
So the table quietly contradicted the prose it was meant to summarize.

Qualify all four rows. The paths match the CLI's own types -
`ContainerDevConfig` carries `images` and `registry`, `ContainerDevImage`
carries `ref` and `service` - so a reader can paste the dotted path against
the YAML example above and land in the right place.

The intro also linked `./hardware-in-the-loop.md` where every other link in
docs-guides is extensionless; seven of them are, and this was the only one
that was not. Beyond consistency, the extension is the part that breaks if
a target is ever renamed to `.mdx`.

Prettier reformatted the table's column widths after the longer keys went
in. Worth noting the file passed `prettier --check` before this change and
the hand-aligned padding broke it, so the reformat is part of the fix
rather than incidental churn - checked both before and after with the
repo's own `src/.prettierrc.json`.

Signed-off-by: Javier Tia <javier@peridio.com>
Copilot AI review requested due to automatic review settings July 30, 2026 22:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Human review recommended

The documentation is explicitly pre-release and dependent on multiple external PRs/releases, so correctness and publish-readiness can’t be fully validated from this change set alone.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

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.

2 participants