Skip to content

Commit 87212cd

Browse files
authored
Merge pull request #270 from thevibeworks/fix/mount-dispatch-and-version-pins
fix(deva): tighten mount dispatch and drop python path helpers
2 parents 3a2276d + 7db8336 commit 87212cd

36 files changed

Lines changed: 3337 additions & 433 deletions

.deva.example

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,34 @@ EPHEMERAL=false
4949
#
5050
# 6. Disable ephemeral containers (persistent):
5151
# EPHEMERAL=false
52+
#
53+
# 7. Enable Codex browser MCP for this project:
54+
# DEFAULT_AGENT=codex
55+
# CODEX_BROWSER_MCP=true
56+
#
57+
# Optional session-only Codex config overrides:
58+
# CODEX_CONFIG=features.apps=false
59+
# CODEX_CONFIG=features.plugins=false
60+
61+
# Hybrid Agent Setup:
62+
#
63+
# Hybrid is the DEFAULT. deva walks every populated subdir under
64+
# ~/.config/deva/ (claude, codex, gemini) and mounts each agent's
65+
# canonical entries into the container. Populated = you either
66+
# hand-created the subdir or autolink symlinked it from legacy
67+
# ~/.claude, ~/.codex, ~/.gemini on first run.
68+
#
69+
# No .deva entries required for the common case. To opt OUT of
70+
# hybrid for a single invocation, pass --config-home DIR to
71+
# isolate that run to a single home.
72+
#
73+
# Use VOLUME= only when you want to mount host paths OUTSIDE
74+
# ~/.config/deva/ (e.g. a shared secrets vault) at an agent target.
75+
# VOLUME= entries win over the default per-agent mount at the same
76+
# container target (first-writer-wins; CLI -v beats .deva).
77+
#
78+
# Auth credentials inside mounted agent dirs ride along — hybrid
79+
# only makes sense if you trust every agent equally.
5280

5381
# Project-Specific Config (.deva in project root):
5482
#

.github/workflows/ci.yml

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,40 @@ jobs:
4444
chmod +x scripts/version-check.sh
4545
./scripts/version-check.sh
4646
47+
- name: Unit tests (release-utils.sh)
48+
run: bash tests/test_release_utils.sh
49+
4750
smoke:
4851
name: Installer Smoke Test
4952
runs-on: ubuntu-latest
5053
steps:
5154
- name: Checkout
5255
uses: actions/checkout@v4
5356

54-
- name: Setup Node
55-
uses: actions/setup-node@v4
56-
with:
57-
node-version: "22"
58-
59-
- name: Resolve tool versions
60-
id: versions
61-
env:
62-
GH_TOKEN: ${{ github.token }}
63-
run: bash ./scripts/resolve-tool-versions.sh
57+
- name: Load pinned versions
58+
id: pins
59+
shell: bash
60+
run: |
61+
set -euo pipefail
62+
source ./scripts/version-pins.sh
63+
load_version_pins
64+
emit_github_outputs "$GITHUB_OUTPUT"
6465
6566
- name: Build local smoke image
6667
run: |
6768
docker build -t deva-smoke:ci \
68-
--build-arg CLAUDE_CODE_VERSION="${{ steps.versions.outputs.claude_code_version }}" \
69-
--build-arg CODEX_VERSION="${{ steps.versions.outputs.codex_version }}" \
70-
--build-arg GEMINI_CLI_VERSION="${{ steps.versions.outputs.gemini_cli_version }}" \
71-
--build-arg ATLAS_CLI_VERSION="${{ steps.versions.outputs.atlas_cli_version }}" \
72-
--build-arg COPILOT_API_VERSION="${{ steps.versions.outputs.copilot_api_version }}" \
69+
--build-arg NODE_MAJOR="${{ steps.pins.outputs.node_major }}" \
70+
--build-arg GO_VERSION="${{ steps.pins.outputs.go_version }}" \
71+
--build-arg PYTHON_VERSION="${{ steps.pins.outputs.python_version }}" \
72+
--build-arg DELTA_VERSION="${{ steps.pins.outputs.delta_version }}" \
73+
--build-arg TMUX_VERSION="${{ steps.pins.outputs.tmux_version }}" \
74+
--build-arg TMUX_SHA256="${{ steps.pins.outputs.tmux_sha256 }}" \
75+
--build-arg CLAUDE_CODE_VERSION="${{ steps.pins.outputs.claude_code_version }}" \
76+
--build-arg CLAUDE_TRACE_VERSION="${{ steps.pins.outputs.claude_trace_version }}" \
77+
--build-arg CODEX_VERSION="${{ steps.pins.outputs.codex_version }}" \
78+
--build-arg GEMINI_CLI_VERSION="${{ steps.pins.outputs.gemini_cli_version }}" \
79+
--build-arg ATLAS_CLI_VERSION="${{ steps.pins.outputs.atlas_cli_version }}" \
80+
--build-arg COPILOT_API_VERSION="${{ steps.pins.outputs.copilot_api_version }}" \
7381
.
7482
7583
- name: Build core and rust images via Makefile
@@ -79,11 +87,22 @@ jobs:
7987
TAG=ci \
8088
CORE_TAG=ci-core \
8189
RUST_TAG=ci-rust \
82-
CLAUDE_CODE_VERSION="${{ steps.versions.outputs.claude_code_version }}" \
83-
CODEX_VERSION="${{ steps.versions.outputs.codex_version }}" \
84-
GEMINI_CLI_VERSION="${{ steps.versions.outputs.gemini_cli_version }}" \
85-
ATLAS_CLI_VERSION="${{ steps.versions.outputs.atlas_cli_version }}" \
86-
COPILOT_API_VERSION="${{ steps.versions.outputs.copilot_api_version }}"
90+
NODE_MAJOR="${{ steps.pins.outputs.node_major }}" \
91+
GO_VERSION="${{ steps.pins.outputs.go_version }}" \
92+
PYTHON_VERSION="${{ steps.pins.outputs.python_version }}" \
93+
DELTA_VERSION="${{ steps.pins.outputs.delta_version }}" \
94+
TMUX_VERSION="${{ steps.pins.outputs.tmux_version }}" \
95+
TMUX_SHA256="${{ steps.pins.outputs.tmux_sha256 }}" \
96+
CLAUDE_CODE_VERSION="${{ steps.pins.outputs.claude_code_version }}" \
97+
CLAUDE_TRACE_VERSION="${{ steps.pins.outputs.claude_trace_version }}" \
98+
CODEX_VERSION="${{ steps.pins.outputs.codex_version }}" \
99+
GEMINI_CLI_VERSION="${{ steps.pins.outputs.gemini_cli_version }}" \
100+
ATLAS_CLI_VERSION="${{ steps.pins.outputs.atlas_cli_version }}" \
101+
COPILOT_API_VERSION="${{ steps.pins.outputs.copilot_api_version }}" \
102+
PLAYWRIGHT_VERSION="${{ steps.pins.outputs.playwright_version }}" \
103+
RUST_TOOLCHAINS="${{ steps.pins.outputs.rust_toolchains }}" \
104+
RUST_DEFAULT_TOOLCHAIN="${{ steps.pins.outputs.rust_default_toolchain }}" \
105+
RUST_TARGETS="${{ steps.pins.outputs.rust_targets }}"
87106
88107
- name: Install and launch each agent without a TTY
89108
shell: bash
@@ -127,6 +146,26 @@ jobs:
127146
grep -F -- "$bridge_dir:/deva-host-chrome-bridge" <<<"$dry_run"
128147
grep -F -- "$profile_dir/Extensions:/home/deva/.config/google-chrome/Default/Extensions:ro" <<<"$dry_run"
129148
149+
- name: Smoke bind mount shape guard
150+
shell: bash
151+
run: |
152+
set -euo pipefail
153+
DEVA_DOCKER_IMAGE=deva-smoke \
154+
DEVA_DOCKER_TAG=ci \
155+
./scripts/test-mount-shape.sh
156+
157+
- name: Smoke agent tooling installer
158+
shell: bash
159+
run: |
160+
set -euo pipefail
161+
./scripts/test-install-agent-tooling.sh
162+
163+
- name: Smoke version targets
164+
shell: bash
165+
run: |
166+
set -euo pipefail
167+
./scripts/test-version-targets.sh
168+
130169
- name: Smoke Chrome bridge entrypoint symlink
131170
shell: bash
132171
run: |

.github/workflows/nightly-images.yml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,34 @@ concurrency:
1818
cancel-in-progress: true
1919

2020
jobs:
21+
load-version-pins:
22+
name: Load Pinned Toolchain Versions
23+
runs-on: ubuntu-latest
24+
outputs:
25+
node_major: ${{ steps.pins.outputs.node_major }}
26+
go_version: ${{ steps.pins.outputs.go_version }}
27+
python_version: ${{ steps.pins.outputs.python_version }}
28+
delta_version: ${{ steps.pins.outputs.delta_version }}
29+
tmux_version: ${{ steps.pins.outputs.tmux_version }}
30+
tmux_sha256: ${{ steps.pins.outputs.tmux_sha256 }}
31+
claude_trace_version: ${{ steps.pins.outputs.claude_trace_version }}
32+
playwright_version: ${{ steps.pins.outputs.playwright_version }}
33+
rust_toolchains: ${{ steps.pins.outputs.rust_toolchains }}
34+
rust_default_toolchain: ${{ steps.pins.outputs.rust_default_toolchain }}
35+
rust_targets: ${{ steps.pins.outputs.rust_targets }}
36+
steps:
37+
- name: Checkout
38+
uses: actions/checkout@v4
39+
40+
- name: Load pins
41+
id: pins
42+
shell: bash
43+
run: |
44+
set -euo pipefail
45+
source ./scripts/version-pins.sh
46+
load_version_pins
47+
emit_github_outputs "$GITHUB_OUTPUT"
48+
2149
resolve-versions:
2250
name: Resolve Latest Tool Versions
2351
runs-on: ubuntu-latest
@@ -59,7 +87,7 @@ jobs:
5987
6088
build-base:
6189
name: Build Nightly Base Image
62-
needs: resolve-versions
90+
needs: [load-version-pins, resolve-versions]
6391
runs-on: ubuntu-latest
6492
steps:
6593
- name: Checkout
@@ -102,15 +130,22 @@ jobs:
102130
cache-from: type=gha,scope=nightly-base
103131
cache-to: type=gha,mode=max,scope=nightly-base
104132
build-args: |
133+
NODE_MAJOR=${{ needs.load-version-pins.outputs.node_major }}
134+
GO_VERSION=${{ needs.load-version-pins.outputs.go_version }}
135+
PYTHON_VERSION=${{ needs.load-version-pins.outputs.python_version }}
136+
DELTA_VERSION=${{ needs.load-version-pins.outputs.delta_version }}
137+
TMUX_VERSION=${{ needs.load-version-pins.outputs.tmux_version }}
138+
TMUX_SHA256=${{ needs.load-version-pins.outputs.tmux_sha256 }}
105139
CLAUDE_CODE_VERSION=${{ needs.resolve-versions.outputs.claude_code_version }}
140+
CLAUDE_TRACE_VERSION=${{ needs.load-version-pins.outputs.claude_trace_version }}
106141
CODEX_VERSION=${{ needs.resolve-versions.outputs.codex_version }}
107142
GEMINI_CLI_VERSION=${{ needs.resolve-versions.outputs.gemini_cli_version }}
108143
ATLAS_CLI_VERSION=${{ needs.resolve-versions.outputs.atlas_cli_version }}
109144
COPILOT_API_VERSION=${{ needs.resolve-versions.outputs.copilot_api_version }}
110145
111146
build-rust:
112147
name: Build Nightly Rust Image
113-
needs: [resolve-versions, build-base]
148+
needs: [load-version-pins, resolve-versions, build-base]
114149
runs-on: ubuntu-latest
115150
steps:
116151
- name: Checkout
@@ -154,6 +189,15 @@ jobs:
154189
cache-to: type=gha,mode=max,scope=nightly-rust
155190
build-args: |
156191
BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${{ needs.resolve-versions.outputs.stamp }}
192+
CLAUDE_CODE_VERSION=${{ needs.resolve-versions.outputs.claude_code_version }}
193+
CLAUDE_TRACE_VERSION=${{ needs.load-version-pins.outputs.claude_trace_version }}
194+
CODEX_VERSION=${{ needs.resolve-versions.outputs.codex_version }}
195+
GEMINI_CLI_VERSION=${{ needs.resolve-versions.outputs.gemini_cli_version }}
196+
ATLAS_CLI_VERSION=${{ needs.resolve-versions.outputs.atlas_cli_version }}
197+
PLAYWRIGHT_VERSION=${{ needs.load-version-pins.outputs.playwright_version }}
198+
RUST_TOOLCHAINS=${{ needs.load-version-pins.outputs.rust_toolchains }}
199+
RUST_DEFAULT_TOOLCHAIN=${{ needs.load-version-pins.outputs.rust_default_toolchain }}
200+
RUST_TARGETS=${{ needs.load-version-pins.outputs.rust_targets }}
157201
158202
summary:
159203
name: Nightly Summary

.github/workflows/release.yml

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,45 +35,64 @@ jobs:
3535
[ -n "$release_tag" ] || { echo "error: empty release tag" >&2; exit 1; }
3636
echo "release_tag=$release_tag" >> "$GITHUB_OUTPUT"
3737
38-
resolve-versions:
39-
name: Resolve Tool Versions
38+
load-version-pins:
39+
name: Load Pinned Tool Versions
4040
runs-on: ubuntu-latest
41+
needs: prepare
4142
outputs:
42-
claude_code_version: ${{ steps.versions.outputs.claude_code_version }}
43-
codex_version: ${{ steps.versions.outputs.codex_version }}
44-
gemini_cli_version: ${{ steps.versions.outputs.gemini_cli_version }}
45-
atlas_cli_version: ${{ steps.versions.outputs.atlas_cli_version }}
46-
copilot_api_version: ${{ steps.versions.outputs.copilot_api_version }}
43+
node_major: ${{ steps.pins.outputs.node_major }}
44+
go_version: ${{ steps.pins.outputs.go_version }}
45+
python_version: ${{ steps.pins.outputs.python_version }}
46+
delta_version: ${{ steps.pins.outputs.delta_version }}
47+
tmux_version: ${{ steps.pins.outputs.tmux_version }}
48+
tmux_sha256: ${{ steps.pins.outputs.tmux_sha256 }}
49+
claude_code_version: ${{ steps.pins.outputs.claude_code_version }}
50+
claude_trace_version: ${{ steps.pins.outputs.claude_trace_version }}
51+
codex_version: ${{ steps.pins.outputs.codex_version }}
52+
gemini_cli_version: ${{ steps.pins.outputs.gemini_cli_version }}
53+
atlas_cli_version: ${{ steps.pins.outputs.atlas_cli_version }}
54+
copilot_api_version: ${{ steps.pins.outputs.copilot_api_version }}
55+
playwright_version: ${{ steps.pins.outputs.playwright_version }}
56+
rust_toolchains: ${{ steps.pins.outputs.rust_toolchains }}
57+
rust_default_toolchain: ${{ steps.pins.outputs.rust_default_toolchain }}
58+
rust_targets: ${{ steps.pins.outputs.rust_targets }}
4759
steps:
4860
- name: Checkout
4961
uses: actions/checkout@v4
50-
51-
- name: Setup Node
52-
uses: actions/setup-node@v4
5362
with:
54-
node-version: "22"
63+
ref: ${{ needs.prepare.outputs.release_tag }}
5564

56-
- name: Resolve versions
57-
id: versions
58-
env:
59-
GH_TOKEN: ${{ github.token }}
60-
run: bash ./scripts/resolve-tool-versions.sh
65+
- name: Load pins
66+
id: pins
67+
shell: bash
68+
run: |
69+
set -euo pipefail
70+
source ./scripts/version-pins.sh
71+
load_version_pins
72+
emit_github_outputs "$GITHUB_OUTPUT"
6173
6274
- name: Summary
6375
run: |
6476
cat <<EOF >> "$GITHUB_STEP_SUMMARY"
65-
## Release Tool Versions
77+
## Release Tool Versions (Pinned)
6678
67-
- Claude Code: \`${{ steps.versions.outputs.claude_code_version }}\`
68-
- Codex: \`${{ steps.versions.outputs.codex_version }}\`
69-
- Gemini CLI: \`${{ steps.versions.outputs.gemini_cli_version }}\`
70-
- Atlas CLI: \`${{ steps.versions.outputs.atlas_cli_version }}\`
71-
- Copilot API: \`${{ steps.versions.outputs.copilot_api_version }}\`
79+
- Node major: \`${{ steps.pins.outputs.node_major }}\`
80+
- Go: \`${{ steps.pins.outputs.go_version }}\`
81+
- Python: \`${{ steps.pins.outputs.python_version }}\`
82+
- Delta: \`${{ steps.pins.outputs.delta_version }}\`
83+
- Claude Code: \`${{ steps.pins.outputs.claude_code_version }}\`
84+
- Claude Trace: \`${{ steps.pins.outputs.claude_trace_version }}\`
85+
- Codex: \`${{ steps.pins.outputs.codex_version }}\`
86+
- Gemini CLI: \`${{ steps.pins.outputs.gemini_cli_version }}\`
87+
- Atlas CLI: \`${{ steps.pins.outputs.atlas_cli_version }}\`
88+
- Copilot API: \`${{ steps.pins.outputs.copilot_api_version }}\`
89+
- Playwright: \`${{ steps.pins.outputs.playwright_version }}\`
90+
- Rust toolchains: \`${{ steps.pins.outputs.rust_toolchains }}\`
7291
EOF
7392
7493
build-and-push:
7594
name: Build and Push Docker Image
76-
needs: [prepare, resolve-versions]
95+
needs: [prepare, load-version-pins]
7796
runs-on: ubuntu-latest
7897
permissions:
7998
contents: read
@@ -118,16 +137,23 @@ jobs:
118137
cache-from: type=gha
119138
cache-to: type=gha,mode=max
120139
build-args: |
121-
CLAUDE_CODE_VERSION=${{ needs.resolve-versions.outputs.claude_code_version }}
122-
CODEX_VERSION=${{ needs.resolve-versions.outputs.codex_version }}
123-
GEMINI_CLI_VERSION=${{ needs.resolve-versions.outputs.gemini_cli_version }}
124-
ATLAS_CLI_VERSION=${{ needs.resolve-versions.outputs.atlas_cli_version }}
125-
COPILOT_API_VERSION=${{ needs.resolve-versions.outputs.copilot_api_version }}
140+
NODE_MAJOR=${{ needs.load-version-pins.outputs.node_major }}
141+
GO_VERSION=${{ needs.load-version-pins.outputs.go_version }}
142+
PYTHON_VERSION=${{ needs.load-version-pins.outputs.python_version }}
143+
DELTA_VERSION=${{ needs.load-version-pins.outputs.delta_version }}
144+
TMUX_VERSION=${{ needs.load-version-pins.outputs.tmux_version }}
145+
TMUX_SHA256=${{ needs.load-version-pins.outputs.tmux_sha256 }}
146+
CLAUDE_CODE_VERSION=${{ needs.load-version-pins.outputs.claude_code_version }}
147+
CLAUDE_TRACE_VERSION=${{ needs.load-version-pins.outputs.claude_trace_version }}
148+
CODEX_VERSION=${{ needs.load-version-pins.outputs.codex_version }}
149+
GEMINI_CLI_VERSION=${{ needs.load-version-pins.outputs.gemini_cli_version }}
150+
ATLAS_CLI_VERSION=${{ needs.load-version-pins.outputs.atlas_cli_version }}
151+
COPILOT_API_VERSION=${{ needs.load-version-pins.outputs.copilot_api_version }}
126152
127153
build-and-push-rust:
128154
name: Build and Push Rust Profile Image
129155
runs-on: ubuntu-latest
130-
needs: [prepare, build-and-push]
156+
needs: [prepare, load-version-pins, build-and-push]
131157
permissions:
132158
contents: read
133159
packages: write
@@ -172,6 +198,15 @@ jobs:
172198
cache-to: type=gha,mode=max
173199
build-args: |
174200
BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.release_tag }}
201+
CLAUDE_CODE_VERSION=${{ needs.load-version-pins.outputs.claude_code_version }}
202+
CLAUDE_TRACE_VERSION=${{ needs.load-version-pins.outputs.claude_trace_version }}
203+
CODEX_VERSION=${{ needs.load-version-pins.outputs.codex_version }}
204+
GEMINI_CLI_VERSION=${{ needs.load-version-pins.outputs.gemini_cli_version }}
205+
ATLAS_CLI_VERSION=${{ needs.load-version-pins.outputs.atlas_cli_version }}
206+
PLAYWRIGHT_VERSION=${{ needs.load-version-pins.outputs.playwright_version }}
207+
RUST_TOOLCHAINS=${{ needs.load-version-pins.outputs.rust_toolchains }}
208+
RUST_DEFAULT_TOOLCHAIN=${{ needs.load-version-pins.outputs.rust_default_toolchain }}
209+
RUST_TARGETS=${{ needs.load-version-pins.outputs.rust_targets }}
175210
176211
release:
177212
name: Create GitHub Release

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- `docs/tmux-bridge-agent-comms.md` explaining the two-layer bridge composition, read-before-act guard, and socket detection order
1515
- CI smoke test exercising the full `tmux-bridge` CLI surface (list/name/resolve/read/type/read-guard) against an ephemeral tmux server inside the built image
1616

17+
### Fixed
18+
- deva no longer adds a redundant project-local `.claude` child bind mount on top of the workspace mount
19+
- startup now rejects recursive child bind mounts that simply rebind a subtree already covered by a parent bind mount
20+
- shared agent tooling installs now switch out of inaccessible working directories before pinned atlas go-install fallback
21+
- `claude-trace` installs are now pinned instead of silently following the latest npm publish
22+
- atlas-cli installs now honor `ATLAS_CLI_VERSION` exactly instead of drifting to upstream `latest`
23+
24+
### Changed
25+
- default Makefile builds now use pinned tool versions; `versions-up` remains the explicit upgrade path
26+
- Rust image rebuild paths now forward the selected agent CLI versions instead of silently reinstalling Dockerfile defaults
27+
- `versions` and `versions-up` now treat Makefile defaults as defaults instead of forcing them as fake "latest" overrides
28+
1729
## [0.10.0] - 2026-03-24
1830

1931
### Added

0 commit comments

Comments
 (0)