Skip to content

S16: persistent Bots from exact proposals and bounded Bot-to-Bot delegation - #447

Merged
chayapats merged 4 commits into
mainfrom
jit/412-413-s16-bots
Nov 7, 2026
Merged

chayapats merged 4 commits into
mainfrom
jit/412-413-s16-bots

Conversation

@chayapats

Copy link
Copy Markdown
Owner

Closes #412
Closes #413
Refs #392

What

Behind explicit bots: true (set by the generated installer), following the owner's 2026-11-07 decisions:

  • Persistent Bots (BOT16-01). A protected Bot directory (bots.sqlite) holds profiles, exact proposals and immutable conversation-to-Bot bindings. A Bot is created only by one-press acceptance of an exact proposal (proposalHash binds the draft, the policy revision and the listed team resources) from the New Bot form or from the chat card the main Bot drafts with propose_bot. Acceptance installs one standing-policy revision that adds the Bot to every team rule naming the main Bot (team defaults); exclusions are refused by the catalog allows.
  • POLICY: membership-only revisions keep running work. A work stays current across a newer revision that differs only in other Bots' references; any change to the work's own Bot memberships or other fields, or an unchanged reinstall, is still stale_authority.
  • One conversation, one Bot, with its route (from approved routes only), owner-confirmed responsibility and exclusions.
  • Archive / restore. Archive marks the catalog identity inactive first, then stops unfinished work, pauses routines and refuses new messages/routines/assignments (bot_archived). Restore reactivates the same identity, so history and sourced memory return; nothing revoked resumes. The main Bot cannot be archived.
  • Duplicate / export / import copy configuration only (no history, memory, files, computer or credentials), each as a new proposal; import lists references this installation lacks.
  • Delegation (DELEG16-01). delegate hands up to 3 assignments to active peers that accept assignments or to a temporary worker (the assigning Bot, not kept). Children run inside the parent's frozen purpose/resources/access with a slice charged to the parent (never refunded; 6 per request, 3 unfinished), without interpretation, memory or further delegation, in their own drain pool sized to the computer's free sessions. Bot-private context refuses a peer (private_context); before every child model send the TEAM handoff from the still-current parent and DATA15 ancestry are checked. Stopping a parent stops its children; stopping one child keeps siblings.
  • Client. s16-client-bots/v1 API, Bots pages, rail roster, "Talk to" for a new chat, proposal card, child cards and assignment banner, in English and Thai.

Decision record: ADR 0088; contract: s16-bots/v1.

Evidence (tested head db904898b41fe199de444321bec16a546ba2c73b)

  • bun run typecheck, git diff --check: pass.
  • bun test tests/s16-bots.test.ts: 10 pass — exact proposal/stale acceptance, team defaults and unchanged other fields, running work kept across the install, per-conversation Bot/route/persona, excluded resource refused, archive during work stops it and fences sends, restore + restart keeps history, duplicate/export/import, peer + temporary results with budget exhaustion, independent child stop with no double attach/charge after restart, private ancestry refused for a peer, withdrawn task source refuses the child's next send, default-policy renewal keeps Bots, POLICY narrowing still stale, interrupted acceptance retry.
  • Focused regressions (23 files incl. S15 composition/conversation/policy/team/memory/first-run/installer and S16 client/computers/routines/steering/notifications/files): 392 pass.
  • JIT_S16_BROWSER_TESTS=1 real-bundle suites (9 files, 28 tests) incl. new tests/s16-bots.browser.test.ts at 1440 (English) and 390 (Thai): all pass; s16-memory.browser failed once under parallel load and passed twice alone.

Pending / limits

…t delegation

BOT16-01 and DELEG16-01 behind explicit bots: true (set by the generated installer):
- protected Bot directory (bots.sqlite): profiles, exact proposals bound to the
  policy revision and team resources, immutable conversation-to-Bot bindings
- one-press acceptance installs a standing-policy revision that adds the Bot to
  every team rule naming the main Bot; POLICY keeps running work across a
  revision that only changes other Bots' membership
- one Bot per conversation with its route, responsibility and excluded resources
- archive fences the Bot's catalog identity, stops its unfinished work, pauses
  its routines and refuses new messages; restore reactivates the same identity
- credential-free duplicate, export and import, each as a new proposal
- delegate tool: peer and temporary assignments inside the parent's frozen scope,
  slices charged to the parent, own drain pool, TEAM handoff and DATA15 ancestry
  checked before every child send; stop cascades from parent to children
- main Bot's propose_bot tool drafts an inert proposal card in the chat
- s16-client-bots/v1 owner API and React Bots pages, roster, Talk to choice,
  proposal and child cards in English and Thai

Closes #412
Closes #413
Adds ADR 0088, the s16-bots/v1 contract summary, CONTEXT terms for persistent
Bots, proposals and temporary workers, and marks BOT16-01/DELEG16-01 as
implemented-deterministic in the S16 roadmap and coverage index.
@greptile-apps

greptile-apps Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The fixes appear safe to merge; the remaining main Bot conversation-list issue is non-blocking.

Findings

  1. P2 Main Bot conversations are missing ▶
Fix with agent prompt
### Issue 1
src/s16/bots/service.ts:undefined-140
The main Bot's detail page never lists its ordinary conversations. `detail` reads only explicit bindings, while main-Bot conversations intentionally stay unbound-even `conversation.bind` returns without inserting one for the main Bot. Include unbound conversations when building the main Bot's recent list.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The fixes in c6b00bb1 tighten Bot lifecycle recovery, route selection and delegation scheduling.

  • Owners create Bots from reviewed proposals and manage them in S16.
  • Bots can hand bounded tasks to peers or temporary helpers.
  • Other Bots can join policy rules without stopping current work.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Archive Bot] --> B[Mark inactive and save cleanup marker]
  B --> C[Stop unfinished work]
  C --> D[Pause active routines]
  D --> E[Clear marker and save receipt]
  F[Retry archive] --> C
  G[Restore Bot] --> H{Cleanup pending?}
  H -->|Yes| C
  H -->|No| I[Reactivate same identity]
  D -->|Restore path| I
Loading

Reviews (2) · Last reviewed commit: "fix(s16): address BOT16/DELEG16 review f..." · Reviewed by Greptile

Comment thread src/s15/policy/service.ts Resolved
Comment thread src/s16/bots/service.ts Resolved
Comment thread src/s16/bots/service.ts Resolved
Comment thread src/s16/bots/service.ts Resolved
Comment thread src/s15/composition.ts Resolved
Comment thread src/s16/web/app.tsx Resolved
Comment thread src/s16/web/app.tsx Resolved
Comment thread src/s16/bots/service.ts Resolved
Comment thread src/s16/bots/service.ts Resolved
Comment thread src/s16/bots/service.ts Outdated
detail(owner: Owner, botId: string): BotDetail {
this.#owner(owner); const record = this.profile(botId);
if (!record || !this.#bots(owner).some(r => r.id === botId)) throw new AppError("not_found", 404);
return { contract: "s16-client-bot/v1", bot: this.#view(record, this.options.selections(owner)), conversations: this.options.conversations.recent(owner, this.boundConversations(botId)).slice(0, 32), impact: this.impact(owner, botId) };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Main Bot conversations are missing

The main Bot's detail page never lists its ordinary conversations. detail reads only explicit bindings, while main-Bot conversations intentionally stay unbound—even conversation.bind returns without inserting one for the main Bot. Include unbound conversations when building the main Bot's recent list.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/s16/bots/service.ts
Line: 140

Comment:
**Main Bot conversations are missing**

The main Bot's detail page never lists its ordinary conversations. `detail` reads only explicit bindings, while main-Bot conversations intentionally stay unbound—even `conversation.bind` returns without inserting one for the main Bot. Include unbound conversations when building the main Bot's recent list.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c6b00bb: the main Bot's detail lists recent top-level conversations whose Bot resolves to it. Test added.

- POLICY: a work stays current only when every revision since its own is a
  membership-only change; an intervening reinstall keeps it stale
- Bot commands commit their change and receipt together; an interrupted
  archive keeps its request ID until stops and routine pauses finish, and its
  retry or a restore finishes them over all of the Bot's conversations
- interpretation uses the conversation Bot's route; a temporary worker keeps
  its parent work's route in the pin
- children run only in computer sessions no ordinary request may hold; a new
  assignment refuses capacity_busy when none is free
- pending proposals are filtered before the page bound; the main Bot page lists
  its unbound conversations and its export carries a usable name
- the client holds one send lock through the Bot binding and binds the chosen
  Bot before opening a routine
@chayapats

Copy link
Copy Markdown
Owner Author

@greptileai review the fixes in c6b00bb

@chayapats
chayapats merged commit e4740f0 into main Nov 7, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant