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
30 changes: 17 additions & 13 deletions bin/gs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ usage() {
cat <<'EOF'
gs - gentle-shell on main, plus one disposable worktree per PR

gs [pi args...] Open gentle-shell (--link) in the current directory.
gs [pi args...] Open gentle-shell (--isolated) in the current directory.
Consumer: always the main build from gs sync.
Workshop: inside a gentle-shell clone or worktree, Pi
loads that path (gs run); elsewhere the synced clone.
Expand All @@ -31,7 +31,7 @@ gs - gentle-shell on main, plus one disposable worktree per PR
gs new <repo> <name> New branch <name> from fresh origin/main
gs review <repo> <pr> Check out someone else's PR to test or review it
gs base <repo> Clean origin/main worktree, to compare failures
gs run [pi args...] Run gentle-shell --link with this worktree as --package-root
gs run [pi args...] Run gentle-shell --isolated with this worktree as --package-root
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)
Expand All @@ -54,7 +54,8 @@ Fastest start:
gs done -> inside the worktree, after the merge
(claim, comment, label, push and merge stay yours)
Each session: one worktree, Pi loads the package from it, /reload picks up edits.
Sessions share ~/.pi/agent (--link) and subagents use the main clone.
Sessions share the isolated home ~/.gentle-shell/agent (--isolated, never
--link) and subagents use the main clone. Workshop sync never runs pi update.
gs sync is separate: run it with no other session open.

gs and gs sync share one source of truth: workshop launches the clone it syncs;
Expand Down Expand Up @@ -183,17 +184,18 @@ open_or_finish() {

pr_prompt() {
# Same cortex-only rule as issue_prompt: the cortex variant is mandatory.
printf 'Review Gentleman-Programming/%s PR #%s using the cortex-maintainer-delivery skill, loading ~/.pi/agent/skills/cortex-maintainer-delivery/SKILL.md first (never the plain maintainer-delivery skill): read the PR, its linked issue, CI status and diff; run its preflight and race check; then report scope, risks, and what to test in Spanish. Do not comment, push, or merge.' "$1" "$2"
printf 'Review Gentleman-Programming/%s PR #%s using the cortex-maintainer-delivery skill, loading it first (never the plain maintainer-delivery skill): read the PR, its linked issue, CI status and diff; run its preflight and race check; then report scope, risks, and what to test in Spanish. Do not comment, push, or merge.' "$1" "$2"
}

issue_prompt() {
# Plan-first: the session presents the kickoff and STOPS. Implementation
# starts only after the user explicitly approves the plan (agreed workflow;
# the previous "then work test-first" wording made sessions auto-implement).
# The CORTEX variant of the skill is mandatory, referenced by name and path:
# The CORTEX variant of the skill is mandatory, referenced by name (no legacy
# ~/.pi/agent path: sessions run on the isolated home):
# there is also a plain maintainer-delivery skill and the session must not
# pick that one.
printf 'Take Gentleman-Programming/%s issue #%s using the cortex-maintainer-delivery skill, loading ~/.pi/agent/skills/cortex-maintainer-delivery/SKILL.md first (never the plain maintainer-delivery skill): run its preflight, read the issue and repo conventions, then present a kickoff plan (expected behavior, approach, out of scope, branch %s) in Spanish and STOP. Do not implement, edit files, or commit: implementation starts only after the user explicitly approves the plan. Claiming, commenting, pushing, and opening the PR stay mine.' "$1" "$2" "$3"
printf 'Take Gentleman-Programming/%s issue #%s using the cortex-maintainer-delivery skill, loading it first (never the plain maintainer-delivery skill): run its preflight, read the issue and repo conventions, then present a kickoff plan (expected behavior, approach, out of scope, branch %s) in Spanish and STOP. Do not implement, edit files, or commit: implementation starts only after the user explicitly approves the plan. Claiming, commenting, pushing, and opening the PR stay mine.' "$1" "$2" "$3"
}

cmd_pr() {
Expand Down Expand Up @@ -269,7 +271,7 @@ cmd_run() {
grep -q '"name": *"gentle-pi"' "$root/package.json" 2>/dev/null || die "$root is not gentle-shell"
[ -d "$root/node_modules" ] || die "no node_modules in $root (pnpm install --frozen-lockfile)"
printf 'gs: gentle-shell @ %s (%s); subagents use main\n' "$(git -C "$root" rev-parse --short HEAD)" "$root" >&2
cd "$root" && exec node "$root/bin/gentle-shell.mjs" --link --package-root "$root" "$@"
cd "$root" && exec node "$root/bin/gentle-shell.mjs" --isolated --package-root "$root" "$@"
}

# Workshop (agent-gentle): clean clones in ~/dev/gentle, Pi loads the gentle-shell clone.
Expand Down Expand Up @@ -365,16 +367,19 @@ sync_dotfiles() {

cmd_sync() {
local ai_files="" dot_change="" repo shell bin="$HOME/.local/share/gentle-ai/main" reg="$HOME/.pi/gentle-ai/dev-binary.json" name
# The dev-binary registration is install-level state: the official launcher
# reads it from ~/.pi/gentle-ai even in the isolated home (gentle-shell
# lib/gentle-shell-launcher.ts UNMIGRATED_CONFIG_FILES), so it stays there.
# Versions before the sync power the closing message: restart only on change.
local shell_before ai_before engram_before
shell_before=$(shell_version); ai_before=$(ai_version); engram_before=$(engram_version)
# Stale GOROOT/GOBIN from a removed version manager breaks every go build.
if [ -n "${GOROOT:-}" ] && [ ! -d "$GOROOT" ]; then unset GOROOT; fi
if [ -n "${GOBIN:-}" ] && [ ! -d "$(dirname "$GOBIN")" ]; then unset GOBIN; fi
# pi may live in its managed home instead of PATH (managed install schema).
command -v pi >/dev/null 2>&1 || export PATH="$HOME/.pi/agent/bin:$PATH"
mkdir -p "$bin" "$HOME/.local/bin" "$(dirname "$reg")"
if is_workshop; then
# Workshop runs the Pi bundled in the clone (node_modules): no legacy
# ~/.pi/agent runtime on PATH and no pi update.
printf 'gs sync — %s — workshop (local clones)\n' "$(date '+%Y-%m-%d %H:%M')"
for repo in $REPOS; do
[ -d "$CLONES/$repo/.git" ] || die "missing clean clone $CLONES/$repo"
Expand All @@ -394,6 +399,8 @@ cmd_sync() {
else
printf 'gs sync — %s — consumer (official update channels)\n' "$(date '+%Y-%m-%d %H:%M')"
command -v gentle-shell >/dev/null 2>&1 || die "consumer sync needs gentle-shell on PATH; install it first"
# pi may live in its managed home instead of PATH (managed install schema).
command -v pi >/dev/null 2>&1 || export PATH="$HOME/.pi/agent/bin:$PATH"
# pi self-update cannot handle every installation schema (e.g. bun-compiled
# /opt/pi binaries): a failure there must not abort the sync, the official
# main channel below is the actual update path for Shell and AI.
Expand Down Expand Up @@ -519,9 +526,6 @@ cmd_sync() {
else
printf 'compat: INCOMPATIBLE (gentle-ai emits %s, gentle-shell reads %s)\n' "$emits" "$reads"
fi
if is_workshop && grep -qE 'npm:gentle-(pi|engram)|git:github.com/Gentleman-Programming/gentle-(pi|shell)' "$HOME/.pi/agent/settings.json" 2>/dev/null; then
printf 'WARN: ~/.pi/agent/settings.json lists a published gentle-pi/gentle-engram again; remove it\n'
fi
if [ -n "$ai_files" ] && [ "$ai_files" -gt 0 ]; then
changed="$changed managed configs ($ai_files files)"
fi
Expand Down Expand Up @@ -581,7 +585,7 @@ cmd_launch() {
root=$(shell_root) || die "gentle-shell not on PATH (install it, then run: gs sync)"
[ -f "$root/bin/gentle-shell.mjs" ] || die "gentle-shell not found at $root (run: gs sync)"
herdr_tab_repo
exec node "$root/bin/gentle-shell.mjs" --link "$@"
exec node "$root/bin/gentle-shell.mjs" --isolated "$@"
}

case "${1:-}" in
Expand Down
1 change: 1 addition & 0 deletions docs/gentle-official-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +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.
- 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
28 changes: 27 additions & 1 deletion docs/gs-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,31 @@
The launcher loads its extensions and its bundled Pi from its own package root,
so the package it starts from decides what you see.

## Isolated home, never `--link`

Every launch (`gs`, `gs run`, and the Pi session opened by `gs pr` / `gs issue`)
passes `--isolated`, so Shell uses the official isolated home
`~/.gentle-shell/agent`; from a clone or worktree it also passes
`--package-root <root>`. `gs` never passes `--link` and never loads `~/.pi/agent`.

Workshop `gs sync` also stays off the legacy Pi home:

- It does not add `~/.pi/agent/bin` to PATH and does not run `pi update` or
`pi update --extensions`; Shell runs the Pi bundled in the clone
(`node_modules/@earendil-works/pi-coding-agent`).
- It registers Gentle AI main in `~/.pi/gentle-ai/dev-binary.json` (file
`0600`, atomic write) with
`{"schema":"gentle-pi.dev-binary/v1","path":"~/.local/share/gentle-ai/main/gentle-ai"}`.
This path is install-level state: the official launcher reads it there even
for the isolated home, so it is not moved to `~/.gentle-shell/gentle-ai`.
- 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.

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`).

## Why this changed

Before, consumer `gs` started
Expand Down Expand Up @@ -51,4 +76,5 @@ Run these on each machine. A machine counts as aligned only after step 3 passes
## Tests

`tests/gs_test.sh` runs offline in a throwaway HOME with stub binaries and covers
the launcher (consumer and workshop) and the sync result messages.
the launcher (consumer and workshop, `gs run`, `gs pr`, `gs issue`), the isolated
registration, and the sync result messages.
27 changes: 27 additions & 0 deletions odd/tasks/agent-gentle-official-home.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# agent-gentle: workshop gs on the official isolated home

Migrate the dogfooding host agent-gentle off the legacy Pi home without losing the workshop `bin/gs` accessories.
Shell keeps running from the gentle-shell clone; only the home, Pi runtime and Gentle AI registration move to the official layout.

## Specs

- S1. Keep every workshop accessory: "tenemos una serie de accesorios tipo gs issue shell 1234 para revisar un issue o un pr ... revisalo bien antes de arrancar". `gs issue`, `gs pr`, `gs review`, `gs new`, `gs base`, `gs ls`, `gs done` and `gs sync` keep their worktree/git/gh behavior.
- S2. Never `--link`: "Shell y Gentle AI SIEMPRE en main. Nunca release, nunca --link, nunca --include-shared." Every Shell launch in `bin/gs` (`gs`, `gs run`, launches from `gs pr`/`gs issue`) uses the isolated home (`--isolated`) and, from a clone or worktree, keeps `--package-root <root>`.
- S3. No legacy Pi runtime: `bin/gs` does not add `~/.pi/agent/bin` to PATH and does not run `pi update` / `pi update --extensions` in workshop mode. Shell uses the Pi package inside the clone (`node_modules/@earendil-works/pi-coding-agent`).
- 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.
- 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
- T2 (S7) parent: deploy and verify on agent-gentle. Commit: n/a (host)

## Log

- L1 User: "bueno ahora tenemos que hacer la que para mi es la mas complicada ... capaz no lo es. Agent-gentle es un entorno tipo dogfooding ... yo siendo vos primero miraría bien quehace. Ahí lo que hacemos es trabajar directo con gentle-shell, gentle-ai y engram. Con eso en mente tenemos una serie de accesorios tipo gs issue shell 1234 para revisar un issue o un pr ... revisalo bien antes de arrancar"
- L2 User approved the approach "mantener el gs de workshop y migrar solo su arranque al home aislado": "si".
- 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.
Loading
Loading