Context
Built a CLAUDE.md-level concurrent-agent detection rule on top of gstack's _SESSIONS mechanism (so a session-start step can force the operator into a separate git worktree when another Claude Code agent is active in the same repo). Two defects surfaced during the ship + dogfooding.
Defect A — _SESSIONS is computed but never echoed
Every skill preamble does:
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
The variable is computed but only consumed by an internal check inside the preamble. The preamble echoes many other state values to stdout for the calling agent to read (BRANCH:, PROACTIVE:, PROACTIVE_PROMPTED:, SKILL_PREFIX:, REPO_MODE:, LAKE_INTRO:, TELEMETRY:, TEL_PROMPTED:, EXPLAIN_LEVEL:, QUESTION_TUNING:, ARTIFACTS_SYNC:, LEARNINGS:, HAS_ROUTING:, ROUTING_DECLINED:, VENDORED_GSTACK:, MODEL_OVERLAY:, CHECKPOINT_MODE:, CHECKPOINT_PUSH:) — but never _SESSIONS:. Any CLAUDE.md rule that tells the agent to "read the preamble's session count" has no value to read.
Cost: my v1 CLAUDE.md rule said exactly that and shipped non-functional. Caught on post-ship audit when I re-read my own /ship preamble output adversarially. Worked around by inlining the bash command (find ~/.gstack/sessions -mmin -120 -type f | wc -l) into the rule itself.
Fix shape (cheap): add echo "SESSIONS: $_SESSIONS" to the preamble's existing echo block. ~1 line. Backwards-compatible.
Defect B — Marker TTL doesn't reflect "currently active"
The touch ~/.gstack/sessions/$PPID runs once per skill preamble invocation. The find -mmin -120 finds markers touched within 2h. A long-running Claude Code session that doesn't invoke a gstack skill for >2h has its marker mtime stay frozen; eventually it falls outside the window and the session reports SESSIONS=0 despite being active.
Reproduced live in my own session post-ship:
$ ls -la ~/.gstack/sessions/
-rw-r--r-- 1 user staff 0 May 21 12:28 65834 ← last skill invocation 10h+ ago
$ find ~/.gstack/sessions -mmin -120 -type f
(empty) ← marker outside the 2h window
$ # but my Claude Code session is still active and editing files
If two long-running sessions hit this state simultaneously, both register SESSIONS=0 and both "proceed normally" while actively colliding — the exact failure mode the marker was designed to prevent.
Fix shapes (pick one):
- Refresh the marker via a
PreToolUse hook (gstack already uses these heavily). touch ~/.gstack/sessions/$PPID on every tool call. Marker mtime tracks "actively using tools," not "ran a skill in the last 2h."
- Shorter TTL + periodic refresh hook. More moving parts.
- Switch to a different detection signal entirely (e.g.,
ps). Platform-dependent, brittle.
Recommendation: option 1. Reuses existing hook infrastructure, minimal added complexity, gives accurate "is this session active" signal.
Why this matters beyond my repo
Any gstack consumer building concurrent-agent safety on top of _SESSIONS will hit both gaps. Filing now so the design conversation happens once at the right layer instead of every consumer rolling their own workaround.
Reference
Full forensic detail (with the multi-month context of the worktree-warfare failure mode this detection was meant to prevent) lives in my local repo at: docs/upstream-issues/gstack-sessions-detection-gaps.md (will be on main once PR Nomo-AI-Labs/nomo-ai#2843 merges).
Context
Built a CLAUDE.md-level concurrent-agent detection rule on top of gstack's
_SESSIONSmechanism (so a session-start step can force the operator into a separate git worktree when another Claude Code agent is active in the same repo). Two defects surfaced during the ship + dogfooding.Defect A —
_SESSIONSis computed but never echoedEvery skill preamble does:
The variable is computed but only consumed by an internal check inside the preamble. The preamble echoes many other state values to stdout for the calling agent to read (
BRANCH:,PROACTIVE:,PROACTIVE_PROMPTED:,SKILL_PREFIX:,REPO_MODE:,LAKE_INTRO:,TELEMETRY:,TEL_PROMPTED:,EXPLAIN_LEVEL:,QUESTION_TUNING:,ARTIFACTS_SYNC:,LEARNINGS:,HAS_ROUTING:,ROUTING_DECLINED:,VENDORED_GSTACK:,MODEL_OVERLAY:,CHECKPOINT_MODE:,CHECKPOINT_PUSH:) — but never_SESSIONS:. Any CLAUDE.md rule that tells the agent to "read the preamble's session count" has no value to read.Cost: my v1 CLAUDE.md rule said exactly that and shipped non-functional. Caught on post-ship audit when I re-read my own /ship preamble output adversarially. Worked around by inlining the bash command (
find ~/.gstack/sessions -mmin -120 -type f | wc -l) into the rule itself.Fix shape (cheap): add
echo "SESSIONS: $_SESSIONS"to the preamble's existing echo block. ~1 line. Backwards-compatible.Defect B — Marker TTL doesn't reflect "currently active"
The
touch ~/.gstack/sessions/$PPIDruns once per skill preamble invocation. Thefind -mmin -120finds markers touched within 2h. A long-running Claude Code session that doesn't invoke a gstack skill for >2h has its marker mtime stay frozen; eventually it falls outside the window and the session reportsSESSIONS=0despite being active.Reproduced live in my own session post-ship:
If two long-running sessions hit this state simultaneously, both register
SESSIONS=0and both "proceed normally" while actively colliding — the exact failure mode the marker was designed to prevent.Fix shapes (pick one):
PreToolUsehook (gstack already uses these heavily).touch ~/.gstack/sessions/$PPIDon every tool call. Marker mtime tracks "actively using tools," not "ran a skill in the last 2h."ps). Platform-dependent, brittle.Recommendation: option 1. Reuses existing hook infrastructure, minimal added complexity, gives accurate "is this session active" signal.
Why this matters beyond my repo
Any gstack consumer building concurrent-agent safety on top of
_SESSIONSwill hit both gaps. Filing now so the design conversation happens once at the right layer instead of every consumer rolling their own workaround.Reference
Full forensic detail (with the multi-month context of the worktree-warfare failure mode this detection was meant to prevent) lives in my local repo at:
docs/upstream-issues/gstack-sessions-detection-gaps.md(will be onmainonce PR Nomo-AI-Labs/nomo-ai#2843 merges).