docs: publish architectural design records#66
Conversation
📝 WalkthroughWalkthroughThis PR adds comprehensive architectural design documentation to the devcontainer library. Seven new design specifications define core contracts for config resolution, runtime abstraction, features pipeline, compose orchestration, Apple container backend, and structured error handling. The documentation is introduced through a new ChangesArchitectural Design Documentation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Six design notes that explain *why* the public API looks the way it
does. Useful for contributors and embedders; not part of the user-
facing surface. Lives under design/, indexed via design/README.md
and linked from the top-level README.
Published records:
- resolved-config.md — the ResolvedConfig type and parse-merge-
substitute pipeline.
- runtime.md — Runtime / Engine / Workspace boundaries.
- runtime-applecontainer.md — Apple's `container` backend over a
cgo + Swift bridge.
- compose-native.md — runtime-agnostic compose orchestrator.
- features.md — Dev Container Features pipeline.
- structured-errors.md — *devcontainer.Error surface.
What's NOT in this commit (kept under design/private/, gitignored):
- status.md — internal milestone tracker.
- upstream-apple-container.md — planning doc for upstream
contributions to apple/container.
- compose.md — superseded by compose-native.md (kept for context).
.gitignore narrowed from `design/` to `design/private/` so the
published records can be tracked while the in-flight planning
material stays local.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
19acad1 to
7067ada
Compare
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (16)
design/compose-native.md (4)
640-643: 💤 Low valueAdd language specifier to JSON error example.
The error message at lines 640-643 is valid JSON and should be marked as such for proper syntax highlighting.
📝 Proposed fix
- ``` + ```json Error: failed to bootstrap container ... (cause: "VZErrorDomain🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/compose-native.md` around lines 640 - 643, The code fence containing the JSON error example ("Error: failed to bootstrap container ... (cause: \"VZErrorDomain Code=2 'The storage device attachment is invalid.'\")") is missing a language specifier; update that triple-backtick fence to include "json" (i.e., change ``` to ```json) so the JSON-like error is highlighted correctly in the compose-native.md example block.
27-50: 💤 Low valueConsider adding language specifier to ASCII diagram code block.
The ASCII diagram is in a fenced code block without a language specifier. While not critical for ASCII art, adding
textorplaintextwould satisfy linting tools and improve consistency.📝 Proposed fix
-``` +```text ┌──────────────────────────────────────────────────────────────────┐ │ Engine (devcontainer pkg) │🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/compose-native.md` around lines 27 - 50, Update the fenced ASCII diagram code block (the block that starts with the box drawing characters and the compose pkg / runtime diagram) to include a language specifier like "text" or "plaintext" after the opening triple backticks so linters recognize it as plain text; e.g., change the opening fence from ``` to ```text and keep the diagram content unchanged.
291-339: 💤 Low valueAdd language specifiers to algorithm pseudocode blocks.
The Up and Down algorithm descriptions (lines 291-339 and 343-358) use fenced code blocks without language specifiers. Consider using
textorpseudocodeto satisfy linting and improve rendering.Also applies to: 343-358
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/compose-native.md` around lines 291 - 339, Update the fenced code blocks that contain the Up and Down algorithm pseudocode so they include a language specifier (e.g., replace ``` with ```text or ```pseudocode); specifically target the block beginning with "Input: Plan {" (the Up algorithm pseudocode) and the subsequent Down algorithm block so the linter and renderer recognize them as pseudocode/text.
141-148: 💤 Low valueAdd language specifiers to label example code blocks.
The label examples at lines 141-148 and 162-166 are in fenced code blocks without language specifiers. These appear to be configuration/label formats.
📝 Proposed fix
For the container labels block:
-``` +```yaml com.docker.compose.project = <projectName> # interop labelFor the network/volume labels block:
-``` +```yaml com.docker.compose.project = <projectName>Also applies to: 162-166
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/compose-native.md` around lines 141 - 148, The fenced code blocks containing the example container labels and the network/volume labels should include a language specifier for syntax highlighting; update both example blocks shown in the diff (the "container labels" example with com.docker.compose.* and dev.containers.* lines and the "network/volume labels" example) to use ```yaml as the opening fence instead of a plain fence so readers get proper YAML highlighting.design/structured-errors.md (3)
187-193: ⚡ Quick winDocument that
With()mutates the receiver.The builder pattern here is clean for the common usage (chained immediately after
New()), but the method should document that it mutates the receiver in place:// With adds a Context entry and returns the receiver for chaining. // It mutates the Error in place; the returned value points to the same instance. func (e *Error) With(key string, val any) *Error { ... }This prevents surprises if someone tries to fork an Error by calling
With()multiple times on the same base instance.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/structured-errors.md` around lines 187 - 193, Add a Go doc comment to the With method on type Error that clearly states it mutates the receiver and returns the same instance for chaining; update the comment above func (e *Error) With(key string, val any) *Error to something like: "With adds a Context entry and returns the receiver for chaining. It mutates the Error in place; the returned value points to the same instance." so callers know not to expect a copy when reusing a base Error.
153-153: 💤 Low valueSpecify the exact
Error()format string.The comment indicates the format will be
"<code>: <reason>", but consider documenting the exact implementation to ensure consistency:func (e *Error) Error() string { return string(e.Code) + ": " + e.Reason }This makes it clear whether there are spaces around the colon, how Code is converted to string, and whether Cause/Context appear in the output.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/structured-errors.md` at line 153, Document and implement Error() for the Error type to return the exact string format "code: reason" (use string(e.Code) + ": " + e.Reason semantics) and explicitly state that neither Cause nor Context are included in Error() output; update the comment for the Error.Error() method to show that format and reference the Error type and its fields Code, Reason, Cause, and Context so readers know how Code is converted and what is omitted.
568-568: 💤 Low valueOptional: Hyphenate compound modifier.
For grammatical consistency, "Runtime-typed errors" should use a hyphen when the compound modifier precedes the noun:
-7. **Existing typed errors stay.** `config/errors.go` and - `runtime/errors.go` types continue to exist as Cause carriers. - Runtime typed errors gain `Stderr()` methods to satisfy + Runtime-typed errors gain `Stderr()` methods to satisfyThis is a minor stylistic point in a design document.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/structured-errors.md` at line 568, Change the phrase "Runtime typed errors" to the hyphenated "Runtime-typed errors" in the sentence "Runtime typed errors gain `Stderr()` methods to satisfy" so the compound modifier is grammatically consistent; locate that exact phrase in the document and update it to "Runtime-typed errors".design/features.md (9)
302-306: ⚡ Quick winClarify mirror URL deduplication mechanism.
The spec states "content-addressed dedupes across mirror URLs" which is excellent, but the mechanism could be clearer. Currently:
index.jsonmaps ref → digest- Cache entries are keyed by digest
So two refs (e.g.,
ghcr.io/org/feat:1anddocker.io/org/feat:1) pointing to the same content would:
- Both appear in index.json with different ref keys
- Both map to the same digest
- Share the same
oci/sha256-<digest>/directoryPlease add a sentence confirming this is the intended deduplication behavior, as it's an important cache efficiency property.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 302 - 306, The spec should explicitly state that deduplication across mirror URLs is achieved by mapping each mutable or mirror ref in index.json to a single content digest and using that digest as the cache key so multiple refs (e.g., ghcr.io/org/feat:1 and docker.io/org/feat:1) that resolve to the same digest will each have separate entries in index.json but point to and share the same on-disk cache directory (oci/sha256-<digest>/), ensuring a single stored copy per content digest.
285-300: 💤 Low valueAdd language identifier to code block.
The cache layout block is missing a language specifier.
📝 Suggested fix
-``` +```text features/ oci/🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 285 - 300, The fenced code block showing the cache layout (the triple-backtick block containing "features/ oci/ sha256-<digest>/ ... index.json") is missing a language specifier; update the opening fence from ``` to ```text so the block is treated as plain text (leave the content and closing fence unchanged).
212-224: 💤 Low valueAdd language identifier to code block.
The build context layout block is missing a language specifier.
📝 Suggested fix
-``` +```text <engine-managed tmp dir>/ Dockerfile # the file above🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 212 - 224, The code block showing the build context layout (starting with "<engine-managed tmp dir>/" and lines like "Dockerfile" and "build-context/") lacks a language identifier; update the opening fence from ``` to ```text (or another appropriate language) so the snippet is rendered correctly and syntax/highlighting is consistent.
19-58: 💤 Low valueAdd language identifier to code block.
The ASCII diagram code block is missing a language specifier.
📝 Suggested fix
-``` +```text devcontainer.json (features map) │🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 19 - 58, The fenced ASCII diagram block is missing a language tag; update the code fence that wraps the diagram (the triple backticks before "devcontainer.json (features map)") to include a language identifier like text (i.e. change ``` to ```text) so the ASCII art renders correctly and avoids markdown highlighting issues for the diagram shown in the feature.Resolve / feature.Order / feature.GenerateDockerfile flow.
201-201: ⚡ Quick winSpecify where
FEATURE_REFvariable is defined.The trap on line 201 references
FEATURE_REFin the error message, but the script doesn't show where this variable is defined. Please clarify:
- Is it injected by the generator as a literal string substitution?
- Is it set in an environment file?
- Should the example show this variable definition?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` at line 201, The trap message references FEATURE_REF but the document doesn't define it; update the example around the trap (the trap 'rc=$?; ... FEATURE_REF ...' line) to either (a) state explicitly that FEATURE_REF is a generator-substituted placeholder, (b) show a preceding example variable definition (e.g., export FEATURE_REF="your-feature-name") or (c) note it is expected from an environment file—choose one approach and add one clear sentence and a sample definition so readers know where FEATURE_REF comes from.
352-352: 💤 Low valueRemove space in code span element.
There's an extra space inside the code span:
>=should be>=.📝 Suggested fix
- version `>= ` requested via semver. Opt-in: + version `>=` requested via semver. Opt-in:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` at line 352, The code span contains an extra trailing space: change the inline code element text from "`>= `" to "`>=`" so the semver comparator has no trailing space; locate the occurrence of the code span "`>= `" in the features.md content and remove the space inside the backticks (replace "`>= `" with "`>=`").
148-149: ⚡ Quick winClarify
installsAfterbehavior for unlisted features.The spec states
installsAfteris a soft hint "if both listed," but doesn't specify what happens when a feature declaresinstallsAfterfor a feature that isn't in the user's configuration. Is this:
- Silently ignored (safest)?
- Treated as a warning?
- An error?
Please add a sentence clarifying this edge case.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 148 - 149, Add a single clarifying sentence to the spec near the `installsAfter` description: state that `installsAfter` is only effective when both features are present in the user's configuration, and if a feature names an `installsAfter` target that is not listed it is ignored (does not block installation); optionally note that implementations may emit a non-fatal warning for missing targets. Ensure the sentence references `installsAfter` and contrasts it with `dependsOn` for clarity.
274-278: ⚡ Quick winClarify "resolved digest" storage for HTTPS features.
The document states "we record the resolved digest on the metadata entry" for version matching. This is clear for OCI features (which have a manifest digest), but HTTPS features use "sha256 of body" as their cache key (§2, line 67).
Please clarify:
- Is the HTTPS sha256 stored in the same
ResolvedReffield as OCI digests?- Does
StrictFeatureVersionMatchbyte-level comparison work identically for both?- Should the metadata entry distinguish between OCI digest and HTTPS content hash?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` around lines 274 - 278, Update the design text to explicitly state that for HTTPS features the sha256(body) is stored in the same ResolvedRef field used for OCI manifest digests, that StrictFeatureVersionMatch performs identical byte-level identity comparison for both OCI manifest digests and HTTPS content hashes, and to add a short note about distinguishing the two in metadata (either by a source/type prefix on ResolvedRef, e.g. "oci:sha256:..." vs "https:sha256:...", or by adding a small discriminator field) so downstream tooling can tell manifest digest vs content hash; reference ResolvedRef, StrictFeatureVersionMatch and the metadata entry when making this clarification.
239-239: ⚡ Quick winSpecify merge semantics for maps/objects.
The merge semantics state "later overrides earlier" for scalars and "concat + dedupe" for lists, but don't address maps/objects (e.g.,
containerEnv,customizations). Are these:
- Shallow overridden (entire map replaced)?
- Deep merged (keys merged recursively)?
Please add a sentence clarifying nested object behavior, as this is common in devcontainer.json (e.g.,
containerEnv: { KEY: value }layers).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@design/features.md` at line 239, The doc omits merge semantics for maps/objects; add a clear sentence stating whether object/map fields are shallow-overridden or deep-merged (and how conflicts are resolved), and give the devcontainer-specific examples `containerEnv` and `customizations` to show expected behavior (e.g., "maps are deep-merged recursively by key, with later values overriding scalar leaves" or "maps are shallow-replaced: the later map completely replaces the earlier"). Update the paragraph that currently documents scalars and lists to include this single clarifying sentence and ensure it mentions recursive key-merge behavior and conflict resolution rules.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@design/compose-native.md`:
- Line 92: Update the §2.1 in-scope table entry for
services.<name>.network_mode: service:<other> to reflect the Apple backend
limitation mentioned in probe R4 — change the description to indicate this is
"docker backend only" (or "Docker backend only; not supported on Apple backend")
so the table matches the probe text in §2.1 and R4; ensure any other references
in §2.1 that mention this feature are consistent with the updated phrasing.
In `@design/features.md`:
- Around line 362-369: Add a clarifying sentence that disambiguates the two
resolution layers: state that config-level resolution (e.g.,
devcontainer.Resolve) only parses the features map and intentionally leaves
per-feature fields like Metadata, Dir, ResolvedRef, and AlreadyInstalled unset,
while feature-level resolution (feature.Store.Resolve) performs the fetch and
populates those fields; also state that Engine.Up is responsible for invoking
feature.Store.Resolve for features not already installed. Reference the exact
names devcontainer.Resolve, feature.Store.Resolve, and Engine.Up in the sentence
to make the distinction clear.
- Around line 81-85: Update the "HTTPS mechanics" section to explicitly specify
the security and network policies for feature downloads: state that TLS
certificates must be validated against system/root CAs and explain whether/when
custom CA bundles are allowed, define redirect handling (follow or reject and a
max redirect depth), set a response body size limit and behavior on overflow,
document request timeouts (connect and overall) and retry/backoff policy, and
enumerate error handling semantics for network failures (which errors are
retriable vs fatal) and how EngineOptions.FeatureDownloadHeaders is applied;
include these details alongside the existing notes about filename validation,
sha256 caching, and streaming/extraction so implementers have a complete,
consistent spec.
- Around line 136-137: The doc is ambiguous about when enum/proposal validation
runs; update the text to state that enum validation occurs after feature
metadata is available (i.e., during feature.Store.Resolve() once
devcontainer-feature.json has been fetched and merged into Metadata), and that
Engine.Up will perform validation as a fallback for any features whose metadata
wasn't resolved earlier (for example when features are injected or mutated
late). Also explicitly document the pre-baked-image hot path behavior: if
features are not fetched because a pre-baked image is used, skip remote metadata
validation and either validate against embedded Metadata (if present) or treat
enums as unvalidated/default to safe behavior; reference
feature.Store.Resolve(), Resolve, Metadata, Engine.Up and the pre-baked-image
hot path in the updated prose so readers know where each validation step happens
and what to expect.
- Around line 175-178: The _REMOTE_USER_HOME value is being computed with whoami
while USER is set to root, so it captures root's home; change the logic that
writes to /tmp/dc-features/builtin.env to look up the home for the intended
target user (use the build ARG _DEV_CONTAINERS_IMAGE_USER or a default) instead
of whoami—either move the ARG _DEV_CONTAINERS_IMAGE_USER earlier so it’s
available in this RUN or defer writing _REMOTE_USER_HOME until after that ARG is
defined, and use getent passwd ${_DEV_CONTAINERS_IMAGE_USER:-root} to populate
_REMOTE_USER_HOME.
In `@design/resolved-config.md`:
- Around line 15-24: Add language identifiers to the two fenced code blocks that
currently use plain backticks so markdownlint stops failing: change the opening
fences for the ASCII diagram block (the box/arrow diagram around "files -> raw
-> merged -> resolved") and the one containing the expression "devcontainerId =
base32(sha256(localWorkspaceFolder + "\x00" + configPath))[:16]" to include a
language tag (e.g., use ```text) so the blocks are explicitly marked; update the
opening triple-backtick lines for those blocks in the document where the diagram
and the devcontainerId expression appear.
In `@design/runtime-applecontainer.md`:
- Around line 205-221: The docs list an InspectImage mapping for runtime.Runtime
but the declared Runtime interface in design/runtime.md does not include
InspectImage; update the contract so they match by either adding InspectImage to
the Runtime interface (and document expected signature/behavior consistent with
the "image service inspect" mapping and labels round-trip note) or remove the
InspectImage entry from design/runtime-applecontainer.md and any Apple-specific
mapping; ensure references to runtime.Runtime, InspectImage, and the image
service/labels behavior are updated accordingly.
- Around line 19-51: The fenced ASCII diagram block (starting with "Engine
(devcontainer pkg)" / the large box diagram) and the other unlabeled fenced
block later (the block covering the section that begins with
"container-apiserver (Apple's daemon; launchd LaunchAgent)" / lines ~258-267)
are missing a language identifier; update both triple-fenced blocks to use
```text so markdownlint passes and tooling renders them as plain text, leaving
the contents unchanged.
- Around line 161-163: The Package.swift manifest currently uses a wildcard
string with the exact requirement (e.g., exact: "0.12.x") which SwiftPM rejects;
update the dependency declaration in Package.swift to use a fully qualified
semantic version (for example change exact: "0.12.x" to exact: "0.12.3") so the
exact: requirement is a concrete version; ensure any other occurrences of exact:
with an x wildcard are replaced with the specific patch version and keep bump
policy (separate PRs + parity integration) unchanged.
In `@design/runtime.md`:
- Around line 17-42: The fenced ASCII architecture diagram in runtime.md lacks a
language token; update the opening code fence to include a language (e.g.,
change ``` to ```text) so the diagram block is recognized as plain text and
resolves markdownlint MD040 and editor rendering issues; locate the ASCII block
that starts with the "Caller (your application, CLI, tests, ...)" diagram and
add the language token to its opening fence.
---
Nitpick comments:
In `@design/compose-native.md`:
- Around line 640-643: The code fence containing the JSON error example ("Error:
failed to bootstrap container ... (cause: \"VZErrorDomain Code=2 'The storage
device attachment is invalid.'\")") is missing a language specifier; update that
triple-backtick fence to include "json" (i.e., change ``` to ```json) so the
JSON-like error is highlighted correctly in the compose-native.md example block.
- Around line 27-50: Update the fenced ASCII diagram code block (the block that
starts with the box drawing characters and the compose pkg / runtime diagram) to
include a language specifier like "text" or "plaintext" after the opening triple
backticks so linters recognize it as plain text; e.g., change the opening fence
from ``` to ```text and keep the diagram content unchanged.
- Around line 291-339: Update the fenced code blocks that contain the Up and
Down algorithm pseudocode so they include a language specifier (e.g., replace
``` with ```text or ```pseudocode); specifically target the block beginning with
"Input: Plan {" (the Up algorithm pseudocode) and the subsequent Down algorithm
block so the linter and renderer recognize them as pseudocode/text.
- Around line 141-148: The fenced code blocks containing the example container
labels and the network/volume labels should include a language specifier for
syntax highlighting; update both example blocks shown in the diff (the
"container labels" example with com.docker.compose.* and dev.containers.* lines
and the "network/volume labels" example) to use ```yaml as the opening fence
instead of a plain fence so readers get proper YAML highlighting.
In `@design/features.md`:
- Around line 302-306: The spec should explicitly state that deduplication
across mirror URLs is achieved by mapping each mutable or mirror ref in
index.json to a single content digest and using that digest as the cache key so
multiple refs (e.g., ghcr.io/org/feat:1 and docker.io/org/feat:1) that resolve
to the same digest will each have separate entries in index.json but point to
and share the same on-disk cache directory (oci/sha256-<digest>/), ensuring a
single stored copy per content digest.
- Around line 285-300: The fenced code block showing the cache layout (the
triple-backtick block containing "features/ oci/ sha256-<digest>/ ...
index.json") is missing a language specifier; update the opening fence from ```
to ```text so the block is treated as plain text (leave the content and closing
fence unchanged).
- Around line 212-224: The code block showing the build context layout (starting
with "<engine-managed tmp dir>/" and lines like "Dockerfile" and
"build-context/") lacks a language identifier; update the opening fence from ```
to ```text (or another appropriate language) so the snippet is rendered
correctly and syntax/highlighting is consistent.
- Around line 19-58: The fenced ASCII diagram block is missing a language tag;
update the code fence that wraps the diagram (the triple backticks before
"devcontainer.json (features map)") to include a language identifier like text
(i.e. change ``` to ```text) so the ASCII art renders correctly and avoids
markdown highlighting issues for the diagram shown in the feature.Resolve /
feature.Order / feature.GenerateDockerfile flow.
- Line 201: The trap message references FEATURE_REF but the document doesn't
define it; update the example around the trap (the trap 'rc=$?; ... FEATURE_REF
...' line) to either (a) state explicitly that FEATURE_REF is a
generator-substituted placeholder, (b) show a preceding example variable
definition (e.g., export FEATURE_REF="your-feature-name") or (c) note it is
expected from an environment file—choose one approach and add one clear sentence
and a sample definition so readers know where FEATURE_REF comes from.
- Line 352: The code span contains an extra trailing space: change the inline
code element text from "`>= `" to "`>=`" so the semver comparator has no
trailing space; locate the occurrence of the code span "`>= `" in the
features.md content and remove the space inside the backticks (replace "`>= `"
with "`>=`").
- Around line 148-149: Add a single clarifying sentence to the spec near the
`installsAfter` description: state that `installsAfter` is only effective when
both features are present in the user's configuration, and if a feature names an
`installsAfter` target that is not listed it is ignored (does not block
installation); optionally note that implementations may emit a non-fatal warning
for missing targets. Ensure the sentence references `installsAfter` and
contrasts it with `dependsOn` for clarity.
- Around line 274-278: Update the design text to explicitly state that for HTTPS
features the sha256(body) is stored in the same ResolvedRef field used for OCI
manifest digests, that StrictFeatureVersionMatch performs identical byte-level
identity comparison for both OCI manifest digests and HTTPS content hashes, and
to add a short note about distinguishing the two in metadata (either by a
source/type prefix on ResolvedRef, e.g. "oci:sha256:..." vs "https:sha256:...",
or by adding a small discriminator field) so downstream tooling can tell
manifest digest vs content hash; reference ResolvedRef,
StrictFeatureVersionMatch and the metadata entry when making this clarification.
- Line 239: The doc omits merge semantics for maps/objects; add a clear sentence
stating whether object/map fields are shallow-overridden or deep-merged (and how
conflicts are resolved), and give the devcontainer-specific examples
`containerEnv` and `customizations` to show expected behavior (e.g., "maps are
deep-merged recursively by key, with later values overriding scalar leaves" or
"maps are shallow-replaced: the later map completely replaces the earlier").
Update the paragraph that currently documents scalars and lists to include this
single clarifying sentence and ensure it mentions recursive key-merge behavior
and conflict resolution rules.
In `@design/structured-errors.md`:
- Around line 187-193: Add a Go doc comment to the With method on type Error
that clearly states it mutates the receiver and returns the same instance for
chaining; update the comment above func (e *Error) With(key string, val any)
*Error to something like: "With adds a Context entry and returns the receiver
for chaining. It mutates the Error in place; the returned value points to the
same instance." so callers know not to expect a copy when reusing a base Error.
- Line 153: Document and implement Error() for the Error type to return the
exact string format "code: reason" (use string(e.Code) + ": " + e.Reason
semantics) and explicitly state that neither Cause nor Context are included in
Error() output; update the comment for the Error.Error() method to show that
format and reference the Error type and its fields Code, Reason, Cause, and
Context so readers know how Code is converted and what is omitted.
- Line 568: Change the phrase "Runtime typed errors" to the hyphenated
"Runtime-typed errors" in the sentence "Runtime typed errors gain `Stderr()`
methods to satisfy" so the compound modifier is grammatically consistent; locate
that exact phrase in the document and update it to "Runtime-typed errors".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 95349023-cbcd-4ae7-9e87-51bb4bde8f32
📒 Files selected for processing (9)
.gitignoreREADME.mddesign/README.mddesign/compose-native.mddesign/features.mddesign/resolved-config.mddesign/runtime-applecontainer.mddesign/runtime.mddesign/structured-errors.md
| | `services.<name>.restart` | Passthrough to `RunSpec.RestartPolicy`. | | ||
| | `services.<name>.labels` | Merged with our project-scoping labels (§3.1). | | ||
| | `services.<name>.networks` (default network only) | Project gets one network (`<project>_default`); services join it. | | ||
| | `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. | |
There was a problem hiding this comment.
Update §2.1 in-scope table to reflect Apple backend limitation.
Line 822 in probe R4 states: "The §2.1 in-scope row for network_mode: service:<other> is updated to docker backend only." However, the actual table entry at line 92 remains unchanged and doesn't indicate this limitation. This creates an inconsistency between the probe findings and the in-scope feature list.
📝 Proposed fix
-| `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. |
+| `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. **Docker backend only** — Apple's VM-per-container model cannot share namespaces (see §11.3 R4). |Also applies to: 818-822
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/compose-native.md` at line 92, Update the §2.1 in-scope table entry
for services.<name>.network_mode: service:<other> to reflect the Apple backend
limitation mentioned in probe R4 — change the description to indicate this is
"docker backend only" (or "Docker backend only; not supported on Apple backend")
so the table matches the probe text in §2.1 and R4; ensure any other references
in §2.1 that mention this feature are consistent with the updated phrasing.
| **HTTPS mechanics:** GET the URL, validate filename matches | ||
| `^devcontainer-feature-[A-Za-z0-9_-]+\.tgz$`, stream body to disk, extract. | ||
| Cache key is the sha256 of the response body so the same content at two | ||
| URLs dedupes. Custom headers (auth) supplied by callers via | ||
| `EngineOptions.FeatureDownloadHeaders map[string]string`. |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Specify HTTPS security requirements.
The HTTPS download mechanism mentions custom headers for auth but does not specify critical security measures:
- TLS certificate validation policy
- HTTP redirect handling (follow/reject, max depth)
- Response size limits to prevent DoS
- Request timeout configuration
- Error handling for network failures
These should be documented to ensure consistent, secure implementations across the codebase.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/features.md` around lines 81 - 85, Update the "HTTPS mechanics"
section to explicitly specify the security and network policies for feature
downloads: state that TLS certificates must be validated against system/root CAs
and explain whether/when custom CA bundles are allowed, define redirect handling
(follow or reject and a max redirect depth), set a response body size limit and
behavior on overflow, document request timeouts (connect and overall) and
retry/backoff policy, and enumerate error handling semantics for network
failures (which errors are retriable vs fatal) and how
EngineOptions.FeatureDownloadHeaders is applied; include these details alongside
the existing notes about filename validation, sha256 caching, and
streaming/extraction so implementers have a complete, consistent spec.
| `install.sh`). Rejecting typos before image build is worth the small | ||
| duplication. |
There was a problem hiding this comment.
Clarify when enum validation occurs.
The statement "We validate enum/proposals at parse time" appears inconsistent with §10 (line 364) which states that Resolve leaves Metadata empty. Enum values are defined in devcontainer-feature.json metadata, which must be fetched before validation can occur.
Please clarify:
- Does "parse time" mean during
feature.Store.Resolve()(after fetch)? - Or does this validation actually occur later in
Engine.Up? - How does this interact with the "pre-baked-image hot path" where features aren't fetched?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/features.md` around lines 136 - 137, The doc is ambiguous about when
enum/proposal validation runs; update the text to state that enum validation
occurs after feature metadata is available (i.e., during feature.Store.Resolve()
once devcontainer-feature.json has been fetched and merged into Metadata), and
that Engine.Up will perform validation as a fallback for any features whose
metadata wasn't resolved earlier (for example when features are injected or
mutated late). Also explicitly document the pre-baked-image hot path behavior:
if features are not fetched because a pre-baked image is used, skip remote
metadata validation and either validate against embedded Metadata (if present)
or treat enums as unvalidated/default to safe behavior; reference
feature.Store.Resolve(), Resolve, Metadata, Engine.Up and the pre-baked-image
hot path in the updated prose so readers know where each validation step happens
and what to expect.
| echo "_CONTAINER_USER_HOME=$(getent passwd root | cut -d: -f6)" \ | ||
| >> /tmp/dc-features/builtin.env && \ | ||
| echo "_REMOTE_USER_HOME=$(getent passwd $(whoami) | cut -d: -f6)" \ | ||
| >> /tmp/dc-features/builtin.env |
There was a problem hiding this comment.
_REMOTE_USER_HOME logic captures root's home, not the remote user's.
Line 168 sets USER root, so the $(whoami) command on line 177 will return root, not the intended remote user. This means _REMOTE_USER_HOME will be set to root's home directory, which is incorrect.
The intent appears to be capturing the home directory of the final container user (specified via _DEV_CONTAINERS_IMAGE_USER on line 192-193). Consider using that ARG value to look up the home directory, or document if there's a different intended behavior.
🔧 Possible fix approach
# Instead of whoami (which is root at this point), use the target user
RUN \
echo "_CONTAINER_USER_HOME=$(getent passwd root | cut -d: -f6)" \
>> /tmp/dc-features/builtin.env && \
echo "_REMOTE_USER_HOME=$(getent passwd ${_DEV_CONTAINERS_IMAGE_USER:-root} | cut -d: -f6)" \
>> /tmp/dc-features/builtin.envHowever, this requires _DEV_CONTAINERS_IMAGE_USER to be available at that RUN layer. The current template defines it as an ARG on line 192, which is after this RUN. The ARG would need to be moved earlier, or the builtin.env generation deferred.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/features.md` around lines 175 - 178, The _REMOTE_USER_HOME value is
being computed with whoami while USER is set to root, so it captures root's
home; change the logic that writes to /tmp/dc-features/builtin.env to look up
the home for the intended target user (use the build ARG
_DEV_CONTAINERS_IMAGE_USER or a default) instead of whoami—either move the ARG
_DEV_CONTAINERS_IMAGE_USER earlier so it’s available in this RUN or defer
writing _REMOTE_USER_HOME until after that ARG is defined, and use getent passwd
${_DEV_CONTAINERS_IMAGE_USER:-root} to populate _REMOTE_USER_HOME.
| full DAG.** `Resolve` parses the features map, applies | ||
| `overrideFeatureInstallOrder`, merges user options with what's | ||
| defaultable without fetching; leaves `Metadata`, `Dir`, `ResolvedRef` | ||
| empty and `AlreadyInstalled` false. `Engine.Up` reads the base | ||
| image's `devcontainer.metadata` label, marks `AlreadyInstalled` for | ||
| matching features, and fetches only the rest — preserving the consumer's | ||
| pre-baked-image hot path. M1's stubbed `WarnUnsupportedFeatureField` | ||
| warning goes away in PR6. |
There was a problem hiding this comment.
Disambiguate "Resolve" operations.
Decision #5 describes a split between "Resolve populates partial Features" and "Engine.Up does fetch + full DAG," stating that Resolve "leaves Metadata, Dir, ResolvedRef empty."
This conflicts with §3 (lines 97-111) where feature.Store.Resolve() returns *Resolved with these fields populated. The apparent resolution:
- Config-level
Resolve(e.g.,devcontainer.Resolve()) parses the features map but doesn't callfeature.Store.Resolve()yet - Feature-level
feature.Store.Resolve()does the actual fetch and returns full metadata Engine.Upcallsfeature.Store.Resolve()for features not already installed
Please add a clarifying sentence distinguishing these two "Resolve" operations by name/layer to prevent implementation confusion. For example: "Config resolution (devcontainer.Resolve) leaves feature metadata unpopulated; feature resolution (feature.Store.Resolve) fetches and populates it; Engine.Up orchestrates the latter."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/features.md` around lines 362 - 369, Add a clarifying sentence that
disambiguates the two resolution layers: state that config-level resolution
(e.g., devcontainer.Resolve) only parses the features map and intentionally
leaves per-feature fields like Metadata, Dir, ResolvedRef, and AlreadyInstalled
unset, while feature-level resolution (feature.Store.Resolve) performs the fetch
and populates those fields; also state that Engine.Up is responsible for
invoking feature.Store.Resolve for features not already installed. Reference the
exact names devcontainer.Resolve, feature.Store.Resolve, and Engine.Up in the
sentence to make the distinction clear.
| ``` | ||
| ┌─────────┐ parse ┌─────────┐ merge ┌─────────┐ substitute ┌──────────┐ | ||
| │ files │ ───────▶ │ raw │ ───────▶ │ merged │ ───────────▶ │ resolved │ | ||
| └─────────┘ └─────────┘ └─────────┘ └──────────┘ | ||
| *.json, one Go raw + host vars | ||
| JSONC struct per image label filled in; | ||
| file metadata + container vars | ||
| feature may remain | ||
| metadata | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced code blocks.
Line 15 and Line 306 use fenced blocks without a language tag, which will keep markdownlint failing and reduce render/tooling quality.
Suggested doc fix
-```
+```text
┌─────────┐ parse ┌─────────┐ merge ┌─────────┐ substitute ┌──────────┐
│ files │ ───────▶ │ raw │ ───────▶ │ merged │ ───────────▶ │ resolved │
└─────────┘ └─────────┘ └─────────┘ └──────────┘
*.json, one Go raw + host vars
JSONC struct per image label filled in;
file metadata + container vars
feature may remain
metadata
-```
+```
-```
+```text
devcontainerId = base32(sha256(localWorkspaceFolder + "\x00" + configPath))[:16]
-```
+```Also applies to: 306-308
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 15-15: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/resolved-config.md` around lines 15 - 24, Add language identifiers to
the two fenced code blocks that currently use plain backticks so markdownlint
stops failing: change the opening fences for the ASCII diagram block (the
box/arrow diagram around "files -> raw -> merged -> resolved") and the one
containing the expression "devcontainerId = base32(sha256(localWorkspaceFolder +
"\x00" + configPath))[:16]" to include a language tag (e.g., use ```text) so the
blocks are explicitly marked; update the opening triple-backtick lines for those
blocks in the document where the diagram and the devcontainerId expression
appear.
| ``` | ||
| ┌──────────────────────────────────────────────────────────────────┐ | ||
| │ Engine (devcontainer pkg) │ | ||
| │ selects runtime.Runtime impl by EngineOptions │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ Runtime interface (runtime pkg) │ | ||
| │ unchanged — both DockerRuntime and AppleContainerRuntime │ | ||
| │ satisfy it; ComposeRuntime sub-interface is Docker-only │ | ||
| └─────────────────────────────┬────────────────────────────────────┘ | ||
| │ | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ runtime/applecontainer (Go, build-tagged darwin && arm64) │ | ||
| │ thin cgo wrapper; marshals options to JSON, calls @_cdecl │ | ||
| │ exports, decodes responses, owns the handle table for │ | ||
| │ cancellation and streams. │ | ||
| └─────────────────────────────┬────────────────────────────────────┘ | ||
| │ cgo | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ libACBridge.dylib (Swift, this repo's applecontainer-bridge/) │ | ||
| │ imports apple/container's ContainerAPIClient + supporting │ | ||
| │ modules; wraps async APIs as fire-and-forget @_cdecl funcs; │ | ||
| │ pipes for high-throughput streams (exec stdio, logs, build). │ | ||
| └─────────────────────────────┬────────────────────────────────────┘ | ||
| │ XPC (mach service) | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ container-apiserver (Apple's daemon; launchd LaunchAgent) │ | ||
| │ owns VMs (Virtualization.framework), virtiofs, image cache, │ | ||
| │ networks, persistent state. Installed via `brew install │ | ||
| │ container`. Started via `container system start`. │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to unlabeled fenced code blocks.
Line 19 and Line 258 use unlabeled fences. Adding text keeps markdownlint clean and improves readability/tool support.
Also applies to: 258-267
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 19-19: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/runtime-applecontainer.md` around lines 19 - 51, The fenced ASCII
diagram block (starting with "Engine (devcontainer pkg)" / the large box
diagram) and the other unlabeled fenced block later (the block covering the
section that begins with "container-apiserver (Apple's daemon; launchd
LaunchAgent)" / lines ~258-267) are missing a language identifier; update both
triple-fenced blocks to use ```text so markdownlint passes and tooling renders
them as plain text, leaving the contents unchanged.
| **Rule:** `Package.swift` uses `.package(url: ..., exact: "0.12.x")`. | ||
| Bumps are their own PRs, gated by re-running the parity integration | ||
| suite (PR-H) against the new version. We do NOT use `from:` or `branch:`. |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does Swift Package Manager allow wildcard values like "0.12.x" with .package(..., exact: "..."), or does exact require a full semantic version such as "0.12.3"?
💡 Result:
Swift Package Manager does not support wildcard values like "0.12.x" with the.exact requirement [1][2]. The.exact requirement expects a specific, fully qualified semantic version (e.g., "0.12.3") [1][2]. If you need to specify a range of versions rather than a single exact version, you should use other dependency requirements, such as: -.upToNextMajor(from:): Allows the package manager to select versions starting from the specified minimum up to, but not including, the next major version (e.g., "1.2.3" allows "1.2.4", "1.3.0", etc., but not "2.0.0") [1][3]. - Range operators: You can use Swift range syntax to define specific bounds, such as "1.2.3"..<"1.2.6" [1]. Using.exact is generally discouraged by Apple because it can lead to dependency graph conflicts when multiple packages depend on the same library [1][2]. Using version ranges is the recommended approach to provide flexibility while maintaining compatibility [1][3].
Citations:
- 1: https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html
- 2: https://developer.apple.com/documentation/packagedescription/package/dependency/requirement-swift.enum/exact(_:)
- 3: https://developer.apple.com/documentation/packagedescription/package/dependency/package(url:from:traits:)?changes=_3_3
Use a concrete semantic version for SwiftPM exact: pins.
Line 161 uses exact: "0.12.x", but Swift Package Manager requires a fully qualified version (e.g., 0.12.3) with the exact requirement; wildcards like 0.12.x are not supported and will cause an invalid manifest.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/runtime-applecontainer.md` around lines 161 - 163, The Package.swift
manifest currently uses a wildcard string with the exact requirement (e.g.,
exact: "0.12.x") which SwiftPM rejects; update the dependency declaration in
Package.swift to use a fully qualified semantic version (for example change
exact: "0.12.x" to exact: "0.12.3") so the exact: requirement is a concrete
version; ensure any other occurrences of exact: with an x wildcard are replaced
with the specific patch version and keep bump policy (separate PRs + parity
integration) unchanged.
| Every method on `runtime.Runtime` (runtime/runtime.go:83-129) is | ||
| reachable through Apple's stack. Direct mapping: | ||
|
|
||
| | `Runtime` method | Apple API | Bridge shape | Notes | | ||
| | ----------------------- | -------------------------------------------------- | ---------------------------- | ----- | | ||
| | `BuildImage` | `ContainerBuild` (BuildKit gRPC) | callback stream for progress | Builder runs in a separate VM; clear error if not started. Heaviest PR (PR-G). | | ||
| | `PullImage` | `ImagePull` via images service | callback stream for progress | low risk | | ||
| | `RunContainer` | `ContainerClient.create` + create-not-start path | sync request/reply | Mounts, env, labels, runArgs map cleanly. Verify UID semantics (§11). | | ||
| | `StartContainer` | `ContainerClient.start` | sync | low risk | | ||
| | `StopContainer` | `ContainerClient.stop` | sync | Timeout maps directly. | | ||
| | `RemoveContainer` | `ContainerClient.delete` / `kill` | sync | Force + remove-volumes flags. | | ||
| | `ExecContainer` | `ContainerExec` flow with `ProcessIO` | pipe fds + callback | Hardest. TTY mode supported by `config.terminal`. Cancellation via Task. | | ||
| | `InspectContainer` | `ContainerClient.get` / `inspect` | sync, JSON response | Confirm Created/StartedAt/ExitCode/FinishedAt all present. | | ||
| | `InspectImage` | image service `inspect` | sync, JSON response | Labels round-trip — load-bearing for the `devcontainer.metadata` fast path. | | ||
| | `ContainerLogs` | `ContainerLogs` flow | pipe fd | Follow + non-follow. | | ||
| | `FindContainerByLabel` | `ContainerClient.list` + client-side label filter | sync | If Apple adds server-side filtering, switch. | | ||
| | `ComposeRuntime` (sub) | not implemented | type assertion fails | See §9. | |
There was a problem hiding this comment.
Align Runtime method mapping with the declared Runtime interface.
This section maps an InspectImage method, but the Runtime interface described in design/runtime.md does not declare InspectImage. Please reconcile the docs so backend implementation scope matches the shared contract.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/runtime-applecontainer.md` around lines 205 - 221, The docs list an
InspectImage mapping for runtime.Runtime but the declared Runtime interface in
design/runtime.md does not include InspectImage; update the contract so they
match by either adding InspectImage to the Runtime interface (and document
expected signature/behavior consistent with the "image service inspect" mapping
and labels round-trip note) or remove the InspectImage entry from
design/runtime-applecontainer.md and any Apple-specific mapping; ensure
references to runtime.Runtime, InspectImage, and the image service/labels
behavior are updated accordingly.
| ``` | ||
| ┌──────────────────────────────────────────────────────────────────┐ | ||
| │ Caller (your application, CLI, tests, ...) │ | ||
| │ eng.Up(ctx, UpOptions{...}) → *Workspace │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ Engine (devcontainer pkg) │ | ||
| │ - resolves config (M1) │ | ||
| │ - builds image (M3) │ | ||
| │ - drives Runtime to create + start │ | ||
| │ - runs lifecycle phases with idempotency markers │ | ||
| │ - manages container-context Substituter │ | ||
| │ - emits Events │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ Runtime interface (runtime pkg) │ | ||
| │ container primitives only — no devcontainer-spec semantics │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| │ | ||
| ┌─────────────────────────────▼────────────────────────────────────┐ | ||
| │ DockerRuntime (runtime/docker) │ | ||
| │ uses the Docker Engine API Go SDK │ | ||
| └──────────────────────────────────────────────────────────────────┘ | ||
| ``` |
There was a problem hiding this comment.
Specify a language for the architecture diagram code fence.
Line 17 has a fenced block without a language token; adding text will resolve markdownlint MD040 and improve editor rendering.
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 17-17: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@design/runtime.md` around lines 17 - 42, The fenced ASCII architecture
diagram in runtime.md lacks a language token; update the opening code fence to
include a language (e.g., change ``` to ```text) so the diagram block is
recognized as plain text and resolves markdownlint MD040 and editor rendering
issues; locate the ASCII block that starts with the "Caller (your application,
CLI, tests, ...)" diagram and add the language token to its opening fence.
Summary
Publishes the architectural design notes that have been internal-only since the repo started. They explain the choices behind the public API for contributors and embedders — not user-facing docs.
Six published records, indexed via
design/README.mdand linked from the top-level README:resolved-config.md— the central data typeruntime.md— Runtime / Engine / Workspace layeringruntime-applecontainer.md— second backend over a Swift bridgecompose-native.md— runtime-agnostic compose orchestratorfeatures.md— Dev Container Features pipelinestructured-errors.md—*devcontainer.ErrorsurfaceInternal planning material (milestone trackers, draft upstream-contribution plans, the superseded shell-out compose design) is kept under
design/private/, which the new.gitignorerule excludes from the repo.What's been scrubbed from the published docs
consumer,your application).§13) was replaced with the underlying point.What remains: some shipping-plan vocabulary (milestone labels, "PR-X" references) is intact where it doesn't impede understanding. These are design records, not living documentation — the conversational language is part of how they read. The status legend in
design/README.mddescribes the convention.Test plan
.gitignorecorrectly excludesdesign/private/while tracking the rest ofdesign/.grep -nE "\bDAP\b" design/*.mdreturns no matches.design/README.mdresolve.## Designsection links intodesign/README.md.🤖 Generated with Claude Code
Summary by CodeRabbit
Documentation
Chores