Problem
The exec beads provider (internal/beads/exec/exec.go) does not pass any store identity (directory, prefix, or BEADS_DIR) on CRUD operations (create, list, list-by-label, get, update, close). Only the init lifecycle operation receives dir and prefix arguments.
This means openRigStore and openCityStoreAt in api_state.go create identical exec.Store instances for both the city store and rig stores — same script, same env. The rigPath parameter is completely ignored for exec providers (line 174-178):
func (cs *controllerState) openRigStore(provider, rigPath string) beads.Store {
if strings.HasPrefix(provider, "exec:") {
s := beadsexec.NewStore(strings.TrimPrefix(provider, "exec:"))
s.SetEnv(citylayout.CityRuntimeEnvMap(cs.cityPath)) // no BEADS_DIR, no prefix
return s
}
Compare with the bd provider path in bdRuntimeEnvForRig (bd_env.go:49) which properly sets BEADS_DIR, GC_RIG_ROOT, and GC_RIG.
How it manifests
In a K8s deployment using GC_BEADS=exec:gc-beads-k8s, the beads runner pod has a single working directory with one active issue_prefix. During startBeadsLifecycle, initAndHookDir is called for the HQ (e.g., prefix "el") then each rig (e.g., prefix "gk"). Each gc-beads-k8s init call runs bd config set issue_prefix, so the last rig's prefix wins.
All subsequent CRUD operations — including session bead creation via cityBeadStore() — hit the runner with the rig prefix active. Session beads get the wrong prefix (e.g., gk- instead of el-), and the controller immediately orphans them on the next tick because they don't match expectations. This creates a create→orphan loop that generates hundreds of zombie beads.
Introduced by
PR #184 (feat: add explicit workspace prefix for HQ beads, merged 2026-03-29) introduced per-workspace HQ prefixes and updated startBeadsLifecycle to init each store with its own prefix. The exec beads protocol and gc-beads-k8s were not updated to handle multiple prefixes on data operations.
Related issues
Suggested fix
Have the exec.Store carry a GC_BEADS_PREFIX env var (set by openRigStore/openCityStoreAt) so every CRUD call tells the script which store to target. gc-beads-k8s would read this var and run bd config set issue_prefix before each operation (or maintain per-prefix working directories).
This mirrors how the local BdStore scopes each command to a directory via cmd.Dir and BEADS_DIR.
Environment
- Gas City HEAD (db4ada7, post-v0.13.4)
- Docker Desktop Kubernetes on WSL2
GC_BEADS=exec:gc-beads-k8s
- City with 1 rig (HQ prefix "el", rig prefix "gk")
Problem
The exec beads provider (
internal/beads/exec/exec.go) does not pass any store identity (directory, prefix, orBEADS_DIR) on CRUD operations (create,list,list-by-label,get,update,close). Only theinitlifecycle operation receivesdirandprefixarguments.This means
openRigStoreandopenCityStoreAtinapi_state.gocreate identicalexec.Storeinstances for both the city store and rig stores — same script, same env. TherigPathparameter is completely ignored for exec providers (line 174-178):Compare with the bd provider path in
bdRuntimeEnvForRig(bd_env.go:49) which properly setsBEADS_DIR,GC_RIG_ROOT, andGC_RIG.How it manifests
In a K8s deployment using
GC_BEADS=exec:gc-beads-k8s, the beads runner pod has a single working directory with one activeissue_prefix. DuringstartBeadsLifecycle,initAndHookDiris called for the HQ (e.g., prefix "el") then each rig (e.g., prefix "gk"). Eachgc-beads-k8s initcall runsbd config set issue_prefix, so the last rig's prefix wins.All subsequent CRUD operations — including session bead creation via
cityBeadStore()— hit the runner with the rig prefix active. Session beads get the wrong prefix (e.g.,gk-instead ofel-), and the controller immediately orphans them on the next tick because they don't match expectations. This creates a create→orphan loop that generates hundreds of zombie beads.Introduced by
PR #184 (feat: add explicit workspace prefix for HQ beads, merged 2026-03-29) introduced per-workspace HQ prefixes and updated
startBeadsLifecycleto init each store with its own prefix. The exec beads protocol andgc-beads-k8swere not updated to handle multiple prefixes on data operations.Related issues
Suggested fix
Have the exec.Store carry a
GC_BEADS_PREFIXenv var (set byopenRigStore/openCityStoreAt) so every CRUD call tells the script which store to target.gc-beads-k8swould read this var and runbd config set issue_prefixbefore each operation (or maintain per-prefix working directories).This mirrors how the local
BdStorescopes each command to a directory viacmd.DirandBEADS_DIR.Environment
GC_BEADS=exec:gc-beads-k8s