Repository navigation
Expand file tree
/
Copy pathdevfile.base.yaml
More file actions
443 lines (427 loc) · 20.1 KB
/
Copy pathdevfile.base.yaml
File metadata and controls
443 lines (427 loc) · 20.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
# devfile.base.yaml — the PARENT every elohim workspace devfile composes from.
#
# Che never launches this file directly (it auto-detects only devfile.yaml). The children
# reference it by URL:
# devfile.yaml the default workspace (LAN node, the x86-64-v3 image)
# devfile_x86_v2.yaml the shem workspace (shem node, the x86-64-v2 image, shem-zfs storage)
# and each child states ONLY what differs: the image, the memory/CPU numbers, the volume size,
# and the placement attributes. Everything a workspace needs to work — environment, endpoints,
# volumes, commands, the post-start setup — lives here once.
#
# A child overrides a parent component by naming it under `parent.components` (not under its
# own top-level `components:`, which would be a name collision). Top-level `attributes` in a
# child replace the parent's attributes key by key, so a child that sets `pod-overrides` must
# carry the securityContext below as well.
#
# The URL the children use points at this file on the `dev` branch, so a child and its parent
# always travel together on the same branch; Che re-reads the parent when a workspace is
# CREATED, and running workspaces keep the flattened devfile they started with.
schemaVersion: 2.2.0
metadata:
name: elohim-devspace-base
displayName: Holochain + Angular Development Environment (base)
description: >-
Full-stack development with Holochain (Rust/Nix) backend and Angular frontend,
plus Claude AI utilities
icon: >-
https://raw.githubusercontent.com/devfile/devfile-web/main/apps/landing-page/public/pwa-192x192.png
tags:
- Rust
- Nix
- Holochain
- Angular
- Node.js
- Java
- ubi10
- Claude
- mempalace
projectType: holochain
language: Polyglot
version: 2.0.0
# Pod-level overrides — DevWorkspace `spec.template.attributes.pod-overrides`,
# strategic-merge-patched into the workspace pod by the DevWorkspace operator.
attributes:
pod-overrides:
spec:
securityContext:
# Che sets fsGroup: 1234 on the pod. With the default policy (Always)
# kubelet recursively chowns EVERY file on the workspace PV at each
# start — ~1.02M inodes / 174G. That full-tree walk lands on the host
# the cluster control plane runs on; on 2026-08-28 a netconsole trace
# tied that host's freezes to kswapd wedged in ext4's extent-status
# shrinker, whose cost scales with inode count. OnRootMismatch stats
# the volume root only and skips the walk when its group already
# matches (it does — the tree is 1234-owned). Operator-requested.
fsGroupChangePolicy: OnRootMismatch
# A separate PVC for the cargo target pool was drafted here on
# 2026-08-28 and RETIRED on 2026-08-29 before provisioning: this
# cluster's openebs-hostpath provisions a DIRECTORY under
# /var/snap/microk8s/common/var/openebs/local — the same /dev/md2p1,
# the same ext4 extent tree, the same two worn NVMes — and both NVMes
# are fully partitioned, so no separate filesystem exists to carve.
# It would have isolated neither the I/O (the 2026-08-29 resets) nor
# the extent tree (the 2026-08-28 kswapd lockup). Taking the pool off
# the root fs needs a physical disk added to the node, not a claim.
# What bounds the pool instead: pool-policy.json keep-warm caps that
# apply to the ACTIVE family, CARGO_BUILD_JOBS below, and the guard's
# one-build-at-a-time + host-I/O-pressure rules.
projects:
- name: elohim
git:
remotes:
origin: https://github.com/ethosengine/elohim.git
# NOTE: the `submodules:` block below is NOT part of the devfile v2.2.0
# spec — devfile clones the parent repo but has no native recurse-
# submodules flag. It's listed here in proposed-spec shape so the
# devfile reads as the source of truth for what the workspace needs.
# Until upstream support exists, run once per workspace:
# git submodule update --init --recursive --jobs 4
# submodules:
# - name: sophia
# path: sophia
# url: https://github.com/ethosengine/sophia.git
# - name: brit
# path: elohim/brit
# url: https://github.com/ethosengine/brit.git
# - name: rakia
# path: elohim/rakia
# url: https://github.com/ethosengine/rakia.git
components:
- name: tools
container:
# Image build source: https://github.com/ethosengine/che-devworkspaces
# containers/udi-plus/Dockerfile — base: claude-code, SonarQube MCP jar,
# Java 21, Node, Chrome for Testing,
# hadolint, yamllint, nerdctl/buildctl
# containers/rust-dev/Dockerfile — adds Rust toolchain at /opt/rust,
# Holochain binaries at /opt/holochain,
# sccache, just, cached nix-installer
# Built via Jenkins (devspaces-udi-plus, devspaces-rust-nix-dev). Image name
# rust-nix-dev:latest is historical — current source folder is rust-dev/.
#
# The image TAG and the memory/CPU numbers are set by each child (the LAN node
# runs the x86-64-v3 build, shem's Sandy Bridge Xeons need the x86-64-v2 build).
# This default is what a child gets if it overrides nothing.
image: harbor.ethosengine.com/devspaces/udi-plus-mem-rust-nix:latest
memoryLimit: 30Gi
memoryRequest: 8Gi
cpuLimit: '10'
cpuRequest: '6'
mountSources: true
sourceMapping: /projects
env:
# Claude and general config
- name: CLAUDE_CONFIG_DIR
value: /projects/.claude-config
# Codex CLI — relocate its entire state dir (config.toml, auth.json,
# sessions, MCP cache) onto the persistent /projects PVC so sign-in
# survives workspace restarts. Codex honors CODEX_HOME for all state,
# so no ~/.codex symlink is needed (unlike CLAUDE_CONFIG_DIR).
- name: CODEX_HOME
value: /projects/.codex-config
- name: USER
value: user
- name: RUST_BACKTRACE
value: '1'
# Playwright: skip auto browser download on install; browsers persist via
# XDG_CACHE_HOME on /nix and are provisioned explicitly via `pnpm a2o:setup`.
- name: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD
value: '1'
# Nix experimental features (required for flakes and nix develop)
- name: NIX_CONFIG
value: 'experimental-features = nix-command flakes'
# XDG directories - subdirs under /nix volume (single PVC)
- name: XDG_CACHE_HOME
value: /nix/xdg/cache
- name: XDG_DATA_HOME
value: /nix/xdg/data
- name: XDG_STATE_HOME
value: /nix/xdg/state
- name: XDG_CONFIG_HOME
value: /nix/xdg/config
- name: NPM_CONFIG_CACHE
value: /nix/xdg/cache/npm
- name: PNPM_HOME
value: /nix/xdg/cache/pnpm
- name: CYPRESS_CACHE_FOLDER
value: /nix/xdg/cache/cypress
# Jenkins integration
- name: JENKINS_URL
value: "https://jenkins.ethosengine.com"
# SonarQube MCP configuration (SONARQUBE_TOKEN comes from K8s secret)
- name: STORAGE_PATH
value: /projects/.sonarqube-mcp
- name: SONARQUBE_URL
value: "https://sonarqube.ethosengine.com"
# Observability MCP (Grafana: metrics/logs/traces); internal SSE, no credentials needed
- name: OBSERVABILITY_MCP_URL
value: "http://observability-mcp.observability.svc.cluster.local:8000/sse"
# GH_TOKEN injected via K8s secret auto-mount annotations
# Chrome for Angular testing
- name: CHROME_BIN
value: /usr/local/bin/chrome
- name: CHROME_PATH
value: /opt/chrome-linux64/chrome
# Rust toolchain (also declared by the image). Container env reaches non-interactive
# background shells too; do not move these declarations into ~/.bashrc.
- name: RUSTUP_HOME
value: /opt/rust/rustup
- name: CARGO_HOME
value: /opt/rust/cargo
# RUSTFLAGS for Holochain WASM builds (getrandom backend for wasm32)
- name: RUSTFLAGS
value: '--cfg getrandom_backend="custom"'
# CC for native compilation (some crates need explicit gcc)
- name: CC
value: gcc
# sccache RETIRED for workspace builds (operator decision 2026-07-03):
# measured Rust hit rate was ~25% (39/157) while the cargo target pool
# already provides the warm-build story, and the wrapper carried two
# recurring failure classes (cache-corruption, spawn ENOENT — memory:
# feedback_sccache_failure_classes) plus a remote Garage S3 dependency
# the workspace can't operate. RUSTC_WRAPPER is now explicitly EMPTY —
# the image still ships the binary and the sccache-credentials Secret
# still auto-mounts, so re-enabling is a one-line flip back to
# `value: sccache`. CI keeps its own independent sccache config.
- name: RUSTC_WRAPPER
value: ''
# Build parallelism is capped by STORAGE, not cores (2026-08-29): the
# node's NVMe mirror is past rated write endurance and two concurrent
# 24-job builds saturated it into two hard resets in one day. 4 jobs
# keeps a build's write burst absorbable; the cargo-disk-guard hook
# refuses heavy cargo without this env or an explicit -j.
- name: CARGO_BUILD_JOBS
value: '4'
# Cargo target pool — family-shared target dirs to keep parallel
# worktree builds from each materializing their own ~18GB target/.
# Hooks at SessionStart/Stop run worktree stewardship; agents read
# the slot path from the hook's context block and set
# CARGO_TARGET_DIR explicitly for native builds.
# Design: genesis/docs/plans/cargo-target-pool-design.md
- name: CARGO_TARGET_POOL_ROOT
value: /projects/.cargo-target-pool
# PATH: Ensure holochain binaries, rust toolchain, helper scripts,
# and genesis/agentic/bin (cargo-pool, pool-*.sh) are available.
- name: PATH
value: '/projects/elohim/genesis/agentic/bin:/nix/xdg/cache/pnpm:/opt/rust/cargo/bin:/opt/holochain/bin:/home/user/bin:/home/user/.nix-profile/bin:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
# Cutover gate #10 — auto-enable the pkarr resolver in Che workspaces
# so dev-time iroh can use the workspace doorway as its resolver.
- name: DOORWAY_PKARR_RESOLVER_ENABLED
value: "true"
- name: DOORWAY_PKARR_CACHE_DIR
value: "/projects/elohim/.doorway/pkarr-cache"
# ===== MemPalace =====
- name: MEMPALACE_HOME
value: /projects/elohim/.mempalace
- name: MEMPALACE_EMBEDDING_BACKEND
value: local
- name: MEMPALACE_EMBEDDING_MODEL
value: sentence-transformers/all-MiniLM-L6-v2
- name: HF_HOME
value: /opt/mempalace/hf-cache
- name: HF_HUB_OFFLINE
value: "1"
- name: TRANSFORMERS_OFFLINE
value: "1"
endpoints:
- name: angular-dev
targetPort: 4200
exposure: public
protocol: http
- name: ui-playground
targetPort: 4201
exposure: public
protocol: http
# Holochain Dev Proxy - unified path-based routing for all conductor access
# Routes: /admin → :4444, /app/:port → :port, /health, /status
- name: hc-dev
targetPort: 8888
exposure: public
protocol: http
#secure:true needed for che http -> ws upgrade, which uses traefik proxy
secure: true
# elohim-storage - blob storage and import processing
- name: hc-storage
targetPort: 8090
exposure: public
protocol: http
# Storybook - sophia component documentation
# Note: secure: false allows unauthenticated access to static assets
# The endpoint is still HTTPS via Che's ingress controller
- name: storybook
targetPort: 6006
exposure: public
protocol: http
# Unified local-mesh system monitor (reader over the existing probe
# surfaces: peer /p2p/status + /metrics, doorway health, quiesce log).
# Started on demand via `just mesh monitor` — never from postStart.
- name: mesh-monitor
targetPort: 4210
exposure: public
protocol: http
volumeMounts:
- name: persistent
path: /nix
# Single PVC — Che consolidates all volumes into one PVC anyway.
# Nix store lives at /nix/store, XDG caches at /nix/xdg/.
# The size is set by each child: a declared size can only grow a claim, never shrink
# it, so a child must never declare less than its live claim holds.
- name: persistent
volume:
size: 220Gi
commands:
- id: setup-git
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
set -e
# $HOME is ephemeral; restore trust after every start, before Git-backed setup.
if ! git config --global --get-all safe.directory | grep -Fxq '*'; then
git config --global --add safe.directory '*'
fi
# Also works before pnpm install, when Husky's generated shims are absent.
node .husky/hooks-path.mjs
- id: setup-pnpm
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
# Install pnpm standalone binary to $PNPM_HOME (on PATH via devfile env).
# Runs as user, no root or corepack needed. Version pinned to match package.json.
if pnpm --version 2>/dev/null | grep -q "10.30.3"; then
echo "pnpm 10.30.3 already installed"
else
curl -fsSL https://get.pnpm.io/install.sh | env PNPM_HOME="$PNPM_HOME" SHELL=/bin/bash bash -
fi
pnpm --version
- id: setup-vscode-cli
exec:
component: tools
commandLine: |
# Create VS Code CLI symlink (code-oss -> code)
# checode only ships ubi8/ubi9 binaries, use ubi9 (forward compatible with ubi10)
mkdir -p /home/user/.local/bin
if [ -f /checode/checode-linux-libc/ubi9/bin/remote-cli/code-oss ]; then
ln -sf /checode/checode-linux-libc/ubi9/bin/remote-cli/code-oss /home/user/.local/bin/code
fi
# Link ~/.claude to persistent config dir for VS Code extension IDE detection
# The extension uses ~/.claude/ide for IPC sockets, must match CLAUDE_CONFIG_DIR
rm -rf /home/user/.claude 2>/dev/null || true
ln -sf "$CLAUDE_CONFIG_DIR" /home/user/.claude
mkdir -p /home/user/.claude/ide
# Antigravity CLI stores settings and its headless credential fallback
# below ~/.gemini/antigravity-cli with no relocation override. Retain
# the persistent parent so first launch can offer Google's supported
# one-time migration of legacy Gemini rules, skills, and session state.
mkdir -p /projects/.gemini-config/antigravity-cli
rm -rf /home/user/.gemini 2>/dev/null || true
ln -sf /projects/.gemini-config /home/user/.gemini
# Default to subscription quota only. Users may opt in later, but a new
# workspace must never consume separately billed AI credits implicitly.
if [ ! -f /home/user/.gemini/antigravity-cli/settings.json ]; then
echo '{"useG1Credits":false}' > /home/user/.gemini/antigravity-cli/settings.json
fi
- id: setup-claude-mcp
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
# Create persistent storage directory for SonarQube MCP
mkdir -p "$STORAGE_PATH"
# Configure SonarQube MCP (env vars from devfile, SONARQUBE_TOKEN from K8s secret)
claude mcp remove sonarqube 2>/dev/null || true
claude mcp add sonarqube \
--env STORAGE_PATH="$STORAGE_PATH" \
--env SONARQUBE_TOKEN="$SONARQUBE_TOKEN" \
--env SONARQUBE_URL="$SONARQUBE_URL" \
-- java -jar /opt/mcp/sonarqube-mcp.jar
# Jenkins MCP is scoped per-subagent via inline `mcpServers` frontmatter on
# ci-observer, ci-investigator, and after-action — not registered globally
# here, so the parent context doesn't load Jenkins tool schemas.
# Configure GitHub CLI authentication
# Commented out 2026-05-10: `gh` is not installed in rust-nix-dev image,
# so this block exit-127s and aborts postStart. Re-enable after gh is
# baked into the image (ethosengine/che-devworkspaces).
# if [ -n "$GH_TOKEN" ]; then
# echo "$GH_TOKEN" | gh auth login --with-token
# gh auth status
# fi
- id: build-happ
exec:
component: tools
workingDir: /projects/elohim/elohim/holochain/dna/elohim
commandLine: |
echo "Building Holochain WASM zomes..."
cargo build --release --target wasm32-unknown-unknown
echo "Packing DNA..."
hc dna pack . -o workdir/lamad.dna
echo "Packing hApp..."
hc app pack workdir -o workdir/elohim.happ
echo "Done! hApp at: workdir/elohim.happ"
- id: seed-holochain
exec:
component: tools
workingDir: /projects/elohim/genesis/seeder
commandLine: |
pnpm install && pnpm run seed
- id: setup-mempalace
exec:
component: tools
commandLine: |
set -e
# MemPalace CLI does NOT read $MEMPALACE_HOME. Default palace is
# ~/.mempalace/palace. To make all CLI calls and the MCP server
# land in the PVC-persisted slot without --palace plumbing, we
# symlink ~/.mempalace -> $MEMPALACE_HOME (mirrors ~/.claude
# -> $CLAUDE_CONFIG_DIR pattern from setup-vscode-cli above).
mkdir -p "$MEMPALACE_HOME/palace"
rm -rf /home/user/.mempalace 2>/dev/null || true
ln -sf "$MEMPALACE_HOME" /home/user/.mempalace
# Mining is operator/agent-driven — historian decides what to mine
# and when. See .claude/agents/historian.md (mcpServers frontmatter)
# for the read-side wiring. Probe palace state so postStart logs it.
mempalace status 2>&1 || true
# Arrival: the two per-device provisions the native memory fold needs on THIS device, declared
# here so a fresh workspace inits itself (elohim/lvi/docs/specs/2026-10-10-workspace-arrival-as-declared-device.md
# §3, §7). Both are idempotent and fail-open (a workspace with no network still starts; `just
# status device` then names the cure). The remaining arrival conditions (device key, roster
# binding, berth) are acts of a person present, never a postStart.
- id: setup-embed-model
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
# The pinned all-MiniLM-L6-v2 ONNX bytes onto the PVC ($XDG_CACHE_HOME/elohim/embed-models/…),
# the model manifest's second resolve entry. Without this the semantic fold reads
# `attested failed: no model directory resolves` on every fresh workspace.
bash genesis/agentic/bin/embed-model-provision || true
- id: setup-device-memory
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
# Claude Code's per-workspace auto-memory → .claude/memory/device/ (gitignored) so the
# device's own fold indexes it and nothing tracked ever carries it.
bash genesis/agentic/bin/device-memory-sync || true
# On demand only: serving this device is an operator action, never workspace arrival.
- id: peer-serve
exec:
component: tools
workingDir: /projects/elohim
commandLine: |
export EPR_PEER_RELAY_URL="${EPR_PEER_RELAY_URL:-https://relay.alpha.elohim.host}"
set -- peer serve --root /projects/elohim --handle matthew --listen "0.0.0.0:${EPR_PEER_PORT:-7777}"
if [ -n "${EPR_PEER_ADDRESS:-}" ]; then
set -- "$@" --peer "$EPR_PEER_ADDRESS"
fi
exec "${EPR_BIN:-epr}" "$@"
events:
postStart:
- setup-git
- setup-pnpm
- setup-vscode-cli
- setup-claude-mcp
- setup-embed-model
- setup-device-memory
# - setup-mempalace