Find a file
monkopedia-coder 43ed76dad4
Some checks failed
Android CI / test (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Build & Test (push) Waiting to run
Relay CI / relay-test (push) Has been cancelled
Bump to v1.0.13 (#797)
Patch release so crash reports from the field become diagnosable, carrying
the app fixes that landed since 1.0.12:

- #781 (#778): a burst of abandoned connections pinned IO threads until the
  whole app wedged — on the owner's phone the UI hung on its loading spinner.
  Sessions moving no bytes now end after 5 minutes and hold a coroutine, not a
  thread, while they wait.
- #796 (#780): a session ending on the device side now closes its mux stream,
  so the client gets EOF instead of hanging and the relay frees the slot.
- #794 (#755): each release now publishes its R8 mapping.txt per flavor as a
  release asset, and the relay keeps R8's map id in stack frames, so reports
  from this version onward can be decoded. 1.0.9-1.0.12 reports cannot: their
  mappings were never kept.

Relay-only fixes since 1.0.12 (#789, #790, #791, #793) are already deployed and
are not part of the app.

Owner instruction, Jason, 2026-10-19 in session: "when it's all landed drive a
patch release so we can get the data on this", and "Sounds fine to include
anything ready to go in."


Claude-Session: https://claude.ai/code/session_01YYSPuh9bZEJkrzvnEpY1QK

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:07:52 -04:00
.claude Cut auto-loaded context overhead (#425) 2026-04-26 17:57:12 -04:00
.github Make release crash reports decodable: publish R8 mappings, keep r8-map-id in frames (#755) (#794) 2026-10-19 11:01:30 -04:00
.signing Fix #205: move release keystore passwords to env/.properties file 2026-04-17 14:36:01 -04:00
api Fix #347: Client-subject notification copy + deep-link taps + Manage action (#362) 2026-04-22 03:11:08 -04:00
app Bump to v1.0.13 (#797) 2026-10-19 12:07:52 -04:00
config/detekt Remove TunnelSessionManager from jvmMain (#671) (#684) 2026-09-02 07:06:24 -04:00
core Close the mux stream whenever a device-side session ends (#780) (#796) 2026-10-19 10:59:46 -04:00
deploy Triage the masked-return findings and enable the two checks (#657) (#682) 2026-09-02 13:59:17 -04:00
device-tests Fix #323: Remove personal machine identifiers from public repo (#326) 2026-04-20 12:24:01 -04:00
docs docs(privacy): name what actually leaves the device (#743) 2026-09-09 23:31:30 -04:00
e2e fix(mcp): advertise the build version in the MCP handshake (#603) (#604) 2026-08-23 16:18:34 -04:00
fastlane/metadata/android/en-US Bump to v1.0.13 (#797) 2026-10-19 12:07:52 -04:00
fdroid Bump to v1.0.13 (#797) 2026-10-19 12:07:52 -04:00
gradle Stop abandoned bridge sessions from pinning IO threads (#778) (#781) 2026-10-19 10:06:18 -04:00
integrations Consult the consent toggles that gate notification actions and DND (#746) (#748) 2026-09-14 11:21:24 -04:00
notifications build(test): make a failing test say what failed, and stop three green-but-empty runs (#645) 2026-08-30 02:19:13 -04:00
relay Make release crash reports decodable: publish R8 mappings, keep r8-map-id in frames (#755) (#794) 2026-10-19 11:01:30 -04:00
scripts Stop abandoned bridge sessions from pinning IO threads (#778) (#781) 2026-10-19 10:06:18 -04:00
work Cap HTTP framing buffers and make refresh-token rotation atomic (F-Droid audit) (#750) 2026-09-14 14:42:16 -04:00
.editorconfig Add Compose screens with mock data, Roborazzi screenshot tests, and HTML dashboard 2026-04-04 16:50:39 -04:00
.gitignore Fix #205: move release keystore passwords to env/.properties file 2026-04-17 14:36:01 -04:00
BLOCKERS.md Configure mTLS client cert for relay WebSocket connection 2026-04-05 19:58:55 -04:00
build.gradle.kts Resolve display date formatters at format time, not class-init (#635) (#651) 2026-08-30 23:27:04 -04:00
glama.json Add glama.json for Glama MCP directory claim 2026-04-30 16:59:43 -04:00
gradle.properties Initial project scaffold: multi-module Android/Kotlin Gradle project 2026-04-03 19:38:30 -04:00
gradlew Initial project scaffold: multi-module Android/Kotlin Gradle project 2026-04-03 19:38:30 -04:00
gradlew.bat Initial project scaffold: multi-module Android/Kotlin Gradle project 2026-04-03 19:38:30 -04:00
last_session Merge T-1 interfaces: TunnelState, TunnelError, CertificateStore, TunnelClient (KMP) 2026-04-05 07:25:50 -04:00
LICENSE Initial commit 2026-04-03 19:35:18 -04:00
README.md Raise targetSdk from 35 to 36 (#745) 2026-09-14 14:46:27 -04:00
settings.gradle.kts Fix #250: App-wired integration test scaffold (Robolectric + real Koin + TestRelayFixture) (#258) 2026-04-18 20:14:48 -04:00

Rouse Context

rouse-context MCP server

Your phone has context that AI doesn't — your health data, your notifications, your app usage. Rouse Context makes that context available to AI assistants on demand, without ever syncing your data to the cloud.

It's an Android app that turns your phone into an MCP server. AI clients like Claude connect to a URL, your phone wakes up, and a direct encrypted session is established. The AI asks for what it needs, your phone responds, and then it goes back to sleep. Your data never leaves your device except through that live session.

Status: v1.0 released. Available on GitHub Releases. For Google Play beta access, email beta@rousecontext.com. Works with any MCP-compatible client.

Home screen with active integrations and audit log    Integration setup with URL to copy    OAuth approval screen

Getting Started

  1. Install — download the APK from GitHub Releases and sideload it (you may need to enable "Install from unknown sources" in your Android settings). Or email beta@rousecontext.com for Google Play beta access. Two builds ship per release — a Firebase-free FOSS APK (-foss.apk) and a Google APK (-google.apk); see docs/distribution.md for which to pick and the F-Droid story.
  2. Onboard — open the app, tap Get Started, grant notification permissions. The app registers with the relay and provisions your device's TLS certificates (~10 seconds).
  3. Enable an integration — tap Add Integration on the home screen. Pick one (e.g. Health Connect), grant the requested permissions, and you'll get a URL like https://brave-health.abc123.rousecontext.com/mcp.
  4. Connect your AI client — paste that URL into Claude (Settings → Connectors → Add custom connector) or any MCP client. The first connection triggers an OAuth approval on your phone — tap Approve.
  5. Use it — ask the AI about your health data, send yourself a notification, check your screen time. Every tool call is logged in the app's Audit tab.

How It Works

AI Client ──TLS──> Relay (SNI passthrough) ──mux WebSocket (mTLS)──> Your Phone
  1. You enable an integration (e.g. Health Connect) and get a URL like https://brave-health.abc123.rousecontext.com/mcp (the integration is identified by the hostname prefix; the path is always /mcp)
  2. Add that URL to Claude or any MCP client
  3. When the client connects, the relay wakes your phone via FCM push
  4. Your phone connects back through a mTLS WebSocket, and the relay splices the two TLS streams together
  5. The AI client talks directly to your phone over end-to-end encrypted TLS — the relay never sees the plaintext

Sessions are ephemeral. The phone goes back to sleep when the client disconnects.

Integrations

Each integration is independently enabled and gets its own MCP endpoint with OAuth authorization (PKCE). 22 tools across 4 integrations:

Health Connect (3 tools)

Query Android Health Connect data across 36 record types in 7 categories (activity, body, sleep, vitals, nutrition, reproductive, mindfulness).

Tool Description
list_record_types List Health Connect record types with permission status
query_health_data Query records by type and time range
get_health_summary Health summary across permitted types for a period

Notifications (5 tools)

Read, search, and interact with device notifications.

Tool Description
list_active_notifications List posted notifications
search_notification_history Search notification history by text, package, or time range
get_notification_stats Notification counts, top apps, and busiest hour for a period
perform_notification_action Invoke an action button on an active notification
dismiss_notification Dismiss an active notification by key

Outreach (10 tools)

Let AI take actions on the device — launch apps, open links, send notifications, manage DND.

Tool Description
launch_app Launch an installed app by package name
open_link Open an http/https URL in the default app
copy_to_clipboard Copy text to the clipboard
send_notification Post a notification with optional action buttons and tap-to-open URL
list_installed_apps List installed apps
create_notification_channel Create a notification channel
list_notification_channels List AI-created notification channels
delete_notification_channel Delete an AI-created notification channel
get_dnd_state Get Do Not Disturb state
set_dnd_state Set Do Not Disturb state

Usage Stats (4 tools)

App usage patterns and screen time analytics.

Tool Description
get_usage_summary Screen time totals and top apps for a period
get_app_usage Per-day usage for one app
get_usage_events Raw app foreground/background events over a range
compare_usage Compare screen time between two periods; biggest deltas first

Architecture

Android App

Module Purpose
:app Compose UI, Koin DI, navigation, theming
:core:tunnel Mux protocol, WebSocket client, TLS accept, CertificateStore
:core:mcp MCP session routing, HTTP server, OAuth (device code + auth code + PKCE), token management
:core:bridge Bridges tunnel mux streams to MCP sessions via TLS
:api McpIntegration interface, IntegrationStateStore
:integrations MCP providers: Health Connect, outreach (calls/SMS/DND), usage stats, notification capture
:notifications Cross-cutting notification infrastructure, audit persistence (Room)
:work Foreground service, FCM receiver, WorkManager
:core:testfixtures Shared fixtures for integration-tier tests that boot the real relay binary

Relay Server (relay/)

Rust binary on a small VPS. Handles:

  • TLS passthrough — routes AI client connections to devices via SNI, never terminates inner TLS
  • Mux WebSocket — multiplexes multiple client sessions over one device connection
  • FCM wakeup — sends push notifications to wake sleeping devices
  • ACME certs — issues per-device TLS certs via Google Trust Services DNS-01 (Cloudflare API); Let's Encrypt also supported
  • Bot protection — secret URL prefix validated before waking device, plus FCM throttle and IP rate limiting

Security

  • End-to-end encrypted — TLS terminates on your phone. The relay does SNI passthrough only.
  • No cloud sync — data is read from on-device sources and served live. Nothing stored remotely.
  • Per-device ACME certs — per-device certs via Google Trust Services (DNS-01), private key in Android Keystore (hardware-backed).
  • mTLS device auth — relay authenticates the device by client certificate before allowing connections.
  • Secret URL prefix — each device URL includes a rotatable per-integration secret (brave-health.abc123.rousecontext.com, where brave-health is {adjective}-{integrationId}). Bots that discover the device subdomain can't wake it without the secret.
  • OAuth per-client — each AI client must be authorized via on-device approval before accessing tools.
  • Audit trail — every tool invocation is logged locally with arguments, response, and duration.

Building

Android

./gradlew assembleDebug

Requires Android SDK (compileSdk 36, targetSdk 36, minSdk 24). Build requires JDK 21 (JAVA_HOME=/usr/lib/jvm/java-21-openjdk).

Coverage report

./gradlew koverHtmlReport

Aggregates line + branch coverage across every module's unit tests and the :core:tunnel:integrationTest tier (real relay subprocess). HTML lands in build/reports/kover/html/index.html. CI publishes the same report as a test-coverage artifact plus a per-module summary on each PR.

Relay

cd relay
cargo build --release

End-to-end tests

The e2e tests drive a real device over adb via a (typically LAN-local) host running adb. The adb.host system property is required and defaults to empty — the :e2e:e2eTest task fails fast if unset. Device serial is optional and only needed if multiple devices are connected to that host.

./gradlew :e2e:e2eTest \
    -Dadb.host=<your-dev-host> \
    -Dadb.serial=<your-device-serial>

The :device-tests module has a separate runner that builds an APK pointed at a locally-running relay. It also requires a LAN IP reachable from the device:

./gradlew :device-tests:test -Dlan.ip=<your-lan-ip>

Without lan.ip, the device-tests skip cleanly via JUnit assumptions.

Status

v1.0 released. 22 tools across 4 integrations, cold-start wake in ~3 seconds, end-to-end encrypted. See docs/design/ for detailed design documents and privacy policy.

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.