Canary Mobile App
This is the small PWA served by canary app. It is meant for the thing you want
on a phone: is the local IBKR setup alive, what does the account look like, and
is the portfolio stress read asking for attention?
Monitor is glance-only. Depth lives in tap-through sheets opened from the
instrument that reports it: the Protection window opens the Protection sheet,
the Rules window opens the rules checklist, and the movers row opens the
Underlyings book.
The Protection sheet shows proposal-bound market-event chips when halt, LULD,
borrow, fee, or Reg SHO flags affect current protection proposals. Active halt
and active LULD chips are hard blockers; recent halt/LULD and borrow/Reg SHO/fee
chips are evidence tags. A reducing short BUY proposal is labeled Buy to cover. Option-exercise opportunities are exception-shaped: an advisory bar at
the top of that sheet when the daemon serves any, and nothing at all when it
does not.
The Underlyings sheet shows held-name market-event tags in the hero and row
tags for affected symbols, including long holdings where borrow pressure is
observational squeeze context. Stale or unknown sources stay visible with
source/as-of detail instead of disappearing.
Settings is the instrument's back panel: engraved banks for Notifications,
Workflows, System (process evidence, moved here from the Alerts log), and
Status, plus the stamped type plate at the foot. Orders is a read-only journal
of order bars; submission stays on the desk.
A Monitor window whose served source health is anything but ok goes dead
rather than calm: no severity tint, the caption naming the served fault word,
and the last-good figure kept with its served as-of. The lamp-test stamp names
the same faults, so a dead window can never sit under a stamp that says every
feed is fine.
The regime grid gives every cluster the daemon ranks a window of its own —
Breadth, Volatility, Credit, Dealer gamma, Funding, FX — in fixed positions.
Each window's third line is the served trip anchor: the daemon's own compact
trigger wording, or the served spot/γ-zero pair for dealer gamma. A window
whose producer serves no trigger stays reading-only; the SPA never supplies a
cutoff of its own. The master subline's "N red" clause now fires only for a
red the panel genuinely cannot show.
The account strip always states the mode. LIVE renders in the plate's
engraved register; PAPER is a deliberate identity exception in the TWS
simulated-trading convention (red field, white text) and uses its own modifier
class rather than a severity lamp — paper is a different desk, not a warning.
Account and position panels use the daemon's account, availability, and
freshness fields directly. A real zero remains a number, a value the broker did
not send shows --, and Canary never supplies USD when the base currency is
unknown. Old position rows may remain visible for reference, but the position
counts, portfolio verdict, Greeks, exposure chart, and P/L summaries stay
unavailable until the selected account has a current position result.
Start the app host on the Mac that runs TWS or IB Gateway:
canary app
Pair a phone from another terminal:
canary app pair
Scan the QR code. The QR opens a short-lived pairing URL; it is not a permanent
secret. After pairing, the browser keeps its own device key and connects back to
the app for bootstrap data and live SSE updates. Restarting the app should not
require pairing again: the old session cookie is in-memory, but the browser can
mint a new session from its saved device key/secret.
The app host keeps one push-alert setting, alert_settings.mode — none,
act_only, or watch_and_act — changed from the PWA's Settings tab (PUT /api/alerts/settings) and stored with the paired-device state under
CANARY_APP_STATE_DIR.
Useful while developing or testing:
make app-check
make app-refresh
make app-refresh-smoke APP_SMOKE_BROWSER=webkit
canary restart --app --timeout 15s
canary app restart --timeout 15s
make app-smoke APP_SMOKE_BROWSER=webkit
make app-render-check APP_SMOKE_BROWSER=webkit
app-render-check is the binding browser gate for pairing, reload, device-cookie
recovery, and production-SPA rendering. It is fully synthetic and blocks every
external request, so it cannot attach to the desk daemon or read account data.
App-process restart behavior is exercised separately by the CLI restart tests;
do not combine it with a browser fixture that discovers the default daemon.
For source edits, prefer make app-refresh before Browser verification because
the SPA is embedded in the installed canary binary. The detailed development
playbook lives in
internal-docs/guides/canary-spa-dev.md.
App icons are generated PNGs. The checked-in icon-512.png is the canonical
512×512 asset; regenerate it and the smaller PWA/favicon sizes with:
web/app/generate-icons.sh
If the original Canary source sheet is available locally, recrop the canonical
512px asset and regenerate all derived sizes with:
CANARY_ICON_SOURCE_SHEET=/path/to/source.png \
CANARY_ICON_CROP=y,x,height,width \
web/app/generate-icons.sh
Trading workflows, HTTP MCP, debug diagnostics, and production relay hosting are
future work.
The original MVP design is preserved as a historical record in
internal-docs/design/mobile-app-mvp.md.