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
16 changes: 13 additions & 3 deletions bin/gs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ gs - gentle-shell on main, plus one disposable worktree per PR
gs sync Bring gentle-shell, gentle-ai and engram to main, run
gentle-ai sync for managed configs, and check compatibility
(workshop: local clones; elsewhere: GitHub)
Workshop: gentle-ai sync --agents claude-code, then
gentle-shell --isolated setup (re-provisions the isolated home)
GS_SYNC_AGENTS=a,b scopes gentle-ai sync to those runtimes;
GS_SKIP_AI_SYNC=1 skips it (binaries only)
GS_SKIP_AI_SYNC=1 skips both steps (binaries only)
Then pulls the dotfiles clone (clean, on main only); the
shell profile reads it in place. GS_SKIP_DOTFILES=1
skips this step
Expand Down Expand Up @@ -458,12 +460,17 @@ cmd_sync() {

# New binaries are not enough: gentle-ai sync materializes the managed configs
# (agents, skills, plugins, engram instructions) every runtime reads.
# GS_SYNC_AGENTS scopes runtimes per host (local env); empty = gentle-ai default.
# GS_SYNC_AGENTS scopes runtimes per host (local env). Workshop defaults to
# claude-code (Shell runs on the isolated home, provisioned below by
# gentle-shell setup); consumer empty = gentle-ai default.
local sync_agents="${GS_SYNC_AGENTS:-}"
is_workshop && sync_agents="${GS_SYNC_AGENTS:-claude-code}"
if [ "${GS_SKIP_AI_SYNC:-}" = 1 ]; then
printf ' %-34s skipped (GS_SKIP_AI_SYNC=1)\n' 'gentle-ai sync'
is_workshop && printf ' %-34s skipped (GS_SKIP_AI_SYNC=1)\n' 'gentle-shell setup (isolated home)'
else
local ai_sync=(sync)
[ -n "${GS_SYNC_AGENTS:-}" ] && ai_sync+=(--agents "$GS_SYNC_AGENTS")
[ -n "$sync_agents" ] && ai_sync+=(--agents "$sync_agents")
# Like run_quiet, but keeps the output: its file count feeds the restart hint.
local ai_out; ai_out=$(mktemp)
if "$ai_bin" "${ai_sync[@]}" >"$ai_out" 2>&1; then
Expand All @@ -475,6 +482,9 @@ cmd_sync() {
fi
ai_files=$(sed -n 's/^Sync actions executed: \([0-9][0-9]*\) files* changed.*/\1/p' "$ai_out" | head -1)
rm -f "$ai_out"
# Official re-provisioning of the isolated home (~/.gentle-shell/agent) from the clone.
is_workshop && run_quiet 'gentle-shell setup (isolated home)' \
node "$CLONES/gentle-shell/bin/gentle-shell.mjs" --isolated setup
fi
sync_dotfiles
# gs sync is the only upgrade path; older homemade scripts drift the hosts apart.
Expand Down
2 changes: 1 addition & 1 deletion docs/gentle-official-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Corrección del usuario, textual:
- Shell mantiene su mecanismo oficial `gentle-shell upgrade --channel main`. No asumir que ese comando actualiza el Gentle AI externo que usa Claude Code.
- Después de actualizar, comprobar qué binario externo resuelve el PATH y qué versión/commit quedó instalado; evitar actualizar una copia y ejecutar otra. Definir y verificar el mecanismo oficial de sincronización de assets de Claude Code cuando se implemente.
- Implementado en [`bin/gs-official`](../bin/gs-official) ([doc](gs-official.md)), desplegado solo en hosts migrados como `~/.local/bin/gs`. El `bin/gs` legacy de Mac y workshop no cambia. El PATH permanente se activa con el fragmento opt-in [`zsh/scripts/official-gentle-path.zsh`](../zsh/scripts/official-gentle-path.zsh), enlazado en `~/.config/cortex-dotfiles/shell/official-gentle-path.zsh`.
- Workshop (agent-gentle): el `bin/gs` de workshop conserva sus accesorios (`gs issue`, `gs pr`, `gs review`, `gs new`, `gs base`, `gs ls`, `gs done`, `gs sync`), pero todo arranque usa el home aislado (`--isolated`, nunca `--link`) y, desde un clon o worktree, `--package-root <root>`. `gs sync` en workshop no agrega `~/.pi/agent/bin` al PATH ni ejecuta `pi update`; registra Gentle AI de main en `~/.pi/gentle-ai/dev-binary.json`: es estado de instalación y el lanzador oficial lo lee ahí también con el home aislado, así que no se mueve ni se retira. Ver [gs-sync.md](gs-sync.md). `gs-official` y Mac/agent-dev no cambian por esto.
- Workshop (agent-gentle): el `bin/gs` de workshop conserva sus accesorios (`gs issue`, `gs pr`, `gs review`, `gs new`, `gs base`, `gs ls`, `gs done`, `gs sync`), pero todo arranque usa el home aislado (`--isolated`, nunca `--link`) y, desde un clon o worktree, `--package-root <root>`. `gs sync` en workshop no agrega `~/.pi/agent/bin` al PATH ni ejecuta `pi update`; registra Gentle AI de main en `~/.pi/gentle-ai/dev-binary.json`: es estado de instalación y el lanzador oficial lo lee ahí también con el home aislado, así que no se mueve ni se retira. Luego ejecuta `gentle-ai sync --agents claude-code` (solo Claude Code; `GS_SYNC_AGENTS` lo sobrescribe) y `node ~/dev/gentle/gentle-shell/bin/gentle-shell.mjs --isolated setup`, que reaprovisiona el home aislado `~/.gentle-shell/agent`; si un paso falla, el sync queda `INCOMPLETE`. `GS_SKIP_AI_SYNC=1` omite ambos pasos. El sync de consumidor no cambia. Ver [gs-sync.md](gs-sync.md). `gs-official` y Mac/agent-dev no cambian por esto.
- El instalador oficial `install.sh --channel beta` falló en esta sesión: `get_main_commit_sha` emite un mensaje informativo en stdout y su captura mezcla ese mensaje con el SHA, causando una URL inválida al buscar `go.mod`. Se comprobó en el script remoto. No parchear el instalador ni desactivar verificaciones como workaround.
- También hubo un error de pegado independiente (`\\ |` en una misma línea). Corregir el pegado no arregla el bug del instalador.

Expand Down
9 changes: 8 additions & 1 deletion docs/gs-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,17 @@ Workshop `gs sync` also stays off the legacy Pi home:
- It no longer warns about `gentle-pi`/`gentle-engram` in the isolated home's
`settings.json`: the official Shell declares and requires them there, and the
`--package-root` take-over loads the clone instead of the published gentle-pi.
- It runs `gentle-ai sync --agents claude-code` (Claude Code only; never the
legacy `pi` agent nor `opencode`). `GS_SYNC_AGENTS=a,b` overrides the agents.
- It then runs `node ~/dev/gentle/gentle-shell/bin/gentle-shell.mjs --isolated setup`
(`gentle-shell setup (isolated home)`), the official re-provisioning of
`~/.gentle-shell/agent`. A failure marks the sync `INCOMPLETE` and shows its output.
- `GS_SKIP_AI_SYNC=1` skips both steps and prints a `skipped` line for each.

The `gs pr` / `gs issue` kickoff prompts name the `cortex-maintainer-delivery`
skill without a home path. Consumer sync keeps its official update steps
(`pi update`, `gentle-shell upgrade --channel main`, `pi update --extensions`).
(`pi update`, `gentle-shell upgrade --channel main`, `pi update --extensions`)
and runs `gentle-ai sync` with `--agents` only when `GS_SYNC_AGENTS` is set.

## Why this changed

Expand Down
8 changes: 5 additions & 3 deletions local/env.zsh.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@
# export CORTEX_BRAINS_PG_HOST="<brains-host>"
# export CORTEX_BRAINS_PG_PORT="5432"

# gs sync runs gentle-ai sync after updating binaries. Scope it to this host's runtimes:
# export GS_SYNC_AGENTS="claude-code,opencode,pi"
# Binaries only, no managed-config sync:
# gs sync runs gentle-ai sync after updating binaries. Workshop defaults to claude-code
# and then runs gentle-shell --isolated setup; consumer defaults to gentle-ai's own set.
# Override the runtimes for this host:
# export GS_SYNC_AGENTS="claude-code"
# Binaries only, no managed-config sync (workshop: also skips gentle-shell setup):
# export GS_SKIP_AI_SYNC=1
# gs sync also pulls the dotfiles clone (clean, on main); the zsh profile reads it in place.
# export GS_SKIP_DOTFILES=1
3 changes: 3 additions & 0 deletions odd/tasks/agent-gentle-official-home.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ Shell keeps running from the gentle-shell clone; only the home, Pi runtime and G
- S4. Gentle AI from main inside Shell: workshop `gs sync` keeps writing the dev-binary registration `{"schema":"gentle-pi.dev-binary/v1","path":"<~/.local/share/gentle-ai/main/gentle-ai>"}` to `~/.pi/gentle-ai/dev-binary.json` (0600, atomic). It is install-level state the official launcher reads there even for the isolated home (gentle-shell `lib/gentle-shell-launcher.ts:252-254`, `lib/gentle-ai-binary.ts:218` `launcherMarker: false`); it is never moved or retired.
- S5. Prompts for `gs pr` / `gs issue` no longer point at `~/.pi/agent/skills/...`; they name the `cortex-maintainer-delivery` skill without a legacy home path.
- S6. Help text and docs (`docs/gs-sync.md`, `docs/gentle-official-migration.md`) describe the new behavior; `gs-official` and Mac/agent-dev are unaffected.
- S8. Workshop `gs sync` syncs external Gentle AI for Claude Code only and provisions the isolated home: "solo claude code". It runs `gentle-ai sync --agents claude-code` by default (never the legacy `pi` agent nor `opencode`; an explicit `GS_SYNC_AGENTS` still overrides), then `gentle-shell setup` on the isolated home from the synced clone (`node ~/dev/gentle/gentle-shell/bin/gentle-shell.mjs --isolated setup`), the official re-provisioning of `~/.gentle-shell/agent`. `GS_SKIP_AI_SYNC=1` skips both. A failed step marks the sync INCOMPLETE. Consumer sync is unchanged.
- S7. Host deploy on agent-gentle: confirm last NAS backup succeeded; then pull dotfiles, run `gs sync`, replace the `~/.local/bin/gentle-shell` wrapper so it no longer sets `GENTLE_SHELL_PI=~/.pi/agent/bin/pi`, and move retired legacy pieces to a `mktemp -d` backup (never delete). Never touch Engram data, credentials, conversations, worktrees with uncommitted changes, or Herdr.

## Tasks

- T1 (S2-S6) worker + parent fixes: change `bin/gs` + tests + docs. Done. Commit: e89c3d1
- T3 (S8) worker: workshop sync scope + isolated setup. Done. Commit: see branch feat/agent-gentle-sync-scope
- T2 (S7) parent: deploy and verify on agent-gentle. Commit: n/a (host)

## Log
Expand All @@ -25,3 +27,4 @@ Shell keeps running from the gentle-shell clone; only the home, Pi runtime and G
- L3 Evidence: official launcher (clone 14f44d11c) accepts `--isolated` with `--package-root` (only `--link`+`--isolated` and `--isolated`+`--home` conflict, `lib/gentle-shell-launcher.ts:169-174`); clone has adjacent Pi 1.4.0; isolated home `~/.gentle-shell/agent` already holds pi-mcp-adapter and brains; Engram already at main tip `7cf4ed29b6f9`.
- L4 Parent review: removed the isolated-settings gentle-pi/gentle-engram warning; on agent-gentle the official Shell declares both there (gentle-engram is its required companion), so it would fire on every sync. Skill cortex-maintainer-delivery exists only in ~/.pi/agent/skills on agent-gentle; T2 must expose it to the isolated home before retiring legacy.
- L5 Verifier FAIL on S4: the launcher reads dev-binary.json from ~/.pi/gentle-ai, not the isolated config home (confirmed on agent-gentle clone 14f44d11c, lib/gentle-ai-binary.ts:218). S4 rewritten: keep writing ~/.pi/gentle-ai/dev-binary.json; T1 reopened and fixed.
- L6 User asked whether gs sync also runs gentle-ai sync and whether gentle-shell has its own: "en el gs sync metimos también un gentle-ai sync? porque eso es lo que esta documentado en el proceso de actualizacion. Hay que revisar si gentle-shell no tiene algo de esto también". Finding: workshop runs bare `gentle-ai sync`; installed_agents on agent-gentle = claude-code, opencode, pi, so it keeps syncing the legacy ~/.pi/agent (gentle-shell README: `gentle-ai sync` is Path B, gentle-pi inside an existing pi) and never the isolated home; `gentle-shell setup` re-provisions the isolated home; the agent-gentle wrapper sets GENTLE_SHELL_NO_AUTO_SETUP=1. User decision on agents: "solo claude code".
24 changes: 24 additions & 0 deletions tests/gs_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ setup() { # mode: consumer | workshop
pkg=$(dirname "$(dirname "$1")"); shift
if [ "${1:-}" = --version ]; then printf 'gentle-shell %s\npi 1.4.0\n' "$(cat "$pkg/VERSION")"; exit 0; fi
echo "launch $pkg $*" >> "$CALLS"
[ "${2:-}" = setup ] && exit "${SETUP_RC:-0}"
exit 0
EOF
printf '#!/bin/sh\necho "go PATH=$PATH" >> "$CALLS"\n' > "$S/go"
for b in pnpm npm; do printf '#!/bin/sh\nexit 0\n' > "$S/$b"; done
Expand Down Expand Up @@ -173,6 +175,22 @@ mkdir -p "$HOME/.gentle-shell/agent"; printf '{"packages":["npm:gentle-pi","npm:
OUT=$("$GS" sync 2>&1)
check "workshop sync: isolated home packages the official Shell requires raise no warning" \
'[[ "$OUT" != *"WARN:"*"settings.json"* ]]'
# S8: workshop gentle-ai sync is Claude Code only, then the isolated home is provisioned.
AI="$HOME/.local/share/gentle-ai/main/gentle-ai"
printf '#!/bin/sh\n[ "$1" = --version ] && { echo "gentle-ai 1.0.0"; exit 0; }\necho "gentle-ai $*" >> "$CALLS"\n' > "$AI"; chmod +x "$AI"
SHELL_CLONE="$HOME/dev/gentle/gentle-shell"
: > "$CALLS"; OUT=$(env -u GS_SKIP_AI_SYNC "$GS" sync 2>&1); rc=$?
check "workshop sync: gentle-ai sync targets claude-code only, then gentle-shell setup on the isolated home" \
'[ $rc -eq 0 ] && [ "$(grep -E "^gentle-ai sync|--isolated setup" "$CALLS")" = "$(printf "gentle-ai sync --agents claude-code\nlaunch %s --isolated setup" "$SHELL_CLONE")" ] && [[ "$OUT" == *"gentle-shell setup (isolated home)"*ok* ]]'
: > "$CALLS"; OUT=$(env -u GS_SKIP_AI_SYNC GS_SYNC_AGENTS=x "$GS" sync 2>&1)
check "workshop sync: GS_SYNC_AGENTS overrides the claude-code default" \
'grep -qx "gentle-ai sync --agents x" "$CALLS"'
: > "$CALLS"; OUT=$(GS_SKIP_AI_SYNC=1 "$GS" sync 2>&1)
check "workshop sync: GS_SKIP_AI_SYNC=1 skips gentle-ai sync and gentle-shell setup" \
'! grep -qE "^gentle-ai sync|--isolated setup" "$CALLS" && [[ "$OUT" == *"gentle-ai sync"*"skipped (GS_SKIP_AI_SYNC=1)"* ]] && [[ "$OUT" == *"gentle-shell setup (isolated home)"*"skipped (GS_SKIP_AI_SYNC=1)"* ]]'
OUT=$(env -u GS_SKIP_AI_SYNC SETUP_RC=1 "$GS" sync 2>&1); rc=$?
check "workshop sync: failed gentle-shell setup is INCOMPLETE, exit 1" \
'[ $rc -eq 1 ] && [[ "$OUT" == *"INCOMPLETE"*"gentle-shell setup (isolated home)"* ]]'
rm "$HOME/.gentle-shell/agent/settings.json"
echo tracked >> "$HOME/dev/gentle/gentle-shell/VERSION"; git -C "$HOME/dev/gentle/gentle-shell" add VERSION
OUT=$("$GS" sync 2>&1); rc=$?
Expand All @@ -190,6 +208,12 @@ check "consumer sync: still runs pi update and pi update --extensions" \
check "sync: warns about the unused legacy checkout without deleting it" \
'[[ "$OUT" == *"stale legacy checkout"* ]] && [ -d "$HOME/.pi/agent/git/github.com/Gentleman-Programming/gentle-pi" ]'

setup consumer; remote_main HEAD
printf '#!/bin/sh\n[ "$1" = --version ] && { echo "gentle-ai 1.0.0"; exit 0; }\necho "gentle-ai $*" >> "$CALLS"\n' > "$HOME/ai"
OUT=$(env -u GS_SKIP_AI_SYNC "$GS" sync 2>&1)
check "consumer sync: still runs bare gentle-ai sync (no --agents) and no gentle-shell setup" \
'grep -qx "gentle-ai sync" "$CALLS" && ! grep -q -- "--isolated setup" "$CALLS" && [[ "$OUT" != *"gentle-shell setup"* ]]'

setup consumer; remote_main HEAD; main=$(sha_of)
echo "4.5.2-main.${main:0:12}" > "$NPM/VERSION"
OUT=$("$GS" sync 2>&1); rc=$?
Expand Down
Loading