Skip to content

bug: exec beads provider ignores store identity on CRUD operations, breaking K8s multi-prefix #391

@stuartparmenter

Description

@stuartparmenter

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")

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugBroken behaviorpriority/p2Medium — real problem, workaround existsstatus/acceptedConfirmed and on our radar

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions