Summary
When --mount-workspace-git-root is true (the default), deacon walks up from --workspace-folder to the enclosing git root and replaces args.workspace_folder with the git root before doing config discovery. The intent of the flag is to mount the git repo so that git operations work inside the container, but the implementation conflates mounting with discovery: .devcontainer/devcontainer.json is now looked up at the git root instead of at the path the user explicitly passed.
Practical effect: any example, fixture, or sub-project that sits inside a larger git-managed workspace silently loads the enclosing repo's devcontainer config instead of its own.
Reproduction
$ cd /workspaces/deacon/examples/up/workspace-mount # has .devcontainer/devcontainer.json
$ deacon read-configuration --workspace-folder . | jq '.configuration.name, .workspace.workspaceFolder, .workspace.configFolderPath'
"Rust Agentic Development" # ← parent repo's name, NOT the example's
"/workspaces/deacon"
"/workspaces/deacon/.devcontainer"
$ deacon read-configuration --workspace-folder . --mount-workspace-git-root false \
| jq '.configuration.name'
"Custom workspaceMount" # ← the example's, as expected
The second invocation is what users would expect from the first.
Code location
crates/deacon/src/commands/up/mod.rs:
let resolved = if args.mount_workspace_git_root {
// ...
deacon_core::workspace::resolve_workspace_root(&ws)? // walks up to git root
} else {
ws.canonicalize()?
};
args.workspace_folder = Some(resolved); // ← overwrites workspace_folder
resolve_workspace_root walks up until it finds .git/. The resolved path is then used for both mounting AND config discovery, because args.workspace_folder is the single input both downstream lookups consume.
Spec position
The containers.dev / devcontainers/spec only mandates that the mount uses the enclosing git repository so git operations inside the container work. It does not say config discovery should change location. The reference CLI does discovery at the user-provided path and mounts the git root separately.
Impact
- Every example under
examples/ that has its own .devcontainer/devcontainer.json is silently overridden by /workspaces/deacon/.devcontainer/devcontainer.json when run from inside the repo. This was invisible while the repo's own devcontainer was lightweight (initial commit had "features": {}); after the repo devcontainer was bulked up with rust/node/docker-in-docker on 2026-02-20 (commit 28404a7), example runs started attempting to install docker-in-docker on alpine:3.18 and failing.
- Any user who checks the repo out and runs
examples/<X>/exec.sh without --mount-workspace-git-root false hits the same problem.
- More generally, anyone who tries deacon on a sub-project sitting inside a monorepo will get the monorepo root's config, not their sub-project's.
Proposed fix
Decouple the two responsibilities:
mount_workspace_git_root: true → the mount source is the git root (current behavior).
- Config discovery +
args.workspace_folder → stays at the path the user passed via --workspace-folder.
Concretely: stop assigning the resolved git root to args.workspace_folder. Carry the git root in a separate field (git_root_for_mount or similar) that the mount-construction step consumes. Leave workspace_folder as the user input.
Acceptance
deacon read-configuration --workspace-folder examples/up/workspace-mount from anywhere in the deacon repo returns the example's configuration (name "Custom workspaceMount"), not the repo's.
deacon up --workspace-folder examples/up/workspace-mount builds the example's image/features, not the parent repo's.
- The mount inside the container still spans the git root when
--mount-workspace-git-root true (default).
--mount-workspace-git-root false continues to work as it does today (use --workspace-folder for both discovery and mount).
Relationship to other issues
Surfaced while drafting and verifying spec-coverage examples under examples/. See sibling issues #65 (config filename validation) and #66 (workspace-folder gating in read-configuration) — together those three explain why most of the new examples can't be verified inside the deacon repo today.
🤖 Generated with Claude Code
Summary
When
--mount-workspace-git-rootis true (the default), deacon walks up from--workspace-folderto the enclosing git root and replacesargs.workspace_folderwith the git root before doing config discovery. The intent of the flag is to mount the git repo so that git operations work inside the container, but the implementation conflates mounting with discovery:.devcontainer/devcontainer.jsonis now looked up at the git root instead of at the path the user explicitly passed.Practical effect: any example, fixture, or sub-project that sits inside a larger git-managed workspace silently loads the enclosing repo's devcontainer config instead of its own.
Reproduction
The second invocation is what users would expect from the first.
Code location
crates/deacon/src/commands/up/mod.rs:resolve_workspace_rootwalks up until it finds.git/. The resolved path is then used for both mounting AND config discovery, becauseargs.workspace_folderis the single input both downstream lookups consume.Spec position
The containers.dev / devcontainers/spec only mandates that the mount uses the enclosing git repository so git operations inside the container work. It does not say config discovery should change location. The reference CLI does discovery at the user-provided path and mounts the git root separately.
Impact
examples/that has its own.devcontainer/devcontainer.jsonis silently overridden by/workspaces/deacon/.devcontainer/devcontainer.jsonwhen run from inside the repo. This was invisible while the repo's own devcontainer was lightweight (initial commit had"features": {}); after the repo devcontainer was bulked up with rust/node/docker-in-docker on 2026-02-20 (commit 28404a7), example runs started attempting to installdocker-in-dockeronalpine:3.18and failing.examples/<X>/exec.shwithout--mount-workspace-git-root falsehits the same problem.Proposed fix
Decouple the two responsibilities:
mount_workspace_git_root: true→ the mount source is the git root (current behavior).args.workspace_folder→ stays at the path the user passed via--workspace-folder.Concretely: stop assigning the resolved git root to
args.workspace_folder. Carry the git root in a separate field (git_root_for_mountor similar) that the mount-construction step consumes. Leaveworkspace_folderas the user input.Acceptance
deacon read-configuration --workspace-folder examples/up/workspace-mountfrom anywhere in the deacon repo returns the example's configuration (name"Custom workspaceMount"), not the repo's.deacon up --workspace-folder examples/up/workspace-mountbuilds the example's image/features, not the parent repo's.--mount-workspace-git-root true(default).--mount-workspace-git-root falsecontinues to work as it does today (use--workspace-folderfor both discovery and mount).Relationship to other issues
Surfaced while drafting and verifying spec-coverage examples under
examples/. See sibling issues #65 (config filename validation) and #66 (workspace-folder gating in read-configuration) — together those three explain why most of the new examples can't be verified inside the deacon repo today.🤖 Generated with Claude Code