Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions charts/workspace/.helmignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ web/vitest.config.ts
web/index.html
web/README.md

# Workspace Python backend — baked into the image (devlaptop/Dockerfile ->
# /opt/browser-src) and seeded by start.sh; NOT rendered into a ConfigMap
# anymore (#430). The chart doesn't reference these at render time, and bundling
# them into the chart tarball blew the 1 MiB Helm-release-Secret limit.
server.py
hypervisor_session.py
gateway.py
harness.py
harness_test.py
mcp_agent_orchestrator.py
mcp_dashboard.py
mcp_memory.py
mcp_registry.py
memory_inject_hook.py
playwright_reaper.py
seed_claude_config.py
seed_demo.py
memory/
skills/
adapters/

# Python bytecode caches
__pycache__/
*.pyc
Expand Down
87 changes: 20 additions & 67 deletions charts/workspace/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -739,62 +739,25 @@ if [ -x "$LIBREFANG_TARGET/bin/librefang" ]; then
|| HOME=/home/dev "$LIBREFANG_TARGET/bin/librefang" start >/dev/null 2>&1 &
fi

# The memory subsystem ships its Python package as flat configmap keys
# (configmap keys cannot contain "/"). Unpack them into a real `memory/`
# tree next to server.py so `from memory.manager import ...` resolves.
mkdir -p /tmp/browser/memory /home/dev/.claude-memory/backups
# ── Workspace Python backend: seed from the image (issue #430) ─────────────
# server.py + the memory/skills/adapters/gateway subsystems are baked into the
# image at /opt/browser-src (they outgrew the 1 MiB ConfigMap). Copy the whole
# tree into /tmp/browser so `import server`, `from memory.manager import ...`,
# `from skills.providers... import ...`, `import gateway`, and
# `from adapters.internal import ...` all resolve.
mkdir -p /tmp/browser /home/dev/.claude-memory/backups
chmod 700 /home/dev/.claude-memory
# Materialize package files (rename flat keys → real layout).
install -m 0644 /browser-config/memory__init__.py /tmp/browser/memory/__init__.py
install -m 0644 /browser-config/memory_store.py /tmp/browser/memory/store.py
install -m 0644 /browser-config/memory_manager.py /tmp/browser/memory/manager.py
install -m 0644 /browser-config/memory_sync.py /tmp/browser/memory/sync.py
install -m 0644 /browser-config/memory_embeddings.py /tmp/browser/memory/embeddings.py
install -m 0644 /browser-config/memory_embeddings_worker.py /tmp/browser/memory/embeddings_worker.py

# The skills subsystem (multi-harness SKILL.md surface, issue #187) ships
# the same way: flat configmap keys reassembled into a real package tree.
mkdir -p /tmp/browser/skills/providers
install -m 0644 /browser-config/skills__init__.py /tmp/browser/skills/__init__.py
install -m 0644 /browser-config/skills_model.py /tmp/browser/skills/model.py
install -m 0644 /browser-config/skills_parser.py /tmp/browser/skills/parser.py
install -m 0644 /browser-config/skills_sync.py /tmp/browser/skills/sync.py
install -m 0644 /browser-config/skills_commands.py /tmp/browser/skills/commands.py
install -m 0644 /browser-config/skills_providers__init__.py /tmp/browser/skills/providers/__init__.py
install -m 0644 /browser-config/skills_providers_claude.py /tmp/browser/skills/providers/claude.py
install -m 0644 /browser-config/skills_providers_opencode.py /tmp/browser/skills/providers/opencode.py
install -m 0644 /browser-config/skills_providers_ante.py /tmp/browser/skills/providers/ante.py
install -m 0644 /browser-config/skills_providers_antigravity.py /tmp/browser/skills/providers/antigravity.py

# The Conversation Gateway (issue #306) — chat with the Hypervisor over a
# channel (WhatsApp) plus the in-app Walkie-Talkie loopback preview — ships
# gateway.py flat and the adapters/ package as flat keys (configmap keys
# cannot contain "/"). Reassemble next to server.py so `import gateway` and
# `from adapters.internal import ...` resolve; without this the gateway
# subsystem self-disables (_GATEWAY_AVAILABLE=False) and every
# /api/gateway/* call 503s.
mkdir -p /tmp/browser/adapters
install -m 0644 /browser-config/gateway.py /tmp/browser/gateway.py
install -m 0644 /browser-config/adapters__init__.py /tmp/browser/adapters/__init__.py
install -m 0644 /browser-config/adapters_whatsapp.py /tmp/browser/adapters/whatsapp.py
install -m 0644 /browser-config/adapters_internal.py /tmp/browser/adapters/internal.py

# Seed the per-user MCP server + user-prompt-submit hook next to the
# SQLite file so claude config points at PVC-backed paths that survive
# configmap rotations.
install -m 0755 /browser-config/mcp_memory.py /home/dev/.claude-memory/mcp_memory.py
install -m 0755 /browser-config/memory_inject_hook.py /home/dev/.claude-memory/memory_inject_hook.py
# The MCP server imports the same memory.* package; expose it alongside.
cp -a /opt/browser-src/. /tmp/browser/

# The memory MCP server (mcp_memory.py) imports the same memory.* package; expose
# it + the user-prompt-submit hook next to the PVC-backed SQLite db so claude
# config points at stable paths across restarts.
install -m 0755 /opt/browser-src/mcp_memory.py /home/dev/.claude-memory/mcp_memory.py
install -m 0755 /opt/browser-src/memory_inject_hook.py /home/dev/.claude-memory/memory_inject_hook.py
rm -rf /home/dev/.claude-memory/memory
mkdir -p /home/dev/.claude-memory/memory
install -m 0644 /tmp/browser/memory/__init__.py /home/dev/.claude-memory/memory/__init__.py
install -m 0644 /tmp/browser/memory/store.py /home/dev/.claude-memory/memory/store.py
install -m 0644 /tmp/browser/memory/manager.py /home/dev/.claude-memory/memory/manager.py
install -m 0644 /tmp/browser/memory/sync.py /home/dev/.claude-memory/memory/sync.py
install -m 0644 /tmp/browser/memory/embeddings.py /home/dev/.claude-memory/memory/embeddings.py
install -m 0644 /tmp/browser/memory/embeddings_worker.py /home/dev/.claude-memory/memory/embeddings_worker.py
# Register the MCP server in the user's claude config (idempotent merge).
python3 /browser-config/seed_claude_config.py || \
cp -a /opt/browser-src/memory /home/dev/.claude-memory/memory
# Register the memory MCP server in the user's claude config (idempotent merge).
python3 /opt/browser-src/seed_claude_config.py || \
log_stage "WARNING: seed_claude_config.py failed (memory MCP not registered)"

# Seed Ante's config so a spawned/selected Ante agent gets the SAME stdio
Expand Down Expand Up @@ -886,24 +849,14 @@ fi
# (/home/dev/.claude-tasks/mcp-servers.json) but most provider configs are
# under the ephemeral $HOME (~/.claude.json, opencode.json) or regenerated
# each boot, so the fan-out must re-run AFTER all the seeding blocks. Runs
# from /browser-config (same delivery as seed_claude_config.py); best-effort —
# from /opt/browser-src (same delivery as seed_claude_config.py); best-effort —
# a failed provider never stalls boot.
log_stage "syncing user MCP servers to provider configs"
python3 /browser-config/mcp_registry.py --sync || \
python3 /opt/browser-src/mcp_registry.py --sync || \
log_stage "WARNING: mcp_registry.py sync failed (user MCP servers not re-applied)"

log_stage "starting browser/Claude API server on :6080"
mkdir -p /tmp/browser
# Copy Python sources (these need a pod restart to take effect).
# Skip the flat memory_* / memory__init__.py keys — reassembled above.
for f in /browser-config/*; do
base=$(basename "$f")
case "$base" in
memory_*|memory__init__.py) continue ;;
skills_*|skills__init__.py) continue ;;
esac
cp "$f" /tmp/browser/
done
mkdir -p /tmp/browser # server.py + subsystems already seeded from /opt/browser-src above
# Symlink HTML/CSS/JS from the separate (non-checksummed) browser-html
# ConfigMap so dashboard edits + helm-upgrade refresh without a pod
# restart. The kubelet syncs the new ConfigMap to /browser-html
Expand Down
74 changes: 0 additions & 74 deletions charts/workspace/templates/browser-configmap.yaml

This file was deleted.

9 changes: 2 additions & 7 deletions charts/workspace/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ spec:
kube-coder.dev/component: workspace
{{- end }}
annotations:
checksum/browser-config: {{ include (print $.Template.BasePath "/browser-configmap.yaml") . | sha256sum }}
# server.py + the Python backend now ship in the image (#430), so an
# image-tag change rolls the pod — no browser-config checksum needed.
checksum/claude-config: {{ include (print $.Template.BasePath "/claude-configmap.yaml") . | sha256sum }}
checksum/terminal-entry: {{ include (print $.Template.BasePath "/terminal-entry-configmap.yaml") . | sha256sum }}
checksum/workspace-entrypoint: {{ include (print $.Template.BasePath "/workspace-entrypoint-configmap.yaml") . | sha256sum }}
Expand Down Expand Up @@ -278,8 +279,6 @@ spec:
volumeMounts:
- name: home
mountPath: /home/dev
- name: browser-config
mountPath: /browser-config
- name: browser-html
mountPath: /browser-html
- name: claude-config
Expand Down Expand Up @@ -402,10 +401,6 @@ spec:
- name: home
persistentVolumeClaim:
claimName: ws-{{ .Values.user.name }}-home
- name: browser-config
configMap:
name: browser-config-{{ .Values.user.name }}
defaultMode: 0755
- name: browser-html
configMap:
name: browser-html-{{ .Values.user.name }}
Expand Down
1 change: 0 additions & 1 deletion charts/workspace/tests/deployment_test.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
suite: deployment tests
templates:
- templates/deployment.yaml
- templates/browser-configmap.yaml
- templates/claude-configmap.yaml
- templates/terminal-entry-configmap.yaml
- templates/workspace-entrypoint-configmap.yaml
Expand Down
14 changes: 3 additions & 11 deletions charts/workspace/tests/mcp_registry_boot_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,19 @@ suite: user MCP server registry boot wiring (#353)
# User-added MCP servers live in one PVC registry and are fanned out to each
# assistant's native config. Most of those configs sit under the ephemeral
# $HOME or are regenerated at boot, so start.sh MUST re-run the fan-out AFTER
# every default-seeding block — and the module itself must ship in the
# browser ConfigMap for both the boot invocation and server.py's import.
# every default-seeding block. The module itself now ships in the image at
# /opt/browser-src (#430), not the browser ConfigMap.
templates:
- templates/workspace-entrypoint-configmap.yaml
- templates/browser-configmap.yaml
values:
- test-values.yaml
tests:
- it: ships mcp_registry.py in the browser ConfigMap
template: templates/browser-configmap.yaml
asserts:
- matchRegex:
path: data["mcp_registry.py"]
pattern: "REGISTRY_FILE = '/home/dev/.claude-tasks/mcp-servers.json'"

- it: re-applies user MCP servers in start.sh after the default seeding
template: templates/workspace-entrypoint-configmap.yaml
asserts:
- matchRegex:
path: data["start.sh"]
pattern: "python3 /browser-config/mcp_registry.py --sync"
pattern: "python3 /opt/browser-src/mcp_registry.py --sync"
# The sync must run AFTER the Codex default seeding (the last of the
# per-provider seeding blocks) so it layers on top of the defaults.
- matchRegex:
Expand Down
15 changes: 15 additions & 0 deletions devlaptop/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,21 @@ OUTER
# migration and at / once Phase 6 cuts over.
COPY --from=dashboard-builder /web/dist /opt/dashboard-dist

# ── Workspace Python backend (server.py + memory/skills/adapters/gateway) ──
# Baked into the image at /opt/browser-src. This used to be embedded in the
# browser-config ConfigMap via {{ .Files.Get }}, but the sources (~1 MB) outgrew
# BOTH the 1 MiB ConfigMap object limit AND the 1 MiB Helm-release-Secret limit,
# which silently blocked every workspace `helm upgrade` (issue #430). start.sh
# seeds /tmp/browser + /home/dev/.claude-memory from here at boot. Consequence:
# backend changes now ship via an image rebuild (a release), not a config-only
# helm upgrade — every release already rebuilds the image, so this is fine.
COPY charts/workspace/*.py /opt/browser-src/
COPY charts/workspace/memory /opt/browser-src/memory
COPY charts/workspace/skills /opt/browser-src/skills
COPY charts/workspace/adapters /opt/browser-src/adapters
RUN find /opt/browser-src -name __pycache__ -type d -prune -exec rm -rf {} + 2>/dev/null; \
find /opt/browser-src -name '*.pyc' -delete 2>/dev/null; true

# Non-root dev user
RUN useradd -m -s /bin/bash dev && echo "dev ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Also give ubuntu user (created by code-server) passwordless sudo
Expand Down