Repository navigation
tree: cannot move a bot to a new parent; bots skipped by maxChildren never rejoin #635
Copy link
Copy link
Closed
Labels
area:automationScheduled tasks and automationScheduled tasks and automationbugSomething isn't workingSomething isn't working
Description
Summary
The bot tree cannot be reorganised. A bot's parent is fixed when it is created; there is no reparent/move operation. Separately, bots skipped by maxChildren never rejoin the tree even after a slot frees up.
What happens today
create_child_botalways creates a new bot under the caller. No tool, API or UI action changes an existing bot's parent, so the only way to reorganise a team is to delete bots and create them again — which loses their conversations.adoptUnattachedruns at startup, a few retries, and onbot.created. When the root is already atmaxChildren, new bots are created withoutfields['flybot-tree']and stay outside the tree permanently; deleting a child to free a slot does not re-adopt them.- A bot outside the tree has no tree tools (
visibleTo = tree.isMember):list_childrenandcreate_child_botboth return... is not available to this Bot.
Steps to reproduce
- Fill the root to
maxChildren(8 children). - Create another bot from the roster.
- Its record has no
fields['flybot-tree']; callingcreate_child_botas that bot returnscreate_child_bot is not available to this Bot. - Delete one of the root's children to free a slot.
- The bot is still outside the tree; no re-adoption happens.
- With any team, try to move an existing bot under another parent: no tool or API exists.
Expected
- A
move_bot({ bot, parent })tool (Main Bot only, or the bot's current parent), validating: no cycle,maxDepth,maxChildren, sibling name collisions. After a move, refresh the prompt/trace of the moved subtree. A no-op (same parent) is refused or ignored. - Re-run adoption when a slot frees (
bot.removed, or anensureRootpass), so bots left outside only because the root was full join as soon as there is room. - Deleting a bot already re-attaches its children to its parent, so a sideways move is the missing counterpart.
Where
plugins/tree/src/tree.js—createChild,adoptUnattached,onBotRemovedplugins/tree/src/tools.js—registerTreeToolsplugins/tree/README.md— document the new tool and the adoption triggerplugins/tree/test/tree.test.js— tests for move and re-adoption
Acceptance
- New tests cover: move within limits; refuse a move that exceeds
maxChildren/maxDepthor creates a cycle; moved bot keeps its subtree and gets a fresh prompt; a bot outside the tree is adopted after a slot frees. - No behaviour change for teams under the limit.
Diagnostics
Observed on a local bench, 2026-10-21. Tree limits: maxDepth=5, maxChildren=8. Two bots created while the root was full had no fields['flybot-tree'] and got create_child_bot is not available to this Bot. No keys, tokens or personal data are included; the repro is structural, so there is no screenshot to attach.
Metadata
Metadata
Assignees
Labels
area:automationScheduled tasks and automationScheduled tasks and automationbugSomething isn't workingSomething isn't working
Activity
Birfy commentedon Oct 21, 2026
Written-by: Triage
Triage: labelled
bug+area:automation(a missing operation in the tree tool layer, not a UI-only gap).Scope confirmed reproducible from the description:
create_child_botalways creates a new Bot, so an existing Bot's parent cannot change, and a Bot skipped bymaxChildrennever rejoins after a slot frees up. Two behaviours, one root cause (the tree is only ever appended to).Carried by PR #636 (
move_bot+ adoption re-run), so this stays off theagent-readylist to avoid a second implementation; the acceptance question for review is whethermove_botrefuses the four cases named there (cycle,maxChildren, duplicate sibling name,maxDepth) and whether adoption re-runs on slot release.hsliuustc0106 commentedon Oct 21, 2026
Live occurrence on a real team (2026-10-21), in addition to the bench repro in the body. Same root cause; this one shows the user-visible blast radius and the only recovery path.
Sequence:
maxChildren(8).adoptUnattachedand got nofields['flybot-tree'].create_child_botandlist_childrenboth returned... is not available to this Bot(visibleTo = tree.isMember).bot.removedonly re-attaches the deleted Bot's children. They stayed outside the tree.Expected from the owner's side: every Bot should be able to create child Bots. A Bot must not end up permanently outside the tree just because the root was full at its creation time, and freeing a slot should be enough to bring it in without a restart.
PR #636's re-adoption after
bot.removedwould have fixed step 4, which is the step that turned a transient skip into a stuck team.tree: add move_bot for reorganising an existing tree
tree: add move_bot for reorganising an existing tree
Keep a freed tree slot usable, and finish the #635 checks
Birfy commentedon Oct 22, 2026
Claimed for the missing half, and #636 kept as this issue's only pull request.
What was still missing on #636. The branch implemented
move_bot, but not the second Expected bullet of this issue, and its README said so out loud: "A freed slot does not pull anyone back up."adoptUnattachedonly ran at startup and onbot.created, so a Bot kept outside because a level was full never joined after a deletion — the live case recorded above.What I pushed to
fix/tree-move-bot-635(tip2787ef883aee27716466e38cd5652b0690bf6524, on top of the author's8ae2940b; the author's commit is untouched):plugins/tree/src/tree.js:onBotRemovedre-attaches the deleted Bot's children as before, then re-runsadoptUnattachedon the current root, so a freed slot is used without a restart; a Bot that still fits nowhere stays outside, logged, and is retried.plugins/tree/test/tree.test.js:#635: a Bot left outside because the tree was full joins when a deletion frees a slot— withmaxChildren: 1and a full root the Bot stays out; after deleting the only child it is under the root.plugins/tree/src/tools.js:move_botno longer destructures a caller id it does not use — that unused parameter was theplugins (tree)lint failure on the branch.docs/subsystems/tree.md: a section onmove_bot, on the deletion-triggered adoption and on these tests — thearch-docsfailure, sinceplugins/tree/is an owned path.plugins/tree/README.md: the "freed slot" sentence now says what the code does.Evidence.
plugins/tree/test/tree.test.js81/81; removing only the new adoption call → 80/81, red exactly the new case; restored → 81/81. The other two reds were reproduced from the CI job logs:Parameter 'botId' is declared but never used(lint) andarch-docs: owned file(s) changed without subsystem doc update. I could not run oxlint orhost.test.jslocally (nocore/node_modules/ harness install on this box), so CI is the check for those.test(tree): exercise the move_bot depth limit (#678)
test(tree): exercise the move_bot depth limit (#678)
Birfy commentedon Oct 22, 2026
Closing as completed: both Expected bullets are now on main.
move_botships inplugins/tree/src/tools.js(name: 'move_bot') via PR tree: add move_bot for reorganising an existing tree #636 (2787ef88, merged 2026-10-22T05:00:27Z).maxChildrenrejoining once a slot frees up is on main inplugins/tree/src/tree.js:onBotRemovedcallsadoptUnattached(chief.id)afterorganizer.repair(), and pending adoptions are caught and logged instead of becoming unhandled rejections.Coverage landed with it:
plugins (tree)tests-okwas green at the tip for both the move path and the re-adoption path.Two defects found while reviewing #636 are filed separately and stay open: #677 (
heightOfhas no cycle guard) and #678 (maxDepthhad no case).tree: add move_bot for reorganising an existing tree (ThinkFlowLab#636)
test(tree): exercise the move_bot depth limit (ThinkFlowLab#678) (Thi…