Repository navigation
Description
Description
Muse Code can't be added on iPhone. #522 and #525 found that Meta offers no sign-in or allowance endpoint an iPhone app can use. Add Account shows the limit as a footer (current main, fc55494):
The desktop tools already read the allowance on the host with muse usage --json: CodexBar for Windows (codexbar#274) and hs-pi-dashboard (#70, #71). hs-pi-dashboard relays that reading as a muse-code usage card. Read-only probes on 2026-10-27 at 01:15 ET found:
- Agent
GET /usagereturns{machine, generatedAt, cards}(4.6 KB). It has no authentication and is served over plain HTTP on a Tailscale IP. - Fleet server
GET https://agents.hemsoft.net/api/fleetreturns every machine'susagealong with projects and session data (1.18 MB, not compressed). It has no authentication. It uses a valid certificate, and its DNS name resolves to a tailnet address. - The Muse card carries
gauges(window,weekly:usedPercent,resetAt,windowSeconds),plan,allowanceSource,observedAt,freshForSecondsanderror. After a failed read it keeps the last good gauges and setserror. It has no schema version and no Meta account identifier.
The iOS app has no remote, relayed or synced source today: no iCloud or CloudKit entitlement, no desktop sync, no custom endpoint and no ATS exception.
Task: let a user who runs such a hub show their real Muse Code 5-hour and weekly allowance on iPhone. No Meta credential goes on the phone. Users without a hub keep a truthful unavailable state.
Why
Franz (2026-10-27): "If CodexBar and Pi Dashboard can report the Muse Code metrics, so can the iPhone." The reading already exists on the user's own machines. The phone only needs a safe way to read it without credential transfer, token copying or estimates.
Goal
Add Account offers Muse Code through a clearly labelled "via your own usage hub" route. The prerequisite is stated before selection. The user enters an HTTPS hub address and connects. The account is created only after a machine reporting Muse Code is bound. The dashboard, widget and watch then show the hub's reading with the #525 validation, freshness and unavailable rules. It is labelled as coming from that machine, never as a verified Meta account.
Acceptance Criteria
- Add Account shows Muse Code in a separate "via your own usage hub" section that states the prerequisite. It isn't hidden, Pro-only or flagged, and the Show Muse Code as unavailable on iPhone with a truthful schema-1 allowance reader #525 "isn't available on iPhone" footer is gone.
- Choosing it opens hub setup without creating an account. Canceling or failing leaves no account and uses no account slot. Free and Pro limits apply when the account is created.
- Only
httpsis accepted, with no ATS exception. The full usage address is required (a bare host is rejected with an example). Userinfo, query and fragment are rejected, and URLs are canonicalised (case, default port, trailing dot). - Connect reads the hub once and lists only online machines that report a
muse-codecard. One machine binds automatically; several show a picker; none shows a clear message. Connect can't run twice at once, and a binding already used by another account is refused. - Requests send no cookies, credentials or auth headers and don't use a cache. Redirects and any non-200 status are failures. Request and resource timeouts are set, and a response-size cap applies (the fleet endpoint gets a larger separate cap).
- DNS or unreachable, TLS, timeout, 401/403, 429, other HTTP errors and malformed or unsupported payloads each show a distinct message.
- The card is read only when
keyismuse-codeandkindisquota.windowandweeklygauges are validated with the Show Muse Code as unavailable on iPhone with a truthful schema-1 allowance reader #525 rules (unique bucket IDs, finite values, strict ISO-8601 dates,windowSecondsthat matches the window, reset rollover, future observation). Freshness usesmin(freshForSeconds, 420). - A card with a non-empty
erroris a failure, never a current reading. Retained gauges may appear only as last known with their measured time, with no alerts, forecast or new history. - Card
errortext,label,projectedEnd,subscriptionPriceUsdandwarningare never shown. There is no SUS or price. - Hub address and machine are refresh inputs and the cache identity. Rebinding drops in-flight responses and cached bars from the old binding. A reading older than the last accepted one for the same binding never replaces it, including across relaunches.
- Setup states that anyone who can reach an unauthenticated hub can read its usage.
- The widget and watch carry bars, plan and times only. Extensions do no networking.
Definition of Done
- Implementation, unit tests for URL rules, transport mapping, the card adapter, the error and staleness policy, binding and the out-of-order guard, and a DEBUG simulator fixture that drives the real client through a URLProtocol.
- MUSE-CODE.md, PRIVACY.md, SUPPORT.md and CHANGELOG.md (Unreleased) updated.
- An hs-pi-dashboard issue requests a lean, versioned usage endpoint and a stable machine/account identifier. No change is made there or in project-manager.
- Pinned SwiftLint has 0 violations. Relevant
CodexBarIOSTestspass. Automatic CI is unchanged. - Clean current-head Codex review, and a Council line recorded on the PR.
Validation
-
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcrun swift package plugin --allow-writing-to-package-directory swiftlint lint --reporter xcode .reports 0 violations. - The unit tests in
CodexBarIOSTestsfor the new hub source pass on the iPhone 17 simulator. - The PR embeds current-head iPhone 17 simulator screenshots of: Add Account with the hub section; hub setup (empty, error, machine picker); a measured hub card; a hub card with a producer
error(last known); unreachable hub. Add a short recording of the setup flow if practical. - Pending for Franz, not an agent gate: a phone comparison against
agents.hemsoft.netwith Tailscale on.

Activity
HemSoft commentedon Oct 27, 2026
Council (design round, before implementation)
Council: Muse Wonder Full 1.0 · missing: GPT 6.1 Sol (Codex seat
pause, weekly 25% used, 182% projected,usage.py2026-10-27 01:17 ET) · adopted: 13 · declined: 1 (partial)Adopted:
errormakes the result a failure, never a current reading./api/fleetisn't an implicit default. The full address is required.kind, unique buckets,windowSeconds,min(freshForSeconds, 420).observedAtis persisted per binding, so older readings never replace it across relaunches.Declined in part: hiding the retained gauges entirely when
erroris set. The producer keeps them as its last good reading, and the app's existing failure policy shows last-known bars with their measured time for every provider. They're shown greyed as last known, under the failure message, with no alerts, forecast or new history.HemSoft commentedon Oct 27, 2026
Parked by Franz (2026-10-27 01:29 ET): CodexBar iOS is a public consumer app, and its users can't reach a personal usage hub. Abandoning the hub route. Revisit only when Meta offers Muse Code usage through a supported API. Until then #525's honest "not available on iPhone" state stands.