garrytan / garrytan/gstack

Support session-aware repo-local loop state for concurrent same-repo workflows

Open
#1,191 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
133k
Forks
19.9k
Avg merge
18h 46m
Merged PRs (30d)
26

Description

## Problem

Some repo-local workflow state in gstack-style loops is effectively single-writer:
- one mutable `current` state file
- one mutable `STATE.md` view

That works for a single active task in a repo, but it breaks down when two AI sessions are working in the same repo at once.

Failure mode:
1. Session A starts a repo-local loop for task A.
2. Session B starts a repo-local loop for task B in the same repo.
3. Session B overwrites the repo-local `current` state.
4. Session A now sees the wrong active task/stage, or cannot safely update its own loop.

This is not hypothetical — it shows up immediately in real multi-session / multi-agent usage, especially when parallel planning/review/shipping work happens in the same repo checkout.

## Why this matters

gstack increasingly supports:
- long-running multi-step workflows
- resumable context
- multi-session usage
- workspace-aware behavior

But repo-local loop state is still vulnerable to silent clobbering if it assumes one active loop per repo checkout.

That causes two problems:
1. **state corruption / confusion** — one session silently hijacks another session's workflow state
2. **bad tool guidance** — guards/hooks may warn against the wrong task because they resolve only the most recently written repo-local state

## Desired behavior

Parallel sessions in the same repo should be able to maintain independent loop state without destroying each other.

A good default model would be:
- durable per-loop state files
- explicit session-to-loop binding
- backward-compatible `current` alias for old tooling
- `list` / `activate` / `status --loop-id` style affordances

## Proposed design

### 1. Durable per-loop state
Instead of only:
- `.gstack/current.json`
- `.gstack/STATE.md`

store canonical loop state under something like:
- `.gstack/loops/.json`
- `.gstack/loops/.md`

Where `loop-id` is unique and human-auditable (timestamp + slug is enough).

### 2. Session binding
Bind the current session to one loop via a lightweight mapping under something like:
- `.gstack/sessions/.json`

Then `status` / `update` can resolve in this order:
1. explicit `--loop-id`
2. session binding
3. legacy/current alias fallback

### 3. Compatibility alias
Keep:
- `.gstack/current.json`
- `.gstack/STATE.md`

as compatibility mirrors of the most recently activated/touched loop.

This avoids breaking older tooling while making the canonical model multi-loop.

### 4. Minimal commands
A small surface is enough:

```bash
gstack loop list
gstack loop activate
gstack loop status [--loop-id ...]
```

(or equivalent within the existing command structure)

## Important implementation point

The upstream version should use a **generic session abstraction**, not host-specific env hacks.

A local overlay can get away with using environment-specific values from the surrounding shell/tooling, but upstream should define a clean `GSTACK_SESSION_ID`-style mechanism first, then optionally allow fallbacks where appropriate.

## Non-goals

This does **not** solve all parallel-work problems.

If two sessions are editing the same checkout and touching the same files, you still have working-tree collisions.

This proposal only fixes the workflow-state collision layer.

The right higher-order pattern is still:
- session-aware loop state for lightweight same-repo concurrency
- separate worktrees for truly parallel implementation

## Why this seems upstream-worthy

The need is generic, not user-specific:
- multi-agent / multi-session work is becoming normal
- silent state clobbering is a predictable failure mode
- a single mutable repo-local loop state becomes the wrong abstraction once concurrency exists

This feels aligned with gstack’s broader direction around workspaces, saved context, and multi-session workflows.

## Concrete acceptance criteria

A good fix would satisfy:
- Session A and Session B can each start loops in the same repo without destroying each other
- `status` in each session resolves to the correct bound loop by default
- `update` advances only the intended loop
- `list` shows all loops in the repo
- old repos with only `current.json` migrate or fall back cleanly
- tooling that only reads `current.json` still works, even if it is only a compatibility alias

## Suggested next step

Open as design/RFC first, then decide whether to implement in core gstack state management or in the specific loop/workspace subsystem that owns repo-local workflow state.

Contributor guide

Open the contributing guide

Research direction

Start by locating the repo-local loop state management and the existing status, update, list, and activation command entry points. Inspect how .gstack/current.json and .gstack/STATE.md are read or written, then define the session-aware behavior and migration compatibility against the listed acceptance criteria.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.