| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
Merge remote-tracking branch 'origin/main' into train/nov4-a # Conflicts: # server/drivers/codex.ts | 1 天前 | |
feat(teams): share a whole team (package format v2), extracted importer, Share team dialog (#1763) * feat(format): package format v2 as one shared validation gate shared/package-format.ts is the single reader for openmaus.package files, used by the server, the renderer's import preview and (through the pinned runtime) Admin. It reads v1 (JSON and BotMRR Markdown) and v2 and always returns v2: team brief and Chief, pictures (PNG/JPEG/WebP, magic-checked, 64 KB), starter notes (MEMORY.md and topic files, never daily logs), connection slots (https MCP addresses and header names, never values or commands), presets (allowlist), room goals, release notes and library-only packages. A file cannot claim a publisher (trust "file" drops it). Also: canonicalJson, secret findings and idempotent redaction over every text part with part-path names, the skill scan over every text part, packageKeys/packageSummary, and downgradeToV1 for older apps. Node-free (TextEncoder/atob), so Admin and the renderer run the same code. Fixtures and manifest.json (expected sha256, keys, summary, secret findings, downgrade) live in shared/package-fixtures/ for Admin's tests. SKILL.md parsing moves to shared/skill-md.ts and fitsOnOneLine to shared/bot-profile.ts; the server modules re-export them. GitHub and catalog links may now point at a v2 file. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(teams): share one whole team and import it through one importer POST /api/teams/export with {format:"package", version:2, team} exports one team with everything but its chat history: bots (standing instructions, looks, pictures the dialog prepared), playbooks, skills (SKILL.md only), group chats, routines and group chat goals, the team's shared instructions and Chief, remote MCP connection slots (address + header names, never values) and, when asked, starter notes. Every text part is redacted and the parts are reported; stdio servers, attachments and oversized pictures or notes are listed as skipped; the result is re-validated by the shared parser (4 MB cap). A dryRun counts without recording anything. v1 bodies keep the original whole-installation Markdown export. Keys never come from names once they exist: published-teams.json records the package id, last release and each bot, group chat and routine key by record id, follows team renames and deletes, and the next share suggests the next patch. A team imported from a file keeps that file's package id and bot keys. The import route's body moves into server/package-import.ts (importPackageDocument / importTeamManifest) with a trust argument that no request can set. File imports add every v2 part as new records: brief, leader, pictures, starter notes, rooms, routines (paused), skills (off), connection slots as switched-off MCP servers with empty values bound only to the servers the import created, installedPackage stamps (source, installId, agentKey, suggestedApproval, never applied). Library-only files are refused with a pointer to the organization shelf; any failure rolls back everything created. The org path (skills on, provenance stamps, deterministic installId, idempotent Add) is ready for the wave-2 shelf. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(ui): Share team… dialog and a full preview of shared teams The team menu and a new Templates → Share tab open Share team…: the file's contents counted by the server's own dry run (bots, skills, playbooks, group chats, routines, shared instructions, Chief, connections, pictures, starter notes), a fixed "never included" line, toggles for pictures, starter notes (on by default, with a plain line saying so) and each skill, version (next patch prefilled) and release notes, then Save file. After saving it lists what was redacted or left out. Pictures are downscaled in the renderer to fit 256×256 (WebP, else PNG, 64 KB each, about 2 MB in all). No confirm step. The import preview reads v2 files with the shared parser and shows the shared instructions, each bot's picture, skills (added switched off) and offered skills, paused routines, connection slots to finish, starter notes and presets (not added by this version). The import toast points at Plugins → MCP servers when connections need values. Strings follow docs/localization.md (English source; other packs fall back). A control-omb ui e2e drives the whole flow against a disposable fixture. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(teams): whole-team sharing and its verification recipe Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 1 个月前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Agents tools: delete_trigger on its own, memory_log back, and merged tools name what they were (#3786) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: no remembered allow reaches further; merged tools name what they were An engine that remembers "always allow" by a tool's name must not let one answer cover more than each of the tools that merged did on its own: - delete_trigger is its own tool (manage_trigger's delete). trigger keeps create, update, pause, resume and run_now, and refuses a delete before anything is sent; delete_trigger only ever deletes. - memory_log is its own tool again: inside memory_update, an allow given for a log line would have covered remove and forget. A test holds every action tool to it: each one's furthest call reaches no further than each of its members did alone, and its actions match the table. In a tool selection, manage_trigger still covers deleting. Each merged tool's description now names its old tools, e.g. "(was create_trigger / manage_trigger)", so a model following a saved skill finds it on engines that refuse unlisted names. The aliases move to shared/agents-tool-names.ts, one table for the call path and selection. Goldens regenerated. Every catalog profile stays within 2% of its baseline, so none is raised; every bridged baseline is lowered to the measured bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
fix(engines): one AI ranking for the new-bot default and the welcome A new bot's default and the welcome's recommended sign-in now follow one ranking in shared/ai-ranking.ts: a Claude account, then a ChatGPT plan, then Gemini, then Grok, then every other AI in the app's own order, and OpenCode running only its free no-login models last. The server used to take the first ready engine in config order after Claude, which put Grok, Kimi and Droid ahead of a ChatGPT plan. The selection also takes what each AI's test message showed: an AI that answered beats one that didn't or wasn't tested, and the ranking decides until a test says otherwise. A saved default still wins over everything. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 11 天前 | |
fix(engines): one AI ranking for the new-bot default and the welcome A new bot's default and the welcome's recommended sign-in now follow one ranking in shared/ai-ranking.ts: a Claude account, then a ChatGPT plan, then Gemini, then Grok, then every other AI in the app's own order, and OpenCode running only its free no-login models last. The server used to take the first ready engine in config order after Claude, which put Grok, Kimi and Droid ahead of a ChatGPT plan. The selection also takes what each AI's test message showed: an AI that answered beats one that didn't or wasn't tested, and the ranking decides until a test says otherwise. A saved default still wins over everything. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 11 天前 | |
Chat apps: comments follow main's comment policy Keep only what the code cannot say: the security rules of the app frame (sandbox tokens, CSP, navigation guard, engagement, fences around app text, what never reaches a view or a log), the WebKit, Chromium, Electron, Android WebView and MCP Apps protocol facts, the wire and config doc comments, and the scripts' usage lines. Spec pointers, rule and slice numbers, file pointers, banners and narration go. app-host.html is unchanged (same sha256), so the phone copies need no regeneration. server/index.ts's ratchet drops to its real 18022 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
Smaller agents tool list: compact schemas, action tools, fewer tools where a turn can't use them (#3773) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Chat apps: comments follow main's comment policy Keep only what the code cannot say: the security rules of the app frame (sandbox tokens, CSP, navigation guard, engagement, fences around app text, what never reaches a view or a log), the WebKit, Chromium, Electron, Android WebView and MCP Apps protocol facts, the wire and config doc comments, and the scripts' usage lines. Spec pointers, rule and slice numbers, file pointers, banners and narration go. app-host.html is unchanged (same sha256), so the phone copies need no regeneration. server/index.ts's ratchet drops to its real 18022 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
feat(apps): show_html can show a page without the card frame (#4314) * feat(apps): show_html can show a page without the card frame A bot can pass frameless: true to show_html (or update_html) and the page is drawn as part of the chat, without the rounded card around it. It stays in its sandboxed frame with its title and tools. An update without the option keeps the frame as it was; a frame-only change saves no new version. Default unchanged (framed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(apps): say what frameless does when a page is replaced Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * build(apps): regenerate app-host.html for the frameless option Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Approval level: change it while the bot works (#3627) * Approval level: change it while the bot works Picking a level no longer needs the bot to stop first. The 409s in the bot and thread routes and the busy checks in the desktop's private approval channel are gone, and the composer, the + menu, bot settings, the bot panel and team settings keep the level selectable while a bot works, with one note saying from when it applies. One mechanism: every approval decision OMB makes for a running turn reads the conversation's saved level at that moment (server/host/live-approval.ts), not the copy taken at dispatch. - The chat runtime reads it before each tool call (approvalModeNow), so API engines apply a change at the next call, up or down. - request.opened answers a native engine's permission prompt at the current level, so raising to Full access answers the next prompt. The engine's own mode (bypass, sandbox, native reviewer) is set when the turn starts, so lowering from Full access or moving between Ask, Auto-accept edits and Approve for me applies from the next turn. An open card stays for the person to answer. Delegated and room levels are unchanged. server/index.ts shrinks by 13 lines. Co-authored-by: ohcedar <ohcedar@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Italian: the approval note for a working bot The Italian pack arrived with the old "stop the bot first" string; it now carries the new note, accepted with generate-locale --accept. Co-authored-by: ohcedar <ohcedar@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: ohcedar <ohcedar@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
Merge bringin/2278 into feat/codex-async-questions Both add question rows and helpers in the same places; this carries the two together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
Merge bringin/2278 into feat/codex-async-questions Both add question rows and helpers in the same places; this carries the two together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
A team bot's shared chat says who can really read it "Shared · everyone in Acme can see" was fixed text, so it showed on bots set to Only people added too. Every person's copy of a bot now says when only the people added see it, without naming them, and the chat says "Shared · only people added and admins can see". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
feat: each bot can be an API A per-bot "Bot API", off by default: a key shown once and kept hashed, a curl command in the bot's panel and in Bot settings, and POST <hooks base>/hooks/api/bots/<id>/messages on the webhook receiver that answers with the bot's reply. The turn it starts is outside work (trigger "api"): it never acts for the person, never uses a lent computer, gets the message as untrusted data, and stops at any approval with needs_approval. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 | |
feat(bot-api): not on the Starter plan; answer before a proxy drops the wait On Starter the section is one line and the usual Upgrade, a new key is refused, and a leftover key answers 403 with an upgrade message. An upgrade works at once. The plan comes from the Admin's signed POST /api/cloud/plan, which now also takes a tier, kept by host/cloud-plan-tier.ts; a home never told is not Starter. The default wait drops to 50 s, under the 60 s of silence Fly's proxy is reported to allow. The card says a key is like a password. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 | |
feat: choose white or black mascot facial features (1/4) | 8 天前 | |
MausBot for everyone: a chrome helper with a Chief's tools, never deleted Every place gets MausBot once: a new install's first bot (its Chief of Staff too), and an install that already has bots a MausBot beside them, its Chief untouched. A new install's MausBot from before is adopted (silver turns chrome), and a ledger stops one ever being made twice. On a Team Cloud each member gets their own, private to them, and the team none of its own. - Never deleted or archived: the server refuses both with a plain message. Its menu and bot settings offer Hide, which turns off the new Settings → General switch "Show MausBot in the sidebar". - Chief-level powers through one shared predicate (chiefLevel): Chief tools, team setup, retries, rooms and the level that flows down. It never changes who the Chief is, and the brief, incidents and routing stay with the Chief. A Team User's MausBot holds none. - Moves carry the mark, the switch and the welcome: one MausBot on My Cloud after a move (its unused starter is archived), and on this computer after coming home. - First message: a short intro in the person's language with example asks, and on a new install the setup still to do (AI, bots, apps, phone, Cloud). It is never a Needs-you item. - First launch after onboarding and its tour: a popup to rename, recolour, pick a body or generate a picture, then Add (pinned, flies into the sidebar) or Not now (switch off). Shown once per person and place. - Chrome, a new bot colour: polished chrome-steel finish on the mascot and its swatch, a readable name tone in every skin, in all 12 languages. New bots never draw it in turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
MausBot for everyone: a chrome helper with a Chief's tools, never deleted Every place gets MausBot once: a new install's first bot (its Chief of Staff too), and an install that already has bots a MausBot beside them, its Chief untouched. A new install's MausBot from before is adopted (silver turns chrome), and a ledger stops one ever being made twice. On a Team Cloud each member gets their own, private to them, and the team none of its own. - Never deleted or archived: the server refuses both with a plain message. Its menu and bot settings offer Hide, which turns off the new Settings → General switch "Show MausBot in the sidebar". - Chief-level powers through one shared predicate (chiefLevel): Chief tools, team setup, retries, rooms and the level that flows down. It never changes who the Chief is, and the brief, incidents and routing stay with the Chief. A Team User's MausBot holds none. - Moves carry the mark, the switch and the welcome: one MausBot on My Cloud after a move (its unused starter is archived), and on this computer after coming home. - First message: a short intro in the person's language with example asks, and on a new install the setup still to do (AI, bots, apps, phone, Cloud). It is never a Needs-you item. - First launch after onboarding and its tour: a popup to rename, recolour, pick a body or generate a picture, then Add (pinned, flies into the sidebar) or Not now (switch off). Shown once per person and place. - Chrome, a new bot colour: polished chrome-steel finish on the mascot and its swatch, a readable name tone in every skin, in all 12 languages. New bots never draw it in turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
Starter makes five bots, then offers the upgrade A Starter Cloud makes up to five bots beside its MausBot (STARTER_BOT_LIMIT in server/host/starter-bot-limit.ts). Past that, every way a bot gets made answers 409 {code: "bot_limit", error} in plain words: New bot and Duplicate on desktop, web and phone, templates and file imports, the organization's shelf, and a Chief's create_bot and propose_team_setup. A group that doesn't fit is refused whole, before anything is written. A bot is told to explain it to the person, not to retry or work around it. No bot is ever taken away. A Cloud over the limit keeps every bot; only making a new one stops. A bot arriving with its own id (a move from a computer) and a restored backup are never refused. Archived and moved-away bots take no room. The plan is read at each request, so an upgrade lifts the limit at once with no restart, and a Cloud whose Admin never named a plan has no limit. The app opens a calm popup when a create button is pressed with no room, before any form, and on the server's refusal when its count was stale. It offers the usual in-app upgrade (preview, then the person's confirmation); a browser tab opens the Plan page instead. Config carries botLimit for the page to count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Store the fleet's bot order: PUT /api/bots/order Bots were always listed in creation order and nothing could change it. PUT /api/bots/order { botIds } now reorders store.bots: a stable partial reorder (the listed bots take, in the order given, the positions they already share; the rest stay put), so a phone can reorder one bucket without knowing the whole fleet. The handler accepts only bots the caller sees (the GET /api/bots filter), persists through saveBots, and emits a whole-list change the server broadcasts as { kind: "bots.order", botIds } (narrowed per member). The desktop store applies that frame to state.bots, so the sidebar re-renders in the new order; the route is on the client scope and the companion allowlist so phones can call it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 13 天前 | |
Store the fleet's bot order: PUT /api/bots/order Bots were always listed in creation order and nothing could change it. PUT /api/bots/order { botIds } now reorders store.bots: a stable partial reorder (the listed bots take, in the order given, the positions they already share; the rest stay put), so a phone can reorder one bucket without knowing the whole fleet. The handler accepts only bots the caller sees (the GET /api/bots filter), persists through saveBots, and emits a whole-list change the server broadcasts as { kind: "bots.order", botIds } (narrowed per member). The desktop store applies that frame to state.bots, so the sidebar re-renders in the new order; the route is on the client scope and the companion allowlist so phones can call it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 13 天前 | |
Team Cloud: every bot reports to someone, and each person can have their own Chief A team bot now has an owner: `reportsTo`, else `createdBy` (stamped when a member creates or moves in a bot; a Chief's specialists get the Chief's owner). Its questions, approvals, sign-ins, failures and routine results reach only that person's Needs you, notifications and brief. In a member's private chat they stay that member's alone. Anyone can still chat with any shared bot. - Sidebar: the owner's face ends each team bot's row ("Reports to Bob: questions and reports go to Bob"), clicking it opens the owner picker for an Admin or the current owner; "Reports to Bob…" in the bot menu; "Set owner for all bots…" on a department and "→ Bob" beside it; the selected bot's ⋯ stays visible; a "Needs you" row lists what bots ask of you. - Open cards in a shared chat say "Asking Bob". New Bot in a team says who it is shared with, links to your own place, and asks who it reports to. - One Chief of Staff per person: an owned Chief coordinates exactly the bots its person owns, in every department (roster, coordination, incidents and escalations), and keeps that person's daily brief in their private chat. - Routes: GET /api/team/people, PUT /api/bots/:id/reports-to, PUT /api/team/reports-to, GET /api/needs-you; presence counts members on a team. Desktop and My Cloud are unchanged. The team wiring lives in server/host/team-owners.ts, the department picker moves to SidebarSectionPicker.tsx and the card requester to server/host/thread-person.ts, so index.ts, store.ts, Sidebar.tsx and store.tsx all shrink under their size pins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix(browser, cloud computer): take over after a lost bot call, answer before the proxy gives up, re-claim after a network failure Browser takeover: take() checks once with the engine whether a bot call that never answered has ended, and grants control when it has. A refused single input event is sent once more, and an unanswered input or command whose read behind it answers is settled instead of needing a restart. Restart browser from the panel works while the browser is interrupted or every busy bot waits on a sign-in card for it; the bot is told its pages are gone. A view another window holds says so instead of dropping clicks. Time budget: one module holds the proxy's 130 s and the harness's 120 s budget. Browser calls count the lane wait, cap the engine call and the reads after it, and answer as a lost call if anything still overruns; cloud computer calls answer within the budget too. The proxy tells a restarting server, a restart mid-call and a timeout apart. Cloud computer claim: the computer list is read once more after a network failure; a claim that stays unreachable leaves the turn running and the next computer call claims again (at most three times). With the included credential, messages name MausBot Cloud's computer service, not boat.dev. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix(live): reuse question recovery and guard media lifecycle | 1 个月前 | |
fix(chat): show a cancelled turn as a quiet stop with retry (#2455) * fix(chat): show a cancelled turn as a quiet stop with retry A client abort was stored as the provider sentence and drawn as an assistant reply. Keep real errors as they are, and reuse regenerate or the room send for Retry. * fix(chat): keep a client abort a stop through completion and retry the stopped room request a stop now drops the text the turn said before it from lastReply, so the digest and the finished notification don't read a half reply. the stop is remembered per thread until turn.completed, which skips the failure incident whatever stopReason the provider settles with. room retry resends the person's message right before the stopped row, with its files and reply target, and offers nothing when a bot's line started that turn. server/cancelled-turn.e2e.test.ts covers it on a disposable server and room. --------- Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 27 天前 | |
Merge origin/main into fix/quiet-chat-rescue Main's ratchets now fail only on growth, so the size pins are main's. App.tsx keeps main's needsYouVersion people loader and this branch's Switch AI keeper; index.ts keeps main's cloud lending and team messages wiring beside this branch's markStopped person stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
A new Cloud's first hour: the Chief greets, connects Gmail and Calendar, takes a first look, and keeps count On a new personal Cloud the app opens on the Chief's chat, which greets the person by name and asks what they want off their plate. After the first answer it offers Gmail and Google Calendar with the reason, and the moment one is in it gives a first look: the week's meetings and overlaps, up to three emails with replies written as drafts, dates and amounts, and one daily job it could take on. While the look runs, the relay lets it only read Gmail and Calendar and write three reply drafts. It then says the 8:00 morning brief is on and offers the phone. The brief on such a Cloud is posted and pushed at 8:00 in the person's zone, led by what was done while they were away, and a sleeping Cloud wakes for it. What the Chief does is counted as it happens (value.json); on day two it posts a recap with the time it gave back. The health report carries the first hour's milestones and the counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix(codex): fail fast without a login, retry a login race once, word Codex usage limits plainly A Codex bot with no Codex login (Move to Cloud leaves sign-ins behind) still started Codex, which reconnected for up to a minute and then showed the raw "401 Unauthorized: Missing bearer or basic authentication" text. Codex's ChatGPT usage-limit text ("Upgrade to Pro") read as MausBot's Pro plan and offered Retry. - Before starting Codex for its own ChatGPT sign-in, a missing or unreadable auth.json is checked with `codex login status`; "not logged in" ends the turn at once as setup: "Codex isn't signed in on this computer…" (plus a My Cloud line on a Cloud home). A login Codex reads elsewhere (keyring) is remembered. - Codex's missing-credentials 401 gets the same sentence. - A refused or credential-less 401 before anything streamed runs the turn again once when a ChatGPT login is readable and Codex launched without it (or another Codex rewrote it), instead of marking every Codex bot signed out. - Codex's usage limit becomes "Your ChatGPT account (used by Codex) reached its Codex usage limit. This is OpenAI's limit, not your MausBot plan." with Codex's reset time; the failed turn links to Codex usage instead of Retry. - Codex error wording and the login check move out of codex.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
feat(permissions): add exact command allowlist to bot controls (#1754) | 1 个月前 | |
Windows: lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on (#3950) * ci(windows): start computer control as the installed app does and lend it A Windows smoke that runs electron/cua.mjs's packaged branch unchanged, in Electron's main process, then takes a Cloud's first look at the PC through the lend path (computer_tools, get_screen_size, list_apps). It reports the driver's mode and whether apps and screen would be lent, and sends no input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): settle each answer with a statement in the lend smoke Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on Computer control on Windows starts once, at launch. When it didn't (a helper Windows Security stopped, or a slow first start), nothing tried again, nothing was recorded (the driver's error carried only its kind, and console output is lost in the packaged app), the app showed nothing and reported Windows as unsupported, and a Cloud's bot was told to have the person "check computer control", which no Windows screen offers, then offered its own cloud computer. - Computer control keeps the reason Windows gave and logs every change to the app's log. On Windows a start that failed for a passing reason is tried again by itself, twice; a blocked or missing helper waits for the person. - The taskbar or menu-bar icon says what the Clouds can't use and why, with the one fix ("Screen control isn't running on this PC", Start screen control). The Computer panel on a PC says the same with a Start button. - A Cloud's bot that needs the person's computer and can't use it calls ask_for_computer: one card with what it wants and why, the reason, and a one-tap Turn on (resume, start screen control, ask macOS, or run commands after the computer's own confirmation), or Get MausBot when the app there is closed, missing or too old. The app on that computer, paused or not, hears the ask and shows its own prompt once, one at a time; the first answer wins. Once the computer lends what was needed the bot's waiting call returns, or its request goes on by itself. Only on the person's own Cloud. - Every "not available" answer a bot gets there points it at the card, and the Cloud prompt says never to switch to its cloud computer unless asked. - The person can keep writing while a Turn on card waits. - CI's Windows CUA job runs for changes to the modules it starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(lending): a neutral computer name in the ask tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): the help names the PC's screen-control status and the Turn on card, in the app's words Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): the lent screen's driver gets Windows' own folders cua-driver 0.28.2 keeps its settings, history and cursor themes under LOCALAPPDATA and APPDATA; the lend path started its proxy without them. They hold no secret, and the app's keys still never reach it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): the lend smoke reports the lending decision the app makes, with why and the fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): on a pull request the lend smoke runs the base branch first, so one run shows the change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): screenshots of the PC's status and the Turn on card, light and dark Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(lending): the ask's internal route answers from its own module, so server/index.ts gains no route Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: build the real installer, install it like a download, and report what Windows Security does A hand-run job on a fresh GitHub Windows machine (workflow_dispatch, or the "defender-check" label on a pull request while the workflow isn't on main): builds the NSIS installer the way the release's Windows job does, turns Defender's protection on the way a home PC has it (GitHub's image turns most of it off and excludes every drive), saves the installer to Downloads with a browser's Zone.Identifier (ZoneId=3), scans it, installs it silently (first the way a double-click starts it), opens the app for two minutes and presses Start screen control through the app's DevTools port. The summary and the defender-check artifact say what the machine allowed, Defender's detections and Operational events 1116, 1117, 1006-1008 and 1015, whether cua-driver-background.exe runs, the app log's computer-control lines and whether Start screen control worked. The run fails when Windows Security flagged the app or screen control doesn't run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: show what holds a downloaded installer, and check Defender's cloud When the double-click start of the downloaded installer is still waiting after 30 s with no installer running, the check records the windows on screen, whether SmartScreen runs and a screenshot, then stops waiting instead of sitting out five minutes. It also records Defender's cloud connection (MpCmdRun -ValidateMapsConnection), the signatures' age, what GitHub's passive-mode policy means on a machine Defender reports in Normal mode, and a screenshot of the app after two minutes. A workflow test keeps the check's build step for step the same as the release's Windows job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows lend smoke: read electron-builder.yml the same with CRLF line endings git checks electron-builder.yml out with CRLF on a Windows runner, so the smoke found none of the CUA resources it places and stopped before starting anything (the first CI run that reached the Windows CUA job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
Windows: lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on (#3950) * ci(windows): start computer control as the installed app does and lend it A Windows smoke that runs electron/cua.mjs's packaged branch unchanged, in Electron's main process, then takes a Cloud's first look at the PC through the lend path (computer_tools, get_screen_size, list_apps). It reports the driver's mode and whether apps and screen would be lent, and sends no input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): settle each answer with a statement in the lend smoke Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on Computer control on Windows starts once, at launch. When it didn't (a helper Windows Security stopped, or a slow first start), nothing tried again, nothing was recorded (the driver's error carried only its kind, and console output is lost in the packaged app), the app showed nothing and reported Windows as unsupported, and a Cloud's bot was told to have the person "check computer control", which no Windows screen offers, then offered its own cloud computer. - Computer control keeps the reason Windows gave and logs every change to the app's log. On Windows a start that failed for a passing reason is tried again by itself, twice; a blocked or missing helper waits for the person. - The taskbar or menu-bar icon says what the Clouds can't use and why, with the one fix ("Screen control isn't running on this PC", Start screen control). The Computer panel on a PC says the same with a Start button. - A Cloud's bot that needs the person's computer and can't use it calls ask_for_computer: one card with what it wants and why, the reason, and a one-tap Turn on (resume, start screen control, ask macOS, or run commands after the computer's own confirmation), or Get MausBot when the app there is closed, missing or too old. The app on that computer, paused or not, hears the ask and shows its own prompt once, one at a time; the first answer wins. Once the computer lends what was needed the bot's waiting call returns, or its request goes on by itself. Only on the person's own Cloud. - Every "not available" answer a bot gets there points it at the card, and the Cloud prompt says never to switch to its cloud computer unless asked. - The person can keep writing while a Turn on card waits. - CI's Windows CUA job runs for changes to the modules it starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(lending): a neutral computer name in the ask tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): the help names the PC's screen-control status and the Turn on card, in the app's words Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): the lent screen's driver gets Windows' own folders cua-driver 0.28.2 keeps its settings, history and cursor themes under LOCALAPPDATA and APPDATA; the lend path started its proxy without them. They hold no secret, and the app's keys still never reach it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): the lend smoke reports the lending decision the app makes, with why and the fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): on a pull request the lend smoke runs the base branch first, so one run shows the change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): screenshots of the PC's status and the Turn on card, light and dark Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(lending): the ask's internal route answers from its own module, so server/index.ts gains no route Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: build the real installer, install it like a download, and report what Windows Security does A hand-run job on a fresh GitHub Windows machine (workflow_dispatch, or the "defender-check" label on a pull request while the workflow isn't on main): builds the NSIS installer the way the release's Windows job does, turns Defender's protection on the way a home PC has it (GitHub's image turns most of it off and excludes every drive), saves the installer to Downloads with a browser's Zone.Identifier (ZoneId=3), scans it, installs it silently (first the way a double-click starts it), opens the app for two minutes and presses Start screen control through the app's DevTools port. The summary and the defender-check artifact say what the machine allowed, Defender's detections and Operational events 1116, 1117, 1006-1008 and 1015, whether cua-driver-background.exe runs, the app log's computer-control lines and whether Start screen control worked. The run fails when Windows Security flagged the app or screen control doesn't run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: show what holds a downloaded installer, and check Defender's cloud When the double-click start of the downloaded installer is still waiting after 30 s with no installer running, the check records the windows on screen, whether SmartScreen runs and a screenshot, then stops waiting instead of sitting out five minutes. It also records Defender's cloud connection (MpCmdRun -ValidateMapsConnection), the signatures' age, what GitHub's passive-mode policy means on a machine Defender reports in Normal mode, and a screenshot of the app after two minutes. A workflow test keeps the check's build step for step the same as the release's Windows job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows lend smoke: read electron-builder.yml the same with CRLF line endings git checks electron-builder.yml out with CRLF on a Windows runner, so the smoke found none of the CUA resources it places and stopped before starting anything (the first CI run that reached the Windows CUA job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix(connectors): reconnect expired apps instead of looping on account labels A Cloud customer could not reconnect Gmail. A toolkit whose only accounts were dead (FAILED, EXPIRED, INACTIVE, INITIATED from earlier sign-ins) still demanded a label, a retry with the first attempt's label got 409 "already in use", an EXPIRED account showed a green check with "Add account", and a bot with no grants or a failed tools/list had no connector tools at all. - One planner (shared/connector-account-link.ts) for the broker and the project-key path: a label is required only beside an ACTIVE (or status-less) account; a label held only by an account that is not active is freed by revoking and deleting that account before the link; a label an active account holds stays 409; the replaced account does not count toward the five-account cap. - Apps: only an ACTIVE account counts as connected (check, count, header icons). An app with no working account shows "Signed out" and Reconnect, which removes the newest dead account and links again under its label; dead rows beside a working account get their own Reconnect. - Connector card: an alias-required or label-taken answer shows a label field instead of resending the refused request; the card route takes that label. - Connector proxy: a failed tool result that reads as signed out (USER_NOT_LOGGED_IN, 401, no connected account, not logged in) gets a note telling the bot to call COMPOSIO_MANAGE_CONNECTIONS to reconnect the app. - COMPOSIO_MANAGE_CONNECTIONS is advertised even with empty grants, with a short prompt line; tools/list is retried once in the proxy, and the harness answers a failed or rate-limited listing with that backend's last good list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
Composio: apps that need your own OAuth app connect with an auth config made in the dashboard A Tool Router Session uses an auth config it names only while that config is enabled for Tool Router. Configs people make themselves can have that unset or off. OpenMausBot named an unset one (Composio ignored it and answered "does not manage auth for toolkit xero ... specify one in auth_config_override") and skipped an off one, telling the person to switch on something they had no obvious way to reach. So Xero and Buffer stayed blocked with the person's own Composio key even after the earlier custom-auth-config work. Own Composio key: - When an app is connected (card requested, Connect clicked, or a call fails for want of a config), its auth config gets is_enabled_for_tool_router turned on through PATCH /auth_configs/{id}, only for that app. - The Session is updated in place (PATCH /tool_router/session/{id} with auth_configs), so a running bot keeps its MCP endpoint and gets the config on its next call; if Composio won't, a new Session is made for the same user. - Several enabled configs for one app: the most recently created wins, and the card's tool result tells the bot which. - COMPOSIO_MANAGE_CONNECTIONS advertises an optional auth_config_id. - A failed call's note says what was done or exactly what is missing; a lookup that found nothing is not cached. Managed service: one plain line, add your Composio project key in Settings → API keys and OpenMausBot uses your auth config from that project. Session code moves to server/composio-session.ts; server/composio.ts shrinks from 1289 to 1091 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 10 天前 | |
Bots add, change, sign in to and remove MCP servers from chat (#4143) * docs: design and plan for MCP servers in chat Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(mcp): one config service for settings and bots Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): keep import hooks, read body before merging, quiet panel refresh Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): rules for what a bot may change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): stricter secret rules for bot updates and listings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): bots add, change, test and remove MCP servers One mcp_server tool replaces add_mcp_server. A Full access bot adds a server and it is turned on and tested as the bot, in the same turn; it can also update, enable, disable, test, sign out and remove servers. A change merges onto the saved entry, and a new destination clears saved secrets and the sign-in. Turning one off and signing out apply at every level; below Full access add saves the server off and other changes ask the person to use Settings until the approval cards land. sign_in answers "Not yet" until its card exists. Each change leaves one activity line in the chat ("Added MCP server linear · Turned on · Test: needs sign-in"). On a Team Cloud only an owner or admin's turn changes the team's servers; guest-driven threads get nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): an import holds the config lock while it reads its body A second import, or any other writer, is refused for the whole of an import request again, so the session-revocation check sees the import mutex. The one busy flag is held across the body read through addMany(read). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): one activity line, stricter tests An mcp_server call now shows as one row: the route writes its line onto the bot's own tool row as a display label, and the chat shows that in place of the raw tool name. Update keeps the add path's folder rules, remove and test follow the policy and other-computer rules, the listing says a server on another computer is not this bot's, and the labels read "Switched off" and "Test: N tools". The update path's secret rules gain regression tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): label the right activity row Engines start every tool block of a response before running any, so two mcp_server calls in one response each found the newest open row. Each call now labels the row whose input names its action and server, in its own turn only (rooms pass the turn too); with no live turn it adds a row instead of touching an older turn's. Advanced run summaries show the label, update applies the folder rules only when the command changes, and the tool's spellings come from the bridge's prefix list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): one-tap cards when a bot isn't on Full access A bot on Ask, Edits or Auto that adds, turns on, changes or removes an MCP server now shows a card in the chat ("Turn on linear?", "Change dodo?", "Remove dodo-test?") with the address or the redacted command, the changed fields, or the other bots that use it, and Cancel as the negative option. Add saves the server off and asks to turn it on. The bot ends its turn; the person's answer applies the change through the same path Full access uses, against the server as it is then, and resumes the bot with the test result. A secretRef on a Change card is redeemed only on allow, so a late answer resumes with "The key expired". Only the owner review that guards team-setup cards may allow; on a Team Cloud that means a workspace admin. Stop closes the card, a restart resumes a turn whose card was answered, and desktop draws the card with its own title and buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): keep pending changes off the wire, safer answers An MCP card now carries only what it shows. The change it stands for, the bot's fields and what the server reached, stays in the server's memory until the person answers, so no value the bot sent reaches the chat, phones or messages.json. After a restart the card expires and the bot is told to ask again. An answer applies nothing when the server's address or command changed since the card was shown, and says so. A busy config answers "Try again in a moment." and keeps the card open. An error while applying settles the card as failed and resumes the bot with the error. Failed and expired cards show their reason. A new OAuth client secret shows as its own change line. The tool description says a card below Full access means ending the turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): hide values under secret names on cards A Change card no longer shows a literal env or header value whose name says it is a secret (API_TOKEN, X-Api-Key, Authorization): it reads "new key for NAME", as a secretRef does. Other values still show. A new card also frees the held change of every earlier card about the same server, so one closed by Stop no longer lingers until a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): sign in from the chat A bot whose MCP server needs a login now calls mcp_server sign_in and the person sees one Sign in card in the chat. The card is the connector card every client already draws, marked source "mcp", so existing iPhone and Android builds show and complete it. Tapping it starts the provider's sign-in owned by the card, so any device that can see the card follows the same sign-in and a second tap reuses it. When the sign-in finishes the card settles and the bot resumes by itself, with no status poll needed; the turn it resumes mounts the server with the new token. Not now cancels the sign-in and tells the bot the server stays on but signed out. A removed server's card says so and resumes the bot once. A phone paired to a local Mac with no public https address is told to open the chat on the Mac, and a sign-in that would need paste-back points to Settings. A shared server's card takes an admin, as Settings does; on a Team Cloud a personal server's card signs in only the person the chat is for, with their own sign-in. Members now reach the card's authorize route, and an app's card stays admin-only in the handler. The authorization URL is never written to a message or card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): sign-in card edge cases A second tap from a browser elsewhere replaces a waiting sign-in that would come back to this computer, so the phone gets a link it can finish. A card left waiting when the server restarted goes back to Sign in when polled. Not now tapped before the bot's turn parks still tells the bot it didn't sign in once the turn parks; a card a newer one replaced is marked superseded and waits on nothing. A sign-in that would need paste-back is refused before any client is registered or port bound. Who may sign in is checked before a removed server settles the card, and a failing onSettled can no longer break a callback or escape the expiry timer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): sign-in card wording on desktop Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(mcp): an authorize refusal shows its sentence on the card An MCP card's 409 shows the server's sentence as calm status text and no sign-in link, even when the refusal carries one. A Composio card's 409 stays the card's error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(mcp): move MCP chat wiring out of index.ts and card types out of wire.ts server/index.ts and shared/wire.ts had grown past their file-size ratchet. The mcp_server route deps, the card and Sign in services, the card answer and the Settings listing with its policy helpers now live in server/host/mcp-chat.ts behind createMcpChat(deps). index.ts builds it where the services were built before, and secretCards and mcpConfig, which are built later, are passed as getters. McpChangeRequest and ConnectorCardData move to shared/mcp-request.ts and shared/connector-card.ts, and every consumer imports them from there. server/store.ts drops a re-export of ConnectorCardData that nothing imported. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a key inside a server's address never reaches the bot or a card list, the Turn on card and the Change card's address line now show a remote address as scheme, host, port and path, without userinfo, query or hash, with every key-shaped path segment (16+ URL-safe characters with a letter and a digit) shown as "…", then passed through redactSecretsInText. A Zapier-style link no longer puts its token in the model's context, messages.json or the phones. An update whose url equals that display form keeps the saved url, so a bot that sends back the address list showed it does not re-point the server at the masked address and lose its headers and sign-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): sign_in refuses a server that is off A turn mounts only servers that are on, so a sign-in card for one that is off ended with the bot told "Its tools are yours from this turn", which was false. sign_in now refuses with "linear is off. Call mcp_server with action enable first." at Full access, or "...enable to ask the person to turn it on." below it. The text a bot hears after the person signs in reads the server's enabled state when it resumes, so a server switched off while the card waited tells the bot it signed in, the server is off, and to call enable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): Turn on and Remove cards survive a restart Every MCP approval card held its change in memory, so a person who answered "Turn on linear?" after relaunching OpenMausBot got "this request expired", though a Turn on or Remove card holds no bot fields. McpChangeRequest now carries targetHash, the sha256 hex of where the server reached when the person was asked. The answer-time "changed since you were asked" check compares that hash for every action, so an allow after a restart applies a Turn on or Remove through the same applyMcpChange path while the server still reaches there, and refuses when it is gone or reaches somewhere else. Only an update's fields are held in memory, and only a Change card still expires after a restart; decided() expires an open card only when its fields were lost. A deny after a restart still settles as denied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): name the dropped OAuth client secret when the client id changes A bot update with a new oauth.clientId cleared the saved client secret without listing it in dropped, so the "these saved values were cleared" line left it out and the bot never knew to ask again. It is now named "oauth client secret", as the url-change path names it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a person who may not sign in gets a calm note, not an error "Only an admin of this installation can sign in to Linear." and "Only Ada can sign in to this." came back as 403, which desktop, iOS and Android draw as a red failure. They are refusals of the same kind as "Open this chat on your Mac to sign in", so the card's authorize now returns them as 409, which all three clients show as a calm note. A session missing a scope at the route gate still gets 403. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a card's targetHash covers the masked display target, never a raw secret Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(mcp): a client-id-only update no longer says the destination changed Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Mask base64, dotted and percent-encoded key path segments Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Tell the bot a removed server is gone, not off Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Tell an MCP sign-in card to sign in on the page that opens An MCP server has no app key, so its card drops that half of the hint. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 3 天前 | |
Analytics: allowlists and event helpers; engine slugs replace instance ids Every product event property is a count, a boolean or a word from a fixed list; anything else becomes "other". message_sent and call_started sent the bot's instance id as driver, which for an added account is a per-install uuid or a name from config.json; they now send the engine slug. The curated Composio slugs move to shared/ so the server's list and the analytics list cannot drift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 天前 | |
fix(apps): a bot's connected apps answer by the same names on every engine (#3755) A bot given Gmail by its Apps switch could call no Gmail tool on any engine. Before the switch also wrote the tool list, it wrote only the read/write scope, so a bot whose tool list was `{}` kept a list that left Gmail out: the connected-apps bridge then offered COMPOSIO_MANAGE_CONNECTIONS alone ("All connections are active", yet no Gmail tool), on Claude and on ACP engines alike. Claude's tool search found nothing for `select:gmail.search_emails` either, since no tool had that name anywhere. - An app a bot's scopes switch on gets its tools: every one, unless the bot's tool list already names some. Existing bots are fixed on the next start, and every later scope change applies the same rule. - The bridge offers plain tools for the common Gmail and Google Calendar actions (gmail.search_emails, read_email, read_email_thread, create_draft, send_email; googlecalendar.list_events, list_calendars) for each connected, granted app, writes only where the bot may write. Each runs its Composio tool through COMPOSIO_MULTI_EXECUTE_TOOL, so the relay judges it exactly as that tool: grant, scope, read-and-draft, outbound approval, team scopes. - Claude Code finds an MCP tool by its own name (`select:gmail.search_emails`) and sanitises the dot in the name it sends, so it gets the dotted names; other engines get gmail_search_emails, which they show the same way. - The prompt names these tools for the apps a bot has. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
fix(apps): a bot's connected apps answer by the same names on every engine (#3755) A bot given Gmail by its Apps switch could call no Gmail tool on any engine. Before the switch also wrote the tool list, it wrote only the read/write scope, so a bot whose tool list was `{}` kept a list that left Gmail out: the connected-apps bridge then offered COMPOSIO_MANAGE_CONNECTIONS alone ("All connections are active", yet no Gmail tool), on Claude and on ACP engines alike. Claude's tool search found nothing for `select:gmail.search_emails` either, since no tool had that name anywhere. - An app a bot's scopes switch on gets its tools: every one, unless the bot's tool list already names some. Existing bots are fixed on the next start, and every later scope change applies the same rule. - The bridge offers plain tools for the common Gmail and Google Calendar actions (gmail.search_emails, read_email, read_email_thread, create_draft, send_email; googlecalendar.list_events, list_calendars) for each connected, granted app, writes only where the bot may write. Each runs its Composio tool through COMPOSIO_MULTI_EXECUTE_TOOL, so the relay judges it exactly as that tool: grant, scope, read-and-draft, outbound approval, team scopes. - Claude Code finds an MCP tool by its own name (`select:gmail.search_emails`) and sanitises the dot in the name it sends, so it gets the dotted names; other engines get gmail_search_emails, which they show the same way. - The prompt names these tools for the apps a bot has. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
feat(tts): add Gemini speech generation provider | 1 天前 | |
fix(automations): plain time zones, "First run Mon 9:00", panels titled by name Times read "weekdays at 9:00 India time", never an IANA id, wherever a schedule is put into words: the automation sentence, the bot's routine results and the routine cards. An automation that hasn't run yet says "First run tomorrow 9:00 AM" instead of "Working · hasn't run yet", and an enabled one is "On" rather than "Working". The detail panel is titled with the automation's name, says when it runs and which bot runs it, and shows its whole instructions. The create result tells the bot the person sees it right here in the chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
feat(data): AG Grid viewer, live SQL, and chat-driven results (#2596) * feat(data): ship AG Grid viewer and chat-driven live SQL * fix(data): drop replaced result tables on the caller's connection showCard awaited dropResult for the previous or abandoned result table on the serialised "bot" connection, so a panel live edit's HTTP response waited behind whatever the bot was running. dropResult now takes the connection (default "bot", as before) and showCard drops on its own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): run live SQL after a 50 ms typing pause, latest text wins Every keystroke posted a live run the server materialised as a table and then interrupted with the next character. The run now waits 50 ms after the last keystroke; a newer run still aborts the in-flight one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): load extensions as their own lane step with their own budget A first-time INSTALL downloads from the core repository, and it ran inside the statement's 60 s timeout; the PR had also reordered failureFrom so a timeout overrode the loader's DataFailure, replacing the "allow extensions.duckdb.org" hint with "narrow the query". The install now runs as its own lane step (5 minutes) ahead of the statement, and a structured failure is returned as-is again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(computer): a model change no longer resets the panel tab The tab-follow effect was keyed on connectionKey, which carries the thread bot's model instance, so changing the model (or Auto resolving its surface) pulled the person off the Data, Files or Routines tab. The tab now follows only the conversation and its chosen place. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): open a result receipt through the bot's own select path openDataResult re-implemented bot selection, so the unread flag, the read cursor and the /read POST that select performs were skipped. It now runs the select and toggleComputer reducers and shares select's read effect. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the sheet no longer caches DuckDB's catalog sheet.json kept a copy of the table list that never matched what listTables returned (described columns and quoted names on one side, plain ones on the other), so every GET /data rewrote the file and broadcast a `data` frame to every client, and a quoted CREATE OR REPLACE TABLE "orders" made a second entry beside orders. DuckDB owns the catalog: GET /data still answers { sheet, tables } with a fresh listTables(), data_describe lists it from the database, and the sheet carries cards and sources only. Client follow-up (owned elsewhere): src/components/data/DataPanel.tsx reads sheet.tables; it should take `tables` from the GET /data response. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the result receipt names its tool, not the card's title The receipt was stored with tool.name = the card's free-form title only so the chips' `if (!tool) return null` passed, and every consumer that reads tool.name as a tool or status identifier misrouted it: a result called "notice: revenue by region" rendered as a status row, one named like the failed-turn marker got a Retry button, the sidebar previewed the bare title. The receipt is now tool { name: "data_show", ok: true } with the title only in dataResult; ChatView and GroupView render a receipt before any status or failed-turn reading (so receipts stored by older servers stay receipts), and activityPreview reads dataResult.title. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): SQL box always available; Cancel for a live run The box mounted only when the shown result had SQL, so a person whose bot had loaded tables but shown nothing could not type a query; a long live edit had no Cancel because the card stays "ready". The box now always mounts (empty on an empty sheet or text result; its first run makes the card through the same run route, and text typed before that card arrives waits for it instead of making a second one), and Running/Cancel shows whenever the panel's own run is on the wire. Cancel drops the request and posts the card's cancel. A card still on its first run is re-run outright rather than locked read-only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(data): one run/cancel mechanism; drop the strings nothing reads The store's runDataSql, cancelDataCard, patchDataCard and deleteDataCard had no dispatchers left (the panel calls the routes itself, since it owns the request it must abort); remove them, their reducer/effect cases and tests. Remove the 31 data.* strings no code reads (explorer, Run button, card toolbar, source view) and guard against the next orphan. Reword data.openInWorkspace so the English copy check passes again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): send the viewed result as its own field, never in the words withDataContext() prepended a <data-context> envelope to the person's text before POST /messages; the server stored that text verbatim and only the desktop renderer hid it, so the companion apps, remote clients, search and memory all saw the raw tag. The client now sends dataContext: { cardId, draftSql? } beside the text (same conditions as before: this bot's own thread, not an opening /command), the server validates it (c_<n>, draft at most 100 KB), stores it on the message, and prepends promptWithDataContext() to the provider text for that turn and every retry of it: an edit/regenerate reuses the message's own context, a queued or steered send carries it, the backup-engine and computer-selection reruns inherit it. Message text is exactly what was typed everywhere; withDataContext/isDataContextLine/withoutDataContext and every stripping call site are gone. Client follow-up (owned elsewhere): src/state/store.tsx's "send" action must carry dataContext into the POST body; src/lib/drafts.ts may keep it beside requestText for an exact retry of a failed send. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the send carries its Data context; the catalog comes from GET /data The two seams the server fixes opened: the composer's send action forwards `dataContext` in the messages POST (the text itself stays what the person typed), and the panel's table list comes from the catalog GET /data reports (`dataTables` in the store) instead of a copy on the sheet, which no longer exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 26 天前 | |
feat(data): AG Grid viewer, live SQL, and chat-driven results (#2596) * feat(data): ship AG Grid viewer and chat-driven live SQL * fix(data): drop replaced result tables on the caller's connection showCard awaited dropResult for the previous or abandoned result table on the serialised "bot" connection, so a panel live edit's HTTP response waited behind whatever the bot was running. dropResult now takes the connection (default "bot", as before) and showCard drops on its own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): run live SQL after a 50 ms typing pause, latest text wins Every keystroke posted a live run the server materialised as a table and then interrupted with the next character. The run now waits 50 ms after the last keystroke; a newer run still aborts the in-flight one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): load extensions as their own lane step with their own budget A first-time INSTALL downloads from the core repository, and it ran inside the statement's 60 s timeout; the PR had also reordered failureFrom so a timeout overrode the loader's DataFailure, replacing the "allow extensions.duckdb.org" hint with "narrow the query". The install now runs as its own lane step (5 minutes) ahead of the statement, and a structured failure is returned as-is again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(computer): a model change no longer resets the panel tab The tab-follow effect was keyed on connectionKey, which carries the thread bot's model instance, so changing the model (or Auto resolving its surface) pulled the person off the Data, Files or Routines tab. The tab now follows only the conversation and its chosen place. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): open a result receipt through the bot's own select path openDataResult re-implemented bot selection, so the unread flag, the read cursor and the /read POST that select performs were skipped. It now runs the select and toggleComputer reducers and shares select's read effect. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the sheet no longer caches DuckDB's catalog sheet.json kept a copy of the table list that never matched what listTables returned (described columns and quoted names on one side, plain ones on the other), so every GET /data rewrote the file and broadcast a `data` frame to every client, and a quoted CREATE OR REPLACE TABLE "orders" made a second entry beside orders. DuckDB owns the catalog: GET /data still answers { sheet, tables } with a fresh listTables(), data_describe lists it from the database, and the sheet carries cards and sources only. Client follow-up (owned elsewhere): src/components/data/DataPanel.tsx reads sheet.tables; it should take `tables` from the GET /data response. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the result receipt names its tool, not the card's title The receipt was stored with tool.name = the card's free-form title only so the chips' `if (!tool) return null` passed, and every consumer that reads tool.name as a tool or status identifier misrouted it: a result called "notice: revenue by region" rendered as a status row, one named like the failed-turn marker got a Retry button, the sidebar previewed the bare title. The receipt is now tool { name: "data_show", ok: true } with the title only in dataResult; ChatView and GroupView render a receipt before any status or failed-turn reading (so receipts stored by older servers stay receipts), and activityPreview reads dataResult.title. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): SQL box always available; Cancel for a live run The box mounted only when the shown result had SQL, so a person whose bot had loaded tables but shown nothing could not type a query; a long live edit had no Cancel because the card stays "ready". The box now always mounts (empty on an empty sheet or text result; its first run makes the card through the same run route, and text typed before that card arrives waits for it instead of making a second one), and Running/Cancel shows whenever the panel's own run is on the wire. Cancel drops the request and posts the card's cancel. A card still on its first run is re-run outright rather than locked read-only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(data): one run/cancel mechanism; drop the strings nothing reads The store's runDataSql, cancelDataCard, patchDataCard and deleteDataCard had no dispatchers left (the panel calls the routes itself, since it owns the request it must abort); remove them, their reducer/effect cases and tests. Remove the 31 data.* strings no code reads (explorer, Run button, card toolbar, source view) and guard against the next orphan. Reword data.openInWorkspace so the English copy check passes again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): send the viewed result as its own field, never in the words withDataContext() prepended a <data-context> envelope to the person's text before POST /messages; the server stored that text verbatim and only the desktop renderer hid it, so the companion apps, remote clients, search and memory all saw the raw tag. The client now sends dataContext: { cardId, draftSql? } beside the text (same conditions as before: this bot's own thread, not an opening /command), the server validates it (c_<n>, draft at most 100 KB), stores it on the message, and prepends promptWithDataContext() to the provider text for that turn and every retry of it: an edit/regenerate reuses the message's own context, a queued or steered send carries it, the backup-engine and computer-selection reruns inherit it. Message text is exactly what was typed everywhere; withDataContext/isDataContextLine/withoutDataContext and every stripping call site are gone. Client follow-up (owned elsewhere): src/state/store.tsx's "send" action must carry dataContext into the POST body; src/lib/drafts.ts may keep it beside requestText for an exact retry of a failed send. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(data): the send carries its Data context; the catalog comes from GET /data The two seams the server fixes opened: the composer's send action forwards `dataContext` in the messages POST (the text itself stays what the person typed), and the panel's table list comes from the catalog GET /data reports (`dataTables` in the store) instead of a copy on the sheet, which no longer exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 26 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Onboarding polish: a first run that keeps its shape and meets the Chief only when it fits - Meet with no AI keeps its shape: the 288px pill signs in (install, sign-in, a pasted or shown code, or the Connect an AI dialog), with "Other ways to connect · Set up later" under it; the AI's test message, Checking, failed and backup states live in the dialog. One sentence typed once, title at weight 400. - The Chief step shows only for a MausBot not yet introduced where no other bot is the Chief; one Create on a new install, Choose beside it where there are bots, a 300 ms input guard, an empty app behind it ("No bots yet"), and MausBot flying to its tile before the chat opens. Dialogs use the shared modal, scrim and pill classes. - MausBot's three new lines, then a follow-up written once by the server (POST /api/bots/:id/helper-followup, MausBot's own person only) as a real message the model reads, and up to three chips for only what is missing. Advanced mode keeps its one-bubble intro, asks and spotlights as before. - What the removed steps did comes back: a first run that could offer the Cloud settles the Cloud Pro popup, and refused microphone or speech access offers Open System Settings. Simple cards carry one-line hints instead of spotlights, MausBot's panel lists Try asking, a first run on this computer takes the account's full name for an empty profile, and MausBot's own welcome card wears the same dialog in Simple mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
Take control where you watch: the panel becomes the live desktop Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 | |
fix(kimi): install and sign in to Kimi from Settings, on a Cloud with no terminal (#4026) * fix(kimi): install and sign in to Kimi from Settings, on a Cloud with no terminal On MausBot Cloud, Settings showed Kimi as not installed with only a `curl | bash` command to copy, and after an install it asked for `kimi login` in a terminal. A Cloud has no terminal, so Kimi could not be set up there. - Install: EngineInstall.npmPackage names Moonshot's npm package (@moonshot-ai/kimi-code). Settings installs it into the app's own folder when the server has npm; a terminal keeps Moonshot's own command. - Sign-in: the Kimi driver gets a DeviceSignIn (`kimi login`). Settings shows Kimi's code and a kimi.com or kimi.ai link, follows the new code Kimi prints when one expires, and confirms the login. The link keeps no query value except a user_code equal to the code. - Signed-in check: Kimi saves a kimi.ai login (the region it picks outside China) as credentials/kimi-code-env-<hash>.json, not kimi-code.json. Both count now, a revoked token file does not, and a Team Cloud's per-person engine homes get the kimi.ai file too. Checked on a Cloud home from source with the real kimi-code 2.4.1 and a free kimi.ai account: install, restart, sign-in, and a turn that reached Kimi's API (refused with Kimi's own 403 for an account with no Kimi Code membership). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(pr): screenshots for installing and signing in to Kimi on a Cloud Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 | |
@devs: report a bug to the MausBot team from any chat (#3620) * @devs: report a bug to the MausBot team from any chat Typing @devs in a chat (last entry of the @ list, or typed by hand) sends one bug report to the MausBot team's endpoint (POST /api/bug-reports on the Cloud origin). The server detects the tag, so the desktop app and the Cloud work the same way. The bot answering the message gets a note on its turn and a new built-in report_bug tool to add a summary: what went wrong, what it saw, steps to reproduce. When no summary comes (no tools, failed turn, tool not called, no bot answered, turn still running after 10 minutes, restart) the server sends the report itself once the conversation is quiet. Facts: app version, OS, desktop or Cloud, each bot's engine, model and engine status, connected apps, recent failed turns, failed tools and stops in that conversation, the server's latest warnings and errors, and the ids. Only the person's message and the bot's summary go, never the conversation or a file. Everything is redacted (key shapes, bearer/basic authorization, cookies, URL credentials and parameters, private keys, the server's own secret env values) and bounded inside the endpoint's limits. The person sees "Sent to the MausBot team (report <id>). Milind and Omkar get it by email and will reply to <email>.": in the bot's reply, or as a notice line when the bot does not say it. A report that cannot go yet (offline, server error, hourly limit) waits in devs-reports.json and is sent again on its own; the notice says so, and says again when it goes. Fixture servers send to a loopback fake or a closed port, never to the team. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * @devs: the @ list's row in Russian Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
fix(devs): a department named devs is tagged, not the bug report (#4091) A message that tagged a department named devs (for example "added Rover to the @devs department") was read as the bug-report tag, because the tag only gave way to bot names. Departments now count too. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 3 天前 | |
Train: team-trial fixes, warm summaries, team bot access, own-server places, server lines (merge with Create a merge commit) (#3999) * Team bots: a level per person (view, chat, edit), shared from each bot A team bot is now shared like a document: what everyone in the team gets (Only people added, or Everyone at Can view, Can chat or Can edit) and a level for each person added. Admins and the bot's owner always edit. - The bot's Share button (bot panel in Simple, settings header in Advanced) opens a Share dialog on a team: people with access with their level, adding teammates by name or email, general access; every change applies at once with an Undo toast. - The server enforces it on every member request after the visibility gate: reads need Can view, writes Can chat (a room needs it on every bot), sharing and a bot's own setup Can edit; a routine needs Can edit unless its writer changes it; a card that changes the bot needs Can edit; a message another app relays needs the named person to chat. - Each copy of a bot carries the viewer's own level; the sharing only on an editor's. The live stream follows a change. - Bots set up before levels keep exactly what their visibility gave (everyone: Everyone, Can chat; admins only: Only people added; a list: those people, Can chat), read from it with nothing rewritten. - A person who can only view sees that in place of the composer, opens the bot's main chat, and is offered no new conversation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Team bot access: before and after pictures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Share dialog test: a whole bot Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(context): the unseen-messages block ends before the person's message When a resumed session has missed messages, the turn's prompt lists them in a block and then gives the person's new message after one blank line, with nothing saying the block is over. In a Team trial the person's next request, written right after a co-founder's relayed reply, was credited to the co-founder. The block now ends with "[End of those messages. Now reply to the user's latest message:]" before the turn's own text, as the full replay already ends its history with "[Now reply to the user's latest message:]". The wording differs from the replay's, so nothing that looks for the replay's end mistakes this block for replayed history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The owner is never told to ask an admin: connection lines know the person's role On a Team Cloud, a member's own bridge that asked for a team app's connection card got "ask an admin to connect it", whatever the person's role. The owner was told to ask an admin, and a bot named a teammate who wasn't one as the admin. - For the Owner or an Admin, the bot asks for the card through the team's composio bridge, whose card lets them connect the app for the whole team in one tap. - A User is told who can connect it, by name: the team's Owner and Admins from the roster the Admin paired here. - "Connect your <app> here" links go where each person's own connections are: the team's Apps page for the Owner and Admins, a User's team home otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(research): offer the research tools only where research works A Cloud home always holds the plan's X relay token, so every bot was offered research_search, research_endpoint and research_call. On a plan whose relay has research off, each call then answered only "Research isn't available right now." - The home asks the relay once, at start, with a search that names no job: the relay answers that with a 400 only once the token, the plan and research are all fine, before it reads its catalog or spends anything. An off answer (402, 404, 401, or 503 service_unavailable) hides the three research tools; x_search stays, since X works without research. It asks again an hour after an off answer, and a research call the relay refuses as off hides them at once. - The person's own treg key goes straight to treg: research is on. - A refusal because research is off now says what to do: tell the person and offer another way (web search or the browser); their own treg key turns research on. - The agents server gets a switch of its own for the research tools (OMB_RESEARCH) beside the X one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): a person's message never waits behind a long tool call A message the person sends their bot while it works is steered into the running turn, and an engine reads it only once the tool call it is in returns. A bot polling CI with `sleep 30` loops kept a person's message unread for 26 minutes and never said the PR it had made existed. - Mechanism: when the person's own one-to-one message waits unread while a tool call has run for a minute (at once if the call had already run that long), the server stops the turn, with a row saying so, and the message runs next, ahead of anything else queued in that chat. Its row is run as is (the follow-up queue can now take a row already in the transcript), and the model is told which step was stopped. Messages from rooms, routines, teammates and apps never do this, nor does one sent while the turn waits on the person or a computer. The wait is OMB_PERSON_FIRST_MS for tests. - Prompt: never wait inside a command for CI, a deploy or another job; check once, say what you made (with links), set wait_until or a one-time trigger to check back, and end the turn; answer the person first. Stopping and re-running works for every engine, and so does every engine's Stop. No engine reads a steered message during a tool call, some cannot steer at all, and Claude's own "send now" depends on moving the tool to the background, which bots run without. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): the person's re-run keeps its place and goes ahead of a teammate's The re-run of a steered message that a long tool call kept unread is now queued by the time the person sent it, ahead of everything but their own earlier messages, and a message of theirs that has to wait in the queue goes ahead of a teammate's or a routine's too. Before, the re-run took the time it was queued again, so on a slow runner it no longer joined the person's next message as one turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(connectors): app tool calls fit their schema, and a refusal says how to call again Composio checks a call's arguments against the tool's schema and refuses the whole call over one. In a Team trial five calls failed that way: COMPOSIO_SEARCH_TOOLS sent { job } (Required at "queries"), COMPOSIO_REMOTE_WORKBENCH sent code for code_to_execute and a timeout as text, and COMPOSIO_MULTI_EXECUTE_TOOL sent its tools list as text. After the search failed, the bot told the person it had no image tool, though an image app was connected. - The connector bridge keeps each listed tool's schema and fits a call to it where the bot plainly meant that shape: arguments or a list written as text, a number or yes/no written as text, a bare string or strings where a list of one-field objects goes, and one missing required field under another name when exactly one sent field can be it. The bot is told how its arguments were read, so it sends that shape next time. Anything not plainly meant still reaches the tool. - A call still refused over its arguments now says how to call again, with a minimal example from the schema (or to read the schema with COMPOSIO_GET_TOOL_SCHEMAS for an app tool), that this says nothing about which apps or tools exist, and which connected apps this bot can use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give main's bot-patch route tests the access level the route now asks for Two tests that came with main (vpsAlias relocation guard, phoneApps) built the route without `levelOf`, so they threw "deps.levelOf is not a function". They now answer "chat", a member's level that still may not move a bot or change what it may do; both refusals hold as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(claude): a bot's hooks fire from inside the bot box The hook helper Claude Code runs for each hook reads the turn's bearer from a file in the data folder, which the bot box replaces with an empty folder. On every Cloud home the helper found no token and quietly did nothing: no hint for a timed-out command, no work summaries, no context at session start. - The token lives in a folder of its own per conversation (hook-tokens/<digest>/token), and the box puts that folder back read-only: only that conversation's token, never the data folder or another conversation's token. The folder, not the file, so the box sees each turn's new token after it is renamed over the old one. Tests: a Claude turn under a stand-in box that hides the token unless a mount line puts it back fires its PostToolUse and Stop hooks with the turn's bearer, and the box shows only that conversation's token folder, read-only. It fails with the bind removed (no hook fires), with the file bound instead of its folder, and with the old shared folder (another conversation's token shows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MCP Settings Test reaches a server the way bots do, through the credential broker Where bots' turns are boxed, a turn's engine reaches a URL MCP server through the credential broker, which adds the server's headers and forwards. The Settings Test connected directly, so a server behind Cloudflare Access tested "Connected" while every bot failed (the broker added a slash to the server's address). - The Test now makes a grant the way a turn gets one, connects through the broker's socket, and revokes the grant when it ends. Where turns aren't boxed, bots and the Test both still go direct. - If the server fails through the broker but answers directly, the Test says "Your bots can't reach this server" with the reason and that the fault is on our side, never "Connected". - A server the broker can't reach reads as unreachable, as a direct test does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A new MCP server saved switched off says so, its switch can't flip it straight back, and a server that failed at engine start reconnects - A new or edited server whose first test fails reads "Saved, but off: the test failed", with the reason and that bots can use it once it's on. While that test runs, the row says it's off until it passes. - A passing test after a save switches the server on by itself. A click on its switch in the next moment was aimed at the Off the person saw, so it keeps the server on ("it passed its test a moment ago") instead of switching it straight back off, which looked like a one-second on/off. - Where bots reach URL servers through the credential broker, a server the engine reported as failed when it started gets the conversation a new grant on its next turn, so the engine starts again and reconnects. The chat says the server didn't connect and that it connects again on the next message, so bots no longer need to ask for a new chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Renderer smoke: a saved server whose first test fails reads "Saved, but off" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the reconnect import on its own line, apart from other open changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A connected app comes before any browser or screen, and a refused one is reported with its fix Bots were told to do web work on the person's own computer in this order: the built-in browser, a cloud computer, then a connected app. A connected app does a task more cheaply and surely than any screen, and one that is refused or broken is the person's to fix. - The order now starts with a connected app that does the task. - Wherever a browser or a screen is mounted (a Cloud home too), bots are told to use a connected app first, and when it is refused or fails, to say so in one plain line with what fixes it and ask before doing the task on a screen instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bug reports: the reporter sees their @devs report's status, and is told once when the fix runs here - The person's @devs message shows its report's status in the app's language: "Bug report sent · Got it, we're looking", then "Fixed in 0.1.x, coming in your next update", then "Fixed in 0.1.x" (bugReport on the message; all 17 language packs). - The server follows each report it sent (devs-reports.json) and asks the MausBot team about the open ones a minute after each start and hourly: POST /api/bug-reports/status at the address reports go to, the same way on the desktop and on a Cloud, which signs its question with its bootstrap secret. Nothing ever has to reach this server, or wake a sleeping Cloud. - Once it runs the fix's release (versionAtLeast: never on a guess) and the answer allows it (never a former customer's Cloud, never a teammate who left), one line in the chat they reported in, "Fixed in 0.1.x. Want to try again?", one notification (on a Team Cloud only to the reporter), and a one-time note on the bot's next turn there. Once per report, across restarts. - OMB_DEVS_STATUS_MS sets the interval for fixtures (control-omb passes it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it never interrupts the person, and questions never go stale At Full access ("Just do it") a question from work a bot handed on goes to the bot that handed it on, which answers it from what it knows; with no answer the asker goes on with the default it named and says so in one line. Its card says who picked what and blocks nothing. Only a sign-in, a payment, a secret or the person's own account reaches the person, once, while the rest of the work moves on. An ask tool in handed-on or unwatched work is answered the same way, and the prompts say to find things out the cheapest way first and ask the person last. On "Ask me first" a question waits for the person however long they take. An answer counts from the card, the inbox, the asking bot's own chat, or passed on by another bot (coordinate_bots answers). A question whose work ended, or that a newer one replaced, closes; a sign-in wait in handed-on work settles from the person's line, an answer passed on, or the bot going on with the site; a restart posts nothing again. Rooms and a bot's own chat get the same tap cards, and prompts name Claude's question tool as mcp__ogb__ask_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it decides only in work the person or their routine started A question in work a webhook or another outside event started still goes to the person at Full access, as an ask tool there does: its brief is not the person's authority, and the question is their check on it. The Just do it line stays out of those turns' prompts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep steering and late answers in the person's own chat as they were A line the person types in their own chat while a question card waits is still steered into the turn or queued, as an engine that can steer expects; only in work a teammate handed on does it answer the card. A question its turn left open keeps waiting for a late answer after other lines. Two peer-question notification tests now run on "Ask me first", where a teammate's question is still the person's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Warm summaries: a long conversation is summarized while it sits idle, so the next answer starts fast On a Team trial every first answer slower than 35 s (35 to 58 s) was Claude Code compacting a conversation of about 162k tokens at the start of the person's turn, warm cache or not: writing the summary is what takes the time. Both kinds of compaction ran only when the next turn started, on the person's time. - After a turn that leaves a direct conversation at 100k tokens or more, its summary is written about 3 minutes later, while the prompt cache is still warm; from 80% of Claude Code's own compaction point (160k of 200k) it starts after about 10 s, because the next turn would summarize anyway. - Claude Code: its own /compact, with instructions to keep the person's latest requests and every open question, on a persisted fork of the session (--resume S --fork-session) launched with the live process's exact contract, as the keep-warm ping is, so it reads the cached prompt start and keeps the conversation's tool list. The conversation moves to the fork only when no turn began meanwhile; its last two exchanges count as not yet seen, so the next turn carries them word for word on the existing, saved "not seen yet" path. The chat shows one line for it. - Other engines: OpenMausBot's own fold runs while idle once the conversation is close to its threshold, instead of at the next turn. - Skipped while work is due (a queued message, a teammate working on this conversation's request, a fired wait, the spend limit); retried while the bot is busy, memory is short or a routine of the bot is due, until the cache would be cold. A turn that starts meanwhile wins, unless it would summarize at its start anyway: then it waits for the summary already being written instead of a second. - The app's presence ping names the open chat: opening a conversation starts an overdue summary at once and keeps its engine process alive while the person is there. - Off with context.autoCompact: false, or OMB_WARM_SUMMARY=0 for this alone. The fake Claude Code gains a growing context, its own compaction at a threshold with a duration, and /compact on a fork. On a long fake conversation whose CLI compaction takes 6 s, the next reply took 6.2 s before and 0.3 s after; one sent while the needed summary was being written took 5.4 s (the rest of it, not a second one); one sent during a summary it did not need, under 0.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * People before bots: a shared @name reaches the person, a bot named like a person is warned, deleting a Chief offers Archive On a Team trial a person's "@<teammate>" reached a bot that had the teammate's name, because a tie went to the bot. Then the person deleted their Chief to fix it, and lost its whole setup chat. - A tag a person and a bot share is the person's: "@Bob" reaches the teammate Bob (or means the writer, for their own name), and only a longer bot name ("@Bob Bot") reaches a bot. The teammate's inbox gets it, the turn no longer tells the bot it was named, and the composer highlights it as the person (shared/person-mention.ts, src/lib/mentions.ts). - A bot made or renamed with a person's name (a teammate's, or the owner's own) says so once in its own chat, and the Chief's create_bot result carries the same warning (server/host/bot-name-clash.ts). Nothing is refused. - Deleting a Chief of Staff offers "Archive instead" first: its chats hold the team's setup. Archiving drops the Chief role, so the server accepts it, and the bot can be restored any time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots in two places: one plain suggestion to bring them together When this computer has bots of its own while a server of the person's own (or My Cloud they keep this computer's bots away from) has bots too, the bots in the two places can't work together. This computer's page now says so once, in a corner card: "Your bots live in two places, so they can't work together. Bring them together on <place>?" One tap starts the one-time move there (Make <server> my home, or letting this computer's bots move to My Cloud), and Not now is remembered for that place. Main reads each place's own move summary, so only bots a move would carry count and a place's untouched first bot never makes two places. A server is asked only while it says it is the person's alone, a sleeping Cloud never, a team's Cloud or a server others sign in to never. Nothing shows while a move is under way, during the welcome or the tour, or on any page but this computer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots say where another bot lives, and how to bring them together A bot that asked for a teammate living in the person's other place (their computer, their own server or My Cloud) only heard that no such bot exists. The person's app now tells each of their own places the names of the bots their other places have, and nothing more (PUT /api/places/elsewhere, from that place's owner only, never a team's place or one others sign in to). With that: - coordinate_bots and bot_idle waits say "Scout lives on Work laptop, the person's computer, not here", that bots work together only within one place, and offer the one tap that brings them together ("Make Garage server my home", or Bring them together for My Cloud); a name nowhere stays no such bot; - a person's @mention of such a bot tells the answering bot where it lives, and in a room one plain line says so to the person; - before the app said anything, a name nowhere here also says that bots work together only within one place, and how to bring them together. Main tells each place only when what it would be told changed, never while a move is under way, and stops telling this computer once its bots moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Server lines in the person's language: the way in, a guard, and bug report lines Lines the server writes for a person (a bot's line, a status row, a card, a notification) now come from the language packs under "server." keys, in the language the person's app shows. - server/server-lines.ts: serverLine(language, key, params) reads the packs; a missing key reads in English, as the app's screens do. The server bundle keeps only the server keys (scripts/server-locale-plugin.mjs), and tsc's copies of the packs are dropped from dist-server. - server/host/person-languages.ts: the app keeps a person's language pick on their own computer, so the server learns it from presence pings (the owner's, or each member's on a Team Cloud). A line for a person reads in theirs, else in the place's: the one set on the server or by the team's Admin, else the one most people's apps show. - Bug report lines (@devs) read in the reporter's language; the marker that tells whether the bot already passed a failure on is "MausBot", which every language keeps. - src/locales/server-lines.test.ts: a guard that fails on an English line written straight into a line a person reads. It follows each place a line is made through consts, helpers and imports; ALLOWED says why text is English on purpose; PENDING lists the 242 lines written before it, by area, and only shrinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Only the tests of other languages' lines read the packs; CI selection knows it CI's import-graph checks failed: the server now loads the language packs, and every server test reaching server-lines.ts counted as reading a translation. - server/server-lines.ts reads English only. server/server-line-packs.ts adds the other languages; server/index.ts loads it at start, and so do the tests that check a line in another language. The guard checks index.ts loads it. - scripts/ci-scope.mjs: those tests run with the locale tests. The packs stay out of SRC_OUTSIDE_RENDERER: a change to English already runs every Linux test, and one to another language runs every test that reads it, so a translation change does not run the server's checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Runs and routines tell the person in their language A routine's line in a chat and the incident a person hears about now read in the language of the person whose conversation it is, through server/server-lines.ts. - "This run didn't finish: …" and "Recovered: … finished OK at …" (with the time in that language's clock), written into the chat a routine reports to. - The text of a routine run's card, for clients that show no cards. - The incident status row and its notification. The Chief's own incident report stays English: only a model reads it. - server/index.ts: threadLanguage(threadId), the language of a conversation's person, else the place's; no line added. - The guard's PENDING drops these 17 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Connect prompts and sign-ins ask in the person's language When a bot needs the person to connect an app, sign in or give a key, what the server writes now reads in the language of the person whose conversation it is. - "I need you to connect …", "I need you to sign in to …" and "I need your …", which a routine writes into its chat while it waits on a card. - The connect card's text and, where the app catalog has no words of its own, its description. - The line under a sign-in card. It moves from shared/ to server/connector-card-text.ts, since shared code cannot read the packs; nothing else used it. - The credential card's text and the sentence on how the bot gets the key. - The guard's PENDING drops this area's 13 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Notifications are titled in the person's language Every notification's title ("… has a question", "…'s routine failed", "… needs you to sign in to …") now reads in the language of the conversation's person: buildNotification asks a resolver the server sets at start (setNotificationLanguage(threadLanguage)), so no caller changes. Also the inbox's "· your assistant answered" and two bodies the server writes itself ("Results in from …", "Open OpenMausBot to sign in to …"). The guard's PENDING drops the area's 8 lines, and checks the server sets the resolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A room's status rows read in its person's language What a group chat shows about its members now reads in the language of its conversation's person: waiting for a busy member and the skips, a mention that missed, archived members, still stopping, held members, no summary, a stalled turn, context compaction, and a bot's receipt in its own chat ("Posted in …", "Opened thread #…"). What a coordinating bot reads stays English. - server/server-lines.ts: isServerLine(key, text) reads a line back in any language; isHeldMemberLine uses it, and the held row keeps "resume", the word the room understands. - The sentinel counts a German stopped room turn as a timeout, and now also skips a held member's row in the shape it reads rows in (a harness notice with names taken out). The openmausbot CLI, which runs it, loads the other languages. - The guard's PENDING drops 20 room lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(team connections): an owner's own-connection lines are checked in her private chat and in a shared one An own bridge only works in the person's private chat now, so the "connect your apps again" check runs there; the connect lines are checked in both places, including an app call through the team's tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates' hand-offs and results read in the person's language What a conversation shows about a teammate's work now reads in the language of that conversation's person: a hand-off going out ("Sent to …"), its result coming back ("… replied", "… — failed:", "Result withheld:"), resuming with results or a question, what came of a teammate's question or approval, what waits behind the person, recalled private chats, a closed thread, a room goal's card, "Answer passed to the waiting work", and the inbox's and team messages' rows. - server/server-lines.ts: one resolver, conversationLanguage(threadId), which the server sets at start; notifications use it too (it replaces setNotificationLanguage), so modules with no person at hand need no new wiring. - What a coordinating bot reads stays English. - The guard's PENDING drops 19 lines; the area keeps feature-flagged escalations, approval level names, the peer approval card and a goal's text after a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it: a question in a person's private chat stays theirs Work a person's request hands on runs in the receiving bot's chat with them when it may use their own apps, and what it hands back keeps a question's words in that chat. Its requester never sees them, so it cannot decide them, and a sign-in among them could not be told apart. Such a question now reaches the person there, as on "Ask me first": the turn result says the question stayed private, and the ask tool is not turned away in that chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acting person): read the private question flag with toMatchObject The hand-back keeps its input's type, which has no privateQuestion field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(analytics): the two-places card's event Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): the engine registry answers null for a missing engine registry.get returns ProviderInstance | null; the host's dependency took only undefined, which failed typecheck once the branch was checked against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): its line in the chat comes from the language packs The line a warm summary leaves in the conversation is now server.warmSummary.summarized, in every pack, written in the language of the conversation's person, as the guard from #3931 asks of every line a person reads. It names no count, so it needs no plural forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Main's guard passes: the same-request notice in the person's language Main went red on the server-lines guard: #3957's "Another teammate asked the same a moment ago…" row landed while #3931's guard was in review, and #3948 reworded a line the guard lists. - The notice reads in the language of the conversation's person (server.teammates.sameRequest, German by hand, every pack). - PENDING follows #3948's rewording of the webhook line. - The guard's check that index.ts loads the other languages matches that import anywhere on its line (as #3960 has it), so another import may follow it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates: the recall row reads in its room's language after main's discloseRecall Main moved this row into discloseRecall(bot, roomThreadId, …), where threadId is not in scope, so the merged branch failed typecheck. The row is the room's: it now asks for roomThreadId's language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bots explain): the one-place hint comes before the reach help, so a refusal still ends with it server/room-coordination.e2e.test.ts pins that a refusal for a name nobody has ends with the reach help (and its "Never use computer control to get around this"). The hint now sits just before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the cards a parked turn waits on move to server/host/resumable-cards.ts resumableCards is a pure read of the conversation; moving it out keeps server/index.ts under its file-size ratchet once #3930 lands with main (the fix #3930's branch made when it merged main, ported here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the MCP reconnect, bot name clash and bug-fixed lines come from the language packs #3922, #3934 and #3937 were written before main's server-lines guard, which fails on their three English lines once they meet it. Each line is now a "server." key (English and German) written with serverLine in the language of the conversation or reporter: server.mcp.reconnect.one/many (server names listed the reader's way), server.bots.nameClash (create_bot's result stays English for the model) and server.reports.fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the bot archive/delete dialog's props move beside botConfirmCopy #3934's Archive-instead offer grew src/components/Sidebar.tsx past the size the 0.1.135 release set (1790 against 1785). botConfirmProps in ArchivedBotsPanel.tsx now builds the dialog (copy, icon, Archive instead for a Chief, confirm); the sidebar keeps the ConfirmDialog and its callbacks, and is 1774 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 5 天前 | |
Train: team-trial fixes, warm summaries, team bot access, own-server places, server lines (merge with Create a merge commit) (#3999) * Team bots: a level per person (view, chat, edit), shared from each bot A team bot is now shared like a document: what everyone in the team gets (Only people added, or Everyone at Can view, Can chat or Can edit) and a level for each person added. Admins and the bot's owner always edit. - The bot's Share button (bot panel in Simple, settings header in Advanced) opens a Share dialog on a team: people with access with their level, adding teammates by name or email, general access; every change applies at once with an Undo toast. - The server enforces it on every member request after the visibility gate: reads need Can view, writes Can chat (a room needs it on every bot), sharing and a bot's own setup Can edit; a routine needs Can edit unless its writer changes it; a card that changes the bot needs Can edit; a message another app relays needs the named person to chat. - Each copy of a bot carries the viewer's own level; the sharing only on an editor's. The live stream follows a change. - Bots set up before levels keep exactly what their visibility gave (everyone: Everyone, Can chat; admins only: Only people added; a list: those people, Can chat), read from it with nothing rewritten. - A person who can only view sees that in place of the composer, opens the bot's main chat, and is offered no new conversation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Team bot access: before and after pictures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Share dialog test: a whole bot Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(context): the unseen-messages block ends before the person's message When a resumed session has missed messages, the turn's prompt lists them in a block and then gives the person's new message after one blank line, with nothing saying the block is over. In a Team trial the person's next request, written right after a co-founder's relayed reply, was credited to the co-founder. The block now ends with "[End of those messages. Now reply to the user's latest message:]" before the turn's own text, as the full replay already ends its history with "[Now reply to the user's latest message:]". The wording differs from the replay's, so nothing that looks for the replay's end mistakes this block for replayed history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The owner is never told to ask an admin: connection lines know the person's role On a Team Cloud, a member's own bridge that asked for a team app's connection card got "ask an admin to connect it", whatever the person's role. The owner was told to ask an admin, and a bot named a teammate who wasn't one as the admin. - For the Owner or an Admin, the bot asks for the card through the team's composio bridge, whose card lets them connect the app for the whole team in one tap. - A User is told who can connect it, by name: the team's Owner and Admins from the roster the Admin paired here. - "Connect your <app> here" links go where each person's own connections are: the team's Apps page for the Owner and Admins, a User's team home otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(research): offer the research tools only where research works A Cloud home always holds the plan's X relay token, so every bot was offered research_search, research_endpoint and research_call. On a plan whose relay has research off, each call then answered only "Research isn't available right now." - The home asks the relay once, at start, with a search that names no job: the relay answers that with a 400 only once the token, the plan and research are all fine, before it reads its catalog or spends anything. An off answer (402, 404, 401, or 503 service_unavailable) hides the three research tools; x_search stays, since X works without research. It asks again an hour after an off answer, and a research call the relay refuses as off hides them at once. - The person's own treg key goes straight to treg: research is on. - A refusal because research is off now says what to do: tell the person and offer another way (web search or the browser); their own treg key turns research on. - The agents server gets a switch of its own for the research tools (OMB_RESEARCH) beside the X one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): a person's message never waits behind a long tool call A message the person sends their bot while it works is steered into the running turn, and an engine reads it only once the tool call it is in returns. A bot polling CI with `sleep 30` loops kept a person's message unread for 26 minutes and never said the PR it had made existed. - Mechanism: when the person's own one-to-one message waits unread while a tool call has run for a minute (at once if the call had already run that long), the server stops the turn, with a row saying so, and the message runs next, ahead of anything else queued in that chat. Its row is run as is (the follow-up queue can now take a row already in the transcript), and the model is told which step was stopped. Messages from rooms, routines, teammates and apps never do this, nor does one sent while the turn waits on the person or a computer. The wait is OMB_PERSON_FIRST_MS for tests. - Prompt: never wait inside a command for CI, a deploy or another job; check once, say what you made (with links), set wait_until or a one-time trigger to check back, and end the turn; answer the person first. Stopping and re-running works for every engine, and so does every engine's Stop. No engine reads a steered message during a tool call, some cannot steer at all, and Claude's own "send now" depends on moving the tool to the background, which bots run without. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): the person's re-run keeps its place and goes ahead of a teammate's The re-run of a steered message that a long tool call kept unread is now queued by the time the person sent it, ahead of everything but their own earlier messages, and a message of theirs that has to wait in the queue goes ahead of a teammate's or a routine's too. Before, the re-run took the time it was queued again, so on a slow runner it no longer joined the person's next message as one turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(connectors): app tool calls fit their schema, and a refusal says how to call again Composio checks a call's arguments against the tool's schema and refuses the whole call over one. In a Team trial five calls failed that way: COMPOSIO_SEARCH_TOOLS sent { job } (Required at "queries"), COMPOSIO_REMOTE_WORKBENCH sent code for code_to_execute and a timeout as text, and COMPOSIO_MULTI_EXECUTE_TOOL sent its tools list as text. After the search failed, the bot told the person it had no image tool, though an image app was connected. - The connector bridge keeps each listed tool's schema and fits a call to it where the bot plainly meant that shape: arguments or a list written as text, a number or yes/no written as text, a bare string or strings where a list of one-field objects goes, and one missing required field under another name when exactly one sent field can be it. The bot is told how its arguments were read, so it sends that shape next time. Anything not plainly meant still reaches the tool. - A call still refused over its arguments now says how to call again, with a minimal example from the schema (or to read the schema with COMPOSIO_GET_TOOL_SCHEMAS for an app tool), that this says nothing about which apps or tools exist, and which connected apps this bot can use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give main's bot-patch route tests the access level the route now asks for Two tests that came with main (vpsAlias relocation guard, phoneApps) built the route without `levelOf`, so they threw "deps.levelOf is not a function". They now answer "chat", a member's level that still may not move a bot or change what it may do; both refusals hold as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(claude): a bot's hooks fire from inside the bot box The hook helper Claude Code runs for each hook reads the turn's bearer from a file in the data folder, which the bot box replaces with an empty folder. On every Cloud home the helper found no token and quietly did nothing: no hint for a timed-out command, no work summaries, no context at session start. - The token lives in a folder of its own per conversation (hook-tokens/<digest>/token), and the box puts that folder back read-only: only that conversation's token, never the data folder or another conversation's token. The folder, not the file, so the box sees each turn's new token after it is renamed over the old one. Tests: a Claude turn under a stand-in box that hides the token unless a mount line puts it back fires its PostToolUse and Stop hooks with the turn's bearer, and the box shows only that conversation's token folder, read-only. It fails with the bind removed (no hook fires), with the file bound instead of its folder, and with the old shared folder (another conversation's token shows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MCP Settings Test reaches a server the way bots do, through the credential broker Where bots' turns are boxed, a turn's engine reaches a URL MCP server through the credential broker, which adds the server's headers and forwards. The Settings Test connected directly, so a server behind Cloudflare Access tested "Connected" while every bot failed (the broker added a slash to the server's address). - The Test now makes a grant the way a turn gets one, connects through the broker's socket, and revokes the grant when it ends. Where turns aren't boxed, bots and the Test both still go direct. - If the server fails through the broker but answers directly, the Test says "Your bots can't reach this server" with the reason and that the fault is on our side, never "Connected". - A server the broker can't reach reads as unreachable, as a direct test does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A new MCP server saved switched off says so, its switch can't flip it straight back, and a server that failed at engine start reconnects - A new or edited server whose first test fails reads "Saved, but off: the test failed", with the reason and that bots can use it once it's on. While that test runs, the row says it's off until it passes. - A passing test after a save switches the server on by itself. A click on its switch in the next moment was aimed at the Off the person saw, so it keeps the server on ("it passed its test a moment ago") instead of switching it straight back off, which looked like a one-second on/off. - Where bots reach URL servers through the credential broker, a server the engine reported as failed when it started gets the conversation a new grant on its next turn, so the engine starts again and reconnects. The chat says the server didn't connect and that it connects again on the next message, so bots no longer need to ask for a new chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Renderer smoke: a saved server whose first test fails reads "Saved, but off" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the reconnect import on its own line, apart from other open changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A connected app comes before any browser or screen, and a refused one is reported with its fix Bots were told to do web work on the person's own computer in this order: the built-in browser, a cloud computer, then a connected app. A connected app does a task more cheaply and surely than any screen, and one that is refused or broken is the person's to fix. - The order now starts with a connected app that does the task. - Wherever a browser or a screen is mounted (a Cloud home too), bots are told to use a connected app first, and when it is refused or fails, to say so in one plain line with what fixes it and ask before doing the task on a screen instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bug reports: the reporter sees their @devs report's status, and is told once when the fix runs here - The person's @devs message shows its report's status in the app's language: "Bug report sent · Got it, we're looking", then "Fixed in 0.1.x, coming in your next update", then "Fixed in 0.1.x" (bugReport on the message; all 17 language packs). - The server follows each report it sent (devs-reports.json) and asks the MausBot team about the open ones a minute after each start and hourly: POST /api/bug-reports/status at the address reports go to, the same way on the desktop and on a Cloud, which signs its question with its bootstrap secret. Nothing ever has to reach this server, or wake a sleeping Cloud. - Once it runs the fix's release (versionAtLeast: never on a guess) and the answer allows it (never a former customer's Cloud, never a teammate who left), one line in the chat they reported in, "Fixed in 0.1.x. Want to try again?", one notification (on a Team Cloud only to the reporter), and a one-time note on the bot's next turn there. Once per report, across restarts. - OMB_DEVS_STATUS_MS sets the interval for fixtures (control-omb passes it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it never interrupts the person, and questions never go stale At Full access ("Just do it") a question from work a bot handed on goes to the bot that handed it on, which answers it from what it knows; with no answer the asker goes on with the default it named and says so in one line. Its card says who picked what and blocks nothing. Only a sign-in, a payment, a secret or the person's own account reaches the person, once, while the rest of the work moves on. An ask tool in handed-on or unwatched work is answered the same way, and the prompts say to find things out the cheapest way first and ask the person last. On "Ask me first" a question waits for the person however long they take. An answer counts from the card, the inbox, the asking bot's own chat, or passed on by another bot (coordinate_bots answers). A question whose work ended, or that a newer one replaced, closes; a sign-in wait in handed-on work settles from the person's line, an answer passed on, or the bot going on with the site; a restart posts nothing again. Rooms and a bot's own chat get the same tap cards, and prompts name Claude's question tool as mcp__ogb__ask_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it decides only in work the person or their routine started A question in work a webhook or another outside event started still goes to the person at Full access, as an ask tool there does: its brief is not the person's authority, and the question is their check on it. The Just do it line stays out of those turns' prompts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep steering and late answers in the person's own chat as they were A line the person types in their own chat while a question card waits is still steered into the turn or queued, as an engine that can steer expects; only in work a teammate handed on does it answer the card. A question its turn left open keeps waiting for a late answer after other lines. Two peer-question notification tests now run on "Ask me first", where a teammate's question is still the person's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Warm summaries: a long conversation is summarized while it sits idle, so the next answer starts fast On a Team trial every first answer slower than 35 s (35 to 58 s) was Claude Code compacting a conversation of about 162k tokens at the start of the person's turn, warm cache or not: writing the summary is what takes the time. Both kinds of compaction ran only when the next turn started, on the person's time. - After a turn that leaves a direct conversation at 100k tokens or more, its summary is written about 3 minutes later, while the prompt cache is still warm; from 80% of Claude Code's own compaction point (160k of 200k) it starts after about 10 s, because the next turn would summarize anyway. - Claude Code: its own /compact, with instructions to keep the person's latest requests and every open question, on a persisted fork of the session (--resume S --fork-session) launched with the live process's exact contract, as the keep-warm ping is, so it reads the cached prompt start and keeps the conversation's tool list. The conversation moves to the fork only when no turn began meanwhile; its last two exchanges count as not yet seen, so the next turn carries them word for word on the existing, saved "not seen yet" path. The chat shows one line for it. - Other engines: OpenMausBot's own fold runs while idle once the conversation is close to its threshold, instead of at the next turn. - Skipped while work is due (a queued message, a teammate working on this conversation's request, a fired wait, the spend limit); retried while the bot is busy, memory is short or a routine of the bot is due, until the cache would be cold. A turn that starts meanwhile wins, unless it would summarize at its start anyway: then it waits for the summary already being written instead of a second. - The app's presence ping names the open chat: opening a conversation starts an overdue summary at once and keeps its engine process alive while the person is there. - Off with context.autoCompact: false, or OMB_WARM_SUMMARY=0 for this alone. The fake Claude Code gains a growing context, its own compaction at a threshold with a duration, and /compact on a fork. On a long fake conversation whose CLI compaction takes 6 s, the next reply took 6.2 s before and 0.3 s after; one sent while the needed summary was being written took 5.4 s (the rest of it, not a second one); one sent during a summary it did not need, under 0.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * People before bots: a shared @name reaches the person, a bot named like a person is warned, deleting a Chief offers Archive On a Team trial a person's "@<teammate>" reached a bot that had the teammate's name, because a tie went to the bot. Then the person deleted their Chief to fix it, and lost its whole setup chat. - A tag a person and a bot share is the person's: "@Bob" reaches the teammate Bob (or means the writer, for their own name), and only a longer bot name ("@Bob Bot") reaches a bot. The teammate's inbox gets it, the turn no longer tells the bot it was named, and the composer highlights it as the person (shared/person-mention.ts, src/lib/mentions.ts). - A bot made or renamed with a person's name (a teammate's, or the owner's own) says so once in its own chat, and the Chief's create_bot result carries the same warning (server/host/bot-name-clash.ts). Nothing is refused. - Deleting a Chief of Staff offers "Archive instead" first: its chats hold the team's setup. Archiving drops the Chief role, so the server accepts it, and the bot can be restored any time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots in two places: one plain suggestion to bring them together When this computer has bots of its own while a server of the person's own (or My Cloud they keep this computer's bots away from) has bots too, the bots in the two places can't work together. This computer's page now says so once, in a corner card: "Your bots live in two places, so they can't work together. Bring them together on <place>?" One tap starts the one-time move there (Make <server> my home, or letting this computer's bots move to My Cloud), and Not now is remembered for that place. Main reads each place's own move summary, so only bots a move would carry count and a place's untouched first bot never makes two places. A server is asked only while it says it is the person's alone, a sleeping Cloud never, a team's Cloud or a server others sign in to never. Nothing shows while a move is under way, during the welcome or the tour, or on any page but this computer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots say where another bot lives, and how to bring them together A bot that asked for a teammate living in the person's other place (their computer, their own server or My Cloud) only heard that no such bot exists. The person's app now tells each of their own places the names of the bots their other places have, and nothing more (PUT /api/places/elsewhere, from that place's owner only, never a team's place or one others sign in to). With that: - coordinate_bots and bot_idle waits say "Scout lives on Work laptop, the person's computer, not here", that bots work together only within one place, and offer the one tap that brings them together ("Make Garage server my home", or Bring them together for My Cloud); a name nowhere stays no such bot; - a person's @mention of such a bot tells the answering bot where it lives, and in a room one plain line says so to the person; - before the app said anything, a name nowhere here also says that bots work together only within one place, and how to bring them together. Main tells each place only when what it would be told changed, never while a move is under way, and stops telling this computer once its bots moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Server lines in the person's language: the way in, a guard, and bug report lines Lines the server writes for a person (a bot's line, a status row, a card, a notification) now come from the language packs under "server." keys, in the language the person's app shows. - server/server-lines.ts: serverLine(language, key, params) reads the packs; a missing key reads in English, as the app's screens do. The server bundle keeps only the server keys (scripts/server-locale-plugin.mjs), and tsc's copies of the packs are dropped from dist-server. - server/host/person-languages.ts: the app keeps a person's language pick on their own computer, so the server learns it from presence pings (the owner's, or each member's on a Team Cloud). A line for a person reads in theirs, else in the place's: the one set on the server or by the team's Admin, else the one most people's apps show. - Bug report lines (@devs) read in the reporter's language; the marker that tells whether the bot already passed a failure on is "MausBot", which every language keeps. - src/locales/server-lines.test.ts: a guard that fails on an English line written straight into a line a person reads. It follows each place a line is made through consts, helpers and imports; ALLOWED says why text is English on purpose; PENDING lists the 242 lines written before it, by area, and only shrinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Only the tests of other languages' lines read the packs; CI selection knows it CI's import-graph checks failed: the server now loads the language packs, and every server test reaching server-lines.ts counted as reading a translation. - server/server-lines.ts reads English only. server/server-line-packs.ts adds the other languages; server/index.ts loads it at start, and so do the tests that check a line in another language. The guard checks index.ts loads it. - scripts/ci-scope.mjs: those tests run with the locale tests. The packs stay out of SRC_OUTSIDE_RENDERER: a change to English already runs every Linux test, and one to another language runs every test that reads it, so a translation change does not run the server's checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Runs and routines tell the person in their language A routine's line in a chat and the incident a person hears about now read in the language of the person whose conversation it is, through server/server-lines.ts. - "This run didn't finish: …" and "Recovered: … finished OK at …" (with the time in that language's clock), written into the chat a routine reports to. - The text of a routine run's card, for clients that show no cards. - The incident status row and its notification. The Chief's own incident report stays English: only a model reads it. - server/index.ts: threadLanguage(threadId), the language of a conversation's person, else the place's; no line added. - The guard's PENDING drops these 17 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Connect prompts and sign-ins ask in the person's language When a bot needs the person to connect an app, sign in or give a key, what the server writes now reads in the language of the person whose conversation it is. - "I need you to connect …", "I need you to sign in to …" and "I need your …", which a routine writes into its chat while it waits on a card. - The connect card's text and, where the app catalog has no words of its own, its description. - The line under a sign-in card. It moves from shared/ to server/connector-card-text.ts, since shared code cannot read the packs; nothing else used it. - The credential card's text and the sentence on how the bot gets the key. - The guard's PENDING drops this area's 13 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Notifications are titled in the person's language Every notification's title ("… has a question", "…'s routine failed", "… needs you to sign in to …") now reads in the language of the conversation's person: buildNotification asks a resolver the server sets at start (setNotificationLanguage(threadLanguage)), so no caller changes. Also the inbox's "· your assistant answered" and two bodies the server writes itself ("Results in from …", "Open OpenMausBot to sign in to …"). The guard's PENDING drops the area's 8 lines, and checks the server sets the resolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A room's status rows read in its person's language What a group chat shows about its members now reads in the language of its conversation's person: waiting for a busy member and the skips, a mention that missed, archived members, still stopping, held members, no summary, a stalled turn, context compaction, and a bot's receipt in its own chat ("Posted in …", "Opened thread #…"). What a coordinating bot reads stays English. - server/server-lines.ts: isServerLine(key, text) reads a line back in any language; isHeldMemberLine uses it, and the held row keeps "resume", the word the room understands. - The sentinel counts a German stopped room turn as a timeout, and now also skips a held member's row in the shape it reads rows in (a harness notice with names taken out). The openmausbot CLI, which runs it, loads the other languages. - The guard's PENDING drops 20 room lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(team connections): an owner's own-connection lines are checked in her private chat and in a shared one An own bridge only works in the person's private chat now, so the "connect your apps again" check runs there; the connect lines are checked in both places, including an app call through the team's tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates' hand-offs and results read in the person's language What a conversation shows about a teammate's work now reads in the language of that conversation's person: a hand-off going out ("Sent to …"), its result coming back ("… replied", "… — failed:", "Result withheld:"), resuming with results or a question, what came of a teammate's question or approval, what waits behind the person, recalled private chats, a closed thread, a room goal's card, "Answer passed to the waiting work", and the inbox's and team messages' rows. - server/server-lines.ts: one resolver, conversationLanguage(threadId), which the server sets at start; notifications use it too (it replaces setNotificationLanguage), so modules with no person at hand need no new wiring. - What a coordinating bot reads stays English. - The guard's PENDING drops 19 lines; the area keeps feature-flagged escalations, approval level names, the peer approval card and a goal's text after a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it: a question in a person's private chat stays theirs Work a person's request hands on runs in the receiving bot's chat with them when it may use their own apps, and what it hands back keeps a question's words in that chat. Its requester never sees them, so it cannot decide them, and a sign-in among them could not be told apart. Such a question now reaches the person there, as on "Ask me first": the turn result says the question stayed private, and the ask tool is not turned away in that chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acting person): read the private question flag with toMatchObject The hand-back keeps its input's type, which has no privateQuestion field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(analytics): the two-places card's event Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): the engine registry answers null for a missing engine registry.get returns ProviderInstance | null; the host's dependency took only undefined, which failed typecheck once the branch was checked against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): its line in the chat comes from the language packs The line a warm summary leaves in the conversation is now server.warmSummary.summarized, in every pack, written in the language of the conversation's person, as the guard from #3931 asks of every line a person reads. It names no count, so it needs no plural forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Main's guard passes: the same-request notice in the person's language Main went red on the server-lines guard: #3957's "Another teammate asked the same a moment ago…" row landed while #3931's guard was in review, and #3948 reworded a line the guard lists. - The notice reads in the language of the conversation's person (server.teammates.sameRequest, German by hand, every pack). - PENDING follows #3948's rewording of the webhook line. - The guard's check that index.ts loads the other languages matches that import anywhere on its line (as #3960 has it), so another import may follow it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates: the recall row reads in its room's language after main's discloseRecall Main moved this row into discloseRecall(bot, roomThreadId, …), where threadId is not in scope, so the merged branch failed typecheck. The row is the room's: it now asks for roomThreadId's language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bots explain): the one-place hint comes before the reach help, so a refusal still ends with it server/room-coordination.e2e.test.ts pins that a refusal for a name nobody has ends with the reach help (and its "Never use computer control to get around this"). The hint now sits just before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the cards a parked turn waits on move to server/host/resumable-cards.ts resumableCards is a pure read of the conversation; moving it out keeps server/index.ts under its file-size ratchet once #3930 lands with main (the fix #3930's branch made when it merged main, ported here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the MCP reconnect, bot name clash and bug-fixed lines come from the language packs #3922, #3934 and #3937 were written before main's server-lines guard, which fails on their three English lines once they meet it. Each line is now a "server." key (English and German) written with serverLine in the language of the conversation or reporter: server.mcp.reconnect.one/many (server names listed the reader's way), server.bots.nameClash (create_bot's result stays English for the model) and server.reports.fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the bot archive/delete dialog's props move beside botConfirmCopy #3934's Archive-instead offer grew src/components/Sidebar.tsx past the size the 0.1.135 release set (1790 against 1785). botConfirmProps in ArchivedBotsPanel.tsx now builds the dialog (copy, icon, Archive instead for a Chief, confirm); the sidebar keeps the ConfirmDialog and its callbacks, and is 1774 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 5 天前 | |
feat(harness): record scoped work summaries and tool evidence (#1560) * feat(harness): command receipts — idempotent mutations on the transcript DB (phase 0, step 1) Every new mutation from Phase 0 on runs as a typed command whose receipt is written in the same SQLite transaction as its rows. A repeat of the same (kind, key) returns the stored result instead of applying twice. Adds the command_receipts table, withCommandReceipt/readCommandReceipt in message-db, and the small runCommand/commandReceipt API in server/commands.ts. Also records the Phase 0 plan under docs/plans. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(harness): work digest per turn, for every engine (phase 0, step 2) At settle the fold writes one bounded record of what the turn did: tool calls by name with failures (from the activity rows every driver already emits), files changed (a settle checkpoint diffed against the dispatch checkpoint via the new checkpoints.diffStat), memory journal rows for the turn, the gist of the reply, usage, and how good the tool evidence is (preview / full / none per driver kind). Stored as a new digest message kind whose text is FTS-indexed and recalled after ordinary text hits; included in the direct replay and the room context so a rebuilt context carries work, not only talk. Activity rows are now attributed to their turn, with a live-turn fallback for drivers that do not stamp items. Transactions in message-db nest so a command's apply can use the store. Renderer shows a quiet digest chip under the tool-calls setting. Verified: unit suites for digest, checkpoints, commands and message-db; an e2e matrix across the fake ACP, Claude, Codex and pi engines, plus the phase's done-when (a file changed during a turn is named in the digest and shown to a different engine taking over the thread). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(harness): engine hooks — full tool results through Claude Code hooks (phase 0, step 3) Adds an engine-agnostic hook channel: a driver that declares capabilities.hooks receives integrations.hooks {url, token} per turn, and the harness accepts POST /api/internal/hook under a turn-scoped 'hooks' capability. The Claude driver registers one helper (server/hooks/omb-hook) for PostToolUse, PreCompact, SessionStart and Stop through the private --settings file it already writes; the helper always exits 0, is bounded, reads its bearer from a per-thread token file the driver rewrites every turn (so a long-lived CLI process never presents a stale token), and prints only the harness's hookSpecificOutput. PostToolUse delivers the full tool result: redacted, spilled to DATA_DIR/tool-results/<thread>/<tool_use_id>.txt (0600, bounded), and attached to the tool's activity row (itemId, outputPath, fullResult), which lets the digest claim full evidence. Other events are accepted and ignored until step 4. OMB_HOOKS=0 registers nothing. Activity rows now carry the driver's item id for every engine. Verified: helper unit tests (garbage input, bearer + hookSpecificOutput, never-answering harness, silent no-output), digest evidence rule, Claude driver suite, and an e2e with the fake CLI honouring settings hooks (full result spilled and attached, forged bearer refused, OMB_HOOKS=0 stays on previews). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(harness): compaction hooks — record it, re-send the latest digests (phase 0, step 4) PreCompact and SessionStart(compact) from the engine now land as transcript chips, and after a compaction the harness hands the thread's last two work digests back to the engine as plain-text context (the only channel Claude Code accepts on SessionStart), so a compacted session still knows what its earlier turns did. Stop is accepted and ignored for now. The hook helper prints a plain-text context body on SessionStart/UserPromptSubmit only. The fake Claude CLI can play a compaction with its hooks on later turns, uses globally unique tool ids like the real CLI, and keeps a turn counter across respawns. The plan records two findings: the per-turn MCP tokens in the Claude spawn contract defeat process reuse on every turn (Phase 1, F1), and the hook-output constraints that shaped this step (F2). Verified: helper unit suite (incl. plain-text context path), hooks e2e (PostToolUse, forged bearer, compaction, OMB_HOOKS=0), Claude driver suite. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(desktop): read past digest receipts in the sidebar preview and mascot mood (phase 0) A digest row now follows every settled turn, so it became the last row of every idle chat: the sidebar previewed "[digest] · tools: …" instead of the reply, and a failed tool call no longer turned the mascot alerting because the receipt hid it. One predicate (src/lib/receipts.ts) now tells both to look past the harness's receipts. Tests: SidebarBotListItem, Sidebar.simple-mode (group preview), mascot.test.ts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(harness): tie work receipts to committed turn evidence * test: wait for gated delegation launch before changing soul * fix: address receipt and hook review findings Flush hook output before exit, keep spill paths private, clean owned digest state on cancellation and deletion, and use portable fixture cleanup. * test: keep digest evidence paths out of logs * feat(context): durable, cancellable long-thread compaction (#1563) * fix(claude): discard retained context when rebuilding a conversation Adapt the explicit-reset foundation from #1272, while preserving ordinary reuse, suppressing stale cursors, and consuming the reset before retrying a new session. Co-authored-by: aivsomkar <aivsomkar@gmail.com> * feat(context): compact long conversations with cancellable durable summaries --------- Co-authored-by: aivsomkar <aivsomkar@gmail.com> --------- Co-authored-by: aivsomkar <aivsomkar@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
Email: read and send mail on any mail host, connected with one card Email appears in Connected apps. The person gives an address and a password once, on the existing secret card in a chat or on the Apps card, and bots get EMAIL_LIST_MAILBOXES, EMAIL_LIST_MESSAGES, EMAIL_SEARCH_MESSAGES, EMAIL_READ_MESSAGE and EMAIL_SEND_MESSAGE. - Servers are found from the address: the domain's autoconfig, well-known providers by domain or MX, Thunderbird's list, SRV records, then the usual names; else the card asks. - Nothing is saved until a real header of the newest message reads back. - The tools run in the server (ImapFlow, Nodemailer, mailparser): a bot's box never holds the password or a route to a mail server. The password rests sealed, goes only over TLS to a host with a valid certificate, never to another host after a refusal, and is masked in anything a bot or a transcript reads. On a Cloud home only public mail servers. - Reads are marked read-only and mark the conversation as outside work; a send goes through the engine's normal approval. Per-bot access follows the connected-apps rules. - Mailboxes move to My Cloud with the rest. A Team Cloud has none yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Merge upstream main; move skillsLibraryEnabled next to the library it gates | 22 天前 | |
Show "Partly done" when the reply came back but a step failed (#4249) A turn or automation run whose final reply came back, and that then stopped because a step failed or wasn't allowed (openai-chat's tool_error stop), was shown as a full red failure. Mark that runtime error partial and show it in amber as "Partly done" in the chat row, preview, screen-reader announcement, automation panel, routine calendar and the automation's chat note, with the error under Details. Run status, retries and failure counting stay the same; a run is marked partly done only when its own turn ended that way and it has a reply. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 | |
fix(chat): an ended rescue notice reads as history When its turn ends without an answer (or a restart ended it), the notice now reads "Maus didn't hear back from OpenCode.", on the desktop and in the plain line phones print, instead of keeping "hasn't heard back ... yet" forever. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 11 天前 | |
Composer: steer, queue or restart a message sent while a bot works (#4069) While a one-to-one bot works, Enter now does the person's chosen follow-up (steer it into the running turn, the default, or queue it for after the turn) and Ctrl/⌘ with the send key does the other one (Ctrl/⌘+Shift+Enter when Ctrl/⌘+Enter is the send key; a Ctrl/⌘-click on Send does the same). A chevron beside Send lists Steer now, Queue and Restart turn, each with a line saying what it does. A turn that cannot be steered always queues, and the menu then offers Queue and Restart turn only. A new setting next to the send key picks the default, on this device. The send body takes followUp: "steer" | "queue" | "restart", for typed messages only, and direct-busy admission applies it. A chosen queue is never cut short by person-first. Restart queues the message ahead and stops the running turn; the queue survives Stop, so it runs next. Rooms keep their queue, double Enter and Steer chip. acceptDirectSend's input and receipt types move to server/direct-send.ts, shared by index.ts and the messages route, so index.ts shrinks. Builds on #4024 (the queue flag through direct-busy admission, its route checks and its e2e). Co-authored-by: Kannu20 <kannutodwal@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 4 天前 | |
Composer: steer, queue or restart a message sent while a bot works (#4069) While a one-to-one bot works, Enter now does the person's chosen follow-up (steer it into the running turn, the default, or queue it for after the turn) and Ctrl/⌘ with the send key does the other one (Ctrl/⌘+Shift+Enter when Ctrl/⌘+Enter is the send key; a Ctrl/⌘-click on Send does the same). A chevron beside Send lists Steer now, Queue and Restart turn, each with a line saying what it does. A turn that cannot be steered always queues, and the menu then offers Queue and Restart turn only. A new setting next to the send key picks the default, on this device. The send body takes followUp: "steer" | "queue" | "restart", for typed messages only, and direct-busy admission applies it. A chosen queue is never cut short by person-first. Restart queues the message ahead and stops the running turn; the queue survives Stop, so it runs next. Rooms keep their queue, double Enter and Steer chip. acceptDirectSend's input and receipt types move to server/direct-send.ts, shared by index.ts and the messages route, so index.ts shrinks. Builds on #4024 (the queue flag through direct-busy admission, its route checks and its e2e). Co-authored-by: Kannu20 <kannutodwal@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 4 天前 | |
Onboarding polish: a first run that keeps its shape and meets the Chief only when it fits - Meet with no AI keeps its shape: the 288px pill signs in (install, sign-in, a pasted or shown code, or the Connect an AI dialog), with "Other ways to connect · Set up later" under it; the AI's test message, Checking, failed and backup states live in the dialog. One sentence typed once, title at weight 400. - The Chief step shows only for a MausBot not yet introduced where no other bot is the Chief; one Create on a new install, Choose beside it where there are bots, a 300 ms input guard, an empty app behind it ("No bots yet"), and MausBot flying to its tile before the chat opens. Dialogs use the shared modal, scrim and pill classes. - MausBot's three new lines, then a follow-up written once by the server (POST /api/bots/:id/helper-followup, MausBot's own person only) as a real message the model reads, and up to three chips for only what is missing. Advanced mode keeps its one-bubble intro, asks and spotlights as before. - What the removed steps did comes back: a first run that could offer the Cloud settles the Cloud Pro popup, and refused microphone or speech access offers Open System Settings. Simple cards carry one-line hints instead of spotlights, MausBot's panel lists Try asking, a first run on this computer takes the account's full name for an empty profile, and MausBot's own welcome card wears the same dialog in Simple mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
Move from Grok Bot: one popup, one dialog, no sign-in (#4306) * Move from Grok Bot: one full-window flow, no sign-in and no network Each Bot writes its own setup; the person brings it back found in Downloads, pasted or dropped, sees what comes over, and gets a checklist of what is left. Replaces the share link, the public card fetch, Sign in with Cursor and the finish-setup screen. An old cursor-session.json is deleted at start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: lint and locale hash cleanup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: Settings → Import in a browser too; the flow holds focus Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: welcome-screen tests, plain-words check, ordinary colours only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: clamp the instructions preview to two lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: say why a found Bot can't be read, keep what a partial add brought, take drops anywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: the flow is a rarely opened screen, not preloaded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: one button in Settings, one dialog, the plain flow Copy the message, bring back the reply, preview, import, report. Removes the onboarding entries, the Templates card, the full-window screens, the checklist and the sign-in rows. Skills come on unless the skill scan flags them, event routines go to a notes file in the bot's memory, routines are named <Bot>: <routine>, and an existing server or an already moved Bot is a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: plain words in the dialog's reasons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: a once-only popup, and the dialog cut to names and counts The popup goes first in the once-only notices queue: after the welcome on a new install and at the next launch otherwise, with Let's start opening the same dialog. It reads nothing on this computer. The preview and the report are now the Bot's name, a count per kind and a few plain lines. Nothing reads the Grok Bot app's chats any more, only its list of Bots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Move from Grok Bot: one popup, one dialog, no sign-in (#4306) * Move from Grok Bot: one full-window flow, no sign-in and no network Each Bot writes its own setup; the person brings it back found in Downloads, pasted or dropped, sees what comes over, and gets a checklist of what is left. Replaces the share link, the public card fetch, Sign in with Cursor and the finish-setup screen. An old cursor-session.json is deleted at start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: lint and locale hash cleanup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: Settings → Import in a browser too; the flow holds focus Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: welcome-screen tests, plain-words check, ordinary colours only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: clamp the instructions preview to two lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: say why a found Bot can't be read, keep what a partial add brought, take drops anywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: the flow is a rarely opened screen, not preloaded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: one button in Settings, one dialog, the plain flow Copy the message, bring back the reply, preview, import, report. Removes the onboarding entries, the Templates card, the full-window screens, the checklist and the sign-in rows. Skills come on unless the skill scan flags them, event routines go to a notes file in the bot's memory, routines are named <Bot>: <routine>, and an existing server or an already moved Bot is a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: plain words in the dialog's reasons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: a once-only popup, and the dialog cut to names and counts The popup goes first in the once-only notices queue: after the welcome on a new install and at the next launch otherwise, with Let's start opening the same dialog. It reads nothing on this computer. The preview and the report are now the Bot's name, a count per kind and a few plain lines. Nothing reads the Grok Bot app's chats any more, only its list of Bots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
feat(mascots): Halloween bodies, carved face and a Halloween skin Ten Halloween bodies a bot can wear (pumpkin, ghost, witch, bat, cat, skull, monster, mummy, vampire, spider), drawn flat in one colour with dark-grey accents and a carved face: two tall pill eyes and a small smile that glance around, blink, and startle into round eyes with an open mouth. The bodies are generated by `pnpm gen:halloween` into shared/halloween-bodies.ts and are accepted wherever a bot body is (shared/bot-body.ts). - MausAvatar renders Halloween ids with the new CarvedAvatar; every other body is unchanged. - The face editors gain a Halloween row. - A Halloween skin (plum ground, pumpkin accent, candle glow, cobweb and two bats behind the chat, off under reduced motion), with Windows caption colours and P3 accents. - "Dress my bots up" in Appearance: while the skin is on, each bot shows its colour's costume; its own body comes back when the skin changes. A Halloween body picked on purpose is kept in any skin. Phones store mascotBody as a string and fall back to the default body for ids they do not know, so they keep working until they get the carved face. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 | |
MausBot tells a User the owner connects the AI With no AI, MausBot told everyone to sign in with Claude or ChatGPT, which a User on a team can't do. It now says who connects it, in the message it stores and in the one a person already has from before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
wip(highlevel): server, agent progress before the session limit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 21 天前 | |
feat(avatars): support Grok and compatible image providers (#1005) * feat(avatars): support Grok and compatible image providers Signed-off-by: milind-soni <milindsoni201@gmail.com> * docs(avatars): include provider settings screenshots Signed-off-by: milind-soni <milindsoni201@gmail.com> --------- Signed-off-by: milind-soni <milindsoni201@gmail.com> | 1 个月前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix: make team imports additive and add portable bot backups (#797) | 1 个月前 | |
Inbox: one definition of waiting on the person, and every kind of card listed The place inbox now reads what an open card waits on through personWait, and lists the conversations resting on the person for a password, a sign-in or an app to connect, each with the chat's own card. The panel keys its answer by the same kinds (question, approval, review, password, sign-in, connect) and answers each with the card the chat already uses. An outbound-call card now counts as waiting, as it does everywhere else. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Usage left as signal bars in the model button, not a pill in the header The chat header's "Claude: at its limit · resets Mon 2:30 PM" pill is gone. The model button shows the engine's usage left as four rising bars after the model name: quiet while there is room, one warning bar from 90% used, and empty bars struck through at the limit. Engines that report no usage (API keys, local models) show nothing. Hovering the bars opens a small card with each window (5-hour, weekly): % left, a thin bar and when it resets. At the limit the deciding window says so, with how it clears and Check again. The same rows open at the top of the model menu for keyboard and touch, and the button's name carries "Claude: 38% used, resets 3:40 PM". The limits report now lists every window beside the deciding one; an older server's single window still shows as one row. In the narrow header the square model button stays a square while there is room and widens to show the bars when they warn. On a phone, where the header has no model button, the bars stand alone while near or at the limit and open the bot's model, and the menu's Model row carries them too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 小时前 | |
The bot is a folder: SOUL.md, self-setup by chat, bot settings dialog, mobile overview (#833) * docs: design the bot folder, self-setup, and bot settings dialog Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: plan step 1 of the bot folder — prompt builder and SOUL.md Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(profile): accept a byte-capped soul field Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(bot-folder): mirror SOUL.md from the record and detect drift Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(bot-folder): drop inert scratch dir; isolation comes from the test home Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(store): soul field with hash, mirror, and setSoul Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(prompt): pure system-prompt builder with shared sentences Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(prompt): build direct and room system prompts through one builder Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(api): soul on PATCH, soul read with drift resolution, system-prompt preview Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(settings): SOUL.md editor with byte counter, drift banner, and migration Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): stop refetching soul info on every keystroke Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(soul): harden mirror writes and close the file-injection gap - writeSoulMirror calls in createBot, setSoul, and the discard-file route are wrapped so a mirror-write failure (unwritable bot folder) never fails the operation; the record stays canonical. Covered by a store unit test that makes the folder path a file so mkdirSync fails. - apply-file now accepts an optional { fileText } body and refuses with 409 when it no longer matches the file on disk, so a click can't apply text the user never actually saw. Backward compatible when the body is absent. - Added the core drift invariant test: an out-of-band SOUL.md edit never reaches a real turn's system prompt, and GET /api/bots reports soulDrift: true afterward. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(web): soul editor - real error toasts, cap gate, PATCH boundary - SoulField now reports Apply/Discard failures through the same error toast other components outside StoreProvider use (useStore().dispatch with an "error" action), instead of swallowing them; refresh() still runs after a failure so the drift banner reflects reality. - resolve("apply-file") sends { fileText: info.fileText } so the server can refuse a stale apply. - Extracted the over-cap gate into a pure src/lib/soul.ts helper (soulPatchFor), tested at the limit, one byte over via a multi-byte character, and empty. - Added "soul" to bot-patch-queue's BotUpdatePatch so it actually rides the desktop's broad bot PATCH boundary, matching its doc comment. - Dropped the redundant aria-label on the textarea; the <label htmlFor>/id pairing already names it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(spec): fix error-copy typo and record the security boundary - Match the spec's error copy to the implementation exactly ("must be at most 24000 bytes", no comma). - Add a Decisions-made-here bullet stating the honest boundary of the mirror-is-never-read rule: it stops a bot with file tools, not one with shell or HTTP tools, since request-auth.ts trusts any loopback process. This branch does not widen that boundary. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: plans for bot-folder steps 2 (propose_profile + history) and 4 (setup mode) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(profile-request): shared card payload types and a line diff Added vite.config.ts test.include entry for shared/**/*.test.ts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: plan for bot-folder step 3 (bot settings dialog) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(plan 3): build the overview once on the server for web and phones Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: plan for bot-folder step 5 (mobile overview) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(history): per-bot profile history log and revision token Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(line-diff): correct LCS matrix init so it typechecks as number[][] Array.from({length}).fill(0) yields unknown[], not number[]. Pre-existing break from the shared card payload types commit; blocks pnpm typecheck. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(profile-request): service that stages and applies profile cards Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(prompt): tell bots about propose_profile Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(agents): propose_profile tool Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(api): propose_profile route, card resolution, profile history and rollback Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(profile): record apply-file history, flush before reads, test the Chief target rule Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(web): render and answer propose_profile cards Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(routines): schedule labels as a tested library Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(routines): prose schedules say hours, not hr Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(profile-requests): redact profileRequest cards, fix isSetup, guard confirm - store.ts: redactBotAuthored had no branch for card.profileRequest, so a proposal's before/changes/reason/targetName could carry a secret straight through the store's redaction boundary (F1). - profileCardCopy computed isSetup from the change-restricted `before` object, so an established bot renamed on its own read as "Set up X?" on any proposal that didn't also touch title/description/soul. Compute it from the target's whole profile snapshot instead (F2). - parseChanges only checked the raw value against the field's cap; a mask can be longer than the secret it replaces (a short "token: sk-ant-..." becomes "token: «redacted N chars»"), so a value that passed the raw check could still cross the cap after redaction. Re-check post-redaction with the same error copy the parser uses (M1). - resolve() never checked that the card's persisted payload requestId still matched the card's own requestId; add the same guard routine-requests.ts has (M2). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(profile-cards): name the cross-bot target, speak the concise title - A cross-bot profile card is shown in the PROPOSING bot's thread, so "wants to update its profile" silently implied the proposer's own profile was changing. profileCardCopy's detail now opens with "Whose profile: @target" for a cross-bot proposal, and ApprovalCard's header names the actual target the same way (F3). - spokenApprovalPrompt read out the full profile diff (pending.detail); speak the card's concise title instead, matching the routine/skill branches, and let the user read the diff on screen (F4). - PendingApproval's strip label for a profile card said "wants to update its profile" instead of an imperative like its routine/skill siblings; changed to "Confirm this profile change". Documented the "profile" DecisionSource value in decision-log.ts's JSDoc (M5). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(profile-history): strip soul bodies by default, flush on shutdown - GET /api/bots/:id/history returned a soul row's full before/after text (up to 24,000 bytes each) by default; strip them unless the caller passes ?full=1, since rollback re-reads the row from disk server-side and never needs the client to have sent it back (F5). - writeRows recreated a deleted bot's folder via mkdirSync if it was gone; skip the write instead when botFolder(botId) does not exist, so a removed bot's data cannot resurrect its own folder (M3a). - Added flushAllProfileHistory(), awaiting every bot's queued history write at once, and wired it into the server's graceful-shutdown cleanup list so an in-flight write lands before the process exits (M3b). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(overview): server-built plain-language overview for a bot Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(store): bot settings dialog remembers its section Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(overview): never claim no connected apps when the inventory is unverifiable; test the auto defaults Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(store): keep the bot settings section when re-selecting the same bot Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(cards): say what happens after approval Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(cards): test the update cadence line; trim the credential sentence Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(settings): centered bot settings dialog with a generated overview Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(setup): setup-mode parser, activation rule, and prompt block Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(setup): coach blank bots and /setup turns through the prompt builder Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(setup): assert the literal /setup never reaches the model Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(composer): /setup slash command Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(fixtures): capture a bot overview for the phone suites Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(settings): skills, memory, routines, and access sections Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(companion): allow paired devices to read a bot's overview GET /api/bots/:id/overview is not yet on the sidecar allowlist, so a real phone hitting the new overview endpoint would get a 404. Add the read-only route (no settings, no transcript) in the same style as the other per-bot GETs, plus the allow/deny test cases. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ios): decode and fetch a bot overview Add BotOverview/BotOverviewWho/BotOverviewRecent alongside Bot in Models.swift, a CompanionClient.overview(botId:) beside routines(), and a Session.botOverview(for:) that returns nil and sets actionError on failure, matching the rest of the read APIs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(fixtures): patch the soul through the paired profile route Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(android): decode and fetch a bot overview Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(setup): replace the onboarding quiz with a greeting that invites setup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ios): read-only What this bot does screen Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(settings): model, permissions, voice, history, usage; retire the side strip Moves the last five sections (Model, Permissions, Voice & alerts, Usage, plus a new History) out of SettingsPanel.tsx and into the bot settings dialog, then deletes the old side-strip component entirely. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(chief): create_bot instructions share the 4000-character description cap Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(fixtures): keep the fleet at one bot when capturing bots-full Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(android): read-only What this bot does screen Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(settings): overview reads live routines, apps, skills, and history - Fetch the first overview/system-prompt load immediately on dialog open or bot switch instead of waiting out the 500ms debounce; later dependency-driven refetches (routines, webhooks, bot record edits) stay debounced so a burst of edits coalesces into one request. - PromptPreview takes an `error` prop distinct from "no data yet", so a failed GET /api/bots/:id/system-prompt renders "Couldn't load the prompt preview." instead of showing Loading… forever. - Recent changes' `when` column now goes through niceTime/niceDate (@/lib/schedule-label) instead of a local duplicate. - rollbackHistory surfaces a failed POST .../history/rollback through the app's error toast (mirrors SoulField's Apply/Discard), then still reloads history so the list matches the server's actual state. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(android): match BotOverviewView's copy and section behavior Section headers ("Can reach", "Recent changes") and the always-shown reaches/wont sections now mirror ios/App/BotOverviewView.swift, which already implements the same screen (Task 3) — the Who block also shows the bot's name, not just its title. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): keep the loaded overview when a refresh fails A background refetch failure (any routine/webhook/bot-record change now refetches the overview) was replacing a fully populated Overview section with "Couldn't load the overview." — the opposite of the data-wins precedence PromptPreview already had. The error block now only shows when overview is still null (never loaded); once it has loaded once, a later failed refetch keeps rendering the data and OverviewSection shows one quiet banner instead: "Couldn't refresh — showing the last loaded overview." Also added the cancelled-flag unmount guard the sibling sections (AccessSection's connected-apps preload) already use around the overview/system-prompt fetch, covering both the immediate first-load call and the debounced refetch — a quick open/close no longer risks setState on an unmounted dialog. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Fix final-review findings for setup mode (F1-F8) - branching.test.ts: drop the stale requestId-less quiz-card assertion after turn 1; setup mode no longer seeds an options card, and the test is about forking, not setup mode. - setup-mode.ts: setupSystemPrompt(active, { skills }) drops the skill_manage mention when skill authoring is off; expand the module comment on card-gating and the /setup transcript-preserving rewrite; replace the closing sentence with the spec'd Access-section pointer. - index.ts: hoist agentsMounted (comms depth + agentsMcp) and gate both the /setup turn-text rewrite and setupModeActive on it, so a driver without agent tools sees the literal message and no coaching block; read one bot snapshot (liveBot) for setupModeActive and the prompt's soul so the two can't disagree; same agentsMcp gate and skills option applied to previewSystemPrompt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Harden fixture capture: wait for room messages, pin the bot's name Poll the room's thread until at least 4 of the 5 posted messages have landed (with a timeout) before writing bots-paged.json, so a slow machine can no longer read the page back mid-write. Fix the stale comment above it that claimed messages=3 pairs with the five room messages, and note near bot-overview.json that it pins the SHAPE only (the does sentence embeds the capture machine's own clock and zone). Also PATCH the primary bot's random starter name to a fixed "Pesto" right after creating it, so recaptures stop churning on an arbitrary name and that bot is no longer confusable with the deliberately created Kiwi (a prior capture had in fact drawn "Kiwi" for it). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * iOS: hide empty overview fields, fix ForEach identity on repeated lines Mirror the desktop OverviewSection.tsx guards: title, blurb, and soulLead now render only when non-empty, instead of showing blank rows. does/reaches/wont were keyed by \.self, which collides when the server sends duplicate lines and drops rows from the list. Key by array offset instead, the way the recent-changes rows already do. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Android: restore empty-field guards on the overview screen, drop a tautological test commit a543a78 dropped the isNotBlank() guards around who.title, who.blurb, and who.soulLead, so the overview screen showed blank lines for bots without a title, blurb, or soul. Restore them. Also delete OverviewRulesTest's "section headers match iOS" test: it only asserted the WHO/DOES/REACHES/WONT/RECENT constants against their own literal values, so it could never fail. Keep the title() test, which is the one piece of copy the object actually computes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * companion: correct two allowlist comments on overview and profile The overview route's comment claimed it was "safe for a phone to poll"; nothing polls it — it's read on open and on pull-to-refresh — so say that instead of implying a poll loop that doesn't exist. The profile route's comment listed only identity, avatar, notifications, and voice as accepted fields, leaving out that soul (standing instructions, byte-capped) is accepted too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(overview): never 500 on an unreadable apps inventory; prose schedules; honest apps lines - botOverview() catches a failing connectedServices() call and marks the inventory unverified instead of failing the whole route. - "Connected apps could not be checked." now appears only when the bot could actually use apps; apps-off / unconfigured / engine-unsupported are definite "Has no connected apps." regardless of inventory state. - Does lines open with plain prose ("Every 5 minutes", "Every weekday at 9:30 AM", "Once on September 5 at 12:00 PM") instead of the approval card's anchored, timezone-suffixed form. - Singular copy: "1 connected app", "about once a day", "one day a week"; soulLead marks its 240-char cut with an ellipsis. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): refetch on overview facts only; nested dialogs own Escape; keep side panels - The overview/system-prompt refetch is keyed on the bot fields the server reads, not the whole bot object, so a streaming reply no longer starves it. - Escape and Tab are left to a nested dialog (routine editor, skill review, model popover, computer warning) while one is open. - toggleSettings no longer closes the computer panel or inspector; only the app settings modal is mutually exclusive with the bot dialog. - History keeps loaded rows through a failed reload with a quiet note. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): section entry points, rail keywords, shared date label, contained model picker - Voice setup opens Voice; the folder chip and computer-panel gear open Access; the usage chip opens Usage; sidebar Edit Profile opens Identity. - Rail search keywords match what each section actually holds (computer, folder, browser, connected apps, always-allow under Access; auto mode and peer rules under Permissions). - One whenLabel() for recent-changes and History rows; dead runsPerDay removed. - ModelPicker is contained again so its menu opens in flow inside the scroller. - Index keys for sentence lists; import success copy; two stale comments. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): re-review round 2 — portaled dialogs own Escape, fuller refetch key, testable inventory fallback - The Escape/Tab guard also yields when the key event's target is outside the settings dialog (BotInstructionsDialog portals to document.body). - The refetch signature now includes peers (typed on the web Bot) and section, both read by the overview / system-prompt preview. - connectedAppsFacts() in bot-overview.ts owns the inventory read and its failing-read fallback, with unit tests; the route just calls it. - "Can talk to 1 other bot" singular. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(setup): working folder via propose_profile; message-before-cards; wider skill import; quieter blurb field From Omkar's first manual test of OMB2: - Setup mode now asks which folder the bot should work in (naming the current one, or that it has none) and the bot proposes it through propose_profile's new `cwd` field. Validated like PATCH /api/bots at proposal and again at confirm (409 if the folder vanished); "" means the private workspace. The card says where the tools will read and write. cwd joins the revision hash, so an outside folder change stales the card. - Setup prompt: send the one-message summary of the cards first, then make the tool calls, then at most one short line — the cards used to land before the explanation. - GitHub skill import discovers up to 30 skills (was 10) and the prompt index lists up to 30 enabled skills (was 15). - Identity's Blurb field reads as the one-liner it is: short placeholder, smaller box, counter only near the cap; the cap itself stays at 4,000. - Spec amended to match. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(agents-proxy): propose_profile empty-change copy names cwd Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(settings): breathing room between the rail title and the search box The title row now matches the 44px header row on the right (py-3), and the search box sits a clear step below it with a slightly taller field. Same change in the app settings modal, whose rail this one copies. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: post-merge follow-through — tests on main's capability auth, rail overflow, continuity-aware cadence line; PR screenshots - index.test: the two propose_profile flows mint a test capability (main replaced the raw comms token); the overview test turns connected apps off so "Has no connected apps." is definite whatever the harness connector reports; the Composio test only requires the page not to contradict itself. - profile-versions.test: cwd is part of the revision and snapshot. - Routine cards: Continuity line first, the cadence consequence last before Instructions, and the consequence no longer says "fresh session" flatly when continuity carries the previous report. - Bot settings dialog: title and search rows are shrink-0 and the section list scrolls, so an overflowing rail no longer clips the bot's name; the dialog is up to 640px tall. - docs/superpowers/specs/assets/bot-folder: screenshots for the PR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix: simplify and harden bot profile setup and settings * fix: prevent replay of superseded profile confirmations * fix: preserve runtime revocation during mixed profile saves * fix: show complete instructions for large profile approvals * fix: queue new messages while Claude is stopping * fix: guard history restores and retire interrupted approvals * test: make settings and permission fixtures deterministic --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 1 个月前 | |
Integrate reviewed desktop, mobile, runtime and provider fixes (#1840) * feat(composer): edit queued messages before they send A queued message could only be steered or deleted. Each queued row now has an Edit (pencil) button that pulls the words back into the composer to tweak or extend, then send again. The server removes the item from the queue first; only a confirmed removal hands the text back, so a message that already drained into a turn is never resent. The text is written through the keyed draft restore path, so it lands in the right thread even if the person switched away while the request was in flight. Anything already typed stays below the restored words. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(cli): add Requesty to the API setup presets Requesty is an OpenAI-compatible router. List it next to OpenAI, OpenRouter and Groq in the CLI API setup, with its base URL and key page, and mention it in the docs that list those services. * Support Codex 6 models and CLI updates * Document Codex model discovery * Normalize Codex driver line endings * Normalize provider docs line endings * fix(server): keep connector verdicts off the prototype chain and legacy relays whole - evaluateConnectorTools reads grants by own property only, so a tool like CONSTRUCTOR_X maps to the inherited constructor and is denied instead of throwing a 500 from grant.tools.includes - an unrecognized tools/call frame is refused only for bots with a connectorTools record; legacy bots keep the pre-grants pass-through the relay always gave them - connector-scope rows now write auto-approved / the new auto-denied kinds, keeping user-* for answers a person actually gave Review follow-ups to #1761. * refactor(drivers): share idle policy, home resolution, model labels, version gates, ask protocol * test(vps): read the generated ssh config from a file, not /dev/stdin spawnSync feeds the child's stdin through a socketpair, and Linux refuses to reopen a socket through /dev/stdin (ENXIO), so the quotes-spaces test failed on every ubuntu CI runner with: Can't open user config file /dev/stdin: No such device or address macOS reopens its /dev/stdin fine and Windows skips the test, so only Linux saw it. Write the generated config to a file whose name keeps a space, so the quoting coverage is unchanged. * fix(config): warn when config.json is ignored instead of failing silently loadConfig() swallowed every error from reading or validating config.json. A missing file (first run) is fine to ignore, but a file that exists and fails to parse or fails the stored schema was dropped whole with no signal: one bad field (for example a threads section without maxConcurrentPerBot) made every instance, account and setting disappear, and the app quietly ran on defaults. Keep the fallback exactly as it was, and keep ENOENT silent, but log one console.warn naming the file and the schema issue. The warning is repeated only when the problem changes, because loadConfig() runs often. saveConfig() already merges into the raw file, so nothing on disk is lost; the user now learns which field to fix. Tests cover: no warning on a first run, a warning that names the path and the failing field on a schema error, and a single warning for invalid JSON across repeated loads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(drivers): refuse relative CODEX_HOME; pin Windows test homes A relative CODEX_HOME is refused by codexHome(), so the catalog must refuse it too instead of silently reading ~/.codex; return the official catalog plus the local-inject merge in that case, with a regression test. The Windows CI legs caught six driver tests that pin only HOME: userHome() now resolves USERPROFILE first on win32 (the audit platform fix), so those tests pin both, mirroring the qwen turn test. * feat(skills): accept skills.sh pages as import sources parseSkillSource now resolves skills.sh/<owner>/<repo>[/skill] to the GitHub repo the registry indexes, filters discovery to the named skill folder, and reports a clear error when that skill is missing. Import caps, markdown-only policy, disabled-on-import, and provenance stay exactly as they are for GitHub sources. * feat(ios): edit queued messages before they send Each held send above the composer now has a pencil beside the bin. It cancels the item on the computer and, only when that is confirmed, puts the words back in the composer (queued text first, any typed draft below), so a send that already joined the turn is never resent. A task switch mid-request stores the words in that task's saved draft. Desktop twin: #1796. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(android): edit queued messages before they send Each held send above the chat bar now has a pencil beside the bin. It cancels the item on the computer and, only when that is confirmed, puts the words back in the chat bar (queued text first, any typed draft below), so a send that already joined the turn is never resent. The words go to that conversation's cached composer, so a thread switch mid-request still lands them in the right draft. Port of the iOS change; desktop twin: #1796. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(drivers): harden session-idle validation and precedence Review follow-ups on the shared idle policy: a delay that is not a positive finite number of at most 2^31-1 ms falls back to the default before the floor applies, so Infinity no longer coerces to a 1 ms timer; the floor is the greater of the built-in ten seconds and any configured minimum, so a per-harness override can raise it but never lower it; and the per-harness env names win over the global ones, matching the documented honored-as-overrides semantics. The claude/acp idle integration tests now exercise the close at the ten-second floor and poll the native log instead of sleeping past a sub-floor window. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * fix(skills): match skills.sh slugs like the registry does Slugs derive from each SKILL.md name via the registry's toSkillSlug, so match the folder name first and fall back to the frontmatter name, mirroring the skills.sh installer. The root SKILL.md early return now respects the filter instead of importing an unrelated root skill, and an exact child match is prioritized ahead of the 60-folder cap. * feat(server): per-recipient delivery receipts on peer sends coordinate_bots, delegate_bot and ask_bot now answer every send with an honest per-recipient receipt: queued (accepted, no turn started), injected (the recipient's turn started with the message) or failed (not delivered). The tri-state follows the seams that actually decide it: room-handoff dispatch is asynchronous, so a fresh enqueue is queued; ask_bot's startTurn admission is injected; refusals, approval denials and dispatch errors are failed even when the lane buffers for later. A duplicate request_key inherits the state of the node already carrying it. Receipts ride the endpoint JSON (coordinate_bots keeps its result JSON-pure) and a one-line "Delivery to" note in the ask_bot/delegate_bot tool prose, sanitized like roster text. A receipt never claims a delivery that did not happen: a failed hand-off may stay buffered, but its receipt stays failed. * fix(bot-settings): parity diffs and expired proposal cards Team-setup proposal cards now render labeled before/after field lines and a SOUL.md line diff (sharing the profile card's large-change fallback) instead of a JSON.stringify blob. Proposal cards that can no longer be confirmed — stale profile revisions, dead team setups and routines, and credential requests replaced by a newer one — settle expired: their options are removed, the approval composer stops taking over, and the card says to ask for a fresh proposal instead of looking actionable. Closes #1788 Part of #1785 * fix(chat): restore scrolling beside run card * fix(server): report failed receipts for dead duplicate hand-offs * fix(bot-settings): reject decisions on expired proposal cards * fix(bot-settings): include model variant in team-setup review text * fix(server): re-check superseded after the phone credential save * ci: re-run matrix after windows provider-key-flow timeout * test(bot-settings): expired Chief-rule card stays terminal * ci: re-run matrix after ThreadNavigationUITests waiter timeout flake * feat(server): make notifications and speakReplies proposal-eligible notifications and speakReplies are quality-of-life toggles with no authority content, but parseChanges rejected every key outside the five profile fields, so the owner had to flip them by hand. Both now ride the existing propose_profile card: one-line before-and-after copy (on/off), confirm-time re-validation through the profile revision, and the same history rows as every other proposable field. Voice stays out of scope pending the harness-backed voice catalog on the card. The agents-catalog wire goldens are regenerated for the two new boolean properties; the direct profile grows 313 bytes (~0.8%), inside the 2% wire budget, so BUDGET_BASELINE stays unchanged. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * fix(server): describe mixed folder-and-toggle proposal cards honestly The closing line of a propose_profile card printed "Changes what X is told on every turn" whenever the card held anything besides only-cwd or only-toggles, so a mixed cwd+toggle card claimed an instruction change that neither field makes. Gate that sentence on a text field (name, title, description, soul) actually changing; every other combination — folder-only, toggle-only, or both — closes with just "Nothing runs." under the existing folder line. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * test(server): assert the readable working-folder line on every platform Main's new cwd coverage quoted the folder with JSON.stringify, which only coincides with the parity card's quoted rendering on POSIX; on Windows the escaped backslashes diverged and shard 2/4 went red. Assert the raw quoted path the card actually prints, matching the profile card's raw-path convention. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * fix(server): refuse non-boolean profile toggles whole-call A non-boolean notifications or speakReplies value was dropped silently while any valid half of the request went through, applying a partial proposal the model never described. Reject the whole call instead; boolean values flow unchanged. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * feat(chat): offer to update Claude Code when it is too old for the model A model newer than the installed Claude Code fails with the CLI's own "Claude Code 2.1.268 does not support this model; version 2.1.280 or newer is required. Run 'claude update'…" api error, which reached the transcript as a bot reply and left the person to find a terminal. The Claude driver now recognises that api-error frame (whatever model triggered it) and reports it as a setup error flagged claudeUpdate, ending the turn with stopReason update_required. The chat error row then offers "Update Claude for me", which runs the existing /api/instances/:id/claude-update route in the background and shows the installed version plus Retry, or "I'll do it myself", which shows the command to copy. Company-managed engines are not offered the update. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(chat): hide the <pasted-text> wrapper in user messages A long paste is sent to the bot wrapped in <pasted-text index="N"> ... </pasted-text> so it can tell pasted from typed text. The user bubble rendered those wrapper lines verbatim, which is noisy on every pasted transcript. Bubbles (1:1 and rooms) now drop the exact wrapper lines composeMessage writes and show just the pasted text; Copy copies the clean text too. The stored message, what the bot receives, edit and Markdown export are unchanged. A tag that is not the exact wrapper line stays visible. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(phones): hide the <pasted-text> wrapper in user messages iOS and Android parse stored user prompts with a port of the desktop splitter, so they rendered the <pasted-text index="N"> wrapper lines verbatim too. AttachedMessageContent now drops the exact wrapper lines and keeps what was pasted; inline or non-wrapper tags stay visible. Desktop twin: #1829. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(phones): offer to update Claude Code when it is too old for the model Phone port of the desktop update card. An error activity whose tool carries claudeUpdate now shows, under the error chip in a bot chat, "Update Claude for me" (POST /api/instances/:id/claude-update for the thread's engine, 200s timeout, then the installed version) or "I'll do it myself" (the command with a Copy button). A failed update shows the server's own message and a retry. The companion allowlist gains exactly that POST: a fixed updater run against the host's configured CLI, which the harness refuses while any Claude turn is running. Instance ids may contain dots, so a dots-only segment is refused. Stacked on feat/claude-update-prompt (#1828) for the server flag. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(server): match propose_profile body to the serialized request * fix(server): append the fresh credential card before superseding priors A failed append used to leave every pending card terminal with nothing actionable in its place, because the supersede loop ran first. Append the replacement card first: if persistence then fails, the prior cards stay actionable instead. True atomicity is not available at this seam (append and each supersede patch are separate SQLite transactions), so also pin the failure path with a test: a second connection holds the write lock, the request fails, the first card stays actionable, and the next request supersedes it normally once the lock releases. * fix: anchor Local VM confirm dialogs to the main window window.confirm() has no parent window, so tiling/non-reparenting window managers (e.g. Hyprland on Linux) can't center it — it renders at a default screen origin instead of over the app, easy to miss entirely. Route the Local VM delete/recreate confirms through a new dialog:confirm IPC call so dialog.showMessageBox can anchor to mainWindow, same pattern already used for the computer-sharing confirmation. Falls back to window.confirm() when window.ogb.confirm isn't available (e.g. non-Electron test/web contexts). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(providers): protect diagnostics and scoped import boundaries * Fix terminal proposal handling and revoked peer receipt visibility * fix(chat): preserve queue edit and Claude recovery guarantees * fix(review): guard native confirmations and verify chat hit targets * test(ui): isolate delayed target from app scroll layout * fix(claude): retire outdated pooled sessions before retry --------- Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> Co-authored-by: aivsomkar <aivsomkar@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Thibault Jaigu <thibault.jaigu@gmail.com> Co-authored-by: robinsonnblack <robinsonnblack@proton.me> Co-authored-by: robinsonnblack <331326017+robinsonnblack@users.noreply.github.com> Co-authored-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> Co-authored-by: 634634624 <634634624@users.noreply.github.com> Co-authored-by: jakequade <241658034+jakequade@users.noreply.github.com> Co-authored-by: Brad Hallett <bradhallett@users.noreply.github.com> Co-authored-by: Kate <buttonsjasper360@gmail.com> | 1 个月前 | |
feat(cloud): lift a lock on the lent Mac from the chat When the owner's own line hits a lock on their lent Mac, a card in the chat shows what changed, with Allow and Not now. Allow runs the same review as Mark reviewed in Memory, for exactly what the card shows. The same card lets the owner's own line through what a webhook or a routine they didn't write posted in that conversation, or the work a bot opened it with, for that line alone: another post, or work handed in after they allowed it, shuts it again. A webhook's or a routine's run and a line a bot handed in never raise one. Only the owner answers it, on screen, and it counts only while it records them as its answerer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
feat(cloud): lift a lock on the lent Mac from the chat When the owner's own line hits a lock on their lent Mac, a card in the chat shows what changed, with Allow and Not now. Allow runs the same review as Mark reviewed in Memory, for exactly what the card shows. The same card lets the owner's own line through what a webhook or a routine they didn't write posted in that conversation, or the work a bot opened it with, for that line alone: another post, or work handed in after they allowed it, shuts it again. A webhook's or a routine's run and a line a bot handed in never raise one. Only the owner answers it, on screen, and it counts only while it records them as its answerer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Live calls: support GPT-Live on Azure OpenAI Live calls could only create their GPT-Live session on api.openai.com with an OpenAI key. Add a Live provider setting so a call can use a gpt-live-1 deployment on the user's own Azure OpenAI / Foundry resource instead. - live.provider ("openai" | "azure"), live.azureEndpoint and live.azureDeployment in config.json, with OMB_LIVE_PROVIDER, OMB_AZURE_OPENAI_LIVE_ENDPOINT and OMB_AZURE_OPENAI_LIVE_DEPLOYMENT. - Session create and the sideband attach go to {endpoint}/openai/v1/live/sessions[/{id}/attach], with the deployment as session.model and the resource key sent as api-key. - The Azure key is only live.key; the OpenAI API key is never used for Azure. The endpoint must be https on an Azure OpenAI host. - A call keeps the endpoint it started with. - Call settings and the "Live needs setup" prompt gain a Service choice with the Azure endpoint, deployment and key fields; errors and the disclosure name Azure OpenAI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFCWE5jB4NijPPZKUWuV4U | 2 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Logins fill on their whole site, submit in one call, and 1Password vaults per bot - Saved logins gain a site (registrable domain, private suffixes via tldts), sign-in hosts and an exact-host option. Older records get their site on read; the file stays readable by the previous release. - fill_login submits by default (Enter, else the form's sign-in button, through the relay), goes through two-step logins in one call, never submits twice, and clears the filled password and code when the site refuses it, asks again or shows a CAPTCHA. - agent_browser_eval is refused on the page for a minute after a fill unless the page moved; a form left for the bot is cleared after that. - A sign-in card saves the site and the sign-in page open on it; a sign-in page on another site only when the person ticks it on the card. - 1Password vaults can be narrowed to chosen bots in Settings, Logins; a vault not granted is invisible to a bot. - The bot's prompt lists saved logins by site. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 天前 | |
Logins fill on their whole site, submit in one call, and 1Password vaults per bot - Saved logins gain a site (registrable domain, private suffixes via tldts), sign-in hosts and an exact-host option. Older records get their site on read; the file stays readable by the previous release. - fill_login submits by default (Enter, else the form's sign-in button, through the relay), goes through two-step logins in one call, never submits twice, and clears the filled password and code when the site refuses it, asks again or shows a CAPTCHA. - agent_browser_eval is refused on the page for a minute after a fill unless the page moved; a form left for the bot is cleared after that. - A sign-in card saves the site and the sign-in page open on it; a sign-in page on another site only when the person ticks it on the card. - 1Password vaults can be narrowed to chosen bots in Settings, Logins; a vault not granted is invisible to a bot. - The bot's prompt lists saved logins by site. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 天前 | |
Team map: show each bot's computer with a live screen Computers are drawn beside the bots that use them, with their newest screen: the frames bots' own turns capture, plus small budgeted captures of running machines while a map is open (never a wake or a create). A Show computers switch is remembered per workspace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 17 天前 | |
fix(files): open a bot's link to a Windows path written with backslashes (#1380) A bot on Windows links a file the way the OS spells it: [Report](C:\Users\me\.openmausbot\workspaces\bot\report.md). Two things broke that link. - Rendering to HTML percent-encodes a destination's backslashes, so chatUrlTransform received C:%5CUsers%5C... . That no longer matched the drive-path pattern, fell through to the default protocol allow-list and came back empty: the link rendered as <a href=""> and a linked image as "Image unavailable". The transform now restores the separators before deciding; every other escape still reaches the server's single decode. A backslash image path also no longer becomes its display name. - Markdown reads "\." as an escaped ".", so the destination parsed as C:\Users\me.openmausbot\... on both sides. The server authorized that collapsed path and then could not find it, and the attachment chip asked for it. A shared mdast extension keeps a backslash before punctuation in a link, image or definition destination that starts with a drive letter; "\\", "\(", "\)", "\<" and "\>" still escape. The server's authorization and image lookup, the message gallery, and the chat renderer all parse with it, so the path the client sends is the path the server grants. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 1 个月前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
refactor: call the mascot's body a body, not a shape The catalog's vocabulary was built on "shape", which the repo bans outright in symbol names (anti-slop/no-shape-in-symbol-names, an error since #190) and which was already the wrong word: the design docs, the picker and the existing `bodyImage` field all say "body". Nothing has shipped, so the persisted field name moves too. Renames only — no behaviour change. `MASCOT_SHAPES` -> `MASCOT_BODIES`, `MascotShapeId` -> `MascotBodyId`, `mascotShape` -> `mascotBody`, `SHAPE_DEFS` -> `BODY_DEFS`, `MausShapes` -> `MausBodies`, and `MausAvatar`'s `shape` prop -> `bodyId` (not `body`: `CursorSilhouette.body` already means SVG markup, and both are in scope inside `Avatar.tsx`). `shared/mascot-shapes.ts`, `scripts/mascot-shapes/` and `MausShapes.swift` move to their `body` names; `gen:shapes` becomes `gen:bodies`. The two generated catalogs were re-emitted by the generator rather than hand-edited, and the solved geometry is byte-for-byte what it was: every fit transform, anchor and path is unchanged, and the golden drift test passes. The ten selectable ids ("cursor", "blob", ...) and every display name are untouched — renaming those would be a data migration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> | 2 个月前 | |
Add an MCP server by pasting its link or setup command The Add MCP server card opens with one box: paste a server's link, a `claude mcp add` or `claude mcp add-json` command, an npx/uvx/docker line, or an mcpServers block. The app fills in the name, transport, headers and environment, and asks only for values the paste left out: a variable from the terminal ($CF_ID, ${CF_ID}) or a placeholder is never saved as written. The full form folds behind Edit details; headers and environment variables are name and value rows with hidden values, and saved values stay write-only. Saving tests the server and turns it on when it answers ("Connected: 12 tools"); otherwise it stays off with the reason and Try again. A signed-in server is turned on the same way. On a Team Cloud the card says everyone on the team can use the server, and Only for me keeps a one-key server as the person's own key. A Team Cloud e2e adds a gateway-protected server (two Cloudflare Access style headers) from the pasted command and has a member's turn list and call its tool; the broker test does the same through the credential broker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
Bots add, change, sign in to and remove MCP servers from chat (#4143) * docs: design and plan for MCP servers in chat Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(mcp): one config service for settings and bots Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): keep import hooks, read body before merging, quiet panel refresh Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): rules for what a bot may change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): stricter secret rules for bot updates and listings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): bots add, change, test and remove MCP servers One mcp_server tool replaces add_mcp_server. A Full access bot adds a server and it is turned on and tested as the bot, in the same turn; it can also update, enable, disable, test, sign out and remove servers. A change merges onto the saved entry, and a new destination clears saved secrets and the sign-in. Turning one off and signing out apply at every level; below Full access add saves the server off and other changes ask the person to use Settings until the approval cards land. sign_in answers "Not yet" until its card exists. Each change leaves one activity line in the chat ("Added MCP server linear · Turned on · Test: needs sign-in"). On a Team Cloud only an owner or admin's turn changes the team's servers; guest-driven threads get nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): an import holds the config lock while it reads its body A second import, or any other writer, is refused for the whole of an import request again, so the session-revocation check sees the import mutex. The one busy flag is held across the body read through addMany(read). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): one activity line, stricter tests An mcp_server call now shows as one row: the route writes its line onto the bot's own tool row as a display label, and the chat shows that in place of the raw tool name. Update keeps the add path's folder rules, remove and test follow the policy and other-computer rules, the listing says a server on another computer is not this bot's, and the labels read "Switched off" and "Test: N tools". The update path's secret rules gain regression tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): label the right activity row Engines start every tool block of a response before running any, so two mcp_server calls in one response each found the newest open row. Each call now labels the row whose input names its action and server, in its own turn only (rooms pass the turn too); with no live turn it adds a row instead of touching an older turn's. Advanced run summaries show the label, update applies the folder rules only when the command changes, and the tool's spellings come from the bridge's prefix list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): one-tap cards when a bot isn't on Full access A bot on Ask, Edits or Auto that adds, turns on, changes or removes an MCP server now shows a card in the chat ("Turn on linear?", "Change dodo?", "Remove dodo-test?") with the address or the redacted command, the changed fields, or the other bots that use it, and Cancel as the negative option. Add saves the server off and asks to turn it on. The bot ends its turn; the person's answer applies the change through the same path Full access uses, against the server as it is then, and resumes the bot with the test result. A secretRef on a Change card is redeemed only on allow, so a late answer resumes with "The key expired". Only the owner review that guards team-setup cards may allow; on a Team Cloud that means a workspace admin. Stop closes the card, a restart resumes a turn whose card was answered, and desktop draws the card with its own title and buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): keep pending changes off the wire, safer answers An MCP card now carries only what it shows. The change it stands for, the bot's fields and what the server reached, stays in the server's memory until the person answers, so no value the bot sent reaches the chat, phones or messages.json. After a restart the card expires and the bot is told to ask again. An answer applies nothing when the server's address or command changed since the card was shown, and says so. A busy config answers "Try again in a moment." and keeps the card open. An error while applying settles the card as failed and resumes the bot with the error. Failed and expired cards show their reason. A new OAuth client secret shows as its own change line. The tool description says a card below Full access means ending the turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): hide values under secret names on cards A Change card no longer shows a literal env or header value whose name says it is a secret (API_TOKEN, X-Api-Key, Authorization): it reads "new key for NAME", as a secretRef does. Other values still show. A new card also frees the held change of every earlier card about the same server, so one closed by Stop no longer lingers until a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): sign in from the chat A bot whose MCP server needs a login now calls mcp_server sign_in and the person sees one Sign in card in the chat. The card is the connector card every client already draws, marked source "mcp", so existing iPhone and Android builds show and complete it. Tapping it starts the provider's sign-in owned by the card, so any device that can see the card follows the same sign-in and a second tap reuses it. When the sign-in finishes the card settles and the bot resumes by itself, with no status poll needed; the turn it resumes mounts the server with the new token. Not now cancels the sign-in and tells the bot the server stays on but signed out. A removed server's card says so and resumes the bot once. A phone paired to a local Mac with no public https address is told to open the chat on the Mac, and a sign-in that would need paste-back points to Settings. A shared server's card takes an admin, as Settings does; on a Team Cloud a personal server's card signs in only the person the chat is for, with their own sign-in. Members now reach the card's authorize route, and an app's card stays admin-only in the handler. The authorization URL is never written to a message or card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): sign-in card edge cases A second tap from a browser elsewhere replaces a waiting sign-in that would come back to this computer, so the phone gets a link it can finish. A card left waiting when the server restarted goes back to Sign in when polled. Not now tapped before the bot's turn parks still tells the bot it didn't sign in once the turn parks; a card a newer one replaced is marked superseded and waits on nothing. A sign-in that would need paste-back is refused before any client is registered or port bound. Who may sign in is checked before a removed server settles the card, and a failing onSettled can no longer break a callback or escape the expiry timer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(mcp): sign-in card wording on desktop Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(mcp): an authorize refusal shows its sentence on the card An MCP card's 409 shows the server's sentence as calm status text and no sign-in link, even when the refusal carries one. A Composio card's 409 stays the card's error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(mcp): move MCP chat wiring out of index.ts and card types out of wire.ts server/index.ts and shared/wire.ts had grown past their file-size ratchet. The mcp_server route deps, the card and Sign in services, the card answer and the Settings listing with its policy helpers now live in server/host/mcp-chat.ts behind createMcpChat(deps). index.ts builds it where the services were built before, and secretCards and mcpConfig, which are built later, are passed as getters. McpChangeRequest and ConnectorCardData move to shared/mcp-request.ts and shared/connector-card.ts, and every consumer imports them from there. server/store.ts drops a re-export of ConnectorCardData that nothing imported. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a key inside a server's address never reaches the bot or a card list, the Turn on card and the Change card's address line now show a remote address as scheme, host, port and path, without userinfo, query or hash, with every key-shaped path segment (16+ URL-safe characters with a letter and a digit) shown as "…", then passed through redactSecretsInText. A Zapier-style link no longer puts its token in the model's context, messages.json or the phones. An update whose url equals that display form keeps the saved url, so a bot that sends back the address list showed it does not re-point the server at the masked address and lose its headers and sign-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): sign_in refuses a server that is off A turn mounts only servers that are on, so a sign-in card for one that is off ended with the bot told "Its tools are yours from this turn", which was false. sign_in now refuses with "linear is off. Call mcp_server with action enable first." at Full access, or "...enable to ask the person to turn it on." below it. The text a bot hears after the person signs in reads the server's enabled state when it resumes, so a server switched off while the card waited tells the bot it signed in, the server is off, and to call enable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): Turn on and Remove cards survive a restart Every MCP approval card held its change in memory, so a person who answered "Turn on linear?" after relaunching OpenMausBot got "this request expired", though a Turn on or Remove card holds no bot fields. McpChangeRequest now carries targetHash, the sha256 hex of where the server reached when the person was asked. The answer-time "changed since you were asked" check compares that hash for every action, so an allow after a restart applies a Turn on or Remove through the same applyMcpChange path while the server still reaches there, and refuses when it is gone or reaches somewhere else. Only an update's fields are held in memory, and only a Change card still expires after a restart; decided() expires an open card only when its fields were lost. A deny after a restart still settles as denied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): name the dropped OAuth client secret when the client id changes A bot update with a new oauth.clientId cleared the saved client secret without listing it in dropped, so the "these saved values were cleared" line left it out and the bot never knew to ask again. It is now named "oauth client secret", as the url-change path names it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a person who may not sign in gets a calm note, not an error "Only an admin of this installation can sign in to Linear." and "Only Ada can sign in to this." came back as 403, which desktop, iOS and Android draw as a red failure. They are refusals of the same kind as "Open this chat on your Mac to sign in", so the card's authorize now returns them as 409, which all three clients show as a calm note. A session missing a scope at the route gate still gets 403. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): a card's targetHash covers the masked display target, never a raw secret Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(mcp): a client-id-only update no longer says the destination changed Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Mask base64, dotted and percent-encoded key path segments Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Tell the bot a removed server is gone, not off Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Tell an MCP sign-in card to sign in on the page that opens An MCP server has no app key, so its card drops that half of the hint. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 3 天前 | |
fix(chat): make wrapped bot mentions trigger in channels (#1607) * fix(chat): align channel mention routing Unify mention boundary handling across renderer, composer prediction, and server routing so bot-authored mentions in channels trigger consistently, including Markdown- and punctuation-wrapped mentions while excluding email/URL-like contexts. Closes #980 Closes #1594 * fix(chat): preserve mention offsets during case folding | 1 个月前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
feat: choose white or black mascot facial features (1/4) | 8 天前 | |
Merge #4388 at 0e22de931 # Conflicts: # shared/notification.ts # src/components/NotificationsPanel.tsx | 22 小时前 | |
OpenCode: Refresh re-reads the provider's models, and a model id can be typed by hand OpenCode 1.19.4 lists models from its models.dev cache (or, with none, the snapshot built into it) and neither `opencode models` nor `opencode acp` refetches it, so the picker's Refresh re-read the same stale list and a model a provider added since never appeared. Refresh now runs `opencode models --refresh` before reading the catalog, and when that changes the list the next turn starts a fresh `opencode acp`, which otherwise keeps the catalog it started with. For a model OpenCode cannot list at all, the OpenCode search box offers the typed `provider/model` id, labelled "typed by hand" and saved as `typed::provider/model`. For that turn the server declares the model under its provider in OPENCODE_CONFIG_CONTENT, which OpenCode merges over the person's config; a plain saved id OpenCode no longer lists still falls back to the default as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 3 天前 | |
Add Watcher native options card bridge (#1815) | 1 个月前 | |
Add Watcher native options card bridge (#1815) | 1 个月前 | |
fix(x-research): say MausBot Cloud, keep x_post off the outbound list, pin the bridged twin - Copy uses main's retired-name rule: "OpenMausBot Cloud" is now "MausBot Cloud" in the card, the bot sentences, the tool description and the docs. - x_post reads a post, but the outbound classifier read its POST as a send, so the bridge kept it always listed, Auto mode would have held it for an outbound confirmation, and a cut turn that used it would never rerun. The agents server's four X reads (under every engine's spelling) are exempt; another server's post still counts as a send. - The tool bridge's goldens get the +x twin of the catalog's new full profile, with its budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 天前 | |
Full access with no sending rule sends at most 25 a day without asking The 26th send is refused before it reaches the app, so nothing is sent, and the bot is told to report it; a routine at the cap ends with that report, never a card. The sends count on the same daily counter the daily allowance uses. A stored rule is kept exactly as set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 23 小时前 | |
The wire contract keeps its size: the card's outside write lives in its own file Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 23 小时前 | |
Team Cloud: connections the whole team shares, or each person connects their own An admin chooses, per app and per MCP server, who connects it: once for the whole team (the default, and every connection made so far), or each person their own. A member's own connection reaches only a turn in their private chat that their own message started: never a group chat, the bot's main chat, another member's chat, an admin writing in theirs, or a routine. - Apps: each member gets their own installation on the connected-apps service (their own Composio user), mounted as a second bridge, own_apps, in their own turns. The relay checks every frame: the team bridge refuses a person's app, a member's bridge refuses a team app and anything outside their own turn. - MCP: a person's server never carries the team's credential; a member's own turn gets it with their own key or sign-in, pinned to its address. - No connection card for a person's app: the bot says one plain line with the link to the member's team page. - Members' keys, tokens and sign-ins live in people-connections/, never in a backup or a bot box, never in a route's answer. The Admin's signed read says who connected, by address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
feat(routines): a shared team keeps its routines' run-on-startup setting Team packages carry runOnStartup next to continuity. Imported routines still arrive paused. A file written for an older app drops it and lists it among the dropped parts. The installed-part value includes it only when on, so routines installed before this keep their recorded hash. Refs #325 | 24 天前 | |
feat(app): silver, a bot colour every picker offers Silver (#A8ADB4) joins the bot colours: every skin names it in a tone that clears 4.5:1 on its thread, each picker swatch shows a plain colour name in all 12 languages, and bot exports, team manifests, team backups and new-bot defaults read the one shared colour list, so a silver bot survives an export and a backup. New bots are still handed the other ten in turn, and a dressed-up silver bot keeps its own body. The shade and skin tones come from Omkar's #3287. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
fix(browser): a passkey sign-in no longer freezes the bot's browser, and says what works A Cloud customer's Google sign-in in his Chief's cloud browser stopped at "Verifying it's you… complete sign-in using your passkey" and never finished. A passkey lives on the person's own phone or computer; a bot's browser runs headless, and a cloud one has no Bluetooth for the phone's QR route, so it can never answer one. Reproduced on real Chrome 155 with a fixture shaped like Google's passkey step: the WebAuthn request waits forever, and Chrome's passkey sheet, which a headless browser has nowhere to show, blocks the tab's input meanwhile. Clicking "Try another way" did nothing, for the bot and for a person in the hand-over view; Escape does not end it, and a reload starts it again. - Headless bot browsers send WebAuthn to CDP's virtual environment (WebAuthn.enable, enableUI false) on every page before it runs: on the Chrome engine at target setup, and through the identity sidecar on agent-browser. A passkey request nobody answers still waits, but the page stays usable, so "Try another way" works. Headed browsers and the person's own Chrome keep the real passkey UI. - The bot is told, on any browser answer that shows a Google or Microsoft passkey step (by Google's challenge address, or the step's wording on that provider's page, in English, Portuguese and Spanish): stop retrying; for Gmail, Calendar or Drive use connected apps (COMPOSIO_MANAGE_CONNECTIONS); otherwise "Try another way" with a saved login and fill_login, or request_sign_in asking for the password and a code; on My Cloud, a lent PC's own browser. Both engines' answers go through one hook in the runtime router; My Chrome is left alone. - The sign-in prompt prefers connected apps over a browser sign-in for Google and Microsoft accounts and points at the notice. - The browser panel (the hand-over view) shows the same explanation on Google's passkey address, with Open Connected apps, the Try another way steps and, on My Cloud, the lent PC by name or how to lend one. English, Brazilian Portuguese and Spanish. - Help page: "Signing in to Google from a cloud browser". request_sign_in's description is unchanged: the bridged hot list has 21 bytes of budget left. Tests: server/browser/passkey-wall.e2e.test.ts on real Chrome (added to both CI browser legs): the notice, the step never finishing, and Try another way working while the passkey waits; unit tests for detection, the notice, the router hook and the sidecar; browser panel tests. Every fix mutation-checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 18 天前 | |
fix(browser): a passkey sign-in no longer freezes the bot's browser, and says what works A Cloud customer's Google sign-in in his Chief's cloud browser stopped at "Verifying it's you… complete sign-in using your passkey" and never finished. A passkey lives on the person's own phone or computer; a bot's browser runs headless, and a cloud one has no Bluetooth for the phone's QR route, so it can never answer one. Reproduced on real Chrome 155 with a fixture shaped like Google's passkey step: the WebAuthn request waits forever, and Chrome's passkey sheet, which a headless browser has nowhere to show, blocks the tab's input meanwhile. Clicking "Try another way" did nothing, for the bot and for a person in the hand-over view; Escape does not end it, and a reload starts it again. - Headless bot browsers send WebAuthn to CDP's virtual environment (WebAuthn.enable, enableUI false) on every page before it runs: on the Chrome engine at target setup, and through the identity sidecar on agent-browser. A passkey request nobody answers still waits, but the page stays usable, so "Try another way" works. Headed browsers and the person's own Chrome keep the real passkey UI. - The bot is told, on any browser answer that shows a Google or Microsoft passkey step (by Google's challenge address, or the step's wording on that provider's page, in English, Portuguese and Spanish): stop retrying; for Gmail, Calendar or Drive use connected apps (COMPOSIO_MANAGE_CONNECTIONS); otherwise "Try another way" with a saved login and fill_login, or request_sign_in asking for the password and a code; on My Cloud, a lent PC's own browser. Both engines' answers go through one hook in the runtime router; My Chrome is left alone. - The sign-in prompt prefers connected apps over a browser sign-in for Google and Microsoft accounts and points at the notice. - The browser panel (the hand-over view) shows the same explanation on Google's passkey address, with Open Connected apps, the Try another way steps and, on My Cloud, the lent PC by name or how to lend one. English, Brazilian Portuguese and Spanish. - Help page: "Signing in to Google from a cloud browser". request_sign_in's description is unchanged: the bridged hot list has 21 bytes of budget left. Tests: server/browser/passkey-wall.e2e.test.ts on real Chrome (added to both CI browser legs): the notice, the step never finishing, and Try another way working while the passkey waits; unit tests for detection, the notice, the router hook and the sidecar; browser panel tests. Every fix mutation-checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 18 天前 | |
Train: team-trial fixes, warm summaries, team bot access, own-server places, server lines (merge with Create a merge commit) (#3999) * Team bots: a level per person (view, chat, edit), shared from each bot A team bot is now shared like a document: what everyone in the team gets (Only people added, or Everyone at Can view, Can chat or Can edit) and a level for each person added. Admins and the bot's owner always edit. - The bot's Share button (bot panel in Simple, settings header in Advanced) opens a Share dialog on a team: people with access with their level, adding teammates by name or email, general access; every change applies at once with an Undo toast. - The server enforces it on every member request after the visibility gate: reads need Can view, writes Can chat (a room needs it on every bot), sharing and a bot's own setup Can edit; a routine needs Can edit unless its writer changes it; a card that changes the bot needs Can edit; a message another app relays needs the named person to chat. - Each copy of a bot carries the viewer's own level; the sharing only on an editor's. The live stream follows a change. - Bots set up before levels keep exactly what their visibility gave (everyone: Everyone, Can chat; admins only: Only people added; a list: those people, Can chat), read from it with nothing rewritten. - A person who can only view sees that in place of the composer, opens the bot's main chat, and is offered no new conversation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Team bot access: before and after pictures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Share dialog test: a whole bot Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(context): the unseen-messages block ends before the person's message When a resumed session has missed messages, the turn's prompt lists them in a block and then gives the person's new message after one blank line, with nothing saying the block is over. In a Team trial the person's next request, written right after a co-founder's relayed reply, was credited to the co-founder. The block now ends with "[End of those messages. Now reply to the user's latest message:]" before the turn's own text, as the full replay already ends its history with "[Now reply to the user's latest message:]". The wording differs from the replay's, so nothing that looks for the replay's end mistakes this block for replayed history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The owner is never told to ask an admin: connection lines know the person's role On a Team Cloud, a member's own bridge that asked for a team app's connection card got "ask an admin to connect it", whatever the person's role. The owner was told to ask an admin, and a bot named a teammate who wasn't one as the admin. - For the Owner or an Admin, the bot asks for the card through the team's composio bridge, whose card lets them connect the app for the whole team in one tap. - A User is told who can connect it, by name: the team's Owner and Admins from the roster the Admin paired here. - "Connect your <app> here" links go where each person's own connections are: the team's Apps page for the Owner and Admins, a User's team home otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(research): offer the research tools only where research works A Cloud home always holds the plan's X relay token, so every bot was offered research_search, research_endpoint and research_call. On a plan whose relay has research off, each call then answered only "Research isn't available right now." - The home asks the relay once, at start, with a search that names no job: the relay answers that with a 400 only once the token, the plan and research are all fine, before it reads its catalog or spends anything. An off answer (402, 404, 401, or 503 service_unavailable) hides the three research tools; x_search stays, since X works without research. It asks again an hour after an off answer, and a research call the relay refuses as off hides them at once. - The person's own treg key goes straight to treg: research is on. - A refusal because research is off now says what to do: tell the person and offer another way (web search or the browser); their own treg key turns research on. - The agents server gets a switch of its own for the research tools (OMB_RESEARCH) beside the X one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): a person's message never waits behind a long tool call A message the person sends their bot while it works is steered into the running turn, and an engine reads it only once the tool call it is in returns. A bot polling CI with `sleep 30` loops kept a person's message unread for 26 minutes and never said the PR it had made existed. - Mechanism: when the person's own one-to-one message waits unread while a tool call has run for a minute (at once if the call had already run that long), the server stops the turn, with a row saying so, and the message runs next, ahead of anything else queued in that chat. Its row is run as is (the follow-up queue can now take a row already in the transcript), and the model is told which step was stopped. Messages from rooms, routines, teammates and apps never do this, nor does one sent while the turn waits on the person or a computer. The wait is OMB_PERSON_FIRST_MS for tests. - Prompt: never wait inside a command for CI, a deploy or another job; check once, say what you made (with links), set wait_until or a one-time trigger to check back, and end the turn; answer the person first. Stopping and re-running works for every engine, and so does every engine's Stop. No engine reads a steered message during a tool call, some cannot steer at all, and Claude's own "send now" depends on moving the tool to the background, which bots run without. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): the person's re-run keeps its place and goes ahead of a teammate's The re-run of a steered message that a long tool call kept unread is now queued by the time the person sent it, ahead of everything but their own earlier messages, and a message of theirs that has to wait in the queue goes ahead of a teammate's or a routine's too. Before, the re-run took the time it was queued again, so on a slow runner it no longer joined the person's next message as one turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(connectors): app tool calls fit their schema, and a refusal says how to call again Composio checks a call's arguments against the tool's schema and refuses the whole call over one. In a Team trial five calls failed that way: COMPOSIO_SEARCH_TOOLS sent { job } (Required at "queries"), COMPOSIO_REMOTE_WORKBENCH sent code for code_to_execute and a timeout as text, and COMPOSIO_MULTI_EXECUTE_TOOL sent its tools list as text. After the search failed, the bot told the person it had no image tool, though an image app was connected. - The connector bridge keeps each listed tool's schema and fits a call to it where the bot plainly meant that shape: arguments or a list written as text, a number or yes/no written as text, a bare string or strings where a list of one-field objects goes, and one missing required field under another name when exactly one sent field can be it. The bot is told how its arguments were read, so it sends that shape next time. Anything not plainly meant still reaches the tool. - A call still refused over its arguments now says how to call again, with a minimal example from the schema (or to read the schema with COMPOSIO_GET_TOOL_SCHEMAS for an app tool), that this says nothing about which apps or tools exist, and which connected apps this bot can use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give main's bot-patch route tests the access level the route now asks for Two tests that came with main (vpsAlias relocation guard, phoneApps) built the route without `levelOf`, so they threw "deps.levelOf is not a function". They now answer "chat", a member's level that still may not move a bot or change what it may do; both refusals hold as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(claude): a bot's hooks fire from inside the bot box The hook helper Claude Code runs for each hook reads the turn's bearer from a file in the data folder, which the bot box replaces with an empty folder. On every Cloud home the helper found no token and quietly did nothing: no hint for a timed-out command, no work summaries, no context at session start. - The token lives in a folder of its own per conversation (hook-tokens/<digest>/token), and the box puts that folder back read-only: only that conversation's token, never the data folder or another conversation's token. The folder, not the file, so the box sees each turn's new token after it is renamed over the old one. Tests: a Claude turn under a stand-in box that hides the token unless a mount line puts it back fires its PostToolUse and Stop hooks with the turn's bearer, and the box shows only that conversation's token folder, read-only. It fails with the bind removed (no hook fires), with the file bound instead of its folder, and with the old shared folder (another conversation's token shows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MCP Settings Test reaches a server the way bots do, through the credential broker Where bots' turns are boxed, a turn's engine reaches a URL MCP server through the credential broker, which adds the server's headers and forwards. The Settings Test connected directly, so a server behind Cloudflare Access tested "Connected" while every bot failed (the broker added a slash to the server's address). - The Test now makes a grant the way a turn gets one, connects through the broker's socket, and revokes the grant when it ends. Where turns aren't boxed, bots and the Test both still go direct. - If the server fails through the broker but answers directly, the Test says "Your bots can't reach this server" with the reason and that the fault is on our side, never "Connected". - A server the broker can't reach reads as unreachable, as a direct test does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A new MCP server saved switched off says so, its switch can't flip it straight back, and a server that failed at engine start reconnects - A new or edited server whose first test fails reads "Saved, but off: the test failed", with the reason and that bots can use it once it's on. While that test runs, the row says it's off until it passes. - A passing test after a save switches the server on by itself. A click on its switch in the next moment was aimed at the Off the person saw, so it keeps the server on ("it passed its test a moment ago") instead of switching it straight back off, which looked like a one-second on/off. - Where bots reach URL servers through the credential broker, a server the engine reported as failed when it started gets the conversation a new grant on its next turn, so the engine starts again and reconnects. The chat says the server didn't connect and that it connects again on the next message, so bots no longer need to ask for a new chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Renderer smoke: a saved server whose first test fails reads "Saved, but off" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the reconnect import on its own line, apart from other open changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A connected app comes before any browser or screen, and a refused one is reported with its fix Bots were told to do web work on the person's own computer in this order: the built-in browser, a cloud computer, then a connected app. A connected app does a task more cheaply and surely than any screen, and one that is refused or broken is the person's to fix. - The order now starts with a connected app that does the task. - Wherever a browser or a screen is mounted (a Cloud home too), bots are told to use a connected app first, and when it is refused or fails, to say so in one plain line with what fixes it and ask before doing the task on a screen instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bug reports: the reporter sees their @devs report's status, and is told once when the fix runs here - The person's @devs message shows its report's status in the app's language: "Bug report sent · Got it, we're looking", then "Fixed in 0.1.x, coming in your next update", then "Fixed in 0.1.x" (bugReport on the message; all 17 language packs). - The server follows each report it sent (devs-reports.json) and asks the MausBot team about the open ones a minute after each start and hourly: POST /api/bug-reports/status at the address reports go to, the same way on the desktop and on a Cloud, which signs its question with its bootstrap secret. Nothing ever has to reach this server, or wake a sleeping Cloud. - Once it runs the fix's release (versionAtLeast: never on a guess) and the answer allows it (never a former customer's Cloud, never a teammate who left), one line in the chat they reported in, "Fixed in 0.1.x. Want to try again?", one notification (on a Team Cloud only to the reporter), and a one-time note on the bot's next turn there. Once per report, across restarts. - OMB_DEVS_STATUS_MS sets the interval for fixtures (control-omb passes it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it never interrupts the person, and questions never go stale At Full access ("Just do it") a question from work a bot handed on goes to the bot that handed it on, which answers it from what it knows; with no answer the asker goes on with the default it named and says so in one line. Its card says who picked what and blocks nothing. Only a sign-in, a payment, a secret or the person's own account reaches the person, once, while the rest of the work moves on. An ask tool in handed-on or unwatched work is answered the same way, and the prompts say to find things out the cheapest way first and ask the person last. On "Ask me first" a question waits for the person however long they take. An answer counts from the card, the inbox, the asking bot's own chat, or passed on by another bot (coordinate_bots answers). A question whose work ended, or that a newer one replaced, closes; a sign-in wait in handed-on work settles from the person's line, an answer passed on, or the bot going on with the site; a restart posts nothing again. Rooms and a bot's own chat get the same tap cards, and prompts name Claude's question tool as mcp__ogb__ask_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it decides only in work the person or their routine started A question in work a webhook or another outside event started still goes to the person at Full access, as an ask tool there does: its brief is not the person's authority, and the question is their check on it. The Just do it line stays out of those turns' prompts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep steering and late answers in the person's own chat as they were A line the person types in their own chat while a question card waits is still steered into the turn or queued, as an engine that can steer expects; only in work a teammate handed on does it answer the card. A question its turn left open keeps waiting for a late answer after other lines. Two peer-question notification tests now run on "Ask me first", where a teammate's question is still the person's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Warm summaries: a long conversation is summarized while it sits idle, so the next answer starts fast On a Team trial every first answer slower than 35 s (35 to 58 s) was Claude Code compacting a conversation of about 162k tokens at the start of the person's turn, warm cache or not: writing the summary is what takes the time. Both kinds of compaction ran only when the next turn started, on the person's time. - After a turn that leaves a direct conversation at 100k tokens or more, its summary is written about 3 minutes later, while the prompt cache is still warm; from 80% of Claude Code's own compaction point (160k of 200k) it starts after about 10 s, because the next turn would summarize anyway. - Claude Code: its own /compact, with instructions to keep the person's latest requests and every open question, on a persisted fork of the session (--resume S --fork-session) launched with the live process's exact contract, as the keep-warm ping is, so it reads the cached prompt start and keeps the conversation's tool list. The conversation moves to the fork only when no turn began meanwhile; its last two exchanges count as not yet seen, so the next turn carries them word for word on the existing, saved "not seen yet" path. The chat shows one line for it. - Other engines: OpenMausBot's own fold runs while idle once the conversation is close to its threshold, instead of at the next turn. - Skipped while work is due (a queued message, a teammate working on this conversation's request, a fired wait, the spend limit); retried while the bot is busy, memory is short or a routine of the bot is due, until the cache would be cold. A turn that starts meanwhile wins, unless it would summarize at its start anyway: then it waits for the summary already being written instead of a second. - The app's presence ping names the open chat: opening a conversation starts an overdue summary at once and keeps its engine process alive while the person is there. - Off with context.autoCompact: false, or OMB_WARM_SUMMARY=0 for this alone. The fake Claude Code gains a growing context, its own compaction at a threshold with a duration, and /compact on a fork. On a long fake conversation whose CLI compaction takes 6 s, the next reply took 6.2 s before and 0.3 s after; one sent while the needed summary was being written took 5.4 s (the rest of it, not a second one); one sent during a summary it did not need, under 0.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * People before bots: a shared @name reaches the person, a bot named like a person is warned, deleting a Chief offers Archive On a Team trial a person's "@<teammate>" reached a bot that had the teammate's name, because a tie went to the bot. Then the person deleted their Chief to fix it, and lost its whole setup chat. - A tag a person and a bot share is the person's: "@Bob" reaches the teammate Bob (or means the writer, for their own name), and only a longer bot name ("@Bob Bot") reaches a bot. The teammate's inbox gets it, the turn no longer tells the bot it was named, and the composer highlights it as the person (shared/person-mention.ts, src/lib/mentions.ts). - A bot made or renamed with a person's name (a teammate's, or the owner's own) says so once in its own chat, and the Chief's create_bot result carries the same warning (server/host/bot-name-clash.ts). Nothing is refused. - Deleting a Chief of Staff offers "Archive instead" first: its chats hold the team's setup. Archiving drops the Chief role, so the server accepts it, and the bot can be restored any time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots in two places: one plain suggestion to bring them together When this computer has bots of its own while a server of the person's own (or My Cloud they keep this computer's bots away from) has bots too, the bots in the two places can't work together. This computer's page now says so once, in a corner card: "Your bots live in two places, so they can't work together. Bring them together on <place>?" One tap starts the one-time move there (Make <server> my home, or letting this computer's bots move to My Cloud), and Not now is remembered for that place. Main reads each place's own move summary, so only bots a move would carry count and a place's untouched first bot never makes two places. A server is asked only while it says it is the person's alone, a sleeping Cloud never, a team's Cloud or a server others sign in to never. Nothing shows while a move is under way, during the welcome or the tour, or on any page but this computer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots say where another bot lives, and how to bring them together A bot that asked for a teammate living in the person's other place (their computer, their own server or My Cloud) only heard that no such bot exists. The person's app now tells each of their own places the names of the bots their other places have, and nothing more (PUT /api/places/elsewhere, from that place's owner only, never a team's place or one others sign in to). With that: - coordinate_bots and bot_idle waits say "Scout lives on Work laptop, the person's computer, not here", that bots work together only within one place, and offer the one tap that brings them together ("Make Garage server my home", or Bring them together for My Cloud); a name nowhere stays no such bot; - a person's @mention of such a bot tells the answering bot where it lives, and in a room one plain line says so to the person; - before the app said anything, a name nowhere here also says that bots work together only within one place, and how to bring them together. Main tells each place only when what it would be told changed, never while a move is under way, and stops telling this computer once its bots moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Server lines in the person's language: the way in, a guard, and bug report lines Lines the server writes for a person (a bot's line, a status row, a card, a notification) now come from the language packs under "server." keys, in the language the person's app shows. - server/server-lines.ts: serverLine(language, key, params) reads the packs; a missing key reads in English, as the app's screens do. The server bundle keeps only the server keys (scripts/server-locale-plugin.mjs), and tsc's copies of the packs are dropped from dist-server. - server/host/person-languages.ts: the app keeps a person's language pick on their own computer, so the server learns it from presence pings (the owner's, or each member's on a Team Cloud). A line for a person reads in theirs, else in the place's: the one set on the server or by the team's Admin, else the one most people's apps show. - Bug report lines (@devs) read in the reporter's language; the marker that tells whether the bot already passed a failure on is "MausBot", which every language keeps. - src/locales/server-lines.test.ts: a guard that fails on an English line written straight into a line a person reads. It follows each place a line is made through consts, helpers and imports; ALLOWED says why text is English on purpose; PENDING lists the 242 lines written before it, by area, and only shrinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Only the tests of other languages' lines read the packs; CI selection knows it CI's import-graph checks failed: the server now loads the language packs, and every server test reaching server-lines.ts counted as reading a translation. - server/server-lines.ts reads English only. server/server-line-packs.ts adds the other languages; server/index.ts loads it at start, and so do the tests that check a line in another language. The guard checks index.ts loads it. - scripts/ci-scope.mjs: those tests run with the locale tests. The packs stay out of SRC_OUTSIDE_RENDERER: a change to English already runs every Linux test, and one to another language runs every test that reads it, so a translation change does not run the server's checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Runs and routines tell the person in their language A routine's line in a chat and the incident a person hears about now read in the language of the person whose conversation it is, through server/server-lines.ts. - "This run didn't finish: …" and "Recovered: … finished OK at …" (with the time in that language's clock), written into the chat a routine reports to. - The text of a routine run's card, for clients that show no cards. - The incident status row and its notification. The Chief's own incident report stays English: only a model reads it. - server/index.ts: threadLanguage(threadId), the language of a conversation's person, else the place's; no line added. - The guard's PENDING drops these 17 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Connect prompts and sign-ins ask in the person's language When a bot needs the person to connect an app, sign in or give a key, what the server writes now reads in the language of the person whose conversation it is. - "I need you to connect …", "I need you to sign in to …" and "I need your …", which a routine writes into its chat while it waits on a card. - The connect card's text and, where the app catalog has no words of its own, its description. - The line under a sign-in card. It moves from shared/ to server/connector-card-text.ts, since shared code cannot read the packs; nothing else used it. - The credential card's text and the sentence on how the bot gets the key. - The guard's PENDING drops this area's 13 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Notifications are titled in the person's language Every notification's title ("… has a question", "…'s routine failed", "… needs you to sign in to …") now reads in the language of the conversation's person: buildNotification asks a resolver the server sets at start (setNotificationLanguage(threadLanguage)), so no caller changes. Also the inbox's "· your assistant answered" and two bodies the server writes itself ("Results in from …", "Open OpenMausBot to sign in to …"). The guard's PENDING drops the area's 8 lines, and checks the server sets the resolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A room's status rows read in its person's language What a group chat shows about its members now reads in the language of its conversation's person: waiting for a busy member and the skips, a mention that missed, archived members, still stopping, held members, no summary, a stalled turn, context compaction, and a bot's receipt in its own chat ("Posted in …", "Opened thread #…"). What a coordinating bot reads stays English. - server/server-lines.ts: isServerLine(key, text) reads a line back in any language; isHeldMemberLine uses it, and the held row keeps "resume", the word the room understands. - The sentinel counts a German stopped room turn as a timeout, and now also skips a held member's row in the shape it reads rows in (a harness notice with names taken out). The openmausbot CLI, which runs it, loads the other languages. - The guard's PENDING drops 20 room lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(team connections): an owner's own-connection lines are checked in her private chat and in a shared one An own bridge only works in the person's private chat now, so the "connect your apps again" check runs there; the connect lines are checked in both places, including an app call through the team's tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates' hand-offs and results read in the person's language What a conversation shows about a teammate's work now reads in the language of that conversation's person: a hand-off going out ("Sent to …"), its result coming back ("… replied", "… — failed:", "Result withheld:"), resuming with results or a question, what came of a teammate's question or approval, what waits behind the person, recalled private chats, a closed thread, a room goal's card, "Answer passed to the waiting work", and the inbox's and team messages' rows. - server/server-lines.ts: one resolver, conversationLanguage(threadId), which the server sets at start; notifications use it too (it replaces setNotificationLanguage), so modules with no person at hand need no new wiring. - What a coordinating bot reads stays English. - The guard's PENDING drops 19 lines; the area keeps feature-flagged escalations, approval level names, the peer approval card and a goal's text after a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it: a question in a person's private chat stays theirs Work a person's request hands on runs in the receiving bot's chat with them when it may use their own apps, and what it hands back keeps a question's words in that chat. Its requester never sees them, so it cannot decide them, and a sign-in among them could not be told apart. Such a question now reaches the person there, as on "Ask me first": the turn result says the question stayed private, and the ask tool is not turned away in that chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acting person): read the private question flag with toMatchObject The hand-back keeps its input's type, which has no privateQuestion field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(analytics): the two-places card's event Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): the engine registry answers null for a missing engine registry.get returns ProviderInstance | null; the host's dependency took only undefined, which failed typecheck once the branch was checked against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): its line in the chat comes from the language packs The line a warm summary leaves in the conversation is now server.warmSummary.summarized, in every pack, written in the language of the conversation's person, as the guard from #3931 asks of every line a person reads. It names no count, so it needs no plural forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Main's guard passes: the same-request notice in the person's language Main went red on the server-lines guard: #3957's "Another teammate asked the same a moment ago…" row landed while #3931's guard was in review, and #3948 reworded a line the guard lists. - The notice reads in the language of the conversation's person (server.teammates.sameRequest, German by hand, every pack). - PENDING follows #3948's rewording of the webhook line. - The guard's check that index.ts loads the other languages matches that import anywhere on its line (as #3960 has it), so another import may follow it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates: the recall row reads in its room's language after main's discloseRecall Main moved this row into discloseRecall(bot, roomThreadId, …), where threadId is not in scope, so the merged branch failed typecheck. The row is the room's: it now asks for roomThreadId's language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bots explain): the one-place hint comes before the reach help, so a refusal still ends with it server/room-coordination.e2e.test.ts pins that a refusal for a name nobody has ends with the reach help (and its "Never use computer control to get around this"). The hint now sits just before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the cards a parked turn waits on move to server/host/resumable-cards.ts resumableCards is a pure read of the conversation; moving it out keeps server/index.ts under its file-size ratchet once #3930 lands with main (the fix #3930's branch made when it merged main, ported here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the MCP reconnect, bot name clash and bug-fixed lines come from the language packs #3922, #3934 and #3937 were written before main's server-lines guard, which fails on their three English lines once they meet it. Each line is now a "server." key (English and German) written with serverLine in the language of the conversation or reporter: server.mcp.reconnect.one/many (server names listed the reader's way), server.bots.nameClash (create_bot's result stays English for the model) and server.reports.fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the bot archive/delete dialog's props move beside botConfirmCopy #3934's Archive-instead offer grew src/components/Sidebar.tsx past the size the 0.1.135 release set (1790 against 1785). botConfirmProps in ArchivedBotsPanel.tsx now builds the dialog (copy, icon, Archive instead for a Chief, confirm); the sidebar keeps the ConfirmDialog and its callbacks, and is 1774 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 5 天前 | |
Train: team-trial fixes, warm summaries, team bot access, own-server places, server lines (merge with Create a merge commit) (#3999) * Team bots: a level per person (view, chat, edit), shared from each bot A team bot is now shared like a document: what everyone in the team gets (Only people added, or Everyone at Can view, Can chat or Can edit) and a level for each person added. Admins and the bot's owner always edit. - The bot's Share button (bot panel in Simple, settings header in Advanced) opens a Share dialog on a team: people with access with their level, adding teammates by name or email, general access; every change applies at once with an Undo toast. - The server enforces it on every member request after the visibility gate: reads need Can view, writes Can chat (a room needs it on every bot), sharing and a bot's own setup Can edit; a routine needs Can edit unless its writer changes it; a card that changes the bot needs Can edit; a message another app relays needs the named person to chat. - Each copy of a bot carries the viewer's own level; the sharing only on an editor's. The live stream follows a change. - Bots set up before levels keep exactly what their visibility gave (everyone: Everyone, Can chat; admins only: Only people added; a list: those people, Can chat), read from it with nothing rewritten. - A person who can only view sees that in place of the composer, opens the bot's main chat, and is offered no new conversation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Team bot access: before and after pictures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Share dialog test: a whole bot Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(context): the unseen-messages block ends before the person's message When a resumed session has missed messages, the turn's prompt lists them in a block and then gives the person's new message after one blank line, with nothing saying the block is over. In a Team trial the person's next request, written right after a co-founder's relayed reply, was credited to the co-founder. The block now ends with "[End of those messages. Now reply to the user's latest message:]" before the turn's own text, as the full replay already ends its history with "[Now reply to the user's latest message:]". The wording differs from the replay's, so nothing that looks for the replay's end mistakes this block for replayed history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The owner is never told to ask an admin: connection lines know the person's role On a Team Cloud, a member's own bridge that asked for a team app's connection card got "ask an admin to connect it", whatever the person's role. The owner was told to ask an admin, and a bot named a teammate who wasn't one as the admin. - For the Owner or an Admin, the bot asks for the card through the team's composio bridge, whose card lets them connect the app for the whole team in one tap. - A User is told who can connect it, by name: the team's Owner and Admins from the roster the Admin paired here. - "Connect your <app> here" links go where each person's own connections are: the team's Apps page for the Owner and Admins, a User's team home otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(research): offer the research tools only where research works A Cloud home always holds the plan's X relay token, so every bot was offered research_search, research_endpoint and research_call. On a plan whose relay has research off, each call then answered only "Research isn't available right now." - The home asks the relay once, at start, with a search that names no job: the relay answers that with a 400 only once the token, the plan and research are all fine, before it reads its catalog or spends anything. An off answer (402, 404, 401, or 503 service_unavailable) hides the three research tools; x_search stays, since X works without research. It asks again an hour after an off answer, and a research call the relay refuses as off hides them at once. - The person's own treg key goes straight to treg: research is on. - A refusal because research is off now says what to do: tell the person and offer another way (web search or the browser); their own treg key turns research on. - The agents server gets a switch of its own for the research tools (OMB_RESEARCH) beside the X one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): a person's message never waits behind a long tool call A message the person sends their bot while it works is steered into the running turn, and an engine reads it only once the tool call it is in returns. A bot polling CI with `sleep 30` loops kept a person's message unread for 26 minutes and never said the PR it had made existed. - Mechanism: when the person's own one-to-one message waits unread while a tool call has run for a minute (at once if the call had already run that long), the server stops the turn, with a row saying so, and the message runs next, ahead of anything else queued in that chat. Its row is run as is (the follow-up queue can now take a row already in the transcript), and the model is told which step was stopped. Messages from rooms, routines, teammates and apps never do this, nor does one sent while the turn waits on the person or a computer. The wait is OMB_PERSON_FIRST_MS for tests. - Prompt: never wait inside a command for CI, a deploy or another job; check once, say what you made (with links), set wait_until or a one-time trigger to check back, and end the turn; answer the person first. Stopping and re-running works for every engine, and so does every engine's Stop. No engine reads a steered message during a tool call, some cannot steer at all, and Claude's own "send now" depends on moving the tool to the background, which bots run without. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): the person's re-run keeps its place and goes ahead of a teammate's The re-run of a steered message that a long tool call kept unread is now queued by the time the person sent it, ahead of everything but their own earlier messages, and a message of theirs that has to wait in the queue goes ahead of a teammate's or a routine's too. Before, the re-run took the time it was queued again, so on a slow runner it no longer joined the person's next message as one turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(connectors): app tool calls fit their schema, and a refusal says how to call again Composio checks a call's arguments against the tool's schema and refuses the whole call over one. In a Team trial five calls failed that way: COMPOSIO_SEARCH_TOOLS sent { job } (Required at "queries"), COMPOSIO_REMOTE_WORKBENCH sent code for code_to_execute and a timeout as text, and COMPOSIO_MULTI_EXECUTE_TOOL sent its tools list as text. After the search failed, the bot told the person it had no image tool, though an image app was connected. - The connector bridge keeps each listed tool's schema and fits a call to it where the bot plainly meant that shape: arguments or a list written as text, a number or yes/no written as text, a bare string or strings where a list of one-field objects goes, and one missing required field under another name when exactly one sent field can be it. The bot is told how its arguments were read, so it sends that shape next time. Anything not plainly meant still reaches the tool. - A call still refused over its arguments now says how to call again, with a minimal example from the schema (or to read the schema with COMPOSIO_GET_TOOL_SCHEMAS for an app tool), that this says nothing about which apps or tools exist, and which connected apps this bot can use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give main's bot-patch route tests the access level the route now asks for Two tests that came with main (vpsAlias relocation guard, phoneApps) built the route without `levelOf`, so they threw "deps.levelOf is not a function". They now answer "chat", a member's level that still may not move a bot or change what it may do; both refusals hold as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(claude): a bot's hooks fire from inside the bot box The hook helper Claude Code runs for each hook reads the turn's bearer from a file in the data folder, which the bot box replaces with an empty folder. On every Cloud home the helper found no token and quietly did nothing: no hint for a timed-out command, no work summaries, no context at session start. - The token lives in a folder of its own per conversation (hook-tokens/<digest>/token), and the box puts that folder back read-only: only that conversation's token, never the data folder or another conversation's token. The folder, not the file, so the box sees each turn's new token after it is renamed over the old one. Tests: a Claude turn under a stand-in box that hides the token unless a mount line puts it back fires its PostToolUse and Stop hooks with the turn's bearer, and the box shows only that conversation's token folder, read-only. It fails with the bind removed (no hook fires), with the file bound instead of its folder, and with the old shared folder (another conversation's token shows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MCP Settings Test reaches a server the way bots do, through the credential broker Where bots' turns are boxed, a turn's engine reaches a URL MCP server through the credential broker, which adds the server's headers and forwards. The Settings Test connected directly, so a server behind Cloudflare Access tested "Connected" while every bot failed (the broker added a slash to the server's address). - The Test now makes a grant the way a turn gets one, connects through the broker's socket, and revokes the grant when it ends. Where turns aren't boxed, bots and the Test both still go direct. - If the server fails through the broker but answers directly, the Test says "Your bots can't reach this server" with the reason and that the fault is on our side, never "Connected". - A server the broker can't reach reads as unreachable, as a direct test does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A new MCP server saved switched off says so, its switch can't flip it straight back, and a server that failed at engine start reconnects - A new or edited server whose first test fails reads "Saved, but off: the test failed", with the reason and that bots can use it once it's on. While that test runs, the row says it's off until it passes. - A passing test after a save switches the server on by itself. A click on its switch in the next moment was aimed at the Off the person saw, so it keeps the server on ("it passed its test a moment ago") instead of switching it straight back off, which looked like a one-second on/off. - Where bots reach URL servers through the credential broker, a server the engine reported as failed when it started gets the conversation a new grant on its next turn, so the engine starts again and reconnects. The chat says the server didn't connect and that it connects again on the next message, so bots no longer need to ask for a new chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Renderer smoke: a saved server whose first test fails reads "Saved, but off" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the reconnect import on its own line, apart from other open changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A connected app comes before any browser or screen, and a refused one is reported with its fix Bots were told to do web work on the person's own computer in this order: the built-in browser, a cloud computer, then a connected app. A connected app does a task more cheaply and surely than any screen, and one that is refused or broken is the person's to fix. - The order now starts with a connected app that does the task. - Wherever a browser or a screen is mounted (a Cloud home too), bots are told to use a connected app first, and when it is refused or fails, to say so in one plain line with what fixes it and ask before doing the task on a screen instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bug reports: the reporter sees their @devs report's status, and is told once when the fix runs here - The person's @devs message shows its report's status in the app's language: "Bug report sent · Got it, we're looking", then "Fixed in 0.1.x, coming in your next update", then "Fixed in 0.1.x" (bugReport on the message; all 17 language packs). - The server follows each report it sent (devs-reports.json) and asks the MausBot team about the open ones a minute after each start and hourly: POST /api/bug-reports/status at the address reports go to, the same way on the desktop and on a Cloud, which signs its question with its bootstrap secret. Nothing ever has to reach this server, or wake a sleeping Cloud. - Once it runs the fix's release (versionAtLeast: never on a guess) and the answer allows it (never a former customer's Cloud, never a teammate who left), one line in the chat they reported in, "Fixed in 0.1.x. Want to try again?", one notification (on a Team Cloud only to the reporter), and a one-time note on the bot's next turn there. Once per report, across restarts. - OMB_DEVS_STATUS_MS sets the interval for fixtures (control-omb passes it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it never interrupts the person, and questions never go stale At Full access ("Just do it") a question from work a bot handed on goes to the bot that handed it on, which answers it from what it knows; with no answer the asker goes on with the default it named and says so in one line. Its card says who picked what and blocks nothing. Only a sign-in, a payment, a secret or the person's own account reaches the person, once, while the rest of the work moves on. An ask tool in handed-on or unwatched work is answered the same way, and the prompts say to find things out the cheapest way first and ask the person last. On "Ask me first" a question waits for the person however long they take. An answer counts from the card, the inbox, the asking bot's own chat, or passed on by another bot (coordinate_bots answers). A question whose work ended, or that a newer one replaced, closes; a sign-in wait in handed-on work settles from the person's line, an answer passed on, or the bot going on with the site; a restart posts nothing again. Rooms and a bot's own chat get the same tap cards, and prompts name Claude's question tool as mcp__ogb__ask_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it decides only in work the person or their routine started A question in work a webhook or another outside event started still goes to the person at Full access, as an ask tool there does: its brief is not the person's authority, and the question is their check on it. The Just do it line stays out of those turns' prompts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep steering and late answers in the person's own chat as they were A line the person types in their own chat while a question card waits is still steered into the turn or queued, as an engine that can steer expects; only in work a teammate handed on does it answer the card. A question its turn left open keeps waiting for a late answer after other lines. Two peer-question notification tests now run on "Ask me first", where a teammate's question is still the person's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Warm summaries: a long conversation is summarized while it sits idle, so the next answer starts fast On a Team trial every first answer slower than 35 s (35 to 58 s) was Claude Code compacting a conversation of about 162k tokens at the start of the person's turn, warm cache or not: writing the summary is what takes the time. Both kinds of compaction ran only when the next turn started, on the person's time. - After a turn that leaves a direct conversation at 100k tokens or more, its summary is written about 3 minutes later, while the prompt cache is still warm; from 80% of Claude Code's own compaction point (160k of 200k) it starts after about 10 s, because the next turn would summarize anyway. - Claude Code: its own /compact, with instructions to keep the person's latest requests and every open question, on a persisted fork of the session (--resume S --fork-session) launched with the live process's exact contract, as the keep-warm ping is, so it reads the cached prompt start and keeps the conversation's tool list. The conversation moves to the fork only when no turn began meanwhile; its last two exchanges count as not yet seen, so the next turn carries them word for word on the existing, saved "not seen yet" path. The chat shows one line for it. - Other engines: OpenMausBot's own fold runs while idle once the conversation is close to its threshold, instead of at the next turn. - Skipped while work is due (a queued message, a teammate working on this conversation's request, a fired wait, the spend limit); retried while the bot is busy, memory is short or a routine of the bot is due, until the cache would be cold. A turn that starts meanwhile wins, unless it would summarize at its start anyway: then it waits for the summary already being written instead of a second. - The app's presence ping names the open chat: opening a conversation starts an overdue summary at once and keeps its engine process alive while the person is there. - Off with context.autoCompact: false, or OMB_WARM_SUMMARY=0 for this alone. The fake Claude Code gains a growing context, its own compaction at a threshold with a duration, and /compact on a fork. On a long fake conversation whose CLI compaction takes 6 s, the next reply took 6.2 s before and 0.3 s after; one sent while the needed summary was being written took 5.4 s (the rest of it, not a second one); one sent during a summary it did not need, under 0.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * People before bots: a shared @name reaches the person, a bot named like a person is warned, deleting a Chief offers Archive On a Team trial a person's "@<teammate>" reached a bot that had the teammate's name, because a tie went to the bot. Then the person deleted their Chief to fix it, and lost its whole setup chat. - A tag a person and a bot share is the person's: "@Bob" reaches the teammate Bob (or means the writer, for their own name), and only a longer bot name ("@Bob Bot") reaches a bot. The teammate's inbox gets it, the turn no longer tells the bot it was named, and the composer highlights it as the person (shared/person-mention.ts, src/lib/mentions.ts). - A bot made or renamed with a person's name (a teammate's, or the owner's own) says so once in its own chat, and the Chief's create_bot result carries the same warning (server/host/bot-name-clash.ts). Nothing is refused. - Deleting a Chief of Staff offers "Archive instead" first: its chats hold the team's setup. Archiving drops the Chief role, so the server accepts it, and the bot can be restored any time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots in two places: one plain suggestion to bring them together When this computer has bots of its own while a server of the person's own (or My Cloud they keep this computer's bots away from) has bots too, the bots in the two places can't work together. This computer's page now says so once, in a corner card: "Your bots live in two places, so they can't work together. Bring them together on <place>?" One tap starts the one-time move there (Make <server> my home, or letting this computer's bots move to My Cloud), and Not now is remembered for that place. Main reads each place's own move summary, so only bots a move would carry count and a place's untouched first bot never makes two places. A server is asked only while it says it is the person's alone, a sleeping Cloud never, a team's Cloud or a server others sign in to never. Nothing shows while a move is under way, during the welcome or the tour, or on any page but this computer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots say where another bot lives, and how to bring them together A bot that asked for a teammate living in the person's other place (their computer, their own server or My Cloud) only heard that no such bot exists. The person's app now tells each of their own places the names of the bots their other places have, and nothing more (PUT /api/places/elsewhere, from that place's owner only, never a team's place or one others sign in to). With that: - coordinate_bots and bot_idle waits say "Scout lives on Work laptop, the person's computer, not here", that bots work together only within one place, and offer the one tap that brings them together ("Make Garage server my home", or Bring them together for My Cloud); a name nowhere stays no such bot; - a person's @mention of such a bot tells the answering bot where it lives, and in a room one plain line says so to the person; - before the app said anything, a name nowhere here also says that bots work together only within one place, and how to bring them together. Main tells each place only when what it would be told changed, never while a move is under way, and stops telling this computer once its bots moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Server lines in the person's language: the way in, a guard, and bug report lines Lines the server writes for a person (a bot's line, a status row, a card, a notification) now come from the language packs under "server." keys, in the language the person's app shows. - server/server-lines.ts: serverLine(language, key, params) reads the packs; a missing key reads in English, as the app's screens do. The server bundle keeps only the server keys (scripts/server-locale-plugin.mjs), and tsc's copies of the packs are dropped from dist-server. - server/host/person-languages.ts: the app keeps a person's language pick on their own computer, so the server learns it from presence pings (the owner's, or each member's on a Team Cloud). A line for a person reads in theirs, else in the place's: the one set on the server or by the team's Admin, else the one most people's apps show. - Bug report lines (@devs) read in the reporter's language; the marker that tells whether the bot already passed a failure on is "MausBot", which every language keeps. - src/locales/server-lines.test.ts: a guard that fails on an English line written straight into a line a person reads. It follows each place a line is made through consts, helpers and imports; ALLOWED says why text is English on purpose; PENDING lists the 242 lines written before it, by area, and only shrinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Only the tests of other languages' lines read the packs; CI selection knows it CI's import-graph checks failed: the server now loads the language packs, and every server test reaching server-lines.ts counted as reading a translation. - server/server-lines.ts reads English only. server/server-line-packs.ts adds the other languages; server/index.ts loads it at start, and so do the tests that check a line in another language. The guard checks index.ts loads it. - scripts/ci-scope.mjs: those tests run with the locale tests. The packs stay out of SRC_OUTSIDE_RENDERER: a change to English already runs every Linux test, and one to another language runs every test that reads it, so a translation change does not run the server's checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Runs and routines tell the person in their language A routine's line in a chat and the incident a person hears about now read in the language of the person whose conversation it is, through server/server-lines.ts. - "This run didn't finish: …" and "Recovered: … finished OK at …" (with the time in that language's clock), written into the chat a routine reports to. - The text of a routine run's card, for clients that show no cards. - The incident status row and its notification. The Chief's own incident report stays English: only a model reads it. - server/index.ts: threadLanguage(threadId), the language of a conversation's person, else the place's; no line added. - The guard's PENDING drops these 17 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Connect prompts and sign-ins ask in the person's language When a bot needs the person to connect an app, sign in or give a key, what the server writes now reads in the language of the person whose conversation it is. - "I need you to connect …", "I need you to sign in to …" and "I need your …", which a routine writes into its chat while it waits on a card. - The connect card's text and, where the app catalog has no words of its own, its description. - The line under a sign-in card. It moves from shared/ to server/connector-card-text.ts, since shared code cannot read the packs; nothing else used it. - The credential card's text and the sentence on how the bot gets the key. - The guard's PENDING drops this area's 13 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Notifications are titled in the person's language Every notification's title ("… has a question", "…'s routine failed", "… needs you to sign in to …") now reads in the language of the conversation's person: buildNotification asks a resolver the server sets at start (setNotificationLanguage(threadLanguage)), so no caller changes. Also the inbox's "· your assistant answered" and two bodies the server writes itself ("Results in from …", "Open OpenMausBot to sign in to …"). The guard's PENDING drops the area's 8 lines, and checks the server sets the resolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A room's status rows read in its person's language What a group chat shows about its members now reads in the language of its conversation's person: waiting for a busy member and the skips, a mention that missed, archived members, still stopping, held members, no summary, a stalled turn, context compaction, and a bot's receipt in its own chat ("Posted in …", "Opened thread #…"). What a coordinating bot reads stays English. - server/server-lines.ts: isServerLine(key, text) reads a line back in any language; isHeldMemberLine uses it, and the held row keeps "resume", the word the room understands. - The sentinel counts a German stopped room turn as a timeout, and now also skips a held member's row in the shape it reads rows in (a harness notice with names taken out). The openmausbot CLI, which runs it, loads the other languages. - The guard's PENDING drops 20 room lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(team connections): an owner's own-connection lines are checked in her private chat and in a shared one An own bridge only works in the person's private chat now, so the "connect your apps again" check runs there; the connect lines are checked in both places, including an app call through the team's tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates' hand-offs and results read in the person's language What a conversation shows about a teammate's work now reads in the language of that conversation's person: a hand-off going out ("Sent to …"), its result coming back ("… replied", "… — failed:", "Result withheld:"), resuming with results or a question, what came of a teammate's question or approval, what waits behind the person, recalled private chats, a closed thread, a room goal's card, "Answer passed to the waiting work", and the inbox's and team messages' rows. - server/server-lines.ts: one resolver, conversationLanguage(threadId), which the server sets at start; notifications use it too (it replaces setNotificationLanguage), so modules with no person at hand need no new wiring. - What a coordinating bot reads stays English. - The guard's PENDING drops 19 lines; the area keeps feature-flagged escalations, approval level names, the peer approval card and a goal's text after a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it: a question in a person's private chat stays theirs Work a person's request hands on runs in the receiving bot's chat with them when it may use their own apps, and what it hands back keeps a question's words in that chat. Its requester never sees them, so it cannot decide them, and a sign-in among them could not be told apart. Such a question now reaches the person there, as on "Ask me first": the turn result says the question stayed private, and the ask tool is not turned away in that chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acting person): read the private question flag with toMatchObject The hand-back keeps its input's type, which has no privateQuestion field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(analytics): the two-places card's event Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): the engine registry answers null for a missing engine registry.get returns ProviderInstance | null; the host's dependency took only undefined, which failed typecheck once the branch was checked against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): its line in the chat comes from the language packs The line a warm summary leaves in the conversation is now server.warmSummary.summarized, in every pack, written in the language of the conversation's person, as the guard from #3931 asks of every line a person reads. It names no count, so it needs no plural forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Main's guard passes: the same-request notice in the person's language Main went red on the server-lines guard: #3957's "Another teammate asked the same a moment ago…" row landed while #3931's guard was in review, and #3948 reworded a line the guard lists. - The notice reads in the language of the conversation's person (server.teammates.sameRequest, German by hand, every pack). - PENDING follows #3948's rewording of the webhook line. - The guard's check that index.ts loads the other languages matches that import anywhere on its line (as #3960 has it), so another import may follow it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates: the recall row reads in its room's language after main's discloseRecall Main moved this row into discloseRecall(bot, roomThreadId, …), where threadId is not in scope, so the merged branch failed typecheck. The row is the room's: it now asks for roomThreadId's language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bots explain): the one-place hint comes before the reach help, so a refusal still ends with it server/room-coordination.e2e.test.ts pins that a refusal for a name nobody has ends with the reach help (and its "Never use computer control to get around this"). The hint now sits just before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the cards a parked turn waits on move to server/host/resumable-cards.ts resumableCards is a pure read of the conversation; moving it out keeps server/index.ts under its file-size ratchet once #3930 lands with main (the fix #3930's branch made when it merged main, ported here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the MCP reconnect, bot name clash and bug-fixed lines come from the language packs #3922, #3934 and #3937 were written before main's server-lines guard, which fails on their three English lines once they meet it. Each line is now a "server." key (English and German) written with serverLine in the language of the conversation or reporter: server.mcp.reconnect.one/many (server names listed the reader's way), server.bots.nameClash (create_bot's result stays English for the model) and server.reports.fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the bot archive/delete dialog's props move beside botConfirmCopy #3934's Archive-instead offer grew src/components/Sidebar.tsx past the size the 0.1.135 release set (1790 against 1785). botConfirmProps in ArchivedBotsPanel.tsx now builds the dialog (copy, icon, Archive instead for a Chief, confirm); the sidebar keeps the ConfirmDialog and its callbacks, and is 1774 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 5 天前 | |
One "needs you" state for every card a bot leaves open A bot that asked for a password, a sign-in or a connection ended its turn and nothing told the person: the thread looked finished and the only alert was "<bot> finished". A card that outlives its turn now makes the conversation wait on the person on every surface, sends its own notification that says what is needed, holds back "finished", and stays in view in the chat until it is answered. Parked hand-offs no longer announce results while they wait on a card. Each wait has a stable kind (question, approval, review, password, sign-in, connect) an inbox can list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
One "needs you" state for every card a bot leaves open A bot that asked for a password, a sign-in or a connection ended its turn and nothing told the person: the thread looked finished and the only alert was "<bot> finished". A card that outlives its turn now makes the conversation wait on the person on every surface, sends its own notification that says what is needed, holds back "finished", and stays in view in the chat until it is answered. Parked hand-offs no longer announce results while they wait on a card. Each wait has a stable kind (question, approval, review, password, sign-in, connect) an inbox can list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
Phone apps as bot tools: bots use your phone's Calendar, Reminders, Contacts, Location and Messages (#3457) * docs: design + plan for phone apps as bot tools, server plumbing (sub-project A) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): shared vocabulary for phone apps, grants and the device.job frame Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): registry of paired phones and what each allows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): job queue a phone long-polls, leases and answers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): byte-measured result cap, turn-ended complete throws 409, poll after close Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): tool catalog, instructions and the per-bot verdict Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): the phone's own routes: register, poll, lease, answer Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a phone's companion identity comes from the verified auth, not headers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): device as a fifth harness MCP kind with its own timeout Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): timeout message names the call's own limit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): every engine that mounts HighLevel mounts the device tools too Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(outbound): move the send hold out of index.ts so other tool kinds can use it The "Send on your behalf?" hold and the dispatch-time allowance check move from the connectors MCP handler into server/outbound-hold.ts as createOutboundHold(deps), with no change in behaviour: the same decision rows, card, activity flips, notification, timeout patch and refusal text. The handler keeps its parsing, scope checks, refuseOutbound, sendsFreely and both requireActiveInternalCapability calls. buildNotification no longer demands a threadId on the bot it never reads, so the hold can take the narrower bot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): keep store.tsx inside its line ratchet after the capability fields Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(outbound): the hold's bot type carries notifications, so a muted bot stays quiet buildNotification reads bot.notifications through the hold's approval notice; OutboundHoldBot now picks it, and the test shows a muted bot still gets the card but no notification. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): MCP host that turns a bot's call into a phone job behind the per-bot verdict and the send hold Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): default phone by last use and by the tool's app, reserve only after every check, hold every outbound phone tool Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): mount the device tools per turn, route the internal MCP, nudge the phone over SSE server/index.ts wires the phone registry, job queue, host and /api/phones routes on existing lines (still 16843): the owner's own direct turn mounts the device server when its bot is granted an app one of the owner's phones allows, /api/internal/device/mcp answers it, a queued job nudges admin SSE clients with device.job, the phone's job long poll is exempt from the maintenance request count, the grants picker lists the phone tools, and shutdown closes the queue. The host is built beside the send hold it takes, which is declared after the HighLevel host. Phone tool rows read as "Phone" in the activity, and the device server is one of the app's own servers for the Today outcomes. The e2e pairs a phone, round-trips a job through poll, lease and result, and shows a bot without a grant and a read-and-draft routine run get no phone (a run of the same routine at the bot's own level does). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): only the owner's admin sessions hold a phone or lend their turn to one; routine reports stay the owner's Off a Cloud home, a request owns the desktop's phones only as the owner on this machine (loopback, the companion included) or an admin session; a client-scope session gets 403 registering one. A turn is the owner's when every line and card in its conversation came from this machine or a live admin session, so the owner's paired phone or iPad can use the phone tools too. Every routine here is the owner's, so a conversation a routine reported into keeps the phone; a webhook's posted payload still makes a conversation someone else's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the desktop owner rule in its own tested module; a bot's ask, a worker's answer and an outside event's report are not the owner's Off a Cloud home, whose turn may use the phones is decided in server/phones/owner.ts: a line with no person is the owner's unless it is a bot's ask, which counts only as this turn's own request and only while the work came from the user; a live admin session's line or answer is the owner's, a client session's, a worker's or an unrecorded one is not; a webhook's payload and an outside event's run report still make a conversation someone else's, while a real routine's report does not. Card answers now record the answering session's person key off a Cloud home too. The e2e shows a thread a webhook's run opens gets no phone (one the owner's turn opens does), and a conversation an outside event's run reported into loses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot phoneApps grant on the bot patch route PATCH /api/bots/:id accepts phoneApps (null clears to the default). Adding a capability or raising read to write against the effective grant, including a Chief's clear-to-everything, counts as loosening. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot Phone apps card in bot settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): list registered phones and their allowed apps in Settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): surface a failed phone removal and block double clicks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): phone-side contract fixture Pins the wire shapes the phone apps parse; the test keeps the file in step with the server's zod schemas and PHONE_TOOLS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(phones): lower the index.ts ratchet and document the phone routes Pins server/index.ts at 16843 lines and adds "Phone apps as bot tools" to docs/ios-companion.md. Fails on base too: - node:sqlite load error on node 22 (125 src/ test files, e.g. src/components/CallSheet.test.ts) - server/browser-live-routes.test.ts - server/chat-apps-mcp.e2e.test.ts - server/cloud-sync.e2e.test.ts - server/control-omb.test.ts - server/device-links.test.ts - server/headless-cli.e2e.test.ts - server/routes/browser-viewers.test.ts - server/usage-traces.e2e.test.ts - server/verification-fixture.e2e.test.ts (server/group-local-vm.e2e.test.ts timed out once under full-suite load; passes alone on the branch.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): off a Cloud home a routine reaches the owner's phone only while the owner wrote it, unchanged A client-scope session could create, edit and run a routine whose run mounted the device server and reached the owner's phone: every non-webhook run counted as owner-written and owner-started, and every routine's report as the owner's. The desktop now records routine authorship the way a Cloud home does (createCloudRoutineAuthors, owner-routines.json): the owner or an admin creating a routine records it; anyone else's edit forgets it; the owner's edit keeps it only when it was theirs or they rewrote its instructions. A run is the owner's when its routine is recorded with the run's fingerprint and a schedule, a restart or the owner's own manual start began it; a routine's report is the owner's only for a routine the owner wrote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): no desktop phones where sign-in lets several people in; a relayed line is not the owner's Off a Cloud home every admin session counted as the one desktop owner, so on a self-hosted server shared through sign-in each admin reached every admin's phones; and a line relayed by an external interface (the Slack worker) names no person, so it passed as typed at this machine. phoneOwnerOf and phoneTurnOwner now offer the desktop owner's phones only where desktopPhonesOffered holds: no shared membership and loopback trust that is the owner, not a service. desktopLendingTurn rewrites relayed user lines to NOT_THE_OWNER, as it does a bot's unvouched ask. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): removing a phone fails its jobs, and a removal on the computer sticks Both DELETE routes only dropped the registry record: a job queued for the phone or in its hands kept waiting out its timeout, and the phone re-registered on its next connect. PhoneJobs.drop(key, text) finishes every job for the key as { ok: false, code: "denied", error: "This phone's access changed." } and wakes its open poll. The admin DELETE /api/phones/:key also records the key in a persisted blocked list in phones.json ({ version: 1, phones, blocked }, the old shape still read), so PUT /api/phones/self from it answers 403 "This phone was removed on the computer. Pair it again to use its apps." until the phone pairs again under a new key. The phone's own DELETE /api/phones/self does not block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): queue and nudge a phone job before asking whether the phone is online PhoneJobs.request waited up to 15 s for online() before it queued the job and sent the device.job nudge, and only a poll refreshes `seen`: a phone listening on its event stream but idle was never told to poll, so every call to it failed as offline. The job is now queued and nudged at once; if it has not been delivered when the 15 s reconnect window ends and the phone is still not online, it fails with the offline sentence (or turn_ended when its turn is over). A job the phone never took times out with "<tool> was never picked up by the phone within N seconds. It did not run."; a delivered or leased one keeps "It may still have run". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a newer phone's registration and job outcome are read, not refused The phones ship on their own schedule, but the registration schema was .strict() with an enum-keyed capability record and the outcome schemas were .strict() with a closed code enum: one new field, app or code from a newer phone made the server refuse its registration or its answer. Both now strip unknown keys; capabilities are filtered to the PHONE_CAPABILITIES this server knows before parsing, so an unknown app (say `inbox`) is dropped and the known ones register; an outcome code outside PHONE_JOB_CODES reads as absent. A known field with a malformed value is still refused. The contract fixture's shapes are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): derive the device call's timeout, test the team-Cloud refusal on a real key, keep the phone label last - The device proxy timeout is DEVICE_PROXY_TIMEOUT_MS = the send hold (OUTBOUND_HOLD_MS, now exported from outbound-hold.ts and imported by index.ts) + PHONE_SEND_TIMEOUT_MS + PHONE_RECONNECT_WAIT_MS (now exported) + 30 s = 705 s. harness-budget.ts writes the sum out instead of importing, so the stdio proxy that reads it loads neither the hold nor zod; harness-mcp-proxy.test.ts holds it to the sum of the real constants. - "a team Cloud offers no phones" authenticates as a verified companion device, so its 403 comes from there being no owner, not from a missing key. - phoneOkResult spreads the phone's answer first and `phone` last, so no key in the answer can relabel where it ran. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(phones): as-built notes on the design for the phone packs Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the owner's existing routines no longer hide the phone from the Chief's chat Routines written before this build kept no authorship record, so their reports made the Chief's main conversation count as someone else's and the phone tools were withheld there; the bot then reached for the USB Android tool. On the first start with authorship records, a desktop only one person uses (phones offered, no other person's session) records its existing routines as the owner's, once. A turn that may not use the phone now hears that a phone is paired and to ask in a new conversation, and both prompts say the mcp__phone__ tools are a USB Android. A phone named after its kind is described as "The iPhone". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(phones): every bot may use the phone, and asks first when the person is at the computer Phone apps are no longer the Chief's alone: with phoneApps unset any bot gets what the phone allows, and an explicit per-bot grant still wins ({} turns it off). The owner rule is unchanged. A send made by a registered phone is noted by its sendId, so the direct turn it starts is told the person is talking from their phone and does reminders, events, contacts, location and texts there. Every other turn (direct from the computer, room turns, the prompt preview) is told to do things the usual way, use the phone only when asked for it, and ask once "here, or on your phone?" when the phone could also do it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): where the person is lives in its own volatile section, unattended turns are told so, and phone sends without an id count The place sentence moves out of the stable "device" section into its own "device-place" section, which is volatile, so a phone turn after a computer one no longer relaunches the engine and re-uploads the conversation. It is emitted only beside a non-empty device section. A direct turn now has three places: the phone (its request is a noted phone send), the computer (a person's own line with no automation, peer ask, coordination or unattended flag) and unattended for everything else, which is told nobody is waiting and to use the phone only when the task names it. Rooms and the preview stay at the computer. A send from a registered phone without a sendId gets one minted, and each Live call line from a registered phone is noted, so walkie, command and call sends count as the phone's. The route's dependency is now fromPhone(auth) plus notePhoneSend(sendId). The computer text now allows reading the phone and asks once before changing anything on it; the phone text adds "as far as the phone allows"; the card's default note and the wire comment follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix phone send after ended turn, stale phoneApps grant, and comment pointers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(phones): drop the plan and spec documents The working plan and design notes were scaffolding for building the feature, not documentation of it. What the phone and the server agree on stays in docs/ios-companion.md and the contract fixture server/testing/fixtures/phone-jobs.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): no card of OpenMausBot's own on phone sends, and no "here or on your phone?" question A phone send already waits on the person: it opens a sheet on the phone and goes only when they tap Send there. It no longer waits first on the "Send on your behalf?" card, so the phone tools leave the outbound hold entirely; the bot's per-app grant still decides whether it may send at all (an RSVP is a Calendar write the same way). Where the person is now decides without asking: a turn that came from the phone does phone things on the phone, a turn at the computer works the usual way and changes the phone only when the person names it, and a run nobody typed uses the phone only when its task names it. The bot settings note says the same. Tests: the rpc and e2e tests send a message, a WhatsApp and an RSVP and check the job reaches the phone at once with only activity rows in the chat and no outbound decision rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(phones): the phone wiring moves to server/host/phones.ts, index.ts unpacked The phone integration had been added to server/index.ts as up to nine statements on one line. It now lives in createPhones (server/host/phones.ts): the registry and jobs, which sends came from a phone, whose turn may reach the owner's phones, where the person is, the mount and prompt parts, the /api/phones routes, and the desktop owner's routine records. index.ts builds it once and calls it from normally formatted lines, so it ends smaller than on main: 16,651 lines, pinned exactly in the file-size ratchet (the route ratchet stays at 6 path.startsWith). server/host/phones.test.ts covers where the person is (a send from the owner's phone is the phone's, the computer stays the computer, a run nobody typed is unattended, no place asks the person to choose) and that shared servers, other people's lines and refused Cloud turns get no phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(phones): translate the phone strings into every language pack The 17 phone strings (Settings > Remote access and the bot's Phone apps card) in all 12 packs, accepted with generate-locale --accept so source-hashes.json records them against the current English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 11 天前 | |
Phone apps as bot tools: bots use your phone's Calendar, Reminders, Contacts, Location and Messages (#3457) * docs: design + plan for phone apps as bot tools, server plumbing (sub-project A) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): shared vocabulary for phone apps, grants and the device.job frame Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): registry of paired phones and what each allows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): job queue a phone long-polls, leases and answers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): byte-measured result cap, turn-ended complete throws 409, poll after close Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): tool catalog, instructions and the per-bot verdict Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): the phone's own routes: register, poll, lease, answer Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a phone's companion identity comes from the verified auth, not headers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): device as a fifth harness MCP kind with its own timeout Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): timeout message names the call's own limit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): every engine that mounts HighLevel mounts the device tools too Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(outbound): move the send hold out of index.ts so other tool kinds can use it The "Send on your behalf?" hold and the dispatch-time allowance check move from the connectors MCP handler into server/outbound-hold.ts as createOutboundHold(deps), with no change in behaviour: the same decision rows, card, activity flips, notification, timeout patch and refusal text. The handler keeps its parsing, scope checks, refuseOutbound, sendsFreely and both requireActiveInternalCapability calls. buildNotification no longer demands a threadId on the bot it never reads, so the hold can take the narrower bot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): keep store.tsx inside its line ratchet after the capability fields Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(outbound): the hold's bot type carries notifications, so a muted bot stays quiet buildNotification reads bot.notifications through the hold's approval notice; OutboundHoldBot now picks it, and the test shows a muted bot still gets the card but no notification. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): MCP host that turns a bot's call into a phone job behind the per-bot verdict and the send hold Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): default phone by last use and by the tool's app, reserve only after every check, hold every outbound phone tool Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): mount the device tools per turn, route the internal MCP, nudge the phone over SSE server/index.ts wires the phone registry, job queue, host and /api/phones routes on existing lines (still 16843): the owner's own direct turn mounts the device server when its bot is granted an app one of the owner's phones allows, /api/internal/device/mcp answers it, a queued job nudges admin SSE clients with device.job, the phone's job long poll is exempt from the maintenance request count, the grants picker lists the phone tools, and shutdown closes the queue. The host is built beside the send hold it takes, which is declared after the HighLevel host. Phone tool rows read as "Phone" in the activity, and the device server is one of the app's own servers for the Today outcomes. The e2e pairs a phone, round-trips a job through poll, lease and result, and shows a bot without a grant and a read-and-draft routine run get no phone (a run of the same routine at the bot's own level does). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): only the owner's admin sessions hold a phone or lend their turn to one; routine reports stay the owner's Off a Cloud home, a request owns the desktop's phones only as the owner on this machine (loopback, the companion included) or an admin session; a client-scope session gets 403 registering one. A turn is the owner's when every line and card in its conversation came from this machine or a live admin session, so the owner's paired phone or iPad can use the phone tools too. Every routine here is the owner's, so a conversation a routine reported into keeps the phone; a webhook's posted payload still makes a conversation someone else's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the desktop owner rule in its own tested module; a bot's ask, a worker's answer and an outside event's report are not the owner's Off a Cloud home, whose turn may use the phones is decided in server/phones/owner.ts: a line with no person is the owner's unless it is a bot's ask, which counts only as this turn's own request and only while the work came from the user; a live admin session's line or answer is the owner's, a client session's, a worker's or an unrecorded one is not; a webhook's payload and an outside event's run report still make a conversation someone else's, while a real routine's report does not. Card answers now record the answering session's person key off a Cloud home too. The e2e shows a thread a webhook's run opens gets no phone (one the owner's turn opens does), and a conversation an outside event's run reported into loses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot phoneApps grant on the bot patch route PATCH /api/bots/:id accepts phoneApps (null clears to the default). Adding a capability or raising read to write against the effective grant, including a Chief's clear-to-everything, counts as loosening. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot Phone apps card in bot settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): list registered phones and their allowed apps in Settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): surface a failed phone removal and block double clicks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): phone-side contract fixture Pins the wire shapes the phone apps parse; the test keeps the file in step with the server's zod schemas and PHONE_TOOLS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(phones): lower the index.ts ratchet and document the phone routes Pins server/index.ts at 16843 lines and adds "Phone apps as bot tools" to docs/ios-companion.md. Fails on base too: - node:sqlite load error on node 22 (125 src/ test files, e.g. src/components/CallSheet.test.ts) - server/browser-live-routes.test.ts - server/chat-apps-mcp.e2e.test.ts - server/cloud-sync.e2e.test.ts - server/control-omb.test.ts - server/device-links.test.ts - server/headless-cli.e2e.test.ts - server/routes/browser-viewers.test.ts - server/usage-traces.e2e.test.ts - server/verification-fixture.e2e.test.ts (server/group-local-vm.e2e.test.ts timed out once under full-suite load; passes alone on the branch.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): off a Cloud home a routine reaches the owner's phone only while the owner wrote it, unchanged A client-scope session could create, edit and run a routine whose run mounted the device server and reached the owner's phone: every non-webhook run counted as owner-written and owner-started, and every routine's report as the owner's. The desktop now records routine authorship the way a Cloud home does (createCloudRoutineAuthors, owner-routines.json): the owner or an admin creating a routine records it; anyone else's edit forgets it; the owner's edit keeps it only when it was theirs or they rewrote its instructions. A run is the owner's when its routine is recorded with the run's fingerprint and a schedule, a restart or the owner's own manual start began it; a routine's report is the owner's only for a routine the owner wrote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): no desktop phones where sign-in lets several people in; a relayed line is not the owner's Off a Cloud home every admin session counted as the one desktop owner, so on a self-hosted server shared through sign-in each admin reached every admin's phones; and a line relayed by an external interface (the Slack worker) names no person, so it passed as typed at this machine. phoneOwnerOf and phoneTurnOwner now offer the desktop owner's phones only where desktopPhonesOffered holds: no shared membership and loopback trust that is the owner, not a service. desktopLendingTurn rewrites relayed user lines to NOT_THE_OWNER, as it does a bot's unvouched ask. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): removing a phone fails its jobs, and a removal on the computer sticks Both DELETE routes only dropped the registry record: a job queued for the phone or in its hands kept waiting out its timeout, and the phone re-registered on its next connect. PhoneJobs.drop(key, text) finishes every job for the key as { ok: false, code: "denied", error: "This phone's access changed." } and wakes its open poll. The admin DELETE /api/phones/:key also records the key in a persisted blocked list in phones.json ({ version: 1, phones, blocked }, the old shape still read), so PUT /api/phones/self from it answers 403 "This phone was removed on the computer. Pair it again to use its apps." until the phone pairs again under a new key. The phone's own DELETE /api/phones/self does not block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): queue and nudge a phone job before asking whether the phone is online PhoneJobs.request waited up to 15 s for online() before it queued the job and sent the device.job nudge, and only a poll refreshes `seen`: a phone listening on its event stream but idle was never told to poll, so every call to it failed as offline. The job is now queued and nudged at once; if it has not been delivered when the 15 s reconnect window ends and the phone is still not online, it fails with the offline sentence (or turn_ended when its turn is over). A job the phone never took times out with "<tool> was never picked up by the phone within N seconds. It did not run."; a delivered or leased one keeps "It may still have run". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a newer phone's registration and job outcome are read, not refused The phones ship on their own schedule, but the registration schema was .strict() with an enum-keyed capability record and the outcome schemas were .strict() with a closed code enum: one new field, app or code from a newer phone made the server refuse its registration or its answer. Both now strip unknown keys; capabilities are filtered to the PHONE_CAPABILITIES this server knows before parsing, so an unknown app (say `inbox`) is dropped and the known ones register; an outcome code outside PHONE_JOB_CODES reads as absent. A known field with a malformed value is still refused. The contract fixture's shapes are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): derive the device call's timeout, test the team-Cloud refusal on a real key, keep the phone label last - The device proxy timeout is DEVICE_PROXY_TIMEOUT_MS = the send hold (OUTBOUND_HOLD_MS, now exported from outbound-hold.ts and imported by index.ts) + PHONE_SEND_TIMEOUT_MS + PHONE_RECONNECT_WAIT_MS (now exported) + 30 s = 705 s. harness-budget.ts writes the sum out instead of importing, so the stdio proxy that reads it loads neither the hold nor zod; harness-mcp-proxy.test.ts holds it to the sum of the real constants. - "a team Cloud offers no phones" authenticates as a verified companion device, so its 403 comes from there being no owner, not from a missing key. - phoneOkResult spreads the phone's answer first and `phone` last, so no key in the answer can relabel where it ran. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(phones): as-built notes on the design for the phone packs Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the owner's existing routines no longer hide the phone from the Chief's chat Routines written before this build kept no authorship record, so their reports made the Chief's main conversation count as someone else's and the phone tools were withheld there; the bot then reached for the USB Android tool. On the first start with authorship records, a desktop only one person uses (phones offered, no other person's session) records its existing routines as the owner's, once. A turn that may not use the phone now hears that a phone is paired and to ask in a new conversation, and both prompts say the mcp__phone__ tools are a USB Android. A phone named after its kind is described as "The iPhone". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(phones): every bot may use the phone, and asks first when the person is at the computer Phone apps are no longer the Chief's alone: with phoneApps unset any bot gets what the phone allows, and an explicit per-bot grant still wins ({} turns it off). The owner rule is unchanged. A send made by a registered phone is noted by its sendId, so the direct turn it starts is told the person is talking from their phone and does reminders, events, contacts, location and texts there. Every other turn (direct from the computer, room turns, the prompt preview) is told to do things the usual way, use the phone only when asked for it, and ask once "here, or on your phone?" when the phone could also do it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): where the person is lives in its own volatile section, unattended turns are told so, and phone sends without an id count The place sentence moves out of the stable "device" section into its own "device-place" section, which is volatile, so a phone turn after a computer one no longer relaunches the engine and re-uploads the conversation. It is emitted only beside a non-empty device section. A direct turn now has three places: the phone (its request is a noted phone send), the computer (a person's own line with no automation, peer ask, coordination or unattended flag) and unattended for everything else, which is told nobody is waiting and to use the phone only when the task names it. Rooms and the preview stay at the computer. A send from a registered phone without a sendId gets one minted, and each Live call line from a registered phone is noted, so walkie, command and call sends count as the phone's. The route's dependency is now fromPhone(auth) plus notePhoneSend(sendId). The computer text now allows reading the phone and asks once before changing anything on it; the phone text adds "as far as the phone allows"; the card's default note and the wire comment follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix phone send after ended turn, stale phoneApps grant, and comment pointers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(phones): drop the plan and spec documents The working plan and design notes were scaffolding for building the feature, not documentation of it. What the phone and the server agree on stays in docs/ios-companion.md and the contract fixture server/testing/fixtures/phone-jobs.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): no card of OpenMausBot's own on phone sends, and no "here or on your phone?" question A phone send already waits on the person: it opens a sheet on the phone and goes only when they tap Send there. It no longer waits first on the "Send on your behalf?" card, so the phone tools leave the outbound hold entirely; the bot's per-app grant still decides whether it may send at all (an RSVP is a Calendar write the same way). Where the person is now decides without asking: a turn that came from the phone does phone things on the phone, a turn at the computer works the usual way and changes the phone only when the person names it, and a run nobody typed uses the phone only when its task names it. The bot settings note says the same. Tests: the rpc and e2e tests send a message, a WhatsApp and an RSVP and check the job reaches the phone at once with only activity rows in the chat and no outbound decision rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(phones): the phone wiring moves to server/host/phones.ts, index.ts unpacked The phone integration had been added to server/index.ts as up to nine statements on one line. It now lives in createPhones (server/host/phones.ts): the registry and jobs, which sends came from a phone, whose turn may reach the owner's phones, where the person is, the mount and prompt parts, the /api/phones routes, and the desktop owner's routine records. index.ts builds it once and calls it from normally formatted lines, so it ends smaller than on main: 16,651 lines, pinned exactly in the file-size ratchet (the route ratchet stays at 6 path.startsWith). server/host/phones.test.ts covers where the person is (a send from the owner's phone is the phone's, the computer stays the computer, a run nobody typed is unattended, no place asks the person to choose) and that shared servers, other people's lines and refused Cloud turns get no phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(phones): translate the phone strings into every language pack The 17 phone strings (Settings > Remote access and the bot's Phone apps card) in all 12 packs, accepted with generate-locale --accept so source-hashes.json records them against the current English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 11 天前 | |
Credit Boat, our sponsor, for the cloud desktops in the app (#3758) Where the app gives or lists cloud desktops, it now says they come from Boat: - the Cloud plan's points: "Voice and cloud desktops by Boat included"; - the cloud desktops list: "Your bots' cloud desktops, by Boat."; - a bot's place: "{bot} gets its own cloud desktop from Boat the first time a task needs one." All 15 languages are updated, with their source hashes recorded against the new English. The place-view jargon test allows Boat on that one state as well as on the two that ask to connect a Boat account. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Credit Boat, our sponsor, for the cloud desktops in the app (#3758) Where the app gives or lists cloud desktops, it now says they come from Boat: - the Cloud plan's points: "Voice and cloud desktops by Boat included"; - the cloud desktops list: "Your bots' cloud desktops, by Boat."; - a bot's place: "{bot} gets its own cloud desktop from Boat the first time a task needs one." All 15 languages are updated, with their source hashes recorded against the new English. The place-view jargon test allows Boat on that one state as well as on the two that ask to connect a Boat account. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
fix(automations): plain time zones, "First run Mon 9:00", panels titled by name Times read "weekdays at 9:00 India time", never an IANA id, wherever a schedule is put into words: the automation sentence, the bot's routine results and the routine cards. An automation that hasn't run yet says "First run tomorrow 9:00 AM" instead of "Working · hasn't run yet", and an enabled one is "On" rather than "Working". The detail panel is titled with the automation's name, says when it runs and which bot runs it, and shows its whole instructions. The create result tells the bot the person sees it right here in the chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
fix(automations): plain time zones, "First run Mon 9:00", panels titled by name Times read "weekdays at 9:00 India time", never an IANA id, wherever a schedule is put into words: the automation sentence, the bot's routine results and the routine cards. An automation that hasn't run yet says "First run tomorrow 9:00 AM" instead of "Working · hasn't run yet", and an enabled one is "On" rather than "Working". The detail panel is titled with the automation's name, says when it runs and which bot runs it, and shows its whole instructions. The create result tells the bot the person sees it right here in the chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
Postiz in Apps: a Social category, so bots can draft, schedule and publish social posts (#3785) * feat(apps): Postiz in a new Social category, so bots can draft, schedule and publish social posts The Apps page gets a Social category with a Postiz card. Connect signs in with Postiz Cloud through the existing MCP sign-in (dynamic registration and PKCE at api.postiz.com/mcp-oauth-dynamic: the loopback callback on the desktop, the Cloud's own address on a Cloud). "Use an API key instead" takes an organisation key and, for a self-hosted Postiz, its server address; the key is checked with MCP initialize and tools/list before it is saved, kept like other app keys (the desktop's encrypted store, the server's config on a Cloud), and sent only to the postiz entry at the address it was saved for. Postiz is one MCP server entry named postiz, so the MCP gate, each bot's server selection, a Team Cloud's scopes (Only for me), Claude Code's tool search and the large-catalog directory treat it like any other server. A revoked sign-in offers Reconnect and a revoked key shows as refused after the card's check. A new ready-made bot, Buzz the social media manager, adds posts to Postiz as drafts or scheduled posts and publishes now only when asked. Tests run an isolated fake-engine server beside stand-in Postiz backends: both connect paths, the bot's turn calling schedulePostTool with the right bearer, the token and key absent from every answer, transcript, prompt, log and data file but the one that stores them, plain refusals, revocation and disconnect. OpenMausBot only calls Postiz's public endpoints; no Postiz code or artwork is included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(postiz): the key does not move to My Cloud yet, so say only what does treat postiz like any server Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(keys): the read-back of every key covers the Postiz key, checked against a loopback stand-in Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
A bot's own routines, skills, profile and model apply at any level, with Undo (#2434) * A bot's own changes apply directly, with a one-line receipt and Undo A bot's change to itself (its routines, skills, profile and default model) now applies at every approval level, not only at Full access, so engines without Full access (Pi) and Ask conversations stop piling up cards for the bot's own bookkeeping. One rule, server/direct-apply.ts, decided by the server per request: Full access applies everything as before with no new limits; otherwise only a change whose target is the proposing bot applies, and a Cloud home's guest-driven turn keeps today's card for everything. Changes for another bot, team setup and peer approvals are unchanged. - Routines: own create/update/pause/resume/delete/run now apply; room goals the bot leads count as its own. Past 20 enabled routines, a create or resume by the self rule shows today's card instead (no cap at Full). - Profile and model: own changes apply through the same validated commit path, keeping every model-switch safeguard. - Skills: skill_manage writes apply through the existing applied path. - Audit: decision source "self" or "full-access"; Undo logs user-undone. - Receipt: applied cards carry autoApplied and render in ChatView and GroupView as one plain line ("Scout scheduled a routine: Check before dentist, today 2:30 PM", never a cron expression) with Details and Undo; after Undo it reads "· Undone" (card.undone, persisted). - Undo: POST /api/threads/:id/undo, authorized like answering the card. Routine create deletes it, update restores the captured definition, pause/resume invert, delete recreates; profile restores the changed fields; model restores the previous default; skill create removes it and update restores the previous SKILL.md. Each refuses once the thing moved ("Changed since, so it can't be undone here."), and a second Undo reports already undone. Cloud authorship stays consistent after Undo. - Bot-facing copy, prompts, docs and tests updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Self changes: keep the folder card, skip the card budget, client Undo, true copy - A bot's own working folder (cwd) keeps today's card below Full access: a new folder widens what its tools read and write without asking. - The 8-open-card budget no longer refuses a change that applies directly (it opens no card); the services check it once the grant is known, and it still holds every card, including past the 20-routine cap. - POST /api/threads/:id/undo is a client route like /respond, so whoever may answer the card may undo it; service trust still cannot. - A self-applied routine whose receipt settlement fails is logged "self". - The Verify card says "Saved as a skill" once the skill applied; Settings, the Skills page and /create-verification-skill no longer promise a review that does not come (stale translations dropped for English fallback). - Tests: per-bot cap and its 20/21 boundary, run_now applying, the budget, Full-access audit source, Cloud guest-driven turns keep cards, Cloud authorship after Undo, and the guest's pending skill card (reviewed hash, stale hold, deny, lost stage, deleted conversation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Undo's route lives in server/routes, so index.ts gains no route handler The index-route ratchet failed: POST /api/threads/:id/undo was a new path.match in server/index.ts (89 > 88). It is now createUndoRoutes in server/routes/undo.ts, wired with the same card-answer authorization and decision actor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 29 天前 | |
Add customizable provider icons (#1382) * Add per-instance provider icons and custom image uploads * Fix provider icon upload ordering, account identity, and localization --------- Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 1 个月前 | |
Add customizable provider icons (#1382) * Add per-instance provider icons and custom image uploads * Fix provider icon upload ordering, account identity, and localization --------- Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 1 个月前 | |
fix: recover provider images, authentication and thread approvals | 1 个月前 | |
Data dashboards: a bundled skill with a tested template, and parquet pages - skills/data-dashboards: a short guide (when to use a chat page, a published page or a schedule; data, chart, colour, layout and access rules) and dashboard.html, a template with DuckDB-WASM 1.32.0 (single threaded, worker from a blob) and ECharts 6.1.0 pinned on jsDelivr: KPI tiles, three charts, two filters, a table, light and dark, phone width, Intl formatting, loading and error states. Mounted only on turns that ask for a dashboard, chart, KPI or graph, so other prompts are unchanged. - publish_page bundles .parquet and .arrow data files (the pages Worker serves them from openmaus-cloud#feat/pages-parquet); .wasm stays out. - show_html and publish_page each point at the skill in one sentence (+138 bytes per catalog profile, +82 bridged; baselines moved by exactly that). - The Data tools no longer forbid dashboard code when the person asks for a dashboard page. - Cloud and server images ship skills/, so bundled skills reach Cloud homes (they read ./skills from /app and found nothing). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 14 天前 | |
React to a bot's message, and a 👍 or 👎 is your answer Every bot message in the chat gets an Add reaction button with 👍 👎 ❤️ 😂 🎉 👀; everyone in the conversation or group sees reactions under the message, one per person. A 👍 or 👎 on a bot's message is the person's reply to it: it starts the bot's next turn, or waits behind the running one, with a prompt that reads it as yes or no, so "Shall I send it?" plus 👍 goes on by itself. In a group it is addressed to the bot that wrote the message. On an open approval or one-question card it answers the card through the same checks a spoken answer on a call uses. The other reactions start no turn; the bot reads them with the person's next message, and in groups under its line. - shared/reactions.ts: the set, what answers yes or no, and one normalizer for clients and chat channels (skin tones, the presentation selector, Slack names) - server/reactions.ts and server/routes/reactions.ts: the rule and the route, out of index.ts; who reacted comes from the session only, never the body - server/person-replies.ts: the late question answer's delivery, moved out of index.ts, now carries reactions too; a person's 👍 reaches a bot once, and one still queued is taken back when they remove it - the guarded send route takes a relayed 👍 or 👎 (the Slack worker's half) - bots ask a plain yes or no in one sentence instead of a widget - reaction lines draw no bubble; retrying one keeps it a reaction - strings in all 12 languages, docs page, verification recipe and evidence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 | |
React to a bot's message, and a 👍 or 👎 is your answer Every bot message in the chat gets an Add reaction button with 👍 👎 ❤️ 😂 🎉 👀; everyone in the conversation or group sees reactions under the message, one per person. A 👍 or 👎 on a bot's message is the person's reply to it: it starts the bot's next turn, or waits behind the running one, with a prompt that reads it as yes or no, so "Shall I send it?" plus 👍 goes on by itself. In a group it is addressed to the bot that wrote the message. On an open approval or one-question card it answers the card through the same checks a spoken answer on a call uses. The other reactions start no turn; the bot reads them with the person's next message, and in groups under its line. - shared/reactions.ts: the set, what answers yes or no, and one normalizer for clients and chat channels (skin tones, the presentation selector, Slack names) - server/reactions.ts and server/routes/reactions.ts: the rule and the route, out of index.ts; who reacted comes from the session only, never the body - server/person-replies.ts: the late question answer's delivery, moved out of index.ts, now carries reactions too; a person's 👍 reaches a bot once, and one still queued is taken back when they remove it - the guarded send route takes a relayed 👍 or 👎 (the Slack worker's half) - bots ask a plain yes or no in one sentence instead of a widget - reaction lines draw no bubble; retrying one keeps it a reaction - strings in all 12 languages, docs page, verification recipe and evidence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 | |
Merge work-stays-with-its-origin at 2f0f27974 into feat/bot-api A Bot API thread is marked outside when it opens, and keeps its own gate on its botApi record; both route fences apply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 小时前 | |
fix(rooms): every room thread change is saved before it is shown, and a failed edit is undone on screen | 18 天前 | |
fix(chat): keep indentation when splitting a conversational reply | 24 天前 | |
Merge main into conversational reply style The quick-model route moves into routeDirectTurn, so startTurn only asks for it, and the usage ledger and the context measurement both name the model that ran. A simple line stays on the configured model when the thread's last context would fill more than 60% of the quick model's window, and compaction and computer-selection turns never route. The bubbles render from a ConversationalReply module; usageSummary moves to src/lib/chat-usage-summary.ts and settledWithin to control-client.ts so ChatView.tsx and index.ts stay under the size ratchet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
Resend once smaller when an OpenAI-compatible provider refuses a turn as too large A provider answering HTTP 413 (or "request entity too large", "payload too large", "request too large") now gets one smaller copy of the request: older screenshots lose their bytes for a short note, long tool output from earlier in the turn is shortened, then the oldest earlier messages go, until the messages are about half the refused size. The system prompt and the person's message, attachments included, never change. If nothing can shrink or the smaller copy is refused too, the turn fails with one plain line, worded again in the reader's language: "This message is too large for <model>. Start a new chat or pick a model that accepts more." Sizes and counts are logged, never content. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 12 天前 | |
Rooms: a bot picked from the @ list is the one reached, even when two share its name When two bots on a Team Cloud share a name, a person's @Name in a room went to whichever sorted first, and the other could not be reached by @ at all, even when picked from the menu. - The composer remembers which bot was picked from the @ list and sends its id with the words (`mentions`, at most 20 ids), in rooms and one-to-one chats. A failed send that hands the words back keeps the pick. - One resolver in shared/ reads @names for the app and the host: among bots that share a name, only the picked one is reached. - A typed shared name with no pick is refused before anything is queued: "Two bots here are named "Quill": Quill, Analyst and Quill, Chief of Staff. Pick the one you mean from the @ list." - The ids survive the room's and the one-to-one queue, and an answer to a bot's question in a room is addressed to that bot by id. - The composer's preview of who answers agrees with the room, and the @ list shows "Chief of Staff" for a Chief with no title. - A one-to-one bot is told about the picked teammate; for a typed shared name, about each bot of that name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 23 小时前 | |
Rooms: a bot picked from the @ list is the one reached, even when two share its name When two bots on a Team Cloud share a name, a person's @Name in a room went to whichever sorted first, and the other could not be reached by @ at all, even when picked from the menu. - The composer remembers which bot was picked from the @ list and sends its id with the words (`mentions`, at most 20 ids), in rooms and one-to-one chats. A failed send that hands the words back keeps the pick. - One resolver in shared/ reads @names for the app and the host: among bots that share a name, only the picked one is reached. - A typed shared name with no pick is refused before anything is queued: "Two bots here are named "Quill": Quill, Analyst and Quill, Chief of Staff. Pick the one you mean from the @ list." - The ids survive the room's and the one-to-one queue, and an answer to a bot's question in a room is addressed to that bot by id. - The composer's preview of who answers agrees with the room, and the @ list shows "Chief of Staff" for a Chief with no title. - A one-to-one bot is told about the picked teammate; for a typed shared name, about each bot of that name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 23 小时前 | |
feat(automations): run when my AI limit resets, and continue on the backup engine A new automation "when": the AI limit resets. - Routines gain a limit_reset schedule {engine, repeat: once | every_reset}. Its time is derived, never taken from input: the engine's reset plus a minute, or none yet ("runs when the limit resets (time not known yet)"). - server/limit-resets.ts keeps each engine's limit from plan usage (Claude five_hour/seven_day, Codex primary/secondary windows) and from refusals (Claude's rate_limit_info, Codex's "try again at …" words): the windows at their limit decide (latest reset), else the fullest window; a live refusal wins unless a later window is still full. Routines are retimed whenever that changes, and usage is polled while one is waiting. - create_trigger when=limit_reset (engine defaults to the bot's own), list_triggers shows it, TRIGGER_PROMPT and the tool description cover "run this when my limit resets" and setting up a continuation when warned near the limit. A turn on an engine at 90%+ is told so on its clock line. - A turn stopped by a usage limit with a known reset offers "Continue at 3:40 PM when your limit resets": one click creates a one-time limit-reset automation in that conversation (the usual card with Pause, Edit, Undo); it runs in that conversation and is told the previous turn hit the limit. - Near-limit warning on the Automations page ("Claude: 92% used · resets 3:40 PM") with "Move to after reset" for schedules due before the reset on that engine (only their next run moves), and a compact notice in the bot's chat. - Calendar: each engine's next reset is a labelled marker; dropping a bot or an automation on it makes a limit-reset automation instead of a fixed time; the editor's When has "When my AI limit resets" with an engine picker. Usage-limit failover, on the existing automatic recovery: - Claude's startup hold also proves a usage-limit refusal (synthetic usage_limit_reached + error result with no new cost, process stopped) and rejects with TurnUsageLimitRefusedError; an engine known to be refusing raises the same error before dispatch, so Codex and automation runs also move without spending a refused turn. - The backup is never another sign-in to the same subscription engine (that circumvents provider usage limits); another engine or a pay-per-use key is fine. One line: "Claude hit its limit (resets 3:40 PM), so Codex took over." - After the reset the next turn goes back to the original engine with one line; no backup → the Continue button. Moved out to keep pinned files shrinking: routine schedule helpers (routine-schedules.ts), routine request schemas (routine-request-schemas.ts), the routine run card (routine-run-card.ts), projectCalls (lib/routine-calendar.ts). Sealed test fixtures no longer read this machine's keychain for plan usage. Catalog goldens re-pinned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 17 天前 | |
Merge remote-tracking branch 'origin/main' into feat/bot-api # Conflicts: # server/index.ts | 2 天前 | |
feat(routines): support timezone-aware cron schedules | 1 个月前 | |
feat(routines): support timezone-aware cron schedules | 1 个月前 | |
Merge remote-tracking branch 'origin/main' into feat/bot-api # Conflicts: # server/index.ts | 2 天前 | |
Threads of one bot run at once, as many as the machine holds, and one per bot on Starter (#4212) * Threads of one bot run at once: a browser or computer is waited for, in plain sight, only by the turn that reaches for it Plain turns already overlapped on every role and engine. What held threads back: - A turn's first browser call claimed the bot's browser until the turn ended, and another thread's call was refused at once, with nothing for the person to see. It now waits with a status row, and a holder quiet for a minute hands it to the waiter; the holder's next call is refused once, so nothing lands on a page it did not open. - A bot on a team's shared computer claimed it while the turn was set up, so a second thread never started even if neither touched the screen. It is now taken at the first screen call. A missing machine stops only the turn that reaches for it. - A bot pinned to a Local VM that is already up did the same; it now takes it at the first screen call too. - On a Linux Cloud the memory gate charged each thread of one bot for the one browser they share, holding a second thread back longer on a 2 GB machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Evals: a bot pinned to the Local VM takes it at its first screen call Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the parked-turn check counts what starts after the computer frees Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the parked-turn check sends its next message once the engine has gone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tests: the browser-free row may land just after the call that took the browser Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A bot runs as many threads as the machine holds, and a Starter Cloud one per bot No fixed cap of three: a Cloud runs up to 16 and its memory gate decides; a machine without the gate runs one per 2 GB of memory, 3 to 16; a saved number still wins. The first event-log setting no longer saves a thread limit nobody chose. A Starter Cloud runs one thread per bot for what a person or a routine starts, whatever number is saved. The Admin says which plan with its signed POST /api/cloud/plan, kept by host/cloud-plan-tier.ts; an Admin that never said means no limit. Work a bot's own turn started goes through, so a turn can never wait on a child queued behind itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 | |
feat(saved-steps): a bot repeats a computer task it has done before, with no AI (#3762) * docs: saved steps design (repeat computer tasks without AI) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: saved steps implementation plan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): request key and word rules Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): the host computer bridge journals each call before the engine sees it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): hold-reply test, guarded reply chain, no partial wire records Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): keep the host computer's journal per request and count its gated calls Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): saveability rules turn a request's journal into a recipe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): refuse journals whose targets or typed text cannot be replayed safely Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): per-bot recipe store with caps and expiry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): re-apply the arg allowlist on read and refuse unsafe bot ids Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): resolve a saved step's target on the live screen Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): refuse cut or degraded trees, window targets without an app, and element steps without their targets Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): match windows by exact title, require complete trees and a target app for every step Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): run saved steps through the gated computer with an approval per action Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): drop stored key and element steps scoped wider than their window Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): replay a saved request in place of the engine, falling back with a note Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): replay only a turn that is exactly the person's one line, refuse an untaintable request, end a broken replay's turn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): replay only where the person picked this computer; a control-gate refusal keeps the recipe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a replayed step waits 60 s, past the control gate's longest hold Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): save a request's steps when it settles and mark the reply Every request end frees its journal: a settled request on requestSettled, any other when the next request takes the thread. A denial, a replay or a turn that sends more than the person's one line keeps the request from saving. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a request whose thread the journal evicted mid-request never saves The journal remembers which generations each evicted thread lost (up to 1024 threads) and takes them as tainted and incomplete, so the calls that follow an eviction can never pass for a whole request. Taking the thread forgets the eviction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): save only a person's computer run that used read-only tools beside it An answered question taints the request like a denial; any tool call other than the computer's or a read-only one (Read, Glob, Grep, LS, ToolSearch, TodoWrite, WebSearch, WebFetch) keeps the request from saving; a request with no person origin counts as automated; queued lines the dispatch cannot mark are held back from saving. The journal evicts the least recently used thread and keeps at most 64 lost generations per evicted thread, past which every generation it is asked about counts as lost. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a select_computer hand-off and an engine's bare computer tool names still save select_computer joins the tools that leave a request saveable, and an activity line named after a driver tool the rules know (an action or observation tool) counts as a computer call, as Codex titles them without the server prefix. Any other bare name still keeps the request from saving. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): pi and chat engines' computer_ tool names save; another computer in the request stops it saving A tool line named computer_<tool> counts as a computer call when the rest is a driver tool the rules know (one prefix, exact name), and Codex's bare select_computer and web_search leave a request saveable. A gate check from a computer that is not this one (Local VM, Cloud Boat, team computer) taints that turn, so a hand-off between computers never saves this computer's steps alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): forget a bot's saved steps over HTTP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(saved-steps): reply chips with Forget, and the Settings switch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(saved-steps): a fake cua-driver with tokens that go stale per snapshot Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(saved-steps): verification recipe, the policy note and the spec's rulings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): typed words repeat only for the exact request; signs, symbols and time words count The key keeps symbols, a leading or inner hyphen and a stop inside a number, so "-5" and "5", or "C++" and "C", are different requests. A recipe that types the person's words or opens their links stores its request word for word and replays only for that exact request (Unicode forms and spacing evened out, case kept); the store drops such a recipe whose request does not hold them. latest, last, first, next, today, unread and the like are moment words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): never save typing that may append or a click that flips a toggle cua-driver 0.28.2's contract does not say whether type_text replaces a field's value, so a step that types refuses saving; set_value, which replaces it, still saves. A click, double click or key press on a check box, switch, toggle, radio button or disclosure triangle flips it from whatever state it is in, so it refuses saving too, and the store drops either from a file. The fixture's driver answers set_value, and its fail file now fails only a set_value on a live element. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a replay says what its steps did, not the AI's old reply A replay answered with the first sentence of the AI's reply from the run it learned from, so "You have 12 unread emails" came back unchanged every time. It now answers with a sentence built from the recipe's steps and their stored targets ("Done — repeated 2 saved steps: opened Mail, clicked “Inbox”."), listing at most five steps. Recipes no longer store the reply; a stored one is ignored on read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a replay runs only the computer tools the bot may use Every engine enforces the bot's tool selection per computer tool, but a replay drove the gated computer directly, so a tool the person turned off in Access could still run from a saved recipe. A replay now needs every step's tool and the three lookups it resolves targets with to be selected; otherwise the AI answers and the recipe is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): key presses save only with the window they went to A press_key or hotkey sent to an app with no window lands in whichever of its windows is in front, so "close the Invoice window" could replay as cmd+W on another document. Key steps now save only with a window_id; replay finds that window by its exact title like element steps, and the store drops a key step without one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): wait up to 3 s for a target an earlier step brings up A replay looked each target up once, at machine speed, so a window that launch_app opens or a sheet a click brings up was often not there yet, the step failed and the recipe was deleted. When no app, window or element matches, the replay now looks again every 250 ms for up to 3 s. A target that matches twice, a cut or unreadable tree and a failed lookup never wait. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): save and replay on macOS only, from trees the driver read whole Replay needs list_windows and a tree that says elements_complete; Linux's cua-driver 0.19.3 and the Windows build were never shown to give either, so a recipe saved there would fail every replay after its first steps ran. Saving and replay now run only on darwin (tests inject the platform). The bridge keeps elements_complete in the slimmed tree, only when the driver read the whole tree and every element survived slimming, and an element step saves only from such a snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): journal only the person's own requests, within a byte budget Every host mount journalled, so room and routine turns, and every turn while the setting was off, posted each computer call and kept its tree in memory for requests that could never save. The mount now sets OMB_COMPUTER_JOURNAL only for a direct request from the person while saved steps are on, and the journal route drops posts while the setting is off. The journal holds at most 256 KB an entry and 32 MB in all; an entry past either budget is not kept and leaves its request incomplete, so it never saves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): the engine's session learns a replayed turn from the conversation, once The replay's events carried the engine's instance and the bound turn id, so the handoff record counted the replayed line and its reply as received by a session that never saw them, and the next AI turn did not learn the task was just repeated. A replay now withholds its turn's handoff (handed back, bound to the replay's turn, if the AI takes over), and when it answers without the AI it sets the conversation's externally-updated marker, which a strict-resume engine with a usable record skips because its record already leaves the turn unseen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): honest learned chip, quoted screen text, gated computer only, limit hold kept - The "Saved these steps · next time no AI" chip shows only when the turn that learned met every replay condition (setting, Full access, a place the person picked, the steps' tools selected); otherwise the steps still save without the promise. - The fallback note quotes the failed step's target and the computer's error as JSON, marked as screen text and not instructions. - openComputerCaller refuses a computer spec without the control gate's address and turn token. - A replay's own events no longer end an engine's usage-limit hold; only a turn that ran on the engine does. The run stays known until its end is published. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): the journal post lets go of its answer; pin the forget route to admins The bridge's journal post now cancels the response body it never reads. A test pins that DELETE /api/bots/:botId/saved-steps/:recipeId needs the admin scope, so a client can never forget a bot's steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): the gated mount always says whether it journals A driver record whose environment already held OMB_COMPUTER_JOURNAL=1 would still journal through a mount that did not ask for it, since the gated environment spreads the driver's. The mount now always sets the switch, to "1" or "0". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(saved-steps): the final review's rulings in the spec, a re-run fixture, 60 s in the plan The spec gets a paragraph for each ruling (reply from the steps, exact request for typed words, key symbols, moment words, tool selection, no type_text or toggle clicks, key steps with their window, the 3 s wait, macOS only, the handoff and context marker, journalling and its budget, the honest chip, the quoted note) and a Decisions entry. The verification recipe uses set_value, replays with the exact words, shows the new reply and note, says outright that no real app has been driven, and records this run in place of the unbacked load claim. The plan's step timeout reads 60 000 ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a saved recipe always reads back, and stale keys are dropped Typed words and links were checked against the raw request at save time, while the stored request and every later check use its evened-out form, so a recipe could save, show its chip and then vanish on read (a doubled inner space, full-width letters). The save-time check now uses the stored form. The store also drops a recipe whose key is not its request's key under today's normalising, so one keyed before symbols counted ("open the C++ tab" keyed "open the c tab") no longer replays for the C tab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): a replay ends its turn even when the conversation cannot be marked Marking the conversation for the engine to read again runs before the replay's reply and turn.completed; when it threw (bots.json not writable) neither was published and the turn stayed open. The mark is now caught and logged, still before the terminal events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): journal only requests that began with the person's own line A turn a peer handed on keeps the person's work origin, so journals() recorded its computer calls although such a request can never save. The request owner now notes when the request began with the person's own line (a continuation, such as a select_computer hand-off, inherits it), and the mount journals only then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(saved-steps): toggles are known by role only; cite the shipped driver's type_text The spec and the verification recipe say that a checkmarked menu item or a toggle that reports itself as AXButton still saves its click. The spec's type_text paragraph and the code note cite the shipped cua-driver 0.28.2 binary: type_text inserts at the selection via AXSetAttribute(kAXSelectedText), and set_value replaces a value. The spec also says which requests journal after the peer-origin fix, and the recipe records the second fixture run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(saved-steps): the fixture passes after the origin/main merge Re-ran the eight rounds at f25286f8d: 34/34 checks, 40 driver calls, 5 engine prompts, and round 5's prompt carries the replayed turn once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): the switch shows only where saved steps can run Saved steps runs only on a Mac, yet its Settings switch showed on Windows and on Cloud homes, where it did nothing. The server now says whether it can run them (features.savedStepsHere) and the row hides otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(saved-steps): config features carry savedStepsHere, true on a Mac only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): never save a final action or a secret, and never type over someone's text - Steps that press a final, can't-undo action are never saved, so that request always goes to the AI: a click or key press on an element whose label, an ancestor's label or the window's title names one (send, delete, buy, pay, post, submit, place an order, transfer, publish and their like, in all 15 languages the app ships), a pop-up choice or a link that names one, Delete or Backspace, command- or control-Return, and Return into a window that shows a final action or was never read whole. - No step on a secret field is saved (a secure text field, or one labelled password, PIN, code or card number), and approvals, items and replies name keys pressed but never the text typed. - A launch's creates_new_application_instance is left out, so a repeat no longer opens a second copy that the next step finds twice. - Steps save only when the same words would repeat them (Full access, a place the person picked, the steps' tools selected), so nothing waits unseen with no Forget. - A repeat types only into an empty field or one already holding that text; otherwise it stops and the AI takes over. Typing saves only where the driver reported what the field held. - The switch leaves Simple General (Advanced keeps it, and features.savedSteps in config.json stays the off switch); Forget shows only to the owner and admins, who alone may call it. - The store's 0600 check is skipped on Windows, which has no such mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(saved-steps): check the screen words cover every shipped language beside the locale tests The coverage check reads the shipped languages, so it lives with the locale tests that CI runs whenever a catalog changes. The word module itself names no catalog, so the tests that import it are not locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(saved-steps): Korean screen words, and plain words in the replies and errors - Korean, now a shipped language, gets its final-action words (send, delete, buy, pay, post, submit, order, transfer, publish and their like) and its secret-field labels; "확인" (OK) stays out. - A replayed reply reads "Done. I repeated 2 saved steps: …" with no em dash, and a declined step says "I stopped the saved steps because a step on “Document” in TextEdit was declined. Nothing after it ran." without a tool name. - The switch's and Forget's errors say what to do next: "Couldn't change this setting. Try again." and "Couldn't forget these steps. Try again." Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 6 天前 | |
A new bot's setup answers follow its name (#3743) * A new bot's setup answers follow its name Renaming a bot while its setup card is unanswered now writes the card's answers again for the new name, so a fresh bot renamed to "Recruiter" offers recruiting jobs. New bot gives a random name, which the writer rightly ignores, so a fresh bot's card never followed what it was called. - Any rename counts, whichever path made it (bot panel, settings, header, a bot renaming itself): the server watches the store's bot changes. A new title or department counts too, since the prompt reads them first. - Same writer, prompt, deadline and checks as at creation: the bot's own engine on its quick model through sideJobs.text("setup-suggestions"). - A picked or blank name goes back to the card a nameless bot gets: the fixed answers at once when nothing else is known about it. - Renames within 600 ms are written for once, and a newer rename aborts a writing still on its way, so the latest name wins. - Never after an answer: a pick, Something else, a message, closing the card or instructions stop it, and a line written mid-rewrite aborts it. - While it is rewritten the greeting carries setupChoicesUpdating (epoch ms). The card keeps its answers on screen, dimmed, and takes no letter or click; the new answers come in the change that clears the stamp and swap in at once. A failed, late or unusable writing keeps the answers. A client stops waiting 8 s after it first sees a stamp, or on one older than 20 s; older clients ignore the field and keep their list. - The setup card's wire fields move from shared/wire.ts to shared/setup-card.ts, which keeps wire.ts under 1,000 lines. - The fake Claude CLI can hold the setup reply back (FAKE_CLAUDE_SETUP_DELAY_MS), so a recipe can see the card while it waits. Evidence: docs/verification/evidence/name-suggestions/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Drop two helpers the rename tests never used Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
Setup import: one bad entry or kind no longer sinks the step - A config.toml header or dotted key of 60,000 parts parsed into a table too deep for JSON.stringify, which threw outside toolEntries' guard: GET answered 500 and the step vanished for every source, and a POST failed after the skills were in. Keys now stop at 16 parts (a TomlError, so only that file is skipped), and each entry's conversion drops only itself. - Skills and tools come in each on their own: a kind that throws (its folder unusable, config.json unwritable) reports its names as "failed" and the other kind still comes in, instead of a 500 that says nothing came in after something did. - Nothing added but something left out reads "Nothing new was added.", without the success mark, instead of "All of it was already here." The failed note names skills and tools and points at Settings -> Replay welcome tour, which can bring them in again. - A different server under a taken name is reported as a conflict, not counted as already here. A name OpenMausBot keeps for itself (browser, data, phone...) comes in as mcp-<name>. A trailing comma in a JSON config is accepted. ~/.claude.json may be up to 256 MB, since only one member is parsed. - With "Also use my Claude Code MCP servers" on, Claude Code's own servers are not offered: Claude bots already run them in place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 天前 | |
Train: team-trial fixes, warm summaries, team bot access, own-server places, server lines (merge with Create a merge commit) (#3999) * Team bots: a level per person (view, chat, edit), shared from each bot A team bot is now shared like a document: what everyone in the team gets (Only people added, or Everyone at Can view, Can chat or Can edit) and a level for each person added. Admins and the bot's owner always edit. - The bot's Share button (bot panel in Simple, settings header in Advanced) opens a Share dialog on a team: people with access with their level, adding teammates by name or email, general access; every change applies at once with an Undo toast. - The server enforces it on every member request after the visibility gate: reads need Can view, writes Can chat (a room needs it on every bot), sharing and a bot's own setup Can edit; a routine needs Can edit unless its writer changes it; a card that changes the bot needs Can edit; a message another app relays needs the named person to chat. - Each copy of a bot carries the viewer's own level; the sharing only on an editor's. The live stream follows a change. - Bots set up before levels keep exactly what their visibility gave (everyone: Everyone, Can chat; admins only: Only people added; a list: those people, Can chat), read from it with nothing rewritten. - A person who can only view sees that in place of the composer, opens the bot's main chat, and is offered no new conversation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Team bot access: before and after pictures Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Share dialog test: a whole bot Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(context): the unseen-messages block ends before the person's message When a resumed session has missed messages, the turn's prompt lists them in a block and then gives the person's new message after one blank line, with nothing saying the block is over. In a Team trial the person's next request, written right after a co-founder's relayed reply, was credited to the co-founder. The block now ends with "[End of those messages. Now reply to the user's latest message:]" before the turn's own text, as the full replay already ends its history with "[Now reply to the user's latest message:]". The wording differs from the replay's, so nothing that looks for the replay's end mistakes this block for replayed history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * The owner is never told to ask an admin: connection lines know the person's role On a Team Cloud, a member's own bridge that asked for a team app's connection card got "ask an admin to connect it", whatever the person's role. The owner was told to ask an admin, and a bot named a teammate who wasn't one as the admin. - For the Owner or an Admin, the bot asks for the card through the team's composio bridge, whose card lets them connect the app for the whole team in one tap. - A User is told who can connect it, by name: the team's Owner and Admins from the roster the Admin paired here. - "Connect your <app> here" links go where each person's own connections are: the team's Apps page for the Owner and Admins, a User's team home otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(research): offer the research tools only where research works A Cloud home always holds the plan's X relay token, so every bot was offered research_search, research_endpoint and research_call. On a plan whose relay has research off, each call then answered only "Research isn't available right now." - The home asks the relay once, at start, with a search that names no job: the relay answers that with a 400 only once the token, the plan and research are all fine, before it reads its catalog or spends anything. An off answer (402, 404, 401, or 503 service_unavailable) hides the three research tools; x_search stays, since X works without research. It asks again an hour after an off answer, and a research call the relay refuses as off hides them at once. - The person's own treg key goes straight to treg: research is on. - A refusal because research is off now says what to do: tell the person and offer another way (web search or the browser); their own treg key turns research on. - The agents server gets a switch of its own for the research tools (OMB_RESEARCH) beside the X one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): a person's message never waits behind a long tool call A message the person sends their bot while it works is steered into the running turn, and an engine reads it only once the tool call it is in returns. A bot polling CI with `sleep 30` loops kept a person's message unread for 26 minutes and never said the PR it had made existed. - Mechanism: when the person's own one-to-one message waits unread while a tool call has run for a minute (at once if the call had already run that long), the server stops the turn, with a row saying so, and the message runs next, ahead of anything else queued in that chat. Its row is run as is (the follow-up queue can now take a row already in the transcript), and the model is told which step was stopped. Messages from rooms, routines, teammates and apps never do this, nor does one sent while the turn waits on the person or a computer. The wait is OMB_PERSON_FIRST_MS for tests. - Prompt: never wait inside a command for CI, a deploy or another job; check once, say what you made (with links), set wait_until or a one-time trigger to check back, and end the turn; answer the person first. Stopping and re-running works for every engine, and so does every engine's Stop. No engine reads a steered message during a tool call, some cannot steer at all, and Claude's own "send now" depends on moving the tool to the background, which bots run without. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(chat): the person's re-run keeps its place and goes ahead of a teammate's The re-run of a steered message that a long tool call kept unread is now queued by the time the person sent it, ahead of everything but their own earlier messages, and a message of theirs that has to wait in the queue goes ahead of a teammate's or a routine's too. Before, the re-run took the time it was queued again, so on a slow runner it no longer joined the person's next message as one turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(connectors): app tool calls fit their schema, and a refusal says how to call again Composio checks a call's arguments against the tool's schema and refuses the whole call over one. In a Team trial five calls failed that way: COMPOSIO_SEARCH_TOOLS sent { job } (Required at "queries"), COMPOSIO_REMOTE_WORKBENCH sent code for code_to_execute and a timeout as text, and COMPOSIO_MULTI_EXECUTE_TOOL sent its tools list as text. After the search failed, the bot told the person it had no image tool, though an image app was connected. - The connector bridge keeps each listed tool's schema and fits a call to it where the bot plainly meant that shape: arguments or a list written as text, a number or yes/no written as text, a bare string or strings where a list of one-field objects goes, and one missing required field under another name when exactly one sent field can be it. The bot is told how its arguments were read, so it sends that shape next time. Anything not plainly meant still reaches the tool. - A call still refused over its arguments now says how to call again, with a minimal example from the schema (or to read the schema with COMPOSIO_GET_TOOL_SCHEMAS for an app tool), that this says nothing about which apps or tools exist, and which connected apps this bot can use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give main's bot-patch route tests the access level the route now asks for Two tests that came with main (vpsAlias relocation guard, phoneApps) built the route without `levelOf`, so they threw "deps.levelOf is not a function". They now answer "chat", a member's level that still may not move a bot or change what it may do; both refusals hold as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(claude): a bot's hooks fire from inside the bot box The hook helper Claude Code runs for each hook reads the turn's bearer from a file in the data folder, which the bot box replaces with an empty folder. On every Cloud home the helper found no token and quietly did nothing: no hint for a timed-out command, no work summaries, no context at session start. - The token lives in a folder of its own per conversation (hook-tokens/<digest>/token), and the box puts that folder back read-only: only that conversation's token, never the data folder or another conversation's token. The folder, not the file, so the box sees each turn's new token after it is renamed over the old one. Tests: a Claude turn under a stand-in box that hides the token unless a mount line puts it back fires its PostToolUse and Stop hooks with the turn's bearer, and the box shows only that conversation's token folder, read-only. It fails with the bind removed (no hook fires), with the file bound instead of its folder, and with the old shared folder (another conversation's token shows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MCP Settings Test reaches a server the way bots do, through the credential broker Where bots' turns are boxed, a turn's engine reaches a URL MCP server through the credential broker, which adds the server's headers and forwards. The Settings Test connected directly, so a server behind Cloudflare Access tested "Connected" while every bot failed (the broker added a slash to the server's address). - The Test now makes a grant the way a turn gets one, connects through the broker's socket, and revokes the grant when it ends. Where turns aren't boxed, bots and the Test both still go direct. - If the server fails through the broker but answers directly, the Test says "Your bots can't reach this server" with the reason and that the fault is on our side, never "Connected". - A server the broker can't reach reads as unreachable, as a direct test does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A new MCP server saved switched off says so, its switch can't flip it straight back, and a server that failed at engine start reconnects - A new or edited server whose first test fails reads "Saved, but off: the test failed", with the reason and that bots can use it once it's on. While that test runs, the row says it's off until it passes. - A passing test after a save switches the server on by itself. A click on its switch in the next moment was aimed at the Off the person saw, so it keeps the server on ("it passed its test a moment ago") instead of switching it straight back off, which looked like a one-second on/off. - Where bots reach URL servers through the credential broker, a server the engine reported as failed when it started gets the conversation a new grant on its next turn, so the engine starts again and reconnects. The chat says the server didn't connect and that it connects again on the next message, so bots no longer need to ask for a new chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Renderer smoke: a saved server whose first test fails reads "Saved, but off" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep the reconnect import on its own line, apart from other open changes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A connected app comes before any browser or screen, and a refused one is reported with its fix Bots were told to do web work on the person's own computer in this order: the built-in browser, a cloud computer, then a connected app. A connected app does a task more cheaply and surely than any screen, and one that is refused or broken is the person's to fix. - The order now starts with a connected app that does the task. - Wherever a browser or a screen is mounted (a Cloud home too), bots are told to use a connected app first, and when it is refused or fails, to say so in one plain line with what fixes it and ask before doing the task on a screen instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bug reports: the reporter sees their @devs report's status, and is told once when the fix runs here - The person's @devs message shows its report's status in the app's language: "Bug report sent · Got it, we're looking", then "Fixed in 0.1.x, coming in your next update", then "Fixed in 0.1.x" (bugReport on the message; all 17 language packs). - The server follows each report it sent (devs-reports.json) and asks the MausBot team about the open ones a minute after each start and hourly: POST /api/bug-reports/status at the address reports go to, the same way on the desktop and on a Cloud, which signs its question with its bootstrap secret. Nothing ever has to reach this server, or wake a sleeping Cloud. - Once it runs the fix's release (versionAtLeast: never on a guess) and the answer allows it (never a former customer's Cloud, never a teammate who left), one line in the chat they reported in, "Fixed in 0.1.x. Want to try again?", one notification (on a Team Cloud only to the reporter), and a one-time note on the bot's next turn there. Once per report, across restarts. - OMB_DEVS_STATUS_MS sets the interval for fixtures (control-omb passes it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it never interrupts the person, and questions never go stale At Full access ("Just do it") a question from work a bot handed on goes to the bot that handed it on, which answers it from what it knows; with no answer the asker goes on with the default it named and says so in one line. Its card says who picked what and blocks nothing. Only a sign-in, a payment, a secret or the person's own account reaches the person, once, while the rest of the work moves on. An ask tool in handed-on or unwatched work is answered the same way, and the prompts say to find things out the cheapest way first and ask the person last. On "Ask me first" a question waits for the person however long they take. An answer counts from the card, the inbox, the asking bot's own chat, or passed on by another bot (coordinate_bots answers). A question whose work ended, or that a newer one replaced, closes; a sign-in wait in handed-on work settles from the person's line, an answer passed on, or the bot going on with the site; a restart posts nothing again. Rooms and a bot's own chat get the same tap cards, and prompts name Claude's question tool as mcp__ogb__ask_user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it decides only in work the person or their routine started A question in work a webhook or another outside event started still goes to the person at Full access, as an ask tool there does: its brief is not the person's authority, and the question is their check on it. The Just do it line stays out of those turns' prompts too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep steering and late answers in the person's own chat as they were A line the person types in their own chat while a question card waits is still steered into the turn or queued, as an engine that can steer expects; only in work a teammate handed on does it answer the card. A question its turn left open keeps waiting for a late answer after other lines. Two peer-question notification tests now run on "Ask me first", where a teammate's question is still the person's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Warm summaries: a long conversation is summarized while it sits idle, so the next answer starts fast On a Team trial every first answer slower than 35 s (35 to 58 s) was Claude Code compacting a conversation of about 162k tokens at the start of the person's turn, warm cache or not: writing the summary is what takes the time. Both kinds of compaction ran only when the next turn started, on the person's time. - After a turn that leaves a direct conversation at 100k tokens or more, its summary is written about 3 minutes later, while the prompt cache is still warm; from 80% of Claude Code's own compaction point (160k of 200k) it starts after about 10 s, because the next turn would summarize anyway. - Claude Code: its own /compact, with instructions to keep the person's latest requests and every open question, on a persisted fork of the session (--resume S --fork-session) launched with the live process's exact contract, as the keep-warm ping is, so it reads the cached prompt start and keeps the conversation's tool list. The conversation moves to the fork only when no turn began meanwhile; its last two exchanges count as not yet seen, so the next turn carries them word for word on the existing, saved "not seen yet" path. The chat shows one line for it. - Other engines: OpenMausBot's own fold runs while idle once the conversation is close to its threshold, instead of at the next turn. - Skipped while work is due (a queued message, a teammate working on this conversation's request, a fired wait, the spend limit); retried while the bot is busy, memory is short or a routine of the bot is due, until the cache would be cold. A turn that starts meanwhile wins, unless it would summarize at its start anyway: then it waits for the summary already being written instead of a second. - The app's presence ping names the open chat: opening a conversation starts an overdue summary at once and keeps its engine process alive while the person is there. - Off with context.autoCompact: false, or OMB_WARM_SUMMARY=0 for this alone. The fake Claude Code gains a growing context, its own compaction at a threshold with a duration, and /compact on a fork. On a long fake conversation whose CLI compaction takes 6 s, the next reply took 6.2 s before and 0.3 s after; one sent while the needed summary was being written took 5.4 s (the rest of it, not a second one); one sent during a summary it did not need, under 0.5 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * People before bots: a shared @name reaches the person, a bot named like a person is warned, deleting a Chief offers Archive On a Team trial a person's "@<teammate>" reached a bot that had the teammate's name, because a tie went to the bot. Then the person deleted their Chief to fix it, and lost its whole setup chat. - A tag a person and a bot share is the person's: "@Bob" reaches the teammate Bob (or means the writer, for their own name), and only a longer bot name ("@Bob Bot") reaches a bot. The teammate's inbox gets it, the turn no longer tells the bot it was named, and the composer highlights it as the person (shared/person-mention.ts, src/lib/mentions.ts). - A bot made or renamed with a person's name (a teammate's, or the owner's own) says so once in its own chat, and the Chief's create_bot result carries the same warning (server/host/bot-name-clash.ts). Nothing is refused. - Deleting a Chief of Staff offers "Archive instead" first: its chats hold the team's setup. Archiving drops the Chief role, so the server accepts it, and the bot can be restored any time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots in two places: one plain suggestion to bring them together When this computer has bots of its own while a server of the person's own (or My Cloud they keep this computer's bots away from) has bots too, the bots in the two places can't work together. This computer's page now says so once, in a corner card: "Your bots live in two places, so they can't work together. Bring them together on <place>?" One tap starts the one-time move there (Make <server> my home, or letting this computer's bots move to My Cloud), and Not now is remembered for that place. Main reads each place's own move summary, so only bots a move would carry count and a place's untouched first bot never makes two places. A server is asked only while it says it is the person's alone, a sleeping Cloud never, a team's Cloud or a server others sign in to never. Nothing shows while a move is under way, during the welcome or the tour, or on any page but this computer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bots say where another bot lives, and how to bring them together A bot that asked for a teammate living in the person's other place (their computer, their own server or My Cloud) only heard that no such bot exists. The person's app now tells each of their own places the names of the bots their other places have, and nothing more (PUT /api/places/elsewhere, from that place's owner only, never a team's place or one others sign in to). With that: - coordinate_bots and bot_idle waits say "Scout lives on Work laptop, the person's computer, not here", that bots work together only within one place, and offer the one tap that brings them together ("Make Garage server my home", or Bring them together for My Cloud); a name nowhere stays no such bot; - a person's @mention of such a bot tells the answering bot where it lives, and in a room one plain line says so to the person; - before the app said anything, a name nowhere here also says that bots work together only within one place, and how to bring them together. Main tells each place only when what it would be told changed, never while a move is under way, and stops telling this computer once its bots moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Server lines in the person's language: the way in, a guard, and bug report lines Lines the server writes for a person (a bot's line, a status row, a card, a notification) now come from the language packs under "server." keys, in the language the person's app shows. - server/server-lines.ts: serverLine(language, key, params) reads the packs; a missing key reads in English, as the app's screens do. The server bundle keeps only the server keys (scripts/server-locale-plugin.mjs), and tsc's copies of the packs are dropped from dist-server. - server/host/person-languages.ts: the app keeps a person's language pick on their own computer, so the server learns it from presence pings (the owner's, or each member's on a Team Cloud). A line for a person reads in theirs, else in the place's: the one set on the server or by the team's Admin, else the one most people's apps show. - Bug report lines (@devs) read in the reporter's language; the marker that tells whether the bot already passed a failure on is "MausBot", which every language keeps. - src/locales/server-lines.test.ts: a guard that fails on an English line written straight into a line a person reads. It follows each place a line is made through consts, helpers and imports; ALLOWED says why text is English on purpose; PENDING lists the 242 lines written before it, by area, and only shrinks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Only the tests of other languages' lines read the packs; CI selection knows it CI's import-graph checks failed: the server now loads the language packs, and every server test reaching server-lines.ts counted as reading a translation. - server/server-lines.ts reads English only. server/server-line-packs.ts adds the other languages; server/index.ts loads it at start, and so do the tests that check a line in another language. The guard checks index.ts loads it. - scripts/ci-scope.mjs: those tests run with the locale tests. The packs stay out of SRC_OUTSIDE_RENDERER: a change to English already runs every Linux test, and one to another language runs every test that reads it, so a translation change does not run the server's checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Runs and routines tell the person in their language A routine's line in a chat and the incident a person hears about now read in the language of the person whose conversation it is, through server/server-lines.ts. - "This run didn't finish: …" and "Recovered: … finished OK at …" (with the time in that language's clock), written into the chat a routine reports to. - The text of a routine run's card, for clients that show no cards. - The incident status row and its notification. The Chief's own incident report stays English: only a model reads it. - server/index.ts: threadLanguage(threadId), the language of a conversation's person, else the place's; no line added. - The guard's PENDING drops these 17 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Connect prompts and sign-ins ask in the person's language When a bot needs the person to connect an app, sign in or give a key, what the server writes now reads in the language of the person whose conversation it is. - "I need you to connect …", "I need you to sign in to …" and "I need your …", which a routine writes into its chat while it waits on a card. - The connect card's text and, where the app catalog has no words of its own, its description. - The line under a sign-in card. It moves from shared/ to server/connector-card-text.ts, since shared code cannot read the packs; nothing else used it. - The credential card's text and the sentence on how the bot gets the key. - The guard's PENDING drops this area's 13 lines. The German tests run with the locale tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Notifications are titled in the person's language Every notification's title ("… has a question", "…'s routine failed", "… needs you to sign in to …") now reads in the language of the conversation's person: buildNotification asks a resolver the server sets at start (setNotificationLanguage(threadLanguage)), so no caller changes. Also the inbox's "· your assistant answered" and two bodies the server writes itself ("Results in from …", "Open OpenMausBot to sign in to …"). The guard's PENDING drops the area's 8 lines, and checks the server sets the resolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * A room's status rows read in its person's language What a group chat shows about its members now reads in the language of its conversation's person: waiting for a busy member and the skips, a mention that missed, archived members, still stopping, held members, no summary, a stalled turn, context compaction, and a bot's receipt in its own chat ("Posted in …", "Opened thread #…"). What a coordinating bot reads stays English. - server/server-lines.ts: isServerLine(key, text) reads a line back in any language; isHeldMemberLine uses it, and the held row keeps "resume", the word the room understands. - The sentinel counts a German stopped room turn as a timeout, and now also skips a held member's row in the shape it reads rows in (a harness notice with names taken out). The openmausbot CLI, which runs it, loads the other languages. - The guard's PENDING drops 20 room lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(team connections): an owner's own-connection lines are checked in her private chat and in a shared one An own bridge only works in the person's private chat now, so the "connect your apps again" check runs there; the connect lines are checked in both places, including an app call through the team's tools. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates' hand-offs and results read in the person's language What a conversation shows about a teammate's work now reads in the language of that conversation's person: a hand-off going out ("Sent to …"), its result coming back ("… replied", "… — failed:", "Result withheld:"), resuming with results or a question, what came of a teammate's question or approval, what waits behind the person, recalled private chats, a closed thread, a room goal's card, "Answer passed to the waiting work", and the inbox's and team messages' rows. - server/server-lines.ts: one resolver, conversationLanguage(threadId), which the server sets at start; notifications use it too (it replaces setNotificationLanguage), so modules with no person at hand need no new wiring. - What a coordinating bot reads stays English. - The guard's PENDING drops 19 lines; the area keeps feature-flagged escalations, approval level names, the peer approval card and a goal's text after a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Just do it: a question in a person's private chat stays theirs Work a person's request hands on runs in the receiving bot's chat with them when it may use their own apps, and what it hands back keeps a question's words in that chat. Its requester never sees them, so it cannot decide them, and a sign-in among them could not be told apart. Such a question now reaches the person there, as on "Ask me first": the turn result says the question stayed private, and the ask tool is not turned away in that chat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(acting person): read the private question flag with toMatchObject The hand-back keeps its input's type, which has no privateQuestion field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(analytics): the two-places card's event Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): the engine registry answers null for a missing engine registry.get returns ProviderInstance | null; the host's dependency took only undefined, which failed typecheck once the branch was checked against main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(warm summary): its line in the chat comes from the language packs The line a warm summary leaves in the conversation is now server.warmSummary.summarized, in every pack, written in the language of the conversation's person, as the guard from #3931 asks of every line a person reads. It names no count, so it needs no plural forms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Main's guard passes: the same-request notice in the person's language Main went red on the server-lines guard: #3957's "Another teammate asked the same a moment ago…" row landed while #3931's guard was in review, and #3948 reworded a line the guard lists. - The notice reads in the language of the conversation's person (server.teammates.sameRequest, German by hand, every pack). - PENDING follows #3948's rewording of the webhook line. - The guard's check that index.ts loads the other languages matches that import anywhere on its line (as #3960 has it), so another import may follow it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Teammates: the recall row reads in its room's language after main's discloseRecall Main moved this row into discloseRecall(bot, roomThreadId, …), where threadId is not in scope, so the merged branch failed typecheck. The row is the room's: it now asks for roomThreadId's language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(bots explain): the one-place hint comes before the reach help, so a refusal still ends with it server/room-coordination.e2e.test.ts pins that a refusal for a name nobody has ends with the reach help (and its "Never use computer control to get around this"). The hint now sits just before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the cards a parked turn waits on move to server/host/resumable-cards.ts resumableCards is a pure read of the conversation; moving it out keeps server/index.ts under its file-size ratchet once #3930 lands with main (the fix #3930's branch made when it merged main, ported here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the MCP reconnect, bot name clash and bug-fixed lines come from the language packs #3922, #3934 and #3937 were written before main's server-lines guard, which fails on their three English lines once they meet it. Each line is now a "server." key (English and German) written with serverLine in the language of the conversation or reporter: server.mcp.reconnect.one/many (server names listed the reader's way), server.bots.nameClash (create_bot's result stays English for the model) and server.reports.fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * train: the bot archive/delete dialog's props move beside botConfirmCopy #3934's Archive-instead offer grew src/components/Sidebar.tsx past the size the 0.1.135 release set (1790 against 1785). botConfirmProps in ArchivedBotsPanel.tsx now builds the dialog (copy, icon, Archive instead for a Chief, confirm); the sidebar keeps the ConfirmDialog and its callbacks, and is 1774 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 5 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Skills at the start of text run only from the person's own line or the owner's routine A webhook, relay, app or another bot's message that starts with /name stays plain text. Also: the Gemini key is masked in diagnostics too, and the Windows path check in the native skills test matches either separator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 | |
fix(skills): the / menu lists the skills the engine loads from its own folders | 12 天前 | |
Merge #2731: feat(skills): share learned skills with the team through the skills library # Conflicts: # scripts/testing/file-size-ratchet.test.ts # server/drivers/agents-catalog-goldens/profiles.json # server/drivers/agents-proxy.test.ts # server/index.ts # server/skills.ts # shared/skill-request.ts | 21 天前 | |
fix(acp): sanitize leaked internal system messages from assistant output | 25 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
A routine outside work wrote stays outside, with what its runs write, its Undo and a backup A routine made or changed from a confined conversation is recorded as outside work's; a bot's change never makes one nobody's, and an Undo puts it back as it was. A conversation's mark survives a team backup and restore. A page in a confined conversation keeps its frame when it is updated too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 小时前 | |
refactor: rename Box to Boat across the repo (#1935) * refactor: rename Box to Boat across the repo Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * fix: restore framework identifiers swept by the Boat rename The rename rewrote Jetpack Compose framework symbols (BoxScope, BoxWithConstraints) and the standard CSS property box-decoration-break. Restore them; only product naming stays Boat. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> * fix: align e2e flags, fixture wire keys, and Boat branding The e2e harness now checks --with-boat (keeping --with-box as a compat alias), the preview fixture answers with the provider wire key box, and the remaining user-facing and docs prose says Boat. Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> --------- Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com> | 1 个月前 | |
feat(chief): a new workspace starts with its Chief of Staff, who adds specialists itself A fresh workspace's first bot is now the Chief of Staff. The seed is the one the server runs at boot, so desktop, headless and Cloud get the same start; existing workspaces are left as they are. Its profile stays empty, so an untouched starter still reads as unused when sending to the Cloud. The Chief's prompt says it is the person's assistant, does the work itself, and adds a specialist with create_bot without asking when a job needs one (an ongoing area, a different skill set, or work in parallel), then says so in one line. It is shorter than before. create_bot no longer waits on a card when the Chief picked the bot itself: every create_bot applies at once with an Undo, inside the per-turn and workspace caps. The suggestion path is deleted: TeamSetupRequestService.suggest, the request's suggestion flag, the "Add bot / Not now" card, its decision note, the schema field and the two Not now strings. A Cloud conversation its owner did not drive still waits for the owner, as every bot-requested change does. Tests: the seed is the Chief and leaves existing workspaces alone; the prompt says the new things; a create_bot with suggestion: true applies at once at Ask with an Undo and no card, and the fifth in a turn is refused. Tests that used a suggestion only to get a waiting card now use a credential card or a durable fixture approval; the ones that pinned the suggestion card are deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 | |
Every thread of a bot runs with the bot's Claude settings and follows it to its working folder (#4014) - A bot has one Claude Code settings file: .claude/settings.json in its working folder, else in its own folder. A turn in any other folder (a thread's own, a room's, one chosen for the thread) carries its hooks, plugins, permission rules and env in OpenMausBot's --settings file, merged the way Claude Code merges two sources. Fields Claude Code would refuse stay behind, since one of them makes it drop the whole file, OpenMausBot's own settings included. Never in a guest's turn, never through a link. - A thread still in its own folder moves to the bot's working folder on its next turn, as a new engine session with the conversation replayed. - create_bot takes instructions up to 4000 characters, and a longer one gets an error that says what to do. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 | |
Every thread of a bot runs with the bot's Claude settings and follows it to its working folder (#4014) - A bot has one Claude Code settings file: .claude/settings.json in its working folder, else in its own folder. A turn in any other folder (a thread's own, a room's, one chosen for the thread) carries its hooks, plugins, permission rules and env in OpenMausBot's --settings file, merged the way Claude Code merges two sources. Fields Claude Code would refuse stay behind, since one of them makes it drop the whole file, OpenMausBot's own settings included. Never in a guest's turn, never through a link. - A thread still in its own folder moves to the bot's working folder on its next turn, as a new engine session with the conversation replayed. - create_bot takes instructions up to 4000 characters, and a longer one gets an error that says what to do. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 | |
Suggest thread links only from successful turns and stricter request URLs Skip link suggestions when a turn fails, require a boundary after the request number, cap the normalized URL length, and offer Assign to thread while write permission loads, matching the composer. | 24 天前 | |
Suggest thread links only from successful turns and stricter request URLs Skip link suggestions when a turn fails, require a boundary after the request number, cap the normalized URL length, and offer Assign to thread while write permission loads, matching the composer. | 24 天前 | |
Threads follow their bot's model, a thread whose model can't run uses the bot's, and Switch them too (#2401) * Threads follow their bot's model; a thread whose model can't run uses the bot's; Switch them too A thread no longer copies its bot's model. It follows the bot (no model of its own) unless a person picks one in that thread; picking the bot's own model is following it. Creating a thread, team setup, propose_model, a default change from a thread, team import and the hosted reconcile stop copying, and no change of the bot's model pins its threads any more. A follower that moves to another engine under a level that engine would have to confirm goes back to Ask, as on every engine switch. One-time cleanup at load: a thread's model equal to its bot's was a copy and is cleared; a different model stays. A marker in the data directory keeps it to once. At a turn's start (startTurn, so direct messages, routines, delegations, webhooks and queued follow-ups alike), a thread's own model that can't run (engine gone, disabled, unavailable or refused, or the model gone from its catalog) gives way to the bot's model: the thread follows the bot from then on and one plain line says so. A signed-out engine gives way only when the bot's model is on another engine that can run; on the same engine the sign-in failure stays. The rule reuses readyToRun and the saved-choice catalog check (offersSelection); the registry keeps each engine's last read so the check never waits on a CLI. The wire keeps sending the effective model, plus followsBotModel. The bot's model setting shows "{n} threads use their own model." with Switch them too (POST /api/bots/:id/threads/follow-model, a route module). A thread's picker offers "Use {bot}'s model" and marks the bot's model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep a thread's model its catalog doesn't list; update tests that pinned copies A model missing from its engine's catalog is no longer a reason for a thread's own model to give way: model IDs are free-form at the API boundary and engines run IDs their catalog does not list (the context-compaction e2e picks claude-sonnet-4-6[1m]) or learn the catalog only when a turn starts. The saved-default check is back as it was. Tests that asserted the old copy-and-pin behaviour now assert that threads without a model of their own follow the bot (store, tasks, independent threads, team setup, bot continuity, Full/Custom provider switch), that a self-opened thread on a removed engine runs on the bot's model with one line, and the hosted fixture seeds a prior release's copies without the cleanup marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 29 天前 | |
Phone apps as bot tools: bots use your phone's Calendar, Reminders, Contacts, Location and Messages (#3457) * docs: design + plan for phone apps as bot tools, server plumbing (sub-project A) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): shared vocabulary for phone apps, grants and the device.job frame Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): registry of paired phones and what each allows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): job queue a phone long-polls, leases and answers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): byte-measured result cap, turn-ended complete throws 409, poll after close Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): tool catalog, instructions and the per-bot verdict Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): the phone's own routes: register, poll, lease, answer Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a phone's companion identity comes from the verified auth, not headers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): device as a fifth harness MCP kind with its own timeout Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): timeout message names the call's own limit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): every engine that mounts HighLevel mounts the device tools too Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(outbound): move the send hold out of index.ts so other tool kinds can use it The "Send on your behalf?" hold and the dispatch-time allowance check move from the connectors MCP handler into server/outbound-hold.ts as createOutboundHold(deps), with no change in behaviour: the same decision rows, card, activity flips, notification, timeout patch and refusal text. The handler keeps its parsing, scope checks, refuseOutbound, sendsFreely and both requireActiveInternalCapability calls. buildNotification no longer demands a threadId on the bot it never reads, so the hold can take the narrower bot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): keep store.tsx inside its line ratchet after the capability fields Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(outbound): the hold's bot type carries notifications, so a muted bot stays quiet buildNotification reads bot.notifications through the hold's approval notice; OutboundHoldBot now picks it, and the test shows a muted bot still gets the card but no notification. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): MCP host that turns a bot's call into a phone job behind the per-bot verdict and the send hold Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): default phone by last use and by the tool's app, reserve only after every check, hold every outbound phone tool Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): mount the device tools per turn, route the internal MCP, nudge the phone over SSE server/index.ts wires the phone registry, job queue, host and /api/phones routes on existing lines (still 16843): the owner's own direct turn mounts the device server when its bot is granted an app one of the owner's phones allows, /api/internal/device/mcp answers it, a queued job nudges admin SSE clients with device.job, the phone's job long poll is exempt from the maintenance request count, the grants picker lists the phone tools, and shutdown closes the queue. The host is built beside the send hold it takes, which is declared after the HighLevel host. Phone tool rows read as "Phone" in the activity, and the device server is one of the app's own servers for the Today outcomes. The e2e pairs a phone, round-trips a job through poll, lease and result, and shows a bot without a grant and a read-and-draft routine run get no phone (a run of the same routine at the bot's own level does). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): only the owner's admin sessions hold a phone or lend their turn to one; routine reports stay the owner's Off a Cloud home, a request owns the desktop's phones only as the owner on this machine (loopback, the companion included) or an admin session; a client-scope session gets 403 registering one. A turn is the owner's when every line and card in its conversation came from this machine or a live admin session, so the owner's paired phone or iPad can use the phone tools too. Every routine here is the owner's, so a conversation a routine reported into keeps the phone; a webhook's posted payload still makes a conversation someone else's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the desktop owner rule in its own tested module; a bot's ask, a worker's answer and an outside event's report are not the owner's Off a Cloud home, whose turn may use the phones is decided in server/phones/owner.ts: a line with no person is the owner's unless it is a bot's ask, which counts only as this turn's own request and only while the work came from the user; a live admin session's line or answer is the owner's, a client session's, a worker's or an unrecorded one is not; a webhook's payload and an outside event's run report still make a conversation someone else's, while a real routine's report does not. Card answers now record the answering session's person key off a Cloud home too. The e2e shows a thread a webhook's run opens gets no phone (one the owner's turn opens does), and a conversation an outside event's run reported into loses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot phoneApps grant on the bot patch route PATCH /api/bots/:id accepts phoneApps (null clears to the default). Adding a capability or raising read to write against the effective grant, including a Chief's clear-to-everything, counts as loosening. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot Phone apps card in bot settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): list registered phones and their allowed apps in Settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): surface a failed phone removal and block double clicks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): phone-side contract fixture Pins the wire shapes the phone apps parse; the test keeps the file in step with the server's zod schemas and PHONE_TOOLS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(phones): lower the index.ts ratchet and document the phone routes Pins server/index.ts at 16843 lines and adds "Phone apps as bot tools" to docs/ios-companion.md. Fails on base too: - node:sqlite load error on node 22 (125 src/ test files, e.g. src/components/CallSheet.test.ts) - server/browser-live-routes.test.ts - server/chat-apps-mcp.e2e.test.ts - server/cloud-sync.e2e.test.ts - server/control-omb.test.ts - server/device-links.test.ts - server/headless-cli.e2e.test.ts - server/routes/browser-viewers.test.ts - server/usage-traces.e2e.test.ts - server/verification-fixture.e2e.test.ts (server/group-local-vm.e2e.test.ts timed out once under full-suite load; passes alone on the branch.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): off a Cloud home a routine reaches the owner's phone only while the owner wrote it, unchanged A client-scope session could create, edit and run a routine whose run mounted the device server and reached the owner's phone: every non-webhook run counted as owner-written and owner-started, and every routine's report as the owner's. The desktop now records routine authorship the way a Cloud home does (createCloudRoutineAuthors, owner-routines.json): the owner or an admin creating a routine records it; anyone else's edit forgets it; the owner's edit keeps it only when it was theirs or they rewrote its instructions. A run is the owner's when its routine is recorded with the run's fingerprint and a schedule, a restart or the owner's own manual start began it; a routine's report is the owner's only for a routine the owner wrote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): no desktop phones where sign-in lets several people in; a relayed line is not the owner's Off a Cloud home every admin session counted as the one desktop owner, so on a self-hosted server shared through sign-in each admin reached every admin's phones; and a line relayed by an external interface (the Slack worker) names no person, so it passed as typed at this machine. phoneOwnerOf and phoneTurnOwner now offer the desktop owner's phones only where desktopPhonesOffered holds: no shared membership and loopback trust that is the owner, not a service. desktopLendingTurn rewrites relayed user lines to NOT_THE_OWNER, as it does a bot's unvouched ask. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): removing a phone fails its jobs, and a removal on the computer sticks Both DELETE routes only dropped the registry record: a job queued for the phone or in its hands kept waiting out its timeout, and the phone re-registered on its next connect. PhoneJobs.drop(key, text) finishes every job for the key as { ok: false, code: "denied", error: "This phone's access changed." } and wakes its open poll. The admin DELETE /api/phones/:key also records the key in a persisted blocked list in phones.json ({ version: 1, phones, blocked }, the old shape still read), so PUT /api/phones/self from it answers 403 "This phone was removed on the computer. Pair it again to use its apps." until the phone pairs again under a new key. The phone's own DELETE /api/phones/self does not block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): queue and nudge a phone job before asking whether the phone is online PhoneJobs.request waited up to 15 s for online() before it queued the job and sent the device.job nudge, and only a poll refreshes `seen`: a phone listening on its event stream but idle was never told to poll, so every call to it failed as offline. The job is now queued and nudged at once; if it has not been delivered when the 15 s reconnect window ends and the phone is still not online, it fails with the offline sentence (or turn_ended when its turn is over). A job the phone never took times out with "<tool> was never picked up by the phone within N seconds. It did not run."; a delivered or leased one keeps "It may still have run". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a newer phone's registration and job outcome are read, not refused The phones ship on their own schedule, but the registration schema was .strict() with an enum-keyed capability record and the outcome schemas were .strict() with a closed code enum: one new field, app or code from a newer phone made the server refuse its registration or its answer. Both now strip unknown keys; capabilities are filtered to the PHONE_CAPABILITIES this server knows before parsing, so an unknown app (say `inbox`) is dropped and the known ones register; an outcome code outside PHONE_JOB_CODES reads as absent. A known field with a malformed value is still refused. The contract fixture's shapes are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): derive the device call's timeout, test the team-Cloud refusal on a real key, keep the phone label last - The device proxy timeout is DEVICE_PROXY_TIMEOUT_MS = the send hold (OUTBOUND_HOLD_MS, now exported from outbound-hold.ts and imported by index.ts) + PHONE_SEND_TIMEOUT_MS + PHONE_RECONNECT_WAIT_MS (now exported) + 30 s = 705 s. harness-budget.ts writes the sum out instead of importing, so the stdio proxy that reads it loads neither the hold nor zod; harness-mcp-proxy.test.ts holds it to the sum of the real constants. - "a team Cloud offers no phones" authenticates as a verified companion device, so its 403 comes from there being no owner, not from a missing key. - phoneOkResult spreads the phone's answer first and `phone` last, so no key in the answer can relabel where it ran. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(phones): as-built notes on the design for the phone packs Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the owner's existing routines no longer hide the phone from the Chief's chat Routines written before this build kept no authorship record, so their reports made the Chief's main conversation count as someone else's and the phone tools were withheld there; the bot then reached for the USB Android tool. On the first start with authorship records, a desktop only one person uses (phones offered, no other person's session) records its existing routines as the owner's, once. A turn that may not use the phone now hears that a phone is paired and to ask in a new conversation, and both prompts say the mcp__phone__ tools are a USB Android. A phone named after its kind is described as "The iPhone". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(phones): every bot may use the phone, and asks first when the person is at the computer Phone apps are no longer the Chief's alone: with phoneApps unset any bot gets what the phone allows, and an explicit per-bot grant still wins ({} turns it off). The owner rule is unchanged. A send made by a registered phone is noted by its sendId, so the direct turn it starts is told the person is talking from their phone and does reminders, events, contacts, location and texts there. Every other turn (direct from the computer, room turns, the prompt preview) is told to do things the usual way, use the phone only when asked for it, and ask once "here, or on your phone?" when the phone could also do it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): where the person is lives in its own volatile section, unattended turns are told so, and phone sends without an id count The place sentence moves out of the stable "device" section into its own "device-place" section, which is volatile, so a phone turn after a computer one no longer relaunches the engine and re-uploads the conversation. It is emitted only beside a non-empty device section. A direct turn now has three places: the phone (its request is a noted phone send), the computer (a person's own line with no automation, peer ask, coordination or unattended flag) and unattended for everything else, which is told nobody is waiting and to use the phone only when the task names it. Rooms and the preview stay at the computer. A send from a registered phone without a sendId gets one minted, and each Live call line from a registered phone is noted, so walkie, command and call sends count as the phone's. The route's dependency is now fromPhone(auth) plus notePhoneSend(sendId). The computer text now allows reading the phone and asks once before changing anything on it; the phone text adds "as far as the phone allows"; the card's default note and the wire comment follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix phone send after ended turn, stale phoneApps grant, and comment pointers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(phones): drop the plan and spec documents The working plan and design notes were scaffolding for building the feature, not documentation of it. What the phone and the server agree on stays in docs/ios-companion.md and the contract fixture server/testing/fixtures/phone-jobs.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): no card of OpenMausBot's own on phone sends, and no "here or on your phone?" question A phone send already waits on the person: it opens a sheet on the phone and goes only when they tap Send there. It no longer waits first on the "Send on your behalf?" card, so the phone tools leave the outbound hold entirely; the bot's per-app grant still decides whether it may send at all (an RSVP is a Calendar write the same way). Where the person is now decides without asking: a turn that came from the phone does phone things on the phone, a turn at the computer works the usual way and changes the phone only when the person names it, and a run nobody typed uses the phone only when its task names it. The bot settings note says the same. Tests: the rpc and e2e tests send a message, a WhatsApp and an RSVP and check the job reaches the phone at once with only activity rows in the chat and no outbound decision rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(phones): the phone wiring moves to server/host/phones.ts, index.ts unpacked The phone integration had been added to server/index.ts as up to nine statements on one line. It now lives in createPhones (server/host/phones.ts): the registry and jobs, which sends came from a phone, whose turn may reach the owner's phones, where the person is, the mount and prompt parts, the /api/phones routes, and the desktop owner's routine records. index.ts builds it once and calls it from normally formatted lines, so it ends smaller than on main: 16,651 lines, pinned exactly in the file-size ratchet (the route ratchet stays at 6 path.startsWith). server/host/phones.test.ts covers where the person is (a send from the owner's phone is the phone's, the computer stays the computer, a run nobody typed is unattended, no place asks the person to choose) and that shared servers, other people's lines and refused Cloud turns get no phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(phones): translate the phone strings into every language pack The 17 phone strings (Settings > Remote access and the bot's Phone apps card) in all 12 packs, accepted with generate-locale --accept so source-hashes.json records them against the current English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 11 天前 | |
Phone apps as bot tools: bots use your phone's Calendar, Reminders, Contacts, Location and Messages (#3457) * docs: design + plan for phone apps as bot tools, server plumbing (sub-project A) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): shared vocabulary for phone apps, grants and the device.job frame Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): registry of paired phones and what each allows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): job queue a phone long-polls, leases and answers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): byte-measured result cap, turn-ended complete throws 409, poll after close Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): tool catalog, instructions and the per-bot verdict Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): the phone's own routes: register, poll, lease, answer Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a phone's companion identity comes from the verified auth, not headers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): device as a fifth harness MCP kind with its own timeout Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): timeout message names the call's own limit Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): every engine that mounts HighLevel mounts the device tools too Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(outbound): move the send hold out of index.ts so other tool kinds can use it The "Send on your behalf?" hold and the dispatch-time allowance check move from the connectors MCP handler into server/outbound-hold.ts as createOutboundHold(deps), with no change in behaviour: the same decision rows, card, activity flips, notification, timeout patch and refusal text. The handler keeps its parsing, scope checks, refuseOutbound, sendsFreely and both requireActiveInternalCapability calls. buildNotification no longer demands a threadId on the bot it never reads, so the hold can take the narrower bot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(ui): keep store.tsx inside its line ratchet after the capability fields Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(outbound): the hold's bot type carries notifications, so a muted bot stays quiet buildNotification reads bot.notifications through the hold's approval notice; OutboundHoldBot now picks it, and the test shows a muted bot still gets the card but no notification. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): MCP host that turns a bot's call into a phone job behind the per-bot verdict and the send hold Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): default phone by last use and by the tool's app, reserve only after every check, hold every outbound phone tool Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): mount the device tools per turn, route the internal MCP, nudge the phone over SSE server/index.ts wires the phone registry, job queue, host and /api/phones routes on existing lines (still 16843): the owner's own direct turn mounts the device server when its bot is granted an app one of the owner's phones allows, /api/internal/device/mcp answers it, a queued job nudges admin SSE clients with device.job, the phone's job long poll is exempt from the maintenance request count, the grants picker lists the phone tools, and shutdown closes the queue. The host is built beside the send hold it takes, which is declared after the HighLevel host. Phone tool rows read as "Phone" in the activity, and the device server is one of the app's own servers for the Today outcomes. The e2e pairs a phone, round-trips a job through poll, lease and result, and shows a bot without a grant and a read-and-draft routine run get no phone (a run of the same routine at the bot's own level does). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): only the owner's admin sessions hold a phone or lend their turn to one; routine reports stay the owner's Off a Cloud home, a request owns the desktop's phones only as the owner on this machine (loopback, the companion included) or an admin session; a client-scope session gets 403 registering one. A turn is the owner's when every line and card in its conversation came from this machine or a live admin session, so the owner's paired phone or iPad can use the phone tools too. Every routine here is the owner's, so a conversation a routine reported into keeps the phone; a webhook's posted payload still makes a conversation someone else's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the desktop owner rule in its own tested module; a bot's ask, a worker's answer and an outside event's report are not the owner's Off a Cloud home, whose turn may use the phones is decided in server/phones/owner.ts: a line with no person is the owner's unless it is a bot's ask, which counts only as this turn's own request and only while the work came from the user; a live admin session's line or answer is the owner's, a client session's, a worker's or an unrecorded one is not; a webhook's payload and an outside event's run report still make a conversation someone else's, while a real routine's report does not. Card answers now record the answering session's person key off a Cloud home too. The e2e shows a thread a webhook's run opens gets no phone (one the owner's turn opens does), and a conversation an outside event's run reported into loses it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot phoneApps grant on the bot patch route PATCH /api/bots/:id accepts phoneApps (null clears to the default). Adding a capability or raising read to write against the effective grant, including a Chief's clear-to-everything, counts as loosening. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): per-bot Phone apps card in bot settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): list registered phones and their allowed apps in Settings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): surface a failed phone removal and block double clicks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(phones): phone-side contract fixture Pins the wire shapes the phone apps parse; the test keeps the file in step with the server's zod schemas and PHONE_TOOLS. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore(phones): lower the index.ts ratchet and document the phone routes Pins server/index.ts at 16843 lines and adds "Phone apps as bot tools" to docs/ios-companion.md. Fails on base too: - node:sqlite load error on node 22 (125 src/ test files, e.g. src/components/CallSheet.test.ts) - server/browser-live-routes.test.ts - server/chat-apps-mcp.e2e.test.ts - server/cloud-sync.e2e.test.ts - server/control-omb.test.ts - server/device-links.test.ts - server/headless-cli.e2e.test.ts - server/routes/browser-viewers.test.ts - server/usage-traces.e2e.test.ts - server/verification-fixture.e2e.test.ts (server/group-local-vm.e2e.test.ts timed out once under full-suite load; passes alone on the branch.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): off a Cloud home a routine reaches the owner's phone only while the owner wrote it, unchanged A client-scope session could create, edit and run a routine whose run mounted the device server and reached the owner's phone: every non-webhook run counted as owner-written and owner-started, and every routine's report as the owner's. The desktop now records routine authorship the way a Cloud home does (createCloudRoutineAuthors, owner-routines.json): the owner or an admin creating a routine records it; anyone else's edit forgets it; the owner's edit keeps it only when it was theirs or they rewrote its instructions. A run is the owner's when its routine is recorded with the run's fingerprint and a schedule, a restart or the owner's own manual start began it; a routine's report is the owner's only for a routine the owner wrote. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): no desktop phones where sign-in lets several people in; a relayed line is not the owner's Off a Cloud home every admin session counted as the one desktop owner, so on a self-hosted server shared through sign-in each admin reached every admin's phones; and a line relayed by an external interface (the Slack worker) names no person, so it passed as typed at this machine. phoneOwnerOf and phoneTurnOwner now offer the desktop owner's phones only where desktopPhonesOffered holds: no shared membership and loopback trust that is the owner, not a service. desktopLendingTurn rewrites relayed user lines to NOT_THE_OWNER, as it does a bot's unvouched ask. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): removing a phone fails its jobs, and a removal on the computer sticks Both DELETE routes only dropped the registry record: a job queued for the phone or in its hands kept waiting out its timeout, and the phone re-registered on its next connect. PhoneJobs.drop(key, text) finishes every job for the key as { ok: false, code: "denied", error: "This phone's access changed." } and wakes its open poll. The admin DELETE /api/phones/:key also records the key in a persisted blocked list in phones.json ({ version: 1, phones, blocked }, the old shape still read), so PUT /api/phones/self from it answers 403 "This phone was removed on the computer. Pair it again to use its apps." until the phone pairs again under a new key. The phone's own DELETE /api/phones/self does not block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): queue and nudge a phone job before asking whether the phone is online PhoneJobs.request waited up to 15 s for online() before it queued the job and sent the device.job nudge, and only a poll refreshes `seen`: a phone listening on its event stream but idle was never told to poll, so every call to it failed as offline. The job is now queued and nudged at once; if it has not been delivered when the 15 s reconnect window ends and the phone is still not online, it fails with the offline sentence (or turn_ended when its turn is over). A job the phone never took times out with "<tool> was never picked up by the phone within N seconds. It did not run."; a delivered or leased one keeps "It may still have run". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): a newer phone's registration and job outcome are read, not refused The phones ship on their own schedule, but the registration schema was .strict() with an enum-keyed capability record and the outcome schemas were .strict() with a closed code enum: one new field, app or code from a newer phone made the server refuse its registration or its answer. Both now strip unknown keys; capabilities are filtered to the PHONE_CAPABILITIES this server knows before parsing, so an unknown app (say `inbox`) is dropped and the known ones register; an outcome code outside PHONE_JOB_CODES reads as absent. A known field with a malformed value is still refused. The contract fixture's shapes are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): derive the device call's timeout, test the team-Cloud refusal on a real key, keep the phone label last - The device proxy timeout is DEVICE_PROXY_TIMEOUT_MS = the send hold (OUTBOUND_HOLD_MS, now exported from outbound-hold.ts and imported by index.ts) + PHONE_SEND_TIMEOUT_MS + PHONE_RECONNECT_WAIT_MS (now exported) + 30 s = 705 s. harness-budget.ts writes the sum out instead of importing, so the stdio proxy that reads it loads neither the hold nor zod; harness-mcp-proxy.test.ts holds it to the sum of the real constants. - "a team Cloud offers no phones" authenticates as a verified companion device, so its 403 comes from there being no owner, not from a missing key. - phoneOkResult spreads the phone's answer first and `phone` last, so no key in the answer can relabel where it ran. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(phones): as-built notes on the design for the phone packs Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(phones): the owner's existing routines no longer hide the phone from the Chief's chat Routines written before this build kept no authorship record, so their reports made the Chief's main conversation count as someone else's and the phone tools were withheld there; the bot then reached for the USB Android tool. On the first start with authorship records, a desktop only one person uses (phones offered, no other person's session) records its existing routines as the owner's, once. A turn that may not use the phone now hears that a phone is paired and to ask in a new conversation, and both prompts say the mcp__phone__ tools are a USB Android. A phone named after its kind is described as "The iPhone". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(phones): every bot may use the phone, and asks first when the person is at the computer Phone apps are no longer the Chief's alone: with phoneApps unset any bot gets what the phone allows, and an explicit per-bot grant still wins ({} turns it off). The owner rule is unchanged. A send made by a registered phone is noted by its sendId, so the direct turn it starts is told the person is talking from their phone and does reminders, events, contacts, location and texts there. Every other turn (direct from the computer, room turns, the prompt preview) is told to do things the usual way, use the phone only when asked for it, and ask once "here, or on your phone?" when the phone could also do it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): where the person is lives in its own volatile section, unattended turns are told so, and phone sends without an id count The place sentence moves out of the stable "device" section into its own "device-place" section, which is volatile, so a phone turn after a computer one no longer relaunches the engine and re-uploads the conversation. It is emitted only beside a non-empty device section. A direct turn now has three places: the phone (its request is a noted phone send), the computer (a person's own line with no automation, peer ask, coordination or unattended flag) and unattended for everything else, which is told nobody is waiting and to use the phone only when the task names it. Rooms and the preview stay at the computer. A send from a registered phone without a sendId gets one minted, and each Live call line from a registered phone is noted, so walkie, command and call sends count as the phone's. The route's dependency is now fromPhone(auth) plus notePhoneSend(sendId). The computer text now allows reading the phone and asks once before changing anything on it; the phone text adds "as far as the phone allows"; the card's default note and the wire comment follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix phone send after ended turn, stale phoneApps grant, and comment pointers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(phones): drop the plan and spec documents The working plan and design notes were scaffolding for building the feature, not documentation of it. What the phone and the server agree on stays in docs/ios-companion.md and the contract fixture server/testing/fixtures/phone-jobs.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(phones): no card of OpenMausBot's own on phone sends, and no "here or on your phone?" question A phone send already waits on the person: it opens a sheet on the phone and goes only when they tap Send there. It no longer waits first on the "Send on your behalf?" card, so the phone tools leave the outbound hold entirely; the bot's per-app grant still decides whether it may send at all (an RSVP is a Calendar write the same way). Where the person is now decides without asking: a turn that came from the phone does phone things on the phone, a turn at the computer works the usual way and changes the phone only when the person names it, and a run nobody typed uses the phone only when its task names it. The bot settings note says the same. Tests: the rpc and e2e tests send a message, a WhatsApp and an RSVP and check the job reaches the phone at once with only activity rows in the chat and no outbound decision rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(phones): the phone wiring moves to server/host/phones.ts, index.ts unpacked The phone integration had been added to server/index.ts as up to nine statements on one line. It now lives in createPhones (server/host/phones.ts): the registry and jobs, which sends came from a phone, whose turn may reach the owner's phones, where the person is, the mount and prompt parts, the /api/phones routes, and the desktop owner's routine records. index.ts builds it once and calls it from normally formatted lines, so it ends smaller than on main: 16,651 lines, pinned exactly in the file-size ratchet (the route ratchet stays at 6 path.startsWith). server/host/phones.test.ts covers where the person is (a send from the owner's phone is the phone's, the computer stays the computer, a run nobody typed is unattended, no place asks the person to choose) and that shared servers, other people's lines and refused Cloud turns get no phone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(phones): translate the phone strings into every language pack The 17 phone strings (Settings > Remote access and the bot's Phone apps card) in all 12 packs, accepted with generate-locale --accept so source-hashes.json records them against the current English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 11 天前 | |
Team Cloud: teammates' pictures instead of their initials A teammate's name and picture are visible to everyone in the team, like any team app; About you and everything else stay private. - GET /api/team/people gives each member's pictureUrl to the team's signed-in members only, and GET /api/team/people/<person>/picture serves the bytes to them alone (403 for any session that isn't one of this team's members, 404 off a team or for someone who isn't a current member). The address never names the upload, changes whenever the picture does, and is revalidated on every use. - PersonFace shows the picture, else the coloured initial, so every place a person appears gets it: the Reports to picker, the owner's face on a bot's row, the Team map's Who reports to whom, Asking lines, the @ list, Told chips, and Needs you lines from a teammate (which now carry fromEmail). - The people list catches up after any profile save, so a new picture shows without reopening the app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
fix(chat-mcp): reach servers past the tool limit through the directory, and show the bot's tool budget On the chat (OpenAI-compatible) engine a turn whose MCP servers offered more than the 128 tools a request may carry dropped whole servers ("skipped for this turn: MCP tool count exceeds the 128-tool limit"), so the model looped looking for a tool that was gone. Now the turn lists as many whole servers as fit, in turn order after the built-ins, and puts the rest behind one tool search (mcp_search_tools / mcp_describe_tool / mcp_call_tool) whose three tools count toward the limit. Calls through it keep the bot's tool selection, schema checks and approval cards (naming the tool run, with the same grant as a direct call). The chat says in one line which servers went through the search. A configured command server's own environment now passes the bot box's allow-list (as Codex and the health check already let it), so a token such as 1Password's OP_SERVICE_ACCOUNT_TOKEN reaches the server in a boxed turn instead of the server exiting or refusing its handshake. Settings Test starts a command server the same way (in the box, from its bot's folder when it is one bot's), and its answer says when the server alone has more tools than the limit, or half of it or more. Third-party tool schemas that strict Ajv refused for keywords that assert nothing (OpenAPI's example/discriminator, x- extensions, editor hints, Effect Schema's repeated $id, draft-07 named without its #) are compiled from a copy without them, instead of dropping the whole server; every assertion is still enforced, and unknown assertions are still refused. The bot's MCP servers card in Access shows its last chat turn's tool count against the limit and the servers it found through tool search. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 3 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
feat(greenference): Greenference as an AI provider, with its own logo Greenference gets a key row under Settings → Connections → AI providers and a "Greenference (API)" engine on the shared chat-completions runtime, like Groq and Cerebras. The model list keeps the ready models that can call tools (5 of 10 today), shows their short names, and sends images only to models whose catalog lists image input. Its key goes only to Greenference's host; the Test button proves it (a wrong key gets 401 from /models). Its site icon is the provider mark, in a teal from its logo that reads on light and dark. A bot can ask for the key in chat. config.ts stays under its size pin by loading the key-only providers' env in one loop. The agents catalog goldens and budget baselines move to the measured sizes. Replaces #2477. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 6 天前 | |
alias: tests call coordinate_bots and assignment_status; the alias-only tests are deleted Rewritten to the real surface with each test's intent kept: the proxy's peer start_thread answer, assignment_status's same-turn 409 relay and parked-question rendering, R3 (consultation) and R4 (one-way notice in a fresh thread), peer allow-list, peer approval, notification routing, routine delegation, the three external-runtime suites, post-to-room's room consultation and same-turn read, independent threads, thread capacity, cloud lending, direct coordination's one-way chain and fresh-thread hand-off. Deleted: the proxy's ask_bot/delegate_bot/check_delegation/wait_delegation/ send_to_bot rendering tests and the external alias test, comms's ask_bot alias scenario (and the askerLegacy instance), runtime-paths R2 (a duplicate of R1, whose reason-on-the-chip check R1 now carries). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 23 天前 | |
Smaller agents tool list: compact schemas, action tools, fewer tools where a turn can't use them (#3773) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Run the bots' browsers on the new engine behind browserEngine.engine=chrome With browserEngine.engine set to "chrome" in config.json, a bot's browser runs on OpenMausBot's own Chrome driver instead of agent-browser: its turns mount the same browser MCP server, which now advertises the 21 new tools and restart_browser, and the phone's and desktop panel's live view go through the v1 adapter. Profiles that use the person's own Chrome stay on agent-browser. The default stays agent-browser, so nothing changes until the flag is set. - The internal MCP route, the live view, preview frames, fill_login, the sign-in card's page check, the system prompt, the browser status and deletion cleanup each go to the engine the session runs on. - On a desktop the headless browser reports the computer's main display and its real scale (2 on a Retina Mac); servers and containers declare 1920x1080 at 1x. OMB_BROWSER_SCREEN overrides it. - Switching the engine is refused while a bot with a browser is in a turn; once switched, the viewers close and each browser the other engine ran closes, so the next call starts on the engine now chosen. - Signed-in sites stay an agent-browser list, so the new browser says it does not list them yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 20 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
See what a bot is doing right now: the step, how it is going, and a Now card (#3736) * See what a bot is doing right now The working line said only "Working · 19m 07s · Running a command": not which command, whether it was getting anywhere, or whether it was stuck. - The line names the step: "Running scrape.py" with the whole command on hover, "Searching the web for “Biber Dammbau”", "Reading linkedin.com". The event bus reads every engine's tool-call start the same way, from the server's redacted summaries; the words are redacted again, capped, and never carry an environment variable's value. The step is kept on the call's chat row, so a reload and finished steps keep the words. - After a step has run past the quiet notice, a quiet second part says how it is doing: its last output's age where the engine streams output (Codex, ACP), else what its own processes show (waiting on the network, busy, idle). This reuses the quiet-status probe and its knobs, limited to the processes the call started. - The line is a button (aria-expanded) that unfolds a small Now card: the ask's last steps, a running command's last lines of output (redacted, at most one update a second) and Open activity, which opens the Activity panel at this run. Click again or Escape folds it. - A working bot's sidebar row shows its current step instead of its last message, in both modes. - The bus keeps a waiting status frame through events the line ignores (token counts, heartbeats); Claude's usage report after every tool start used to drop it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Before and after captures of the working line, its Now card and the sidebar row From the isolated fixture at 1338×870@2x: a long command, a web search and a page, in Midnight and Daylight, Simple and Advanced, with a German set; the Now card open, a Codex bot's streamed output, and Open activity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Give the process-sampling test a margin a busy runner keeps Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
fix(browser): stage Chrome uploads before any wait; refuse workspace uploads on Windows (#3716) * fix(browser): stage Chrome uploads before browser waits Copy staged uploads from a checked no-follow file descriptor instead of creating hard links. Stage unnamed Chrome workspace files before startup and picker waits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 070d649726fc41e5b9443cb9f0324c9ac476701a) * fix(browser): reject upload directory symlink swaps Check the opened Linux descriptor path before reading. Use Darwin O_NOFOLLOW_ANY to reject symlinks in every component, including a parent replaced while another batch file copies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 61fa263214e06e96404eca835a9306b47d291024) * fix(browser): bind Windows uploads to checked file identities Compare bigint device and inode metadata from lstat and the opened handle before copying any bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 2800cf443b6788749d4a5a1538cbc2f8b14fb0e6) * fix(browser): remove the whole failed upload batch Track every staging directory created by the batch and delete them all when any source fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 32a83a2a557bf6a11bbb9856fff5403ea00426de) * fix(browser): bound upload batches and copy without blocking Reuse the 25 MiB attachment and 100 MiB browser upload limits. Pin and inspect all source descriptors before writing, then copy with asynchronous reads and writes. Await staging before browser dispatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit aa8908d88ece20fe8a20a22afb1676dfda2647f6) * fix(browser): use compatible Darwin upload flags Select O_NOFOLLOW_ANY without O_NOFOLLOW on Darwin. Exercise each platform branch and reject the XNU-invalid flag combination in the regression fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 12d5f2c26b8c050db49598402b4840c13f627257) * fix(browser): revalidate Windows upload targets after open Resolve allowlisted roots and sources with the native realpath API. After opening a Windows source, require its canonical path to remain exactly the allowlisted source and compare the resolved file bigint device and inode with the open handle. This stricter path check rejects all junction redirects without carrying allowed roots through the staging API. Cover a junction swap before open, a swap after open, and restoration of the allowed directory after opening an outside file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 17682d681413a7d569871b526fe882a508cdda55) * fix(browser): refuse workspace-file staging on Windows Reject staging before opening a workspace file until the opened handle can be checked by final path. Keep uploads of bytes supplied by a person working on all platforms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 419f789eb86c72fda425670497630f3f69303255) * Return browser upload refusals as tool errors Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(browser): canonicalize upload fixture paths natively Resolve both upload fixture roots with realpathSync.native so expected paths match uploadableFiles when Windows expands an 8.3 temp directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: await staged browser uploads before removing the read gate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(browser): Windows still uploads attachments and workspace files, staged before any wait Refusing every staged upload on Windows also refused a chat attachment sent under the person's own name, with every engine, which worked before; a workspace file given to agent-browser by its own name still went through unstaged. On Windows the staged copy is now read from the path the allowlist just checked (Windows has no O_NOFOLLOW), before the browser starts or the picker opens. Linux and macOS keep the symlink-proof open. Tests: the Windows cases expect a private copy instead of a refusal, and the attachment-name tests run on Windows again, as they did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 8 天前 | |
Team Cloud: connections the whole team shares, or each person connects their own An admin chooses, per app and per MCP server, who connects it: once for the whole team (the default, and every connection made so far), or each person their own. A member's own connection reaches only a turn in their private chat that their own message started: never a group chat, the bot's main chat, another member's chat, an admin writing in theirs, or a routine. - Apps: each member gets their own installation on the connected-apps service (their own Composio user), mounted as a second bridge, own_apps, in their own turns. The relay checks every frame: the team bridge refuses a person's app, a member's bridge refuses a team app and anything outside their own turn. - MCP: a person's server never carries the team's credential; a member's own turn gets it with their own key or sign-in, pinned to its address. - No connection card for a person's app: the bot says one plain line with the link to the member's team page. - Members' keys, tokens and sign-ins live in people-connections/, never in a backup or a bot box, never in a route's answer. The Admin's signed read says who connected, by address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 13 天前 | |
feat(cloud): this computer works for each of your Clouds automatically (#3734) * feat(cloud): a rail of Clouds, and + to buy another or add your own server Someone with two places or more (their Clouds, their teams' Clouds, servers they connected themselves) gets a narrow rail of circles at the window's left edge: initials on each place's colour, the place on screen marked, a dot when something needs them there, a ring while a Cloud is set up, ⋯ past eight, and + last. With one place there is no rail and nothing changes. The desktop session may list every Cloud of the person's (contract v1 `clouds`), read strictly; without it the app reads `cloud` and `teams` exactly as before. Each own Cloud besides My Cloud becomes a saved place, named and coloured by the Admin, and opens like a team's Cloud: pairHome(cloudId) sends { cloudId } and takes only a grant for that Cloud's own address. My Cloud stays the one home. isOwnCloud(origin) comes from the verified session only, and the update banner, sign-in and plan card now work on each own Cloud's page. The rail's list carries names, colours and states, never an address, and goes only to this app's page and to pages of Clouds MausBot runs that the session lists; a circle opens only an id main listed, through its own switch, from a click. + buys another Cloud (a plan, its name and swatch, POST /api/cloud/desktop/clouds and the returned checkout, followed to "ready"), or the calm one-Cloud word on an Admin that sells one, and walks through adding a server of one's own with today's pairing link. main.mjs stays under its size ratchet: the window's size-and-place file moved to window-state-file.mjs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cloud): each place's colour at the top of its sidebar, and signed-in servers on the rail The place on screen tints the top of its sidebar in its colour, faintly, so people can tell their places apart at a glance; with no colour the sidebar looks as before. Settings > Appearance changes it with the rail's six swatches. A Cloud's colour is the Admin's (PATCH desktop/clouds/:id, for its owner or its team's admins; a member sees it locked), so every app of theirs follows; a server connected by hand keeps its colour in this app. The circle, the switcher's dot and the tint follow at once, and nothing is saved when the Admin refuses or lacks the route. The session's list may now carry the person's own servers and computers that signed in with their account (managed: false). They are never a Cloud of theirs to pair with or lend to. The rail shows them with a server mark, offline with when they were last seen, connected ones as their saved place, and nothing to open when only their own network reaches them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cloud): read the Admin's reason for refusing another Cloud, and remind of updates Adding a Cloud is refused with the Admin's own reason whatever the status: 409 for its cap or another open checkout, 429 for too many at once, 503 while sign-ups are closed. The sheet now keys on that reason, so a closed sign-up is the calm line instead of an error. When another Cloud's checkout is still open, the Admin's page for it is kept here and the sheet follows that Cloud, with Reopen checkout and Copy link; nothing opens by itself. A server of the person's own that signed in runs a release the Admin names; while it names a newer one (the session's latestVersion), the rail gives that server a quiet reminder. With no newest release named, there is none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cloud): lend this computer to each Cloud of the person's own "Let my bots use this computer" now goes to the Cloud that asks: another Cloud of the person's own has the same switch on its own page, and this computer's Settings gets a "Which Cloud" picker once there are two. Each Cloud is checked at its own address and sleeps on a gate of its own, so one asleep never holds another's lending. My Cloud's Off stops all lending, as before; another Cloud's stops only that one. Use my Mac on another Cloud's page lends to it, the tray's Terminal reaches every Cloud lent to (asking once), and "Choose folders" in its welcome opens its own Settings. The move stays My Cloud's, the one home. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cloud): this computer works for each of your Clouds automatically Every Cloud of the person's own (the verified session's, never a Team Cloud) uses this computer by itself while the app runs and is signed in: the internet connection, their Chrome, the home folder with editing, and apps and screen once computer control works (on a Mac lacking only its permissions, macOS is asked the first time a Cloud's bot needs them). Never the terminal. Folders lent before stay lent, so Files keeps their copies. There is nothing to set: the switches, the Which Cloud picker, the lending cards in Settings and on Cloud pages, the Use my Mac popup and link, the Terminal's question and the welcome's lending step are gone, with their channels, bridges and 97 strings in every language. The menu bar names the Clouds using this computer and offers Pause/Resume, which lasts across restarts, and See activity. Someone who had turned lending off, or unticked the internet connection, starts Paused. The protections hold, and the home folder's are added: shell start-up files, git's configuration and PowerShell profiles stay private, and a write through the home folder never reaches its hidden files, Library or AppData. Bots' texts on the Cloud say what is true now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(verification): pictures of lending without settings, from the merged tree Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(chrome): the not-lent guidance says the app lends its Chrome by itself Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Fix the latency probe's first-audio and per-thread delta attribution Derive first audio from the earliest playback start across all blocks: a block the probe never saw finish no longer nulls the whole reply's first-audio latency, while gap accounting still requires both bounds. Track the pending first delta per thread instead of in one module-level variable, so interleaved threads cannot consume each other's t0; the completed-message recorder now takes the message's thread id. | 15 天前 | |
feat(waits): "tell me when…" with no AI running while a bot waits (#3763) * docs: waits design (tell me when, no AI while waiting) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: waits implementation plan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): file and process probes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): page probe that only reaches public addresses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): page timeout covers the lookup; stronger probe tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): WaitManager with a 5 s tick, limits and expiry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): rename the record's then field to followUp Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): recheck limits before saving, catch tick failures, full rollback, save before follow-up Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): wire shapes, wait notification and follow-up run plumbing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): internal route with source, host and ownership checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): scope list and cancel to the chat, one-line labels, normalised urls Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): wait_until, list_waits and cancel_wait in the agents catalog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): run waits in the server, tie them to bots, keep them out of backups Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): cancel waits when automations switch off for a move, no guest follow-ups, backup notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): a wait's card reads as one line with Cancel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(verification): waits recipe, exercised against a fixture Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): classify wait notices for MausBot and keep wire.ts under 1,000 lines Main's MausBot notification list needs a lean for every kind: a wait that fired tells the person something happened and asks nothing, so it is fyi, like done. WaitCardData moves to shared/wait-request.ts next to the other card payloads so shared/wire.ts stays under the file-size ratchet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): keep the wait kinds and hours in shared/waits.ts so the agents proxy no longer loads the wait manager The tool module imported WAIT_KINDS from server/waits.ts, which pulled config, atomic writes and the probes into every agents proxy (86 bundled modules; 43 now). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): a full bot's refusal names only this chat's waits, and the copy says "in this chat" The refusal listed every chat's waits, so a turn in one chat could read the labels and follow-ups of another person's waits. It now lists this chat's waits and counts the rest. list_waits and cancel_wait only see this chat's waits, so their "none" and "no such id" answers say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): refuse a program wait where this computer can't list its programs A failed process listing reads as "not met", so on a computer without ps a program wait was made and silently never fired. Creation now refuses it; a listing that fails later still just waits for the next check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): moving a bot from My Cloud into a team cancels its waits A moved bot stays here archived, and its waits kept firing: lines, notifications and follow-up runs for a bot that now lives in the team. Holding it for the move and its arrival both cancel its waits, which settles their cards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): check pages outside the tick's busy window, so a slow page no longer refuses a backup or restore A page check can take 15 s, and the whole tick counted as busy for backups and restores. The checks now run first and only deciding and posting count as busy; what a check finds after the waits were stopped is not posted, and that wait is checked again once they start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): a restore ends the waits already here, and the backup notes stop saying waits watch this computer waits.json was kept in place across a restore, so waits made before it went on checking and posted into the restored chats while routines stayed paused. It now moves aside with the rest of the old data (the safety copy keeps it). Page waits look at the internet, not this computer, so the exclusion note no longer says each one watches it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): the card says how a wait ended, its Cancel reads as Cancel, and a Cancel on an ended wait settles it Labels are noun phrases ("the build"), so the card's subtitle is "Then <bot> will: …" rather than "When <label>, …". After a wait fired, expired or was cancelled the card said "<bot> is waiting for …" (a cancelled one with "· Undone"); each now has its own line. The button reads Cancelling… and Couldn't cancel. A Cancel that finds the wait already ended settles the card as ended, so the button goes away; a card settles once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): on a Cloud home, say that checks pause while My Cloud sleeps and where the follow-up reports My Cloud is not kept awake for waits, so on a Cloud home the wait_until answer and the tool description say checks pause while it sleeps; the answer also says a follow-up runs in its own results chat, as it does there. The tool asks for a noun-phrase label ("the build") and list_waits says it lists this chat's waits. Goldens regenerated; every profile grows 57 bytes and its budget moves with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(waits): the fixture keeps the fake engine's calls, and the follow-up turn's wait_until is refused The recipe emptied calls.json and said the follow-up would otherwise set a second wait; it is refused instead, which is the no-self-renewal guard. Re-ran the fixture with noun-phrase labels: one card, one fired line, the follow-up's call refused, waits.json empty. The quoted lines say they are abridged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): the wait fields' docs live on their types, keeping shared/wire.ts at 1000 lines Main's newer fields and the two wait fields took wire.ts to 1002 lines, past the ratchet's 1000-line listing threshold. The types carry the docs instead, as TeamSetupRequest and QuotaSwitchCardData already do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): only a personal My Cloud says its checks pause while it sleeps A Team Cloud's plan never sleeps, yet its bots told people their wait might come late because My Cloud sleeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: list list_waits and cancel_wait only while the bot has a wait; shorter wait_until In the spirit of #3773's "fewer tools where a turn can't use them": - A new switch in a turn's agents profile, OMB_ACTIVE_WAITS, set from WaitManager.count(botId) and carried by the HTTP mount. Every turn outside a room lists wait_until; list_waits and cancel_wait are listed only while the bot has a wait that has not ended, so the turn after one is set sees them. A room lists list_waits alone, and only then. - Unlisted, the two still answer a call (a wait made this turn, a list read earlier): the agents server's unknown-tool check reads callableTools, so a direct call or use_tool reaches the waits route, which scopes it to the chat. A room still refuses cancel_wait as a tool it is not given. find_tool offers them only while they are listed. - wait_until says only what the model needs: the kinds, no AI while waiting, follow_up and 1 to 168 hours. Its result already explains a condition that holds, a computer that can't check files or programs, and My Cloud's sleep. It advertises 1,070 bytes, down from 1,912. - Budgets: 16 catalog profiles stay inside main's +2%. The nine non-Chief profiles that list wait_until move their BUDGET_BASELINE by the measured overage only (39 to 153 bytes). No bridged baseline moves; no file cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: list list_waits and cancel_wait only for a wait in this chat Both act only on the chat's own waits, so a wait the bot keeps in another chat no longer lists them here. OMB_ACTIVE_WAITS now comes from WaitManager.count(botId, threadId), on the same OMB_ROOM line of server/index.ts. A room never holds a wait, so its turn lists none of the three. Unlisted, both still answer a call as before. No catalog bytes change: every golden profile has the switch off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wire: a card's waitRequest comes from a WaitCardField mixin, so shared/wire.ts stays at 1,000 lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: read a page's words in one linear pass The text-stripping patterns backtracked: a page of 128 KB of `<` took 5 s, and 2 MB, the most a check reads, about 20 minutes, freezing the whole server on create, every minute after and again after a restart. pageText now walks the page once with indexOf and bounded patterns; a hostile 2 MB page reads in milliseconds. Well-formed pages read exactly as before. A comment, script or style left open now hides the rest, as in a browser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: refuse a network path for a file wait A file wait checks its path every 5 seconds. On Windows a path such as \\host\share\x makes that check sign in to the host, sending it the person's password hash. A path starting with \\ or //, with either slash, mixed or percent-encoded, is refused before anything looks at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: url_missing fires only once a check saw the text A check reads the page's HTML without running its scripts, so on a page its scripts draw the text looked gone from the first check: the wait answered "already" and the bot told the person, say, that the shoes were back in stock when they were not. Like bot_idle's sawBusy, the condition now keeps sawText and fires only after a check found the text and a later one does not. A wait made while the text is not on the page says so, for the bot to tell the person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: a sleeping Cloud wakes every 30 minutes while a wait is open Waits were left out of the wake schedule, so a My Cloud that slept never checked them. While a wait is open the home's nextDueAt now includes a time 30 minutes on: the home may still sleep (a page is due every minute, which would keep it awake), and the Admin wakes it to check about every half hour. The wait's answer tells the bot the message can come up to 30 minutes late. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: plain words in the wait card and the bot's refusals Following #3865: the refusals say MausBot and "a private desktop or a cloud desktop" instead of OpenMausBot and Local VM, and each error says what to do next (guests leave out follow_up, a bot waits for another bot rather than itself, a program wait on a computer that can't list its programs waits for a file or a page, a private address takes a page on the public web, a vanished bot is picked again from list_bots). The card's failed Cancel says "Couldn't cancel the wait. Try again, or ask {name} to stop it." in place of a raw error, and a Cancel that finds the wait already ended shows no error: the card then says how it ended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: Korean says {app} like the other packs, and the release's hashes follow #3865's English main fails pnpm i18n:check with 128 problems from three changes landing together. #3852's Korean was written before #3865 turned OpenMausBot into {app}, so 110 Korean lines lost a placeholder; the 0.1.133 release had recorded source hashes that #3865's English then changed. As #3865 did for every other pack, Korean's OpenMausBot becomes {app} (106 lines; MausBot ends in a consonant too, so the particles stay right). Four lines that swap can't fix fall back to English until the next translation run: the three VPS desktop lines #3865 reworded and dropped from every pack, and the same-machine setup line, which names the app twice where the English now names it once. The 18 stale hashes are refreshed: approval.status.timedOut (15 packs) and German approval.status.expired changed punctuation only, and the three Chinese environment errors already carry #3865's next step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(touch): the calendar's resize handle lives in CalendarEventCard now #3863 moved the call event's mouse drag-resize handle from RoutineCalendarPage.tsx into routines/CalendarEventCard.tsx, but the touch test's not-an-action entry still named the old file, so it reported the handle as a hover-only action and its own entry as stale. main never ran it: its locale check failed first. The entry now names the new file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 6 天前 | |
feat(waits): "tell me when…" with no AI running while a bot waits (#3763) * docs: waits design (tell me when, no AI while waiting) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: waits implementation plan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): file and process probes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): page probe that only reaches public addresses Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): page timeout covers the lookup; stronger probe tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): WaitManager with a 5 s tick, limits and expiry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): rename the record's then field to followUp Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): recheck limits before saving, catch tick failures, full rollback, save before follow-up Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): wire shapes, wait notification and follow-up run plumbing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): internal route with source, host and ownership checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): scope list and cancel to the chat, one-line labels, normalised urls Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): wait_until, list_waits and cancel_wait in the agents catalog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): run waits in the server, tie them to bots, keep them out of backups Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): cancel waits when automations switch off for a move, no guest follow-ups, backup notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(waits): a wait's card reads as one line with Cancel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(verification): waits recipe, exercised against a fixture Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): classify wait notices for MausBot and keep wire.ts under 1,000 lines Main's MausBot notification list needs a lean for every kind: a wait that fired tells the person something happened and asks nothing, so it is fyi, like done. WaitCardData moves to shared/wait-request.ts next to the other card payloads so shared/wire.ts stays under the file-size ratchet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): keep the wait kinds and hours in shared/waits.ts so the agents proxy no longer loads the wait manager The tool module imported WAIT_KINDS from server/waits.ts, which pulled config, atomic writes and the probes into every agents proxy (86 bundled modules; 43 now). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): a full bot's refusal names only this chat's waits, and the copy says "in this chat" The refusal listed every chat's waits, so a turn in one chat could read the labels and follow-ups of another person's waits. It now lists this chat's waits and counts the rest. list_waits and cancel_wait only see this chat's waits, so their "none" and "no such id" answers say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): refuse a program wait where this computer can't list its programs A failed process listing reads as "not met", so on a computer without ps a program wait was made and silently never fired. Creation now refuses it; a listing that fails later still just waits for the next check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): moving a bot from My Cloud into a team cancels its waits A moved bot stays here archived, and its waits kept firing: lines, notifications and follow-up runs for a bot that now lives in the team. Holding it for the move and its arrival both cancel its waits, which settles their cards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): check pages outside the tick's busy window, so a slow page no longer refuses a backup or restore A page check can take 15 s, and the whole tick counted as busy for backups and restores. The checks now run first and only deciding and posting count as busy; what a check finds after the waits were stopped is not posted, and that wait is checked again once they start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): a restore ends the waits already here, and the backup notes stop saying waits watch this computer waits.json was kept in place across a restore, so waits made before it went on checking and posted into the restored chats while routines stayed paused. It now moves aside with the rest of the old data (the safety copy keeps it). Page waits look at the internet, not this computer, so the exclusion note no longer says each one watches it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): the card says how a wait ended, its Cancel reads as Cancel, and a Cancel on an ended wait settles it Labels are noun phrases ("the build"), so the card's subtitle is "Then <bot> will: …" rather than "When <label>, …". After a wait fired, expired or was cancelled the card said "<bot> is waiting for …" (a cancelled one with "· Undone"); each now has its own line. The button reads Cancelling… and Couldn't cancel. A Cancel that finds the wait already ended settles the card as ended, so the button goes away; a card settles once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): on a Cloud home, say that checks pause while My Cloud sleeps and where the follow-up reports My Cloud is not kept awake for waits, so on a Cloud home the wait_until answer and the tool description say checks pause while it sleeps; the answer also says a follow-up runs in its own results chat, as it does there. The tool asks for a noun-phrase label ("the build") and list_waits says it lists this chat's waits. Goldens regenerated; every profile grows 57 bytes and its budget moves with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(waits): the fixture keeps the fake engine's calls, and the follow-up turn's wait_until is refused The recipe emptied calls.json and said the follow-up would otherwise set a second wait; it is refused instead, which is the no-self-renewal guard. Re-ran the fixture with noun-phrase labels: one card, one fired line, the follow-up's call refused, waits.json empty. The quoted lines say they are abridged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(waits): the wait fields' docs live on their types, keeping shared/wire.ts at 1000 lines Main's newer fields and the two wait fields took wire.ts to 1002 lines, past the ratchet's 1000-line listing threshold. The types carry the docs instead, as TeamSetupRequest and QuotaSwitchCardData already do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(waits): only a personal My Cloud says its checks pause while it sleeps A Team Cloud's plan never sleeps, yet its bots told people their wait might come late because My Cloud sleeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: list list_waits and cancel_wait only while the bot has a wait; shorter wait_until In the spirit of #3773's "fewer tools where a turn can't use them": - A new switch in a turn's agents profile, OMB_ACTIVE_WAITS, set from WaitManager.count(botId) and carried by the HTTP mount. Every turn outside a room lists wait_until; list_waits and cancel_wait are listed only while the bot has a wait that has not ended, so the turn after one is set sees them. A room lists list_waits alone, and only then. - Unlisted, the two still answer a call (a wait made this turn, a list read earlier): the agents server's unknown-tool check reads callableTools, so a direct call or use_tool reaches the waits route, which scopes it to the chat. A room still refuses cancel_wait as a tool it is not given. find_tool offers them only while they are listed. - wait_until says only what the model needs: the kinds, no AI while waiting, follow_up and 1 to 168 hours. Its result already explains a condition that holds, a computer that can't check files or programs, and My Cloud's sleep. It advertises 1,070 bytes, down from 1,912. - Budgets: 16 catalog profiles stay inside main's +2%. The nine non-Chief profiles that list wait_until move their BUDGET_BASELINE by the measured overage only (39 to 153 bytes). No bridged baseline moves; no file cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: list list_waits and cancel_wait only for a wait in this chat Both act only on the chat's own waits, so a wait the bot keeps in another chat no longer lists them here. OMB_ACTIVE_WAITS now comes from WaitManager.count(botId, threadId), on the same OMB_ROOM line of server/index.ts. A room never holds a wait, so its turn lists none of the three. Unlisted, both still answer a call as before. No catalog bytes change: every golden profile has the switch off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * wire: a card's waitRequest comes from a WaitCardField mixin, so shared/wire.ts stays at 1,000 lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: read a page's words in one linear pass The text-stripping patterns backtracked: a page of 128 KB of `<` took 5 s, and 2 MB, the most a check reads, about 20 minutes, freezing the whole server on create, every minute after and again after a restart. pageText now walks the page once with indexOf and bounded patterns; a hostile 2 MB page reads in milliseconds. Well-formed pages read exactly as before. A comment, script or style left open now hides the rest, as in a browser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: refuse a network path for a file wait A file wait checks its path every 5 seconds. On Windows a path such as \\host\share\x makes that check sign in to the host, sending it the person's password hash. A path starting with \\ or //, with either slash, mixed or percent-encoded, is refused before anything looks at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: url_missing fires only once a check saw the text A check reads the page's HTML without running its scripts, so on a page its scripts draw the text looked gone from the first check: the wait answered "already" and the bot told the person, say, that the shoes were back in stock when they were not. Like bot_idle's sawBusy, the condition now keeps sawText and fires only after a check found the text and a later one does not. A wait made while the text is not on the page says so, for the bot to tell the person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: a sleeping Cloud wakes every 30 minutes while a wait is open Waits were left out of the wake schedule, so a My Cloud that slept never checked them. While a wait is open the home's nextDueAt now includes a time 30 minutes on: the home may still sleep (a page is due every minute, which would keep it awake), and the Admin wakes it to check about every half hour. The wait's answer tells the bot the message can come up to 30 minutes late. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * waits: plain words in the wait card and the bot's refusals Following #3865: the refusals say MausBot and "a private desktop or a cloud desktop" instead of OpenMausBot and Local VM, and each error says what to do next (guests leave out follow_up, a bot waits for another bot rather than itself, a program wait on a computer that can't list its programs waits for a file or a page, a private address takes a page on the public web, a vanished bot is picked again from list_bots). The card's failed Cancel says "Couldn't cancel the wait. Try again, or ask {name} to stop it." in place of a raw error, and a Cancel that finds the wait already ended shows no error: the card then says how it ended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: Korean says {app} like the other packs, and the release's hashes follow #3865's English main fails pnpm i18n:check with 128 problems from three changes landing together. #3852's Korean was written before #3865 turned OpenMausBot into {app}, so 110 Korean lines lost a placeholder; the 0.1.133 release had recorded source hashes that #3865's English then changed. As #3865 did for every other pack, Korean's OpenMausBot becomes {app} (106 lines; MausBot ends in a consonant too, so the particles stay right). Four lines that swap can't fix fall back to English until the next translation run: the three VPS desktop lines #3865 reworded and dropped from every pack, and the same-machine setup line, which names the app twice where the English now names it once. The 18 stale hashes are refreshed: approval.status.timedOut (15 packs) and German approval.status.expired changed punctuation only, and the three Chinese environment errors already carry #3865's next step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(touch): the calendar's resize handle lives in CalendarEventCard now #3863 moved the call event's mouse drag-resize handle from RoutineCalendarPage.tsx into routines/CalendarEventCard.tsx, but the touch test's not-an-action entry still named the old file, so it reported the handle as a hover-only action and its own entry as stale. main never ran it: its locale check failed first. The entry now names the new file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 6 天前 | |
feat(triggers): set up schedules and webhooks from chat, manage them in one place A trigger is "when something happens, a bot does something". A bot now sets one up from chat with create_trigger in the same turn, at every access level, with no confirmation card. The conversation shows a live trigger card (what fires it, who does what, next run or last fire) with Edit, Pause, Undo, Copy link and Open in Triggers. Triggers, first in the sidebar in every mode, lists schedules and webhooks with a calendar and the run history. - Tools: list_triggers, create_trigger, manage_trigger replace list_routines, propose_routine and propose_routine_action. - A bot-made webhook's secret never reaches the transcript; the person mints the link with Copy link. - Deleted: the footer Triggers pop-up and triggersOpen, the footer Routines and Triggers rows, the standalone Webhooks panel and tab, the routine Confirm path (SELF_ROUTINE_CAP, the pending submit outcome, the composer's routine Confirm), and per-run cards in a chat that holds the live card. - routines.json, webhooks.json, webhook URLs and /hooks/* are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 天前 | |
Webhooks: one admission check, no secret to the room sink, room can be cleared - dispatch() kept its own copy of every check admit() now holds (pause, missing bot, event type, duplicates, queue depth, rate). Both delivery paths go through admit(), which returns the delivery id or the finished ignored/duplicate receipt, so the receipt is no longer rebuilt from the last attempt. - The room sink got a spread of the stored trigger, which carries the secret's hash and, since secrets are kept, its sealed copy. It gets the public trigger. - An edit with groupId null takes the room off, so a room webhook can go back to posting in its own thread. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 16 天前 | |
Chat widgets: draw charts with the app's Vega-Lite pipeline A widget Chart becomes a Vega-Lite spec (shared/widget-chart.ts) drawn by vega-embed with the one config every OMB chart uses, instead of a hand-drawn SVG in skin colours. Widget charts now share the Data panel's palette, type and hairlines, get hover tips and per-mark screen-reader labels, and the server can render the same spec headless. The canonical node is unchanged, so phones are unaffected. Rows and series are keyed by position, so duplicate row names stay separate bands and duplicate labels keep their own colours. Stacked bars keep list order, lines break at missing values, and the height rule (height, else aspect ratio, else 160; 80 to 400) is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 | |
Smaller agents tool list: compact schemas, action tools, fewer tools where a turn can't use them (#3773) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Smaller agents tool list: compact schemas, action tools, fewer tools where a turn can't use them (#3773) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 | |
Merge #4208 at 813b1f70c | 19 小时前 | |
Merge origin/main into #2416 tools layout; fit the toolbar under the collapsible Tools header The layout row moves to AppearanceSelectRows so SettingsModal stays at its ratchet, and the toolbar applies to main's labeled Tools section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
fix(move): bring a Windows PC's paths over to My Cloud and say what stayed behind A move from the Windows app restored C:\ paths onto a Linux Cloud: routine prompts, standing instructions and memory still named the PC's data folder, bots kept working folders that do not exist there (turns failed before the engine started), the data-folder match was case-sensitive (c:\ vs C:\), and nothing told the person which folders and files did not come over. - Restore rewrites the source data folder wherever it is written, case insensitively for Windows sources: path fields as before, plus bot instructions (and their SOUL.md mirror), room instructions, routine prompts and memory files. Only that exact prefix changes; the rest of the text is kept, with its separators turned into this computer's. - From another kind of computer (Windows to Linux or back), a bot's, room's or conversation's working folder outside that data folder is cleared, with the engine sessions tied to it, so it starts in its own folder. - Those folders and the files instructions name there are kept in the restore receipt (up to 20), served with the copy status, and the desktop says so in one line after the move. - The lending switch and its copy say "this computer" instead of "this Mac". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
fix(skills): quote-safe frontmatter round-trip and visible sibling skips on import The 2026-10-13 skill audit caught three importer defects: - parseSkillMd stripped a leading or trailing quote from every frontmatter value, so a description ending in a quote imported truncated (prove-it-works), and written skills re-emitted parsed descriptions raw, so any description containing ': ' came back out as invalid YAML (show-me-your-work). The reader now unwraps only a matched quote pair (unescaping " \ \n, folding '') and a new yamlFrontmatterValue emitter double-quotes anything ambiguous, used by writtenSkillMd, which now round-trips the description, not just the name. - writtenSkillDescription stripped surrounding quotes before trimming, so padded input kept its quotes into the stored frontmatter; trim first. - fetchSkillDir listed only markdown files, so non-markdown siblings and subfolders never reached the install and skippedFiles reported [] while their references were silently dropped. Every other folder entry now comes back as a path-only file and lands in skippedFiles/warnings; SKILL.md is always downloaded even past the markdown cap. Imported SKILL.md bytes were already stored verbatim, so extra frontmatter fields (disable-model-invocation, allowed-tools) survive install; a test now pins that. | 21 天前 | |
chore(skills): trim new comments to the AGENTS.md comment rules Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 | |
X card: every call used reads as used up; analytics docs list treg Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 14 天前 | |
Only the desktop app's own server may use this computer A second OpenMausBot server on the same Mac (a copy run from source) read the desktop app's driver record from ~/Library/Application Support and drove the person's signed-in Chrome with no prompt, while its own panel said this computer was not ready. - The desktop hands the driver connection to the one server it launched, over that child's private utility-process port, and again on every change. The server reads this computer only from that message; no file, environment variable or route supplies it. - On Auto, the bot's own browser is mounted beside this computer, and web work goes to it first, then a cloud computer, then a connected app; the person's own browser or screen comes last. - Before a bot's first action on the person's own computer in a request, unless they picked it as the place, they are asked once in plain words at every approval level, "Just do it" included. No is an answer, not a failure. - Plain words for every reason this computer can't be used, and in what the bot tells the person; Boat stays credited for cloud desktops. Translated in all locales. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 | |
Only the desktop app's own server may use this computer A second OpenMausBot server on the same Mac (a copy run from source) read the desktop app's driver record from ~/Library/Application Support and drove the person's signed-in Chrome with no prompt, while its own panel said this computer was not ready. - The desktop hands the driver connection to the one server it launched, over that child's private utility-process port, and again on every change. The server reads this computer only from that message; no file, environment variable or route supplies it. - On Auto, the bot's own browser is mounted beside this computer, and web work goes to it first, then a cloud computer, then a connected app; the person's own browser or screen comes last. - Before a bot's first action on the person's own computer in a request, unless they picked it as the place, they are asked once in plain words at every approval level, "Just do it" included. No is an answer, not a failure. - Plain words for every reason this computer can't be used, and in what the bot tells the person; Boat stays credited for cloud desktops. Translated in all locales. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 8 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 天前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 7 天前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 21 天前 | ||
| 7 天前 | ||
| 21 天前 | ||
| 1 天前 | ||
| 9 天前 | ||
| 21 天前 | ||
| 21 天前 | ||
| 1 天前 | ||
| 3 天前 | ||
| 2 天前 | ||
| 8 天前 | ||
| 13 天前 | ||
| 13 天前 | ||
| 1 天前 | ||
| 13 天前 | ||
| 13 天前 | ||
| 13 天前 | ||
| 22 天前 | ||
| 21 天前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 27 天前 | ||
| 9 天前 | ||
| 22 天前 | ||
| 8 天前 | ||
| 22 天前 | ||
| 21 天前 | ||
| 1 个月前 | ||
| 5 天前 | ||
| 5 天前 | ||
| 22 天前 | ||
| 21 天前 | ||
| 10 天前 | ||
| 3 天前 | ||
| 20 天前 | ||
| 7 天前 | ||
| 7 天前 | ||
| 1 天前 | ||
| 9 天前 | ||
| 26 天前 | ||
| 26 天前 | ||
| 22 天前 | ||
| 8 天前 | ||
| 15 天前 | ||
| 4 天前 | ||
| 9 天前 | ||
| 3 天前 | ||
| 5 天前 | ||
| 5 天前 | ||
| 1 个月前 | ||
| 1 天前 | ||
| 22 天前 | ||
| 2 天前 | ||
| 11 天前 | ||
| 4 天前 | ||
| 4 天前 | ||
| 8 天前 | ||
| 1 天前 | ||
| 1 天前 | ||
| 22 天前 | ||
| 15 天前 | ||
| 1 天前 | ||
| 21 天前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 1 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 19 小时前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 天前 | ||
| 1 天前 | ||
| 2 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 20 天前 | ||
| 20 天前 | ||
| 17 天前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 2 个月前 | ||
| 9 天前 | ||
| 3 天前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 8 天前 | ||
| 22 小时前 | ||
| 3 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 19 天前 | ||
| 23 小时前 | ||
| 23 小时前 | ||
| 13 天前 | ||
| 24 天前 | ||
| 13 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 18 天前 | ||
| 18 天前 | ||
| 5 天前 | ||
| 5 天前 | ||
| 1 天前 | ||
| 1 天前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 7 天前 | ||
| 7 天前 | ||
| 9 天前 | ||
| 9 天前 | ||
| 7 天前 | ||
| 29 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 14 天前 | ||
| 15 天前 | ||
| 15 天前 | ||
| 20 小时前 | ||
| 18 天前 | ||
| 24 天前 | ||
| 21 天前 | ||
| 12 天前 | ||
| 23 小时前 | ||
| 23 小时前 | ||
| 17 天前 | ||
| 2 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 天前 | ||
| 2 天前 | ||
| 6 天前 | ||
| 8 天前 | ||
| 20 天前 | ||
| 5 天前 | ||
| 22 天前 | ||
| 1 天前 | ||
| 12 天前 | ||
| 21 天前 | ||
| 25 天前 | ||
| 22 天前 | ||
| 22 小时前 | ||
| 1 个月前 | ||
| 15 天前 | ||
| 4 天前 | ||
| 4 天前 | ||
| 24 天前 | ||
| 24 天前 | ||
| 29 天前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 9 天前 | ||
| 3 天前 | ||
| 22 天前 | ||
| 6 天前 | ||
| 23 天前 | ||
| 7 天前 | ||
| 20 天前 | ||
| 22 天前 | ||
| 8 天前 | ||
| 8 天前 | ||
| 13 天前 | ||
| 7 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 15 天前 | ||
| 6 天前 | ||
| 6 天前 | ||
| 19 天前 | ||
| 16 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 7 天前 | ||
| 7 天前 | ||
| 19 小时前 | ||
| 21 天前 | ||
| 21 天前 | ||
| 21 天前 | ||
| 21 天前 | ||
| 14 天前 | ||
| 8 天前 | ||
| 8 天前 |