@@ -161,9 +161,10 @@ func cleanBeadsRuntimeFiles(beadsDir string) {
161161// - worktreePath: the worktree directory (e.g., <rig>/crew/<name> or <rig>/refinery/rig)
162162//
163163// The function:
164- // 1. Computes the relative path from worktree to rig-level .beads
165- // 2. Cleans up runtime files (preserving tracked files like formulas/)
166- // 3. Creates the redirect file
164+ // 1. Finds the canonical beads location (rig/.beads or mayor/rig/.beads)
165+ // 2. Computes the relative path from worktree to that location
166+ // 3. Cleans up runtime files (preserving tracked files like formulas/)
167+ // 4. Creates the redirect file
167168//
168169// Safety: This function refuses to create redirects in the canonical beads location
169170// (mayor/rig) to prevent circular redirect chains.
@@ -186,10 +187,47 @@ func SetupRedirect(townRoot, worktreePath string) error {
186187 }
187188
188189 rigRoot := filepath .Join (townRoot , parts [0 ])
190+
191+ // Find the canonical beads location. In order of preference:
192+ // 1. rig/.beads (if it exists and has content or a redirect)
193+ // 2. mayor/rig/.beads (tracked beads architecture)
194+ //
195+ // The tracked beads architecture stores the actual database in mayor/rig/.beads
196+ // and may not have a rig/.beads directory at all.
189197 rigBeadsPath := filepath .Join (rigRoot , ".beads" )
198+ mayorBeadsPath := filepath .Join (rigRoot , "mayor" , "rig" , ".beads" )
190199
191- if _ , err := os .Stat (rigBeadsPath ); os .IsNotExist (err ) {
192- return fmt .Errorf ("no rig .beads found at %s" , rigBeadsPath )
200+ // Compute depth for relative paths
201+ // e.g., crew/<name> (depth 2) -> ../../
202+ // refinery/rig (depth 2) -> ../../
203+ depth := len (parts ) - 1 // subtract 1 for rig name itself
204+ upPath := strings .Repeat ("../" , depth )
205+
206+ var redirectPath string
207+
208+ // Check if rig-level .beads exists
209+ if _ , err := os .Stat (rigBeadsPath ); err == nil {
210+ // rig/.beads exists - check if it has a redirect to follow
211+ rigRedirectPath := filepath .Join (rigBeadsPath , "redirect" )
212+ if data , err := os .ReadFile (rigRedirectPath ); err == nil {
213+ rigRedirectTarget := strings .TrimSpace (string (data ))
214+ if rigRedirectTarget != "" {
215+ // Rig has redirect (e.g., "mayor/rig/.beads" for tracked beads).
216+ // Redirect worktree directly to the final destination.
217+ redirectPath = upPath + rigRedirectTarget
218+ }
219+ }
220+ // If no redirect in rig/.beads, point directly to rig/.beads
221+ if redirectPath == "" {
222+ redirectPath = upPath + ".beads"
223+ }
224+ } else if _ , err := os .Stat (mayorBeadsPath ); err == nil {
225+ // No rig/.beads but mayor/rig/.beads exists (tracked beads architecture).
226+ // Point directly to mayor/rig/.beads.
227+ redirectPath = upPath + "mayor/rig/.beads"
228+ } else {
229+ // Neither location exists - this is an error
230+ return fmt .Errorf ("no beads found at %s or %s" , rigBeadsPath , mayorBeadsPath )
193231 }
194232
195233 // Clean up runtime files in .beads/ but preserve tracked files (formulas/, README.md, etc.)
@@ -201,25 +239,6 @@ func SetupRedirect(townRoot, worktreePath string) error {
201239 return fmt .Errorf ("creating .beads dir: %w" , err )
202240 }
203241
204- // Compute relative path from worktree to rig root
205- // e.g., crew/<name> (depth 2) -> ../../.beads
206- // refinery/rig (depth 2) -> ../../.beads
207- depth := len (parts ) - 1 // subtract 1 for rig name itself
208- redirectPath := strings .Repeat ("../" , depth ) + ".beads"
209-
210- // Check if rig-level beads has a redirect (tracked beads case).
211- // If so, redirect directly to the final destination to avoid chains.
212- // The bd CLI doesn't support redirect chains, so we must skip intermediate hops.
213- rigRedirectPath := filepath .Join (rigBeadsPath , "redirect" )
214- if data , err := os .ReadFile (rigRedirectPath ); err == nil {
215- rigRedirectTarget := strings .TrimSpace (string (data ))
216- if rigRedirectTarget != "" {
217- // Rig has redirect (e.g., "mayor/rig/.beads" for tracked beads).
218- // Redirect worktree directly to the final destination.
219- redirectPath = strings .Repeat ("../" , depth ) + rigRedirectTarget
220- }
221- }
222-
223242 // Create redirect file
224243 redirectFile := filepath .Join (worktreeBeadsDir , "redirect" )
225244 if err := os .WriteFile (redirectFile , []byte (redirectPath + "\n " ), 0644 ); err != nil {
0 commit comments