Skip to content

Commit 7f127c3

Browse files
committed
Migrate shared skills from PVC sync to image-baked mode
1 parent 78b5fb7 commit 7f127c3

15 files changed

Lines changed: 132 additions & 673 deletions

README.md

Lines changed: 46 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -8,188 +8,94 @@ Helm chart that extends Nebari's data-science JupyterHub stack with a Pi coding-
88
- Pi named-server profiles (`pi-small`, `pi-medium`, `pi-large`)
99
- Pi home/quick-access UI customizations
1010
- Optional Pi session sharing RBAC + handlers
11-
- Optional shared-skills distribution via PVC-subpath synced from immutable URL artifacts
1211
- Optional relay subsystem (core + dummy/slack/whatsapp adapters)
12+
- Shared skills delivered from the Pi runtime image (no PVC sync job)
1313

14-
## Architecture (high level)
14+
## Architecture
1515

16-
- JupyterHub remains control plane.
16+
- JupyterHub remains the control plane.
1717
- User requests Pi via launcher.
1818
- JupyterHub spawns/controls named server `pi` per user.
1919
- Pi pod serves browser terminal via `jhsingle_native_proxy` + `ttyd` + `pi` CLI.
20-
- Pi image also includes `nebari_app_*` wrappers (`deploy/status/logs/stop/delete/doctor`) for jhub-app lifecycle operations.
20+
- Pi startup includes `--skill /opt/nebari/baked-skills/shared-skills`.
2121

2222
## Install
2323

2424
```bash
25-
helm dependency update PACKS/nebari-pi-pack
26-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
25+
helm dependency update .
26+
helm upgrade --install data-science-pack . \
2727
--namespace data-science \
28-
--set nebariapp.hostname=jupyter.nebari.local \
2928
--wait --timeout 40m
3029
```
3130

32-
For RECREATE.md local flow, use ready-made examples:
31+
### Example values
3332

3433
```bash
35-
# Pi core (no relay)
36-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
34+
# Local baseline
35+
helm upgrade --install data-science-pack . \
3736
--namespace data-science \
38-
-f PACKS/nebari-pi-pack/examples/values-local.yaml \
37+
-f examples/values-local.yaml \
3938
--wait --timeout 40m
4039

41-
# Pi + relay
42-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
40+
# Local reliable
41+
helm upgrade --install data-science-pack . \
4342
--namespace data-science \
44-
-f PACKS/nebari-pi-pack/examples/values-relay.yaml \
45-
--wait --timeout 50m
43+
-f examples/values-local-reliable.yaml \
44+
--wait --timeout 45m
4645

47-
# Pi + pvc-subpath shared-skills with release rotation sync job
48-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
46+
# Relay profile
47+
helm upgrade --install data-science-pack . \
4948
--namespace data-science \
50-
-f PACKS/nebari-pi-pack/examples/values-pvc-shared-skills-sync.yaml \
49+
-f examples/values-relay.yaml \
5150
--wait --timeout 50m
52-
```
53-
54-
### Reliable local Pi testing profile (recommended)
55-
56-
Use `examples/values-local-reliable.yaml` for more deterministic local behavior:
57-
- registry-backed Pi image (no `k3d image import` race)
58-
- immutable Pi image ref (`@sha256:...`)
59-
- prePullers disabled (lower disk churn)
60-
- Pi user pods pinned to one node in local multi-node clusters
6151

62-
```bash
63-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
52+
# Production-style baked skills profile
53+
helm upgrade --install data-science-pack . \
6454
--namespace data-science \
65-
-f PACKS/nebari-pi-pack/examples/values-local-reliable.yaml \
55+
-f examples/values-baked-skills.yaml \
6656
--wait --timeout 45m
6757
```
6858

69-
If you rebuild the Pi image, update both:
70-
- `pi.image.repository` + `pi.image.tag`
71-
- `jupyterhub.custom.pi-image` (prefer digest-pinned value)
72-
73-
For best local dev stability, prefer a single-node k3d cluster for Pi work.
74-
75-
#### Local k3d registry flow (recommended)
76-
77-
```bash
78-
# Create local registry attached to the cluster network (one-time)
79-
k3d registry create pi-registry.localhost --port 5001 --default-network k3d-nebari-local
80-
81-
# Configure node-side registry mirrors (one-time per cluster lifecycle)
82-
cat >/tmp/k3s-registries-pi.yaml <<'YAML'
83-
mirrors:
84-
"k3d-pi-registry.localhost:5000":
85-
endpoint:
86-
- "http://k3d-pi-registry.localhost:5000"
87-
"localhost:5001":
88-
endpoint:
89-
- "http://k3d-pi-registry.localhost:5000"
90-
YAML
91-
for n in k3d-nebari-local-server-0 k3d-nebari-local-agent-0 k3d-nebari-local-agent-1; do
92-
docker cp /tmp/k3s-registries-pi.yaml "$n":/etc/rancher/k3s/registries.yaml
93-
done
94-
docker restart k3d-nebari-local-agent-0 k3d-nebari-local-agent-1 k3d-nebari-local-server-0
95-
96-
# Build Pi image (includes pi CLI + nebari_app_* wrappers)
97-
docker build -t nebari-pi-agent:local-slim PACKS/nebari-pi-pack/images/pi-agent
98-
99-
# Tag + push immutable Pi image to local registry
100-
TAG=dev-$(date +%Y%m%d-%H%M%S)
101-
docker tag nebari-pi-agent:local-slim localhost:5001/nebari-pi-agent:${TAG}
102-
docker push localhost:5001/nebari-pi-agent:${TAG}
103-
104-
# Update values-local-reliable.yaml with the new tag/digest, then deploy
105-
helm upgrade --install data-science-pack PACKS/nebari-pi-pack \
106-
--namespace data-science \
107-
-f PACKS/nebari-pi-pack/examples/values-local-reliable.yaml \
108-
--wait --timeout 45m
109-
```
110-
111-
## Migrate from existing data-science-pack
112-
113-
Use same release and namespace:
114-
115-
```bash
116-
helm upgrade data-science-pack PACKS/nebari-pi-pack \
117-
--namespace data-science \
118-
-f <your-values.yaml> \
119-
--wait --timeout 40m
120-
```
121-
12259
## Important values
12360

124-
- `pi.enabled`
12561
- `pi.image.*`
126-
- `pi.sharing.enabled`
12762
- `pi.sharedSkills.enabled`
128-
- `pi.sharedSkills.mode` (`pvc-subpath` only)
129-
- `pi.sharedSkills.sync.*` (chart-managed PVC sync/rotation pipeline for URL artifacts)
130-
- `relay.enabled`
131-
- `relay.deployMode` (`configmap` or `image`)
132-
- `relay.core.piAgentDir`
133-
134-
Also review `jupyterhub.custom.*` Pi fields in `values.yaml`, consumed by Hub config modules (including `pi-coding-agent-dir` for writable Pi runtime state location).
135-
Keep `jupyterhub.custom.pi-coding-agent-dir` aligned with `relay.core.piAgentDir` when relay is enabled.
136-
137-
### Production-style shared-skills updates (PVC mode)
138-
139-
When `pi.sharedSkills.mode=pvc-subpath`, enable chart-managed sync/rotation and feed it immutable artifacts built from your skills repo CI.
63+
- `pi.sharedSkills.mode` (`image`)
64+
- `pi.sharedSkills.imagePath`
65+
- `jupyterhub.custom.pi-image`
66+
- `jupyterhub.custom.pi-skills-path`
67+
- `jupyterhub.custom.pi-coding-agent-dir`
68+
- `relay.*`
14069

141-
Recommended values:
70+
When relay is enabled, keep these aligned:
14271

143-
- `pi.sharedSkills.sync.enabled=true`
144-
- `pi.sharedSkills.sync.source.type=url`
145-
- `pi.sharedSkills.sync.source.url=https://.../shared-skills-<version>.tar.gz`
146-
- `pi.sharedSkills.sync.source.sha256=<artifact-sha256>`
147-
- `pi.sharedSkills.sync.releaseId=<same-version-or-git-sha>`
148-
- `pi.sharedSkills.sync.keepReleases=<N>`
149-
150-
Behavior on each Helm install/upgrade:
151-
- syncs archive into `<pvcSubPath>/releases/<release-id>/...`
152-
- updates symlink: `<pvcSubPath>/current -> releases/<release-id>`
153-
- prunes old releases (keep latest N)
154-
155-
This gives reproducible roll-forward/rollback via `helm upgrade` without rebuilding the whole cluster.
72+
- `relay.core.piAgentDir`
73+
- `jupyterhub.custom.pi-coding-agent-dir`
15674

157-
#### Private artifact endpoints
75+
## Build Pi image with baked skills
15876

159-
If your artifact URL requires auth, set:
77+
`images/pi-agent/Dockerfile` expects:
16078

161-
- `pi.sharedSkills.sync.source.auth.secretName=<secret-name>`
162-
- `pi.sharedSkills.sync.source.auth.tokenKey=<key>` (default `token`)
79+
- `PI_SKILLS_URL` (required)
80+
- `PI_SKILLS_SHA256` (optional)
16381

164-
Create secret example:
82+
Example:
16583

16684
```bash
167-
kubectl -n data-science create secret generic pi-shared-skills-artifact-token \
168-
--from-literal=token='<your-bearer-token>'
85+
docker build \
86+
-t quay.io/openteams/pi-coding-agent-demo:baked-<tag> \
87+
--build-arg PI_SKILLS_URL="https://github.com/nenb/nebari-agent-skills/releases/download/<release>/shared-skills-<sha>.tar.gz" \
88+
--build-arg PI_SKILLS_SHA256="<sha256>" \
89+
images/pi-agent
16990
```
17091

171-
#### GitHub Actions CI workflow (skills repo)
172-
173-
Use the dedicated skills repository (`nenb/nebari-agent-skills`) to publish immutable artifacts.
174-
175-
A workflow template is provided at:
176-
177-
- `.github/workflows/publish-pi-shared-skills-artifact.yml`
178-
179-
Run this workflow in the **skills repo**, not in the Pi pack repo. It should publish:
180-
- `shared-skills-<sha>.tar.gz` (immutable asset)
181-
- `shared-skills.tar.gz` (rolling latest asset)
182-
- matching `.sha256` files
183-
- release tag: `pi-shared-skills-<sha>`
184-
185-
Then point `pi.sharedSkills.sync.source.url` to either:
186-
- immutable URL (recommended), or
187-
- latest URL (convenient, less reproducible)
92+
Then set your Helm values to the pushed image tag/digest:
18893

189-
If you use immutable URL, set `releaseId` to the same tag/sha.
94+
- `pi.image.repository`
95+
- `pi.image.tag`
96+
- `jupyterhub.custom.pi-image` (prefer digest pin)
19097

191-
## Security notes
98+
## Notes
19299

193-
- No hardcoded long-lived Pi tooling token in source.
194-
- M4 tooling token is generated/stored in chart-managed Secret (`pi-secrets`) and injected into Hub env.
195-
- Relay secrets use keep/lookup behavior for stable upgrades.
100+
- Legacy PVC-based shared-skills sync is removed from runtime flow.
101+
- Existing running Pi sessions keep old image/skills until pod restart.

config/jupyterhub/08-pi-home-and-spawn-fixes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,13 +515,23 @@
515515
_orig_profile_list = c.KubeSpawner.profile_list
516516

517517
PI_IMAGE = str(z2jh.get_config("custom.pi-image", "quay.io/nebari/pi-agent:latest") or "quay.io/nebari/pi-agent:latest")
518+
PI_SKILL_PATH = str(
519+
z2jh.get_config(
520+
"custom.pi-skills-path",
521+
"/opt/nebari/baked-skills/shared-skills",
522+
)
523+
or "/opt/nebari/baked-skills/shared-skills"
524+
)
518525
PI_ENV = {
519526
# Token is injected by chart via hub env -> singleuser profile env.
520527
"NEBARI_HUB_API_TOKEN": os.environ.get("PI_M4_TOOLS_API_TOKEN", ""),
521528
"NEBARI_HUB_API_URL": str(z2jh.get_config("custom.pi-hub-api-url", "http://hub:8081/hub/api") or "http://hub:8081/hub/api"),
522529
"NEBARI_PROXY_URL": str(z2jh.get_config("custom.pi-proxy-url", "http://proxy-public") or "http://proxy-public"),
523530
# Keep Pi runtime state outside potentially read-only /home mounts.
524531
"PI_CODING_AGENT_DIR": str(z2jh.get_config("custom.pi-coding-agent-dir", "/tmp/pi-agent") or "/tmp/pi-agent"),
532+
# Shared skills are baked into the image.
533+
"NEBARI_SHARED_SKILLS_MODE": "image",
534+
"NEBARI_SHARED_SKILLS_DIR": PI_SKILL_PATH,
525535
}
526536
PI_CMD = [
527537
"python",
@@ -544,6 +554,8 @@
544554
"7681",
545555
"--",
546556
"pi",
557+
"--skill",
558+
PI_SKILL_PATH,
547559
]
548560

549561
PI_SPECS_BY_SIZE = {

0 commit comments

Comments
 (0)