Skip to content

feat(bots): always-on bots you can chat with from web and mobile - #21

Open
vkpdeveloper wants to merge 40 commits into
mainfrom
feat/bots
Open

vkpdeveloper wants to merge 40 commits into
mainfrom
feat/bots

Conversation

@vkpdeveloper

@vkpdeveloper vkpdeveloper commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

I wanted always-on assistants like Grok's bots: give one a name, a face, a model and a machine, then just talk to it from web or my phone. Today every chat is a throwaway thread tied to a repo, so there was no place for that.

A bot is now a project with one long-lived session on the computer you pick. Create it from the Bots sidebar (web) or the new Bots tab (mobile, replaces Usage, which moves into Settings).

Bots sidebar / Bots tab
  New bot  -> createBot RPC -> project (kind: bot) + its single thread on the chosen computer
  Bot chat -> normal turn pipeline, bot header (face + name), no git / New task
  Details  -> Details | Artifacts (folders, file icons, download) | Computer
  Replies  -> mobile push with the final reply text
  • Server: createBot is retry-safe and cleans up on failure. Migration 078_ProjectionProjectBot stores the avatar and model.
  • Client runtime: shared bot list state, avatar shapes and colours, and the commands. The list shows each bot's last message and unread replies.
  • Web: Grok-style sidebar, a bot page, a New bot dialog using the composer model picker, and animated avatars that blink and glance. The Artifacts tab browses the bot's folders and downloads files to Downloads.
  • Mobile: Bots tab, New bot form with avatar, model and machine pickers, a bot details sheet, and push notifications for bot replies.

New bot form
Bot artifacts tab

Note: a bot can only be created on a computer running this build. Older servers lack the createBot RPC and fail with "An error occurred".

Validation: vp run check:changed passes (format, lint, knip, typecheck, tests, React Compiler). Tested in the web app at desktop and phone widths, and on Android.

A bot is a project rooted at <T3 home>/bots/<name> whose bot record holds
its session thread, avatar and description. BotService creates the folder
(AGENTS.md, artifacts/, its own git repo), launches the session in
full-access with auto-settle off, and edits, deletes and generates avatars
through Codex image generation. The bot's agent sets its own description
with the t3_bot_update MCP tool.
A retried create returns the bot it already made. Failure or interruption
after the folder is claimed deletes only this attempt's project and then
its folder. git init failures fail the create. Generated avatars must
resolve inside the Codex instance's generated_images directory.
Bot projects and every thread inside them leave the project and thread
lists but stay reachable by id. A shared bot list orders bots by latest
activity and marks replies the user has not opened as unread.
A Bots button in the sidebar footer switches the sidebar to a chat-style
bot list (avatar, name, last reply, unread dot, newest first). The button
shows the avatar of a bot with an unread reply. New bots pick a shape and
color, a connected computer, and a model with reasoning.
A bot's session shows its avatar, name, and Details, Artifacts, and
Computer tabs in place of the workspace controls. The avatar can be
redrawn from shapes and colors or generated with Codex when it is set
up. Routines are the session's scheduled tasks.
Concurrent retries of one create now return a single bot, the bot folder
cleanup is armed atomically with the claim, and the CLI Codex snapshot
reports its homes so generated avatars can be read.
The model picker hides its Runtime row when the caller has no runtime
mode, since creating a bot takes only a model selection.
Tabs are now Threads, Bots, PRs and Settings. Usage stays reachable from
Settings. The Bots list opens a bot's chat in the detail column, and bot
chats are kept out of the Threads tab's remembered selection and the
archive.
Edit the avatar (or generate one when Codex is ready), rename, describe,
open artifacts, toggle routines, see the machine, and delete the bot.
Back from a bot chat on Android returns to the Bots tab.
Switching the sidebar to Bots opens the newest bot, or a create form when
there are none, instead of leaving a new thread draft in view. The create
form keeps the chosen computer, picks a new request id after a definite
failure, and cannot be dismissed mid-create.
Every avatar shape gets a face that blinks on hover, and one shared timer
blinks a random avatar every few seconds so idle avatars never repaint.
The bots sidebar gets round search and new bot buttons and roomier rows,
and opening /bots directly shows the bots sidebar.
Rebased onto main: provide the bot service to main's newer server test
layers, add the bot migration to the expected list, and raise the MCP
tool budget for t3_bot_update. The new bot form now uses the composer's
model picker, with the reasoning column and speed footer; permissions
are left out because bots always run with full access.
Same eye positions as web, from the shared avatar resolver. One shared
timer closes a single avatar's eyes every few seconds, so a list never
runs an animation per row. Reduced motion turns blinking off.
Polygon shapes get rounded corners. Avatars now look around with a
pseudo 3D head turn (body tilt, face slide and squash), rest in a three
quarter pose in the picker grid and face front when picked, and spring in
from a side when the shape or color changes. All motion is one-shot from
one shared timer, and reduced motion turns it off.
The Bots page redirected to the newest bot as soon as it appeared, which
can happen before its launch finishes. A failed launch then left the user
on a missing thread without the form. The page now waits while creating.
With columns on iOS, opening a bot's chat replaced the chat or draft the
Threads tab remembered, and the check that rejects bot chats then left
Threads on an empty detail column. Bot chats are no longer recorded as the
Threads selection.
A timer blink set while hover already ran the same animation never
restarted, so animationend never cleared it and that avatar stopped
moving for good. The motion flag now clears on a timer matching the CSS
durations.
Thread shells carry no message text, so the bots list always showed an
empty preview and never marked a reply unread. A bots.previews query
returns each bot's newest visible message and refetches only when a bot
gets a new message or finishes a run. Unread now follows the thread rule:
a run finished after the user last opened the chat.
The transcript hides both, so the list kept showing text the chat no
longer had after a checkpoint restore or a cancelled queued message.
Artifacts showed only top-level files and stayed stale until reopened.
Folders now expand in place and every open folder re-reads after a run
finishes. Quick avatar picks build on the newest pick, so a color picked
right after a shape no longer undoes the shape. Image generation needs
Codex ready, not just installed.
The outbox looked up a queued message's thread in the thread lists,
which leave out bot chats. Once the environment's list was current it
read the bot thread as deleted and discarded the message unsent. Lookups
now go by thread id.
A bot has no repository and its chat is its only thread, so the header
no longer offers git controls or New task there. Generating an avatar
takes an optional idea, like web, and quick shape and color picks build
on each other instead of undoing one another.
A save can return before the project update arrives, so dropping the
local pick on success briefly restored the old avatar and the next pick
saved over it. The pick now stays until the bot's avatar moves off the
one it was picked over. A folder reopened within the cache window kept
a listing from before the latest run; it now re-reads once when its
listing is older than that run.
The robot glyph read as clip art. Bots now use a round face with pill
eyes on the web sidebar and the Android and iOS tab bars (outline when
unselected on iOS, filled when selected). The empty Bots list centers
its New bot button under the message.
… its name

The chat header showed the bot's name twice next to a project icon. Bot
chats now show the bot's avatar and name once, on web and mobile.

Bot details no longer lists the folder. Delete bot opens a dialog that
stays locked until the bot's name is typed, and its copy now says files
stay on disk, which is what the server does.
At phone width the chat header's controls float over the sidebar sheet's
top row, covering Search and New bot. On phones those actions now sit in
a row below it, like the threads sidebar.

Bot list previews showed raw Markdown, such as a link's local path, which
pushed the useful text out of view. Previews now show the rendered text.
A finished bot reply sent the same push as any finished task: the bot's
name over "Done: <bot name>". Bots are chats, so the push should read
like one.

For a bot's completed run, the server now attaches a plain-text preview
of the reply to the activity it publishes, and the relay uses it as the
push body. Other threads and phases are unchanged. The field is
optional, so older servers and relays keep their current behavior.

The Markdown stripping used for bot list previews moves to shared so the
list and the push read the same text.
Subagent threads share their parent's project, so a bot's subagents
showed the bot's name and lost their own title and breadcrumb. The bot
header now applies only to the thread the bot owns.

Delete bot also follows the delete permission, like mobile does.
Code spans lost their backticks before emphasis stripping, so names like
__init__.py lost underscores. Links with parentheses in the URL or
brackets in the text were left half stripped. Code spans now keep their
contents, links allow one level of nesting, and only the start of a
reply is scanned since previews are short.
…alone

Providers can finalize several messages in a run with one timestamp, so
the push could show an earlier progress note instead of the final reply.
The server now picks the reply by turn order.

Live Activity rows carried the reply text too, which the widget never
shows, and on tight payloads it pushed rows out of the 4 KB budget.
Live Activity content now omits it.
The Bots tab change dropped the prop that Settings' split pane and sidebar
pass, which broke the mobile typecheck.
throw and finally inside the handler made React Compiler skip ArtifactFile.
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Nov 2, 2026
An error with an empty message skipped the toast.
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for cd6ac93.

This comment will update automatically after the next completed run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant