What happened
Running /gstack-upgrade from 1.26.4.0 → 1.29.0.0 inside Claude Code's Bash tool (no TTY, but a real human was present and steering). ./setup ran gstack-upgrade/migrations/v1.27.0.0.sh automatically because the script detected non-interactive context and printed:
(non-interactive: proceeding automatically)
Step 1 (gh repo rename gstack-brain-$USER → gstack-artifacts-$USER) failed:
WARNING: gh rename failed (repo may not exist or permission denied)
skipping step 1; subsequent steps still run
Steps 2-5 then ran successfully, leaving the system in an inconsistent state:
~/.gstack-artifacts-remote.txt → gstack-artifacts-$USER.git (new name)
- Actual GitHub repo → still
gstack-brain-$USER (rename didn't take)
~/.gstack/config.yaml → artifacts_sync_mode (new key)
- CLAUDE.md "Artifacts" labels (new terminology)
Net effect: artifacts sync would have pushed to a non-existent repo on the next run.
Why this is a problem
-
The user wasn't asked. This is a project-level rename decision (which is fine for the gstack maintainers to make), but executing it automatically without a "do you want this?" gate on someone else's GitHub account is a different category of change.
-
"No TTY" ≠ "no human present." Claude Code, Cursor, Aider, OpenAI Codex CLI, and most other agent runners shell out without allocating a PTY. There is a human watching the agent's output in real time — just no /dev/tty. Auto-proceed-on-no-TTY is the wrong default for that context.
-
Step 1 failure is silent and non-recoverable from the migration's own state. When the gh rename fails, the journal still marks step 1 as "attempted, skipping" and steps 2-5 commit anyway. The resulting inconsistency (config points at new name, repo still has old name) only surfaces on the next sync attempt.
Suggested fix
When non-interactive AND no --yes/GSTACK_AUTO_MIGRATE=1 env opt-in:
- Default to skip, not proceed.
- Write a
pending-user-confirmation marker so the next interactive session re-prompts.
- Print a clear "this migration is waiting on you, run
gstack-rerun-migration v1.27.0.0 when ready" line.
For step 1 specifically: if gh repo rename fails, abort the migration rather than continuing through steps 2-5. The system being half-renamed is worse than not renamed at all.
Reproduction
- Be on gstack 1.26.x with a
gstack-brain-$USER repo on GitHub.
- Run
/gstack-upgrade from inside an agent runner that doesn't allocate a TTY (Claude Code, Cursor, etc.).
- Observe: migration auto-runs, gh rename fails, local state advances anyway.
Environment
- gstack: 1.26.4.0 → 1.29.0.0
- Runner: Claude Code (Anthropic CLI)
- OS: Debian 12, Linux 6.1
- gh: authenticated, but rename appears to have failed for a different reason (repo exists, permissions are fine — possibly an interactive confirm prompt that got auto-declined?)
What happened
Running
/gstack-upgradefrom 1.26.4.0 → 1.29.0.0 inside Claude Code's Bash tool (no TTY, but a real human was present and steering)../setuprangstack-upgrade/migrations/v1.27.0.0.shautomatically because the script detected non-interactive context and printed:Step 1 (
gh repo rename gstack-brain-$USER → gstack-artifacts-$USER) failed:Steps 2-5 then ran successfully, leaving the system in an inconsistent state:
~/.gstack-artifacts-remote.txt→gstack-artifacts-$USER.git(new name)gstack-brain-$USER(rename didn't take)~/.gstack/config.yaml→artifacts_sync_mode(new key)Net effect: artifacts sync would have pushed to a non-existent repo on the next run.
Why this is a problem
The user wasn't asked. This is a project-level rename decision (which is fine for the gstack maintainers to make), but executing it automatically without a "do you want this?" gate on someone else's GitHub account is a different category of change.
"No TTY" ≠ "no human present." Claude Code, Cursor, Aider, OpenAI Codex CLI, and most other agent runners shell out without allocating a PTY. There is a human watching the agent's output in real time — just no
/dev/tty. Auto-proceed-on-no-TTY is the wrong default for that context.Step 1 failure is silent and non-recoverable from the migration's own state. When the
ghrename fails, the journal still marks step 1 as "attempted, skipping" and steps 2-5 commit anyway. The resulting inconsistency (config points at new name, repo still has old name) only surfaces on the next sync attempt.Suggested fix
When non-interactive AND no
--yes/GSTACK_AUTO_MIGRATE=1env opt-in:pending-user-confirmationmarker so the next interactive session re-prompts.gstack-rerun-migration v1.27.0.0when ready" line.For step 1 specifically: if
gh repo renamefails, abort the migration rather than continuing through steps 2-5. The system being half-renamed is worse than not renamed at all.Reproduction
gstack-brain-$USERrepo on GitHub./gstack-upgradefrom inside an agent runner that doesn't allocate a TTY (Claude Code, Cursor, etc.).Environment