diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97ff0ad53..d718cb561 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,11 @@ makes a PR easy to merge. Read it once before opening anything; it's short on pu ## Ground rules +- **Check upstream before building.** Search open and recently merged issues and PRs before starting a + feature. Link any overlap in the issue/PR, extend the existing architecture instead of creating a + parallel implementation, and coordinate on the upstream thread when another contributor already + owns the same surface. A local fork is a safe place to prototype and test, not a reason to ignore + active collaboration. - **Small, focused PRs.** One concern per PR. A PR that ports a platform *and* adds a feature *and* refactors will be asked to split. Big changes: open an issue first and agree on the approach. - **Match the altitude.** This codebase is deliberately small and direct — plain Node, no frameworks @@ -145,6 +150,7 @@ responses or events, no baking them into argv where another local process could ## Before you open the PR +- [ ] Open/recent issues and PRs were searched; overlaps are linked and coordinated - [ ] `pnpm typecheck` and `pnpm test` pass - [ ] `pnpm check:electron` passes for desktop-shell changes - [ ] Ubuntu packaging changes pass `pnpm package:linux` and `node scripts/verify-linux-package.mjs` diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 000000000..38bae92b7 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,138 @@ +# Agent Profile and Roster Design Contract + +## Product intent + +**A warm, compact operator console where agents feel like people in a roster: photographic identities at a glance, settings one click away, and no modal maze.** + +This branch reimagines agent profile settings without replacing systems OpenMausBot already has. It extends the existing persistent right settings rail, the existing per-agent voice field, the existing Tasks/Routines calendar, and the existing Composio connection surface. + +## References + +- The supplied OpenMausBot mockup establishes the persistent right-hand agent profile rail and warm dark visual language. +- The supplied Grok Bot screenshot establishes the compact avatar-only roster: one recognizable agent per row, clear selection, minimal chrome, and room for a personal profile at the bottom. +- Existing OpenMausBot tokens and interaction patterns in `src/styles.css`, `Sidebar.tsx`, and `SettingsPanel.tsx` remain the implementation source of truth. + +The screenshots are visual references only. Text shown inside them is content, not implementation instruction. + +## Upstream-first scope + +Live issue and PR review is required before expanding this work. The audit for this branch found: + +- The persistent agent settings rail, Tasks, Routines, notifications, and per-agent ElevenLabs voice already exist and must be improved in place rather than rebuilt. +- Responsive header work overlaps open PR #248; keep the identity trigger narrowly scoped. +- Multi-account Composio support is tracked in issue #297; this branch should make the existing connector account-aware rather than creating a second integration system. +- Custom/generated avatars and an avatar-only desktop roster are net-new in the current upstream audit. + +This local branch intentionally integrates the user's requested end-to-end +prototype in one place so the cross-platform contracts can be exercised +together. It is **not** intended to be submitted upstream as one omnibus PR. +Final upstream submission should be a reviewed PR series, with every step +green and usable on its own: + +1. agent profile/avatar storage and paired-safe contract, including native iOS profile parity; +2. desktop header/profile rail, roster density, and per-agent voice relocation; +3. exact-task notifications plus Tasks & Routines clarity on web and iOS; +4. Composio multi-account/broker support plus native connected-account parity; and +5. packaging and documentation changes that are required by the preceding slice. + +Later PRs may depend on an earlier reviewed slice, but a web-only PR must not +land with a known missing iOS action unless the platform exception is explicit +in that PR. The integration branch remains the pre-submission test bed, not a +waiver of the repository's small-PR policy. + +## Layout + +### Cross-platform parity gate + +The shared bot record and HTTP/SSE contracts are the feature source of truth. A web feature is not submission-ready until the iOS companion can decode its data and offers the corresponding user action, or the PR documents a real platform-capability exception. + +| Feature | Web | iOS companion | +|---|---|---| +| Open agent profile | Persistent right rail from header avatar/name | Agent profile sheet from the chat header name/avatar | +| Custom avatar and shape | Upload/generate and roster rendering | Upload/generate and native roster/chat rendering | +| Per-agent voice | Shared workspace credential plus agent voice selection/preview | Agent voice selection/preview through the paired server | +| Tasks and routines | Calendar, routine editor, webhook view | Native task/routine list and editor with the same terminology and receipts | +| Notifications | Exact agent/task navigation | Exact agent/task navigation from the system notification response | +| Connected accounts | Multi-account aliases and explicit selection | Account-aware status and management through paired, renderer-neutral endpoints | +| Sidebar density | 320/272/80 px desktop modes | Not copied literally on iPhone: the roster is already a separate screen; custom avatars and compact native rows provide the identity parity. An iPad split-view treatment can adopt the same modes later without blocking phone parity. | + +Workspace secret entry remains computer-only on iOS. This is a deliberate security boundary: losing the phone must not grant control of provider credentials or pairing policy. iOS may select an agent voice, request a preview, and generate an avatar through the paired server without receiving stored API keys. + +### Agent roster + +The desktop sidebar has three persistent density modes: + +| Mode | Width | Avatar | Purpose | +|---|---:|---:|---| +| Comfortable | 320 px | 56 px | Full names, status, previews, and sections | +| Compact | 272 px | 40 px | Faster scanning with the same information hierarchy | +| Avatars only | 80 px | 44 px | Grok-like visual roster for custom icons and photos | + +- Changing mode must not change the active agent, scroll context, or conversation. +- The avatars-only rail must keep accessible names through `aria-label`/tooltips and visible focus states. +- Custom images take precedence over the mascot everywhere agent identity is primary; the mascot remains the fallback. +- Rooms may use overlapping member avatars. Overflow is expressed as `+N`, never silently dropped. +- A direct collapse/expand affordance is required; the full density selector may remain adjacent. + +### Agent profile rail + +- Clicking the selected agent's avatar **or name** in the chat header opens the existing right rail. +- The rail stays mounted beside the conversation until explicitly closed. It is not a modal and is not hidden behind a context menu. +- Identity controls appear first: avatar, shape, upload/generate action, name, title, and description. +- Agent-specific behavior follows: role/persona, model/computer, memory, Auto mode, voice, notifications, and connected apps. +- Workspace credentials such as the ElevenLabs or image-provider key remain write-only and shared. The agent profile chooses the per-agent voice/image behavior; it never exposes stored secret values. + +### Tasks and routines + +- **Task:** one agent conversation with its own context and result. +- **Routine:** a reusable schedule that starts a fresh task for every run. +- **Webhook:** an event endpoint that starts a fresh task when another app calls it. +- Users choose ordinary date/time/day controls. Do not expose cron syntax as the primary model. +- A routine inherits the selected agent's model, permissions, computer, tools, and connected apps; it does not create a parallel agent configuration. +- Run receipts remain visible and distinguish queued, active, waiting, completed, missed, failed, and cancelled states. + +## Avatar contract + +- Accepted custom upload: image files only, with existing attachment size/security limits enforced by the server. +- Supported presentation shapes: mascot/fallback, circle, rounded square, and square. +- Generated avatars use the same stored provider credential pattern as other API features. Generation failures must leave the current avatar untouched and surface a useful error. +- Uploaded/generated assets are stored by durable attachment URL; do not persist data URLs or secret-bearing remote URLs in bot records. +- Every avatar renderer needs a deterministic mascot fallback for missing, corrupt, or deleted files. + +Avatar images currently share the existing attachment store with message +images. Clearing or replacing a profile therefore clears the reference but +does not delete the file: immediate deletion could remove an image still used +by a message or another duplicated agent. A follow-up storage PR should add a +reference-aware, age-bounded orphan sweep and a workspace quota after scanning +both bot records and message attachment references. Until then, per-upload +validation and the 10 MB request cap limit individual writes, but repeated +uploads can still grow the local attachment directory; this is recorded release +debt rather than hidden behind unsafe eager deletion. + +## Voice contract + +- The shared ElevenLabs key is configured from an agent profile, but remains workspace-wide and write-only. +- Voice selection is stored on the agent (`bot.voice`). Different agents can select different voices while sharing the same key. +- A preview action must use the currently selected agent voice and report provider/configuration failures inline. +- App Settings must not maintain a competing voice-selection flow. + +## Motion, accessibility, and performance + +- Sidebar width transitions are 200 ms or less and must respect `prefers-reduced-motion` through existing global motion rules. +- Uploaded images use stable dimensions and `object-fit: cover` to prevent layout shift. +- All icon-only actions require accessible names, hover/focus explanations, and at least a 40 px effective target in the avatar rail. +- Opening the profile rail must not steal focus from an in-progress message or rename field unless the user explicitly activates a form control. +- No decorative animation is added unless it communicates working, waiting, success, or failure. + +## Visual QA checklist + +- Comfortable, compact, and avatars-only modes at desktop width. +- Avatar-only rail with mascot, uploaded portrait, generated image, room stack, selected state, unread state, and Chief of Staff state. +- Header name and avatar both open the same profile rail. +- Profile rail remains usable at the minimum supported app width and scrolls independently. +- Keyboard traversal and visible focus in every density. +- Reduced-motion behavior. +- Empty, loading, error, and provider-unconfigured states for avatar generation and voice preview. +- Tasks/Routines copy explains the relationship without requiring knowledge of cron. +- iPhone profile, roster, task/routine, notification-deep-link, voice-preview, and connected-account flows use the same shared records as the web app. +- Swift package tests and an iOS simulator build pass with old fixtures that omit every new optional field. diff --git a/companion/README.md b/companion/README.md index 60193e20d..6424bf210 100644 --- a/companion/README.md +++ b/companion/README.md @@ -31,7 +31,7 @@ upstream hardened its loopback gate. |---|---| | **Pairing** | A high-entropy QR credential plus a six-digit manual fallback, valid two minutes and single-use. Redeeming either returns a device token stored only as a SHA-256 digest. | | **Authorisation** | Every request needs that token. Full cloud-desktop access is a separate per-device capability, off by default. A rebinding page cannot obtain either. | -| **The allowlist** | Default deny, per method and path (`src/routes.ts`) — the list is every request the app makes, and nothing else. General bot/room PATCH routes stay closed; read state and approval grants use narrow verbs. A route that appears in the harness later is closed to devices until someone adds it here on purpose. | +| **The allowlist** | Default deny, per method and path (`src/routes.ts`) — the list is every request the app makes, and nothing else. General bot/room PATCH routes stay closed; profile identity, avatar, voice, routines, and account-specific connector management use narrow verbs that never return provider credentials. A route that appears in the harness later is closed to devices until someone adds it here on purpose. | | **Scrubbing** | `resumeCursors` — the harness's own provider session ids — never reach a device, whether or not the harness still sends them. | | **Discovery** | Bonjour, so a phone finds the computer by name instead of by typed address. | @@ -64,8 +64,14 @@ trusted-network-only rather than described as something it is not. request that carries one is a browser that has found this port. Refused before the token is even looked at — stricter than the harness's own rule, which allows loopback origins. -- **Hold credentials, settings, or Local VM control.** Those stay on the - machine. See `src/routes.ts` for the exact refusals and why. +- **Return provider keys, webhook secrets, or expose Local VM control.** Those + stay on the machine. A paired phone does receive the user profile (including + email), room timeout and provider-configured booleans; connector catalog and + account metadata, authorization URLs, ids, aliases, and status; voice ids, + labels, descriptions, and generated audio; plus routine definitions, prompts, + schedules, and run data. These are application data forwarded on the narrow + allowlisted routes, not provider credentials. See `src/routes.ts` for the exact + allowances and refusals. ## Running it diff --git a/docs/ios-companion.md b/docs/ios-companion.md index f3f6f4d2f..9baa6c82f 100644 --- a/docs/ios-companion.md +++ b/docs/ios-companion.md @@ -16,13 +16,25 @@ The first version includes: manual fallback, plus per-device tokens, device listing, and revocation. - Bot and room lists, paged transcripts, sending, interruption, and unread state. +- Native agent profiles opened from the chat identity: name, role, + description, agent notifications, authenticated custom avatars, avatar + generation through the computer's configured provider, and per-agent voice. +- Tasks & Routines with native date/time/day controls, lifecycle actions, and + run receipts. Each routine run creates a fresh task; no cron string reaches + the phone. +- Account-aware connected apps: aliases, add-another OAuth, refresh, and + account-specific disconnect for multiple Slack/Google accounts. - Approvals and questions, including narrow “always allow” grants. - Resumable SSE, streamed reply text, reconnect hydration, and an opt-in live computer view. +- Native notification alerts and exact `botId + threadId` routing when a user + taps one, including detached tasks reached after replay. - Markdown rendering and Keychain storage for the device token. -It is foreground-only. Push notifications, background delivery, voice, App -Store release automation, and a hosted relay are not part of this version. +The live companion connection remains foreground-oriented. Native alerts are +delivered from live or cursor-replayed frames, but closed-app APNs delivery and +a hosted relay are not part of this version. Voice selection and preview are +included; a live call mode is not. ## Runtime architecture @@ -145,9 +157,20 @@ Allowed in the first release: - Send messages, interrupt bots, answer approvals/questions, and mark chats read. - Create a basic bot. - -The write surface uses purpose-built `read` and `always-allow` endpoints. The -general bot and room `PATCH` endpoints are not reachable through the sidecar. +- Edit only the paired-safe profile fields: identity text, agent notification + preference, avatar URL/shape, voice id, and spoken-reply preference. +- Upload/fetch app-owned raster avatars (10 MB maximum) and ask the computer to + generate one using its already-configured shared image-provider key. +- List voice labels, select a per-agent voice, and receive synthesized preview + audio from the computer's shared ElevenLabs configuration. +- List/create/edit/pause/resume/run/delete routines and read their run receipts. +- List connected-app account ids/aliases/status, start external OAuth with an + explicit alias for additional accounts, and disconnect one exact account. + +The write surface uses purpose-built `read`, `always-allow`, and +`PATCH /api/bots/:id/profile` endpoints. The profile route rejects every field +outside its safe allowlist. General bot and room `PATCH` endpoints are not +reachable through the sidecar. An always-allow request succeeds only when its server-issued key is still on a pending approval for that bot, so possession of a device token is not enough to invent a broad execution grant. @@ -156,8 +179,12 @@ Intentionally refused: - API keys and provider configuration. - Pairing, device revocation, or companion lifecycle control. -- Local VM lifecycle, webhooks, connectors, routines, team import/export, and - internal peer-agent routes. +- Local VM lifecycle, webhook creation/rotation/signing secrets, team + import/export, and internal peer-agent routes. +- Bulk or implicit connected-app removal. The phone can remove only an exact + opaque account id already proven to belong to the requested toolkit/user. +- Routine-run cancellation/receipt mutation and arbitrary cron/RRULE input; + the native feature uses the existing once/selected-days schedule contract. - Cloud computer provisioning, sleep, shell execution, and screenshot APIs. The phone receives only the fresh `join` viewer URL, never the provider key. - New harness routes that have not been reviewed for phone access. @@ -221,9 +248,12 @@ xcodebuild -project OpenMausCompanion.xcodeproj \ ``` The simulator validates compilation, launch, layout, manual address parsing, -and failure states. Bonjour, Local Network permission, Tailscale routing, -Keychain behavior across a reboot, and approval delivery still require a real -iPhone pass. +profile/routine/connector screen construction, and failure states. The focused +contract suites also pin old/new avatar decoding, notification target parsing, +and every newly allowed sidecar method/path. Bonjour, Local Network permission, +Tailscale routing, Keychain behavior across a reboot, avatar upload/generation, +OAuth return, audio playback, exact-task notification taps, and approval +delivery still require a real-iPhone pass. ## Follow-on releases @@ -235,12 +265,20 @@ distribution scope: 2. **Desktop conversation parity:** task create/switch/rename/delete, SQLite search with exact-message landing, transcript export/share, reactions, and edit/version controls. Archived or hidden chat management remains desktop-only. -3. **Notifications:** native permission, live/replayed alerts, time-sensitive - approvals, badges, and background reconciliation are in the app. Closed-app - delivery still requires project-owned APNs credentials and a hosted relay; - Tailscale cannot wake a terminated iOS process. -4. **Distribution:** signing, bundle ownership, privacy declarations, +3. **Profiles and workspace parity:** paired-safe identity/avatar/voice, + Tasks & Routines, multi-account connector aliases, and exact-task + notification taps are in the app. The iPhone's compact custom-avatar roster + is the native equivalent of desktop's collapsible avatar rail; a literal + desktop sidebar and iPad split view are outside this release. Lock-screen + Live Activities retain the deterministic mascot because the widget extension + is deliberately not given the paired-device token or private avatar bytes. +4. **Notifications:** native permission, live/replayed alerts, time-sensitive + approvals, badges, exact-task routing, and background reconciliation are in + the app. Closed-app delivery still requires project-owned APNs credentials + and a hosted relay; Tailscale cannot wake a terminated iOS process. +5. **Distribution:** signing, bundle ownership, privacy declarations, TestFlight, and App Store review material. Swift tests and an unsigned simulator build already run in the repository CI. -5. **Optional expansion:** voice/call mode, Local VM or host-computer - interaction, or a hosted relay. Each requires its own threat-model review. +6. **Optional expansion:** live call mode, webhook administration, Local VM or + host-computer interaction, iPad split view, or a hosted relay. Each requires + its own threat-model and platform review. diff --git a/ios/AppStore/RELEASE.md b/ios/AppStore/RELEASE.md index 5b3d7abfa..16e604850 100644 --- a/ios/AppStore/RELEASE.md +++ b/ios/AppStore/RELEASE.md @@ -18,7 +18,11 @@ The app is native Swift and uses XcodeGen; EAS commands do not apply. 4. Increment `CURRENT_PROJECT_VERSION` for every upload. Update `MARKETING_VERSION` only for a new App Store version. 5. Archive a generic iOS device build and validate it in Xcode Organizer. 6. Upload to App Store Connect and distribute to internal TestFlight testers first. -7. Complete a real-iPhone pass for pairing, Bonjour permission, Keychain restore, Tailscale, approvals, background/foreground reconciliation, and transcript sharing. +7. Complete the real-iPhone matrix in [`../TESTING.md`](../TESTING.md): pairing, Bonjour permission, + Keychain restore, Tailscale, approvals, background reconciliation, avatar + upload/generation, per-agent voice/default validation, routine location/expired-run + rules and receipts, multi-account aliases/account-specific disconnect, exact-task + notification routing, and sharing. 8. After internal testing, submit to an external TestFlight group before App Review. ## App Store Connect diff --git a/ios/AppStore/en-US/release_notes.txt b/ios/AppStore/en-US/release_notes.txt index 8de8b9ee5..ce3a6c811 100644 --- a/ios/AppStore/en-US/release_notes.txt +++ b/ios/AppStore/en-US/release_notes.txt @@ -1,7 +1,10 @@ Welcome to OpenMausMobile 1.0. • Pair securely with your OpenMausBot computer -• Chat with bots and rooms -• Answer approvals and questions +• Chat with agents and rooms; answer approvals and questions +• Give each agent a custom uploaded or generated avatar and shape +• Edit agent identity, notifications, and per-agent voice settings +• Create, edit, pause, resume, run, and review Tasks & Routines, including computer or available Cloud VM execution +• Connect multiple Slack or Google accounts with clear account aliases +• Open the exact detached task when you tap an agent notification • Search, manage tasks, edit versions, react, and share transcripts -• Follow live work and reconnect without losing events diff --git a/ios/AppStore/review-notes.md b/ios/AppStore/review-notes.md index 0dea5091d..5efd08505 100644 --- a/ios/AppStore/review-notes.md +++ b/ios/AppStore/review-notes.md @@ -21,3 +21,12 @@ session and does not use or store the provider API key. The phone and computer must be on the same trusted network. Alternatively, both may be signed into the same Tailscale network and the reviewer may enter the computer's `.ts.net` MagicDNS name. No purchase or subscription is required. The computer is the source of bot data and credentials; the developer cannot provide a universal demo account without routing reviewers into someone else's private computer. + + +Agent profile, avatar upload/generation, voice preview, routines, and connected-app +account management call only the paired computer. API/OAuth/provider keys are never +returned to or stored by the iOS app. OAuth authorization opens the provider URL +externally and returns to the app; each additional account requires an alias. Webhook +creation and signing-secret rotation remain computer-only. A routine can run on the +paired computer or an available Cloud VM; iOS reads only configured/availability +status and never receives the VM credential. diff --git a/ios/README.md b/ios/README.md index 53b9a294c..4c97dd2b2 100644 --- a/ios/README.md +++ b/ios/README.md @@ -55,6 +55,10 @@ ios/ Discovery.swift NWBrowser for _openmausbot._tcp Keychain.swift the device token MausAvatar.swift the mascot face, in the desktop's palette + BotAvatarView.swift authenticated custom image + mascot fallback + AgentProfileView.swift identity, avatar generation/upload, per-agent voice + TasksRoutinesView.swift schedules and run receipts, without cron syntax + ConnectedAppsView.swift account aliases and account-specific disconnect PairingView.swift QR handoff, discovery, address and code fallback PairingScanner.swift native QR camera, permission and recovery UI Glass.swift the one material the chrome is made of (Liquid Glass on 26+) @@ -66,7 +70,7 @@ ios/ ChatView.swift transcript, tailed bubbles, approval cards, composer ComputerView.swift opt-in live view of a bot's computer MarkdownText.swift the supported Markdown presentation layer - SettingsView.swift status, and unpair + SettingsView.swift status, workspace feature entry points, and unpair ``` ## Building @@ -123,13 +127,20 @@ here by simply not having the methods: | Send messages, make a bot or a room | Manage pairing or revoke devices | | **Answer approvals and questions** | Drive the Local VM or this computer | | Interrupt a bot, mark chats read | Reach `/api/internal/*` | +| Edit the narrow safe agent profile subset | General bot PATCH / execution policy | +| Upload/fetch app-owned avatars; request configured image generation | Read or write image-provider keys | +| Choose/preview a valid per-agent or configured workspace voice | Read or write the shared ElevenLabs key | +| List/create/edit/pause/run/delete routines, choose an available run location, and read receipts | Create/rotate webhooks or their secrets | +| Fetch all connected-app statuses, add aliased accounts, disconnect one exact account | Read OAuth/provider credentials or remove all accounts implicitly | | Fetch screen images on demand | Load the packaged desktop UI | | Open an explicitly enabled cloud desktop | Provision, sleep or run shell commands on cloud computers | -Marking a chat read and remembering an approval use purpose-built server -verbs. The sidecar does not expose the general bot or room `PATCH` routes, -because those can also change execution policy, computers, connected apps, and -working directories. +Marking a chat read, remembering an approval, and editing a profile use +purpose-built server verbs. `PATCH /api/bots/:id/profile` rejects every field +except name, title, description, notifications, avatar URL/shape, voice, and +spoken-reply preference. The sidecar does not expose the general bot or room +`PATCH` routes, because those can also change execution policy, computers, +connected-app permission, and working directories. Companion settings stay on the computer on purpose: losing the phone must not mean losing the ability to lock it out. @@ -161,6 +172,16 @@ the host computer remain unreachable through the companion. - **No optimistic state.** Actions call the harness and let the event stream deliver the result. A phone that draws its own version of what just happened is a phone that disagrees with the laptop. +- **Native density, not a desktop sidebar copied onto a phone.** The iPhone roster + is already a compact, scrollable list and now uses custom agent photos at identity + size. Desktop's collapsible avatar-only rail has no literal iPhone equivalent; + this is the accepted platform-capability exception. iPad split view is not part + of this release. +- **Lock-screen identity stays a mascot.** The Live Activity/widget extension is + not given the paired-device bearer token or an App Group copy of private avatar + bytes. Duplicating that credential into an extension would widen the trust + boundary, so lock-screen surfaces keep the deterministic color mascot while + authenticated in-app identity surfaces use custom images. - **Messaging-app shape, not settings-list shape.** Mascot faces at roster size, the bot's role as a chip beside its name, timestamps that say "Yesterday" rather than a date, and a gap-based separator in the transcript instead of a @@ -182,9 +203,12 @@ the host computer remain unreachable through the companion. The live connection is foreground-only. Notification frames produce native banners, sounds, time-sensitive approval alerts, and an app badge while connected; the resume cursor replays alerts missed during a short background pause. There is -no APNs delivery after the app is terminated, no voice/call mode, and no hosted relay. -Task management, SQLite transcript search, -transcript sharing, reactions, and edit/version controls use narrow companion -routes and the computer remains the source of truth. Tailscale is supported +no APNs delivery after the app is terminated, no live call mode, and no hosted relay. +Per-agent ElevenLabs voice selection and preview are available, but all synthesis +still happens on the paired computer with its shared key. Tasks, routines, connected +app aliases, SQLite transcript search, transcript sharing, reactions, and +edit/version controls use narrow companion routes and the computer remains the +source of truth. Webhook creation/secret rotation, provider keys, pairing/revocation, +Local VM, and arbitrary execution policy remain computer-only. Tailscale is supported through manual MagicDNS entry; it is not a dependency and OpenMausBot does not operate a cloud copy of local data. diff --git a/ios/TESTING.md b/ios/TESTING.md index 88b4c61a9..5191ed004 100644 --- a/ios/TESTING.md +++ b/ios/TESTING.md @@ -220,7 +220,29 @@ On the phone, in order: then come back. The transcript should catch up *without* a visible reload — that is the resumable stream doing its job. Watch the harness log to confirm it replayed rather than re-hydrated. -6. **Revoke.** Remove the device in Settings → Companion on the computer. The +6. **Profile parity.** Tap an agent's name in chat. Change identity fields and + notifications; upload each supported raster type (including one rejected over + 10 MB), switch all four shapes, clear the image, and generate once with and once + without the desktop image key configured. Relaunch and confirm the roster/header. +7. **Voice parity.** With the shared ElevenLabs key configured on the computer, + first leave the workspace default voice empty: iOS must require an agent-specific + voice before it enables spoken replies or preview. Then select a voice, enable + spoken replies, and preview it. Repeat with a workspace default configured. + Confirm no key appears in device logs, network response JSON, defaults, or Keychain. +8. **Tasks & Routines.** Create one-time and selected-day routines with native + date/time controls. Confirm the run-location picker offers This computer and only + enables Cloud VM when Box is configured and its agent is available; an existing + cloud routine must retain its location while unavailable. Edit, pause, resume, run + now, and delete. Confirm an expired one-time routine has no Resume action, each run + creates a fresh task, and receipts show queued/running/waiting/completed/failed. +9. **Connected accounts.** Connect Slack or Google, add a second account with an + explicit alias, return from external OAuth, refresh, and disconnect only one + alias. Confirm the other remains connected and that one refresh returns every + connected account, including services outside the current visible catalog page. +10. **Notification routing.** Create two detached tasks for one agent, trigger a + notification from the non-active task, tap it, and confirm iOS activates that + exact `botId + threadId`, not merely the agent's current task. +11. **Revoke.** Remove the device in Settings → Companion on the computer. The phone should land on "This phone was unpaired" rather than silently failing. --- @@ -274,8 +296,13 @@ Not built yet, so not bugs: - **Nothing arrives after the app is terminated.** Live and replayed notification frames now become native alerts and badges, but closed-app push still needs an APNs relay with project-owned Apple credentials. -- **No voice or routine management.** Tasks, SQLite transcript search/export, - reactions, and edit/version switching are available from the conversation UI. +- **No closed-app APNs relay or call mode.** Per-agent voice selection/preview, + Tasks & Routines, and multi-account connected-app management are available. +- **Webhook management is computer-only.** Creating an internet-reachable trigger + or rotating its signing secret is outside the paired-phone allowlist; webhook + run receipts are still visible on iOS. +- **No literal desktop avatar-only sidebar.** iPhone uses a compact custom-avatar + roster; iPad split view is not part of this release. (Two entries that used to sit on this list have since shipped: replies stream token by token as the provider emits them, and each bot has a computer panel —