Integrate the shared Agent room, durable outbox, cursor replay and read state on iPhone and iPad. Reuse message rendering with native messaging layout and expandable tool details. Validated with 58 Xcode package tests, six Simulator UI scenarios, read-only production connectivity and independent review.
Sybil for iOS and Mac Catalyst
Run just run for the iPhone simulator, or just run-mac for Mac Catalyst.
just build-mac builds without launching the Mac app. Both regenerate the Xcode
project from project.yml. The Mac recipes use ad-hoc signing for local development;
release/archive signing settings are unchanged.
The conversation sidebar includes Search chats and web searches on iPhone,
iPad, and Mac. It searches all saved history by title, conversation text, and saved
web-search query/answer, with single-line excerpts that bold matching words and
truncate in the middle. Search waits briefly while typing,
cancels superseded requests, and leaves the current conversation open. Clear the
field to return to recent items. Searches use word prefixes (for example, plan
finds planning); if more than 100 items match, refine the query.
Sybil Agent
The permanent Sybil Agent sidebar item opens the persistent room on both
phone and iPad. It uses the configured Sybil API URL (including an explicit
/api path) and token. The room stays subscribed while other chats are selected;
foreground and network recovery replay from the last merged cursor. Shared unread
counts include only public assistant replies and are acknowledged after the
visible transcript reaches the bottom and its entrance animation finishes.
Multiple messages can be queued while the Agent works. The local outbox is saved atomically under Application Support before submission and is scoped to the API base URL. An interrupted send stays on its original bubble with Retry, retaining its request ID and timestamp across relaunch. A canonical server echo confirms it even if the HTTP acknowledgement is lost. Tool cards expand to show input, result, and error details. Attachments and model selection belong to ordinary chats.
Agent contracts remain in ../docs/api/rest.md and
../docs/api/streaming-chat.md; this client requires no backend deployment.
Agent regression and Simulator checks
Run these commands from this worktree's ios/ directory:
just build
just test
just run
just screenshot build/agent-evidence/simulator.png
just test runs reducer, cursor, outbox, presentation, shared-read and lifecycle
regressions along with the existing app tests through Xcode on iPhone 16e.
For interactive UI coverage, start the local fixture (Python with aiohttp):
python3 Tests/Fixtures/agent_server.py
In a second terminal, run:
just generate
xcodebuild test -scheme SybilAgentUI \
-destination 'platform=iOS Simulator,name=iPhone 16e,OS=latest' \
-parallel-testing-enabled NO \
-resultBundlePath build/agent-evidence/phone-ui.xcresult
The fixture binds only to 127.0.0.1:8799, uses fixture-token, and never contacts
external services. UI tests exercise the real REST/WebSocket client and retain
screenshots in the result bundle. They cover queued submissions, uncertain
admission/retry, tools, asynchronous replies, inactive sidebar unread counts,
shared reads, reconnect/malformed replay, foreground recovery, long-history scroll
anchors and multiline keyboard layout. The launch arguments select the fixture
through ordinary API settings; no fixture mode is compiled into the application.
Use a fresh result-bundle path for each run. Check the same UI on iPad and with
Simulator Reduce Motion enabled before release.
Quick Question on macOS
While the Catalyst app is running, Option+Space toggles a floating Quick Question panel, including over other applications. The prompt is focused as soon as it opens, with any existing prompt selected so typing replaces it. The same select-on-open behavior applies to Quick Question on iPhone and iPad. Return submits; Shift+Return inserts a new line. Escape, a second Option+Space, the close button, or clicking outside dismisses it. Hiding the panel preserves the draft and answer and lets an in-flight answer finish. Open in Chat saves the question and answer in the regular workspace.
Quick Question defaults to OpenAI chat-latest on iPhone, iPad, and Mac. Its saved
provider/model selection takes precedence and is separate from regular chat preferences.
The regular Mac chat/search composer uses the same Return/Shift+Return rules. Holding Return does not repeatedly submit. On iOS, Return submits from Quick Question, while the normal chat/search composer continues to use Return for a new line.
Closing the last Mac window leaves Sybil running, so Option+Space still works. Use Sybil → Quit Sybil or Command+Q to quit the application. The Catalyst build opts out of automatic termination, and the native shortcut service holds a matching automatic-termination activity until it stops. No hidden keep-alive window or sleep-preventing activity is used. Mac scene support also allows the workspace to reopen after its last window is closed.
When Catalyst is backgrounded, opening Quick Question first requests app activation and waits for UIKit to enter the foreground before creating or ordering the native panel. Presentation is deferred out of the hotkey event callback. Pressing Option+Space again cancels a pending presentation. Dismissing a panel that required activation returns focus to the previous app; explicitly opening the workspace keeps focus in Sybil.
On Mac, Command+N starts a new chat in the focused workspace, or opens a new workspace window when none are open. Command+Shift+N always opens a new window, including while signed out. Command+Option+N starts a new search; iOS retains its existing Command+Shift+N search shortcut.
The shortcut is also shown under File → Quick Question. If another application already owns Option+Space, the panel reports that the shortcut is unavailable; the menu item can still be clicked. No Accessibility or Input Monitoring grant is needed for the registered hotkey.
The native AppKit panel and Carbon hotkey live in Apps/SybilMacQuickQuestion,
a macOS bundle embedded only for the Mac Catalyst destination. Catalyst loads it
through the Foundation-only SybilMacQuickQuestionBridge contract. Requests,
provider/model preferences, streaming, and conversion to chat remain in the
existing SybilViewModel; there is no separate backend or API contract. The panel
uses AppKit controls rather than trying to load the macOS SwiftUI runtime into a
Catalyst process.
The iPhone/iPad app keeps its existing Quick Question sheet and Home Screen quick action, and does not build or embed the macOS helper.
Verification
just test: existing Swift package tests on the iPhone simulator.- From
Packages/Sybil, runxcodebuild test -scheme Sybil -destination 'platform=macOS,variant=Mac Catalyst' -parallel-testing-enabled NOfor package tests including the Catalyst panel controller. - For a manual Mac check, open the panel from another app, type immediately, submit, hide/reopen during streaming, and verify Escape/outside-click dismissal returns input to the previous app. Check a second display and a full-screen Space when available.
- Close every Mac window, invoke Option+Space, and verify the saved question and answer remain available. Reopen the workspace from the panel, then explicitly quit with Command+Q. Rebuild and relaunch after changing lifecycle plist keys.
- In both Mac and iOS Quick Question, reopen an existing prompt and type to replace it. On iOS, verify Return submits Quick Question while Return in the normal prompt adds a newline. In the Mac workspace, verify Return submits and Shift+Return adds a newline.
- Check Command+N both with a workspace open and after closing every workspace. Command+Shift+N must open another window even when one already exists, and Command+Option+N must start a search without opening a window.
- With all workspace windows closed, switch to another app and repeatedly open
and dismiss Quick Question, including two quick Option+Space presses while it
is opening. Check that no late panel appears after cancellation and that no
UINSAppLifecycleStateRunningNoOpenWindowsassertion occurs.