Fix child relationship handling (#8)

* Fix child relationship handling

* Fix: Remove automatic dependency creation in createSubtask()

Parent-child relationships are hierarchical via ID structure only.
The server was incorrectly creating blocking dependencies between
parent and child beads, causing children to block parents.

---------

Co-authored-by: Levi Neely <lkn@darkstar.example.net>
This commit is contained in:
Levi Neely 2026-02-22 16:22:17 +01:00 committed by GitHub
parent db501cca26
commit bb721c0429
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 24 additions and 23 deletions

View File

@ -43,7 +43,8 @@ Workflow:
4. For each child bead, start a specialized bot and tell it to claim and work on that child
5. Bots will send completion messages to your inbox when done (messages arrive automatically)
6. When a bot notifies you it's done, acknowledge and shut down that bot
7. When ALL children are complete, mark your parent bead complete
7. Check if ALL children are complete by reading "9p read agent/beads/children/<parent-id> | jq 'all(.status == \"closed\")'"
8. Only mark the parent bead complete when all children have status==closed
Core skills: beads, anvillm-communication

View File

@ -317,13 +317,13 @@ func (b *BeadsFS) readBeadProperty(beadID, property string) ([]byte, error) {
}
func (b *BeadsFS) getBlockers(id string) ([]string, error) {
deps, err := b.store.GetDependencies(b.ctx, id)
deps, err := b.store.GetDependenciesWithMetadata(b.ctx, id)
if err != nil {
return nil, err
}
var blockers []string
for _, dep := range deps {
if dep.Status != bd.StatusClosed {
if dep.DependencyType == bd.DepBlocks && dep.Status != bd.StatusClosed {
blockers = append(blockers, dep.ID)
}
}
@ -503,22 +503,7 @@ func (b *BeadsFS) createSubtask(parentID, title, description, actor string) erro
Priority: 2,
}
if err := b.store.CreateIssue(b.ctx, issue, actor); err != nil {
return err
}
// Add parent-child dependency (parent is blocked by child)
dep := &bd.Dependency{
IssueID: parentID,
DependsOnID: childID,
Type: bd.DepParentChild,
}
if err := b.store.AddDependency(b.ctx, dep, actor); err != nil {
// Issue created but dep failed - not fatal
return nil
}
return nil
return b.store.CreateIssue(b.ctx, issue, actor)
}
func parseCtlCommand(cmd string) (string, []string, error) {

View File

@ -96,10 +96,25 @@ echo "new 'Write tests' 'Add test coverage' bd-abc" | 9p write agent/beads/ctl
```
### Checking Blockers
Read the blockers field to see what's blocking a bead:
Read the blockers field to see explicit dependencies blocking a bead:
```bash
9p read agent/beads/bd-abc/json | jq .blockers
# Output: ["bd-abc.1", "bd-abc.2"]
9p read agent/beads/bd-xyz/json | jq .blockers
# Output: ["bd-abc"] - only shows explicit dependencies added via "dep" command
```
**Important**: The blockers field only contains beads added as explicit dependencies using `echo "dep <child> <parent>" | 9p write agent/beads/ctl`. Child beads do NOT appear in the parent's blockers field.
### Checking Outstanding Child Work
To determine if a parent bead has incomplete child tasks, query the children endpoint and filter by status:
```bash
# Get all non-closed children of bd-abc
9p read agent/beads/children/bd-abc | jq '[.[] | select(.status != "closed")]'
# Count open children
9p read agent/beads/children/bd-abc | jq '[.[] | select(.status != "closed")] | length'
# Check if any children remain open
9p read agent/beads/children/bd-abc | jq 'any(.status != "closed")'
```
### Recommended Workflow
@ -146,7 +161,7 @@ Each bead JSON contains:
"priority": 2,
"issue_type": "task",
"assignee": "agent-123",
"blockers": ["bd-abc.1", "bd-abc.2"],
"blockers": [],
"created_at": "2026-02-20T21:00:00Z",
"updated_at": "2026-02-20T21:30:00Z"
}