npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thecsguy/androidex

v0.1.0

Published

Pair Android with Codex from the Codex Mac app.

Readme

Androidex

Production-shaped vertical slice for controlling a Mac Codex app from Android through a sidecar and encrypted relay.

What Is Built

  • relay/: WebSocket relay that routes opaque encrypted envelopes, queues frames while a target device is offline, and can run locally or as a token-gated public endpoint behind TLS.
  • sidecar-node/: JavaScript sidecar executable with AES-GCM/HKDF framing, generated pairing payload/QR output, relay reconnect/backoff, a mock Codex adapter, and a real codex app-server adapter. This is what Androidex installs under launchd.
  • sidecar/: Swift reference/dev implementation kept for parity work; it is not required by the Androidex skill workflow.
  • android/: native Kotlin/Compose Android app that scans the pairing QR code or parses the pairing payload, securely stores it with Android Keystore encryption, opens and reconnects the relay WebSocket, subscribes to remote Mac progress, browses projects and thread history, creates/renames/archives/deletes threads, adds/clears projects, configures model/thread settings, streams events, and sends prompts.
  • skills/androidex/: Codex skill that lets a Mac user type /androidex to install or repair the sidecar/relay/tunnel LaunchAgents and render the Android pairing QR directly in chat.
  • e2e/: Node mobile-client harness that proves relay + Node sidecar + encrypted protocol end to end.

Mobile App Surface

The Android app is shaped as a mobile sidecar rather than a desktop clone:

  • Project rail sourced from Codex config plus local thread history, with add, rename, and clear actions.
  • Thread rail with live status, model/reasoning metadata, resume, paginated older message history, read-only project file browsing, rename, archive, restore from history, fork, code review, compact, rollback, and create actions.
  • Transcript workbench with streaming assistant deltas, prompt composer, image URL/Mac-local image/Android image upload/skill/mention attachments, tap-to-attach project files and enabled skills, active-turn steering, and a Stop action for the active remote turn.
  • Phone layout collapses account, tool/plugin, and background relay controls into a compact status strip, then folds project/thread navigation into a tappable focus bar after a thread is selected so the transcript and composer stay prominent on a single mobile viewport.
  • Header controls for code review, thread goals, and compact token-usage readouts when the Mac app reports them.
  • Account and quota strip showing the active Codex account, plan, credit state, and primary rate-limit usage when available.
  • Tools panel showing MCP server count, enabled skills, active plugins, installed/featured plugin names, and guarded plugin install/uninstall toggles resolved through the Mac sidecar.
  • Settings dialog with thread/default scope switching for work mode, model, config profile picker, provider/review-model overrides, reasoning effort, reasoning summary, model verbosity, web search mode/context/domain allowlist, image-view tool access, base/developer instructions, personality, memory generation, approval policy, approval reviewer, sandbox mode, network access, and service tier, plus guarded resets for per-thread mobile overrides and local Codex memories.
  • Activity cards for tool progress, web searches, command output, reasoning deltas, turn diffs, file-change patches/summaries, image-generation artifacts, and approval prompts, with approve, approve-for-session, and deny decisions sent back through the sidecar.
  • New project and new thread dialogs optimized for quick mobile entry.
  • Confirmation dialogs for archiving/deleting threads and clearing projects from a small mobile target, plus a History dialog for restoring or clearing archived threads.
  • QR-code pairing, saved pairing, and a visible forget/re-pair action, so the app can reconnect after restart without storing the pairing secret in plaintext.
  • Running-thread refresh while connected or reconnecting, so missed Mac-side progress is recovered by polling the selected running thread history.
  • Local Android notifications for background approval, turn start/completion/interrupt, and account sign-in events, backed by a foreground relay observer that keeps listening after the app leaves the screen; approval notifications include encrypted approve/session/deny actions when decisions are available.
  • Background relay status and toggle controls in the mobile workspace, including notification-permission state and last connection/event timing, so users can pause always-on listening without deleting their pairing.
  • Simple pairing and empty transcript states, plus Androidex launcher artwork and a monochrome themed-icon layer.

The sidecar protocol now exposes:

  • project.list, project.create, project.rename, project.delete
  • project.files.list, project.file.read
  • thread.list, thread.read, thread.resume, thread.messages.list, thread.create, thread.rename, thread.archive, thread.archive.list, thread.unarchive, thread.delete, thread.fork, thread.compact, thread.rollback
  • thread.goal.read, thread.goal.update, thread.goal.clear
  • model.list, settings.read, settings.update, settings.reset, memory.reset, account.read, account.login.start, account.login.cancel, account.logout, extensions.read
  • plugin.install, plugin.uninstall
  • review.start
  • approval.respond
  • events.subscribe, events.unsubscribe
  • turn.start, turn.steer, turn.interrupt

For the real codex app-server adapter, verified app-server calls are used for thread creation, resume, paginated message history, read-only project file listing/read, Git branch/SHA metadata display, rename, archive, archived history listing, unarchive, delete when available, fork, code review start, compact, rollback, goal read/update/clear, thread memory mode updates, global memory reset, account/rate-limit reads, device-code ChatGPT sign-in/cancel, sign-out, MCP server status, skills, plugin marketplace summaries, plugin install/uninstall, model listing, collaboration mode listing, config reads, project config writes, global default config writes, structured turn start/steer input with text, image URL, Mac-local image, encrypted Android image upload, skill, and mention items, turn interrupt. Project rename is kept as a sidecar display alias because Codex projects are keyed by local path; sidecar project aliases, hidden/cleared projects and threads, and per-thread settings persist across sidecar restarts in ~/Library/Application Support/Codex Remote/sidecar-state.json by default. Mobile-added projects and global default settings are written back to the user's Codex config through app-server when supported, with sidecar state retained as a cache/fallback. Project clearing removes the Codex config project entry when possible, hides the project as a fallback, hides matching active and archived project threads, and removes transient sidecar-added projects from the mobile view. Project file reads are scoped to the selected project root and capped before returning over the relay. Android subscribes after pairing so Mac-side turn, tool, approval, review, account/rate-limit, account login, extensions, thread goal, token usage, and thread lifecycle notifications can update the mobile workspace even when Android did not initiate the work. A separate foreground-service observer uses its own stable relay device id for background notifications, so it does not replace the interactive Android socket. If Android reconnects during an already-running thread, it keeps refreshing running thread state and selected history until the turn settles. When Android opens a thread or starts a turn, the sidecar resumes that thread through app-server first so on-disk Mac sessions are loaded back into the live runtime before mobile interaction continues, then loads a bounded recent-turn page with on-demand older pages so large Mac transcripts do not overflow relay frames.

Getting Started

1. Install the Codex Skill

On the Mac where you use Codex, install Androidex with npx:

npx @thecsguy/androidex install-skill

Restart Codex if it asks you to reload skills. Then open a Codex chat and run:

/androidex

Androidex installs or repairs its LaunchAgents, starts the local relay plus Cloudflare Quick Tunnel, keeps the sidecar alive with launchd, and shows a pairing QR code in chat.

2. Install the Android App

On your Android phone, download androidex-v0.1.0-debug.apk from the latest GitHub release, open the APK, and allow Android to install it. The APK is debug-signed for direct sideload testing, so Android may ask you to allow installs from your browser or files app.

Open Androidex, scan the QR code shown by /androidex, and the phone will connect to Codex through the encrypted relay.

Relay Development

When working from a checkout before the npm package is published, install the skill locally:

npm run install-skill

Build and install the Android app from source:

npm ci
npm run android:assemble
adb install -r android/app/build/outputs/apk/debug/app-debug.apk

If you want a stable relay hostname instead of the managed temporary tunnel, pass an existing public relay:

/androidex --relay "wss://relay.example.com/ws?token=..."

Run the relay:

npm run build:relay
npm run start:relay

For use away from your Mac, run the relay on an internet-reachable host behind TLS and require an admission token:

HOST=0.0.0.0 PORT=8787 RELAY_TOKEN="$(openssl rand -hex 32)" npm run start:relay

The relay can also be packaged as the production container used by the deploy smoke test:

export RELAY_TOKEN="$(openssl rand -hex 32)"
npm run relay:docker:build
npm run relay:docker:run
curl -fsS "http://127.0.0.1:8787/health?token=$RELAY_TOKEN"

For a single-host public relay with automatic TLS certificates, point a DNS A/AAAA record at the host, open ports 80 and 443, then run the Caddy-backed stack:

export RELAY_DOMAIN="relay.example.com"
export RELAY_TOKEN="$(openssl rand -hex 32)"
npm run relay:docker:run:tls

After Caddy provisions a certificate, pair Android and the Mac sidecar with wss://$RELAY_DOMAIN/ws?token=$RELAY_TOKEN. The TLS stack does not publish the relay container's raw ws:// port; Caddy is the only public entry point.

The relay CLI refuses non-loopback binds such as HOST=0.0.0.0 unless RELAY_TOKEN is set. The container includes a Node-based HEALTHCHECK that calls /health with RELAY_TOKEN. For non-container hosts, npm run relay:healthcheck runs the same check against HEALTH_HOST/PORT/RELAY_TOKEN. Public relay deployments send WebSocket heartbeat pings every 30 seconds by default and terminate clients that stop answering pongs; set RELAY_HEARTBEAT_INTERVAL_MS to tune that interval. Offline delivery is bounded by per-device and per-realm queue caps so a stale or abused relay token cannot grow memory without limit.

Put that container behind a TLS reverse proxy or hosted WebSocket load balancer, then use the public wss://.../ws?token=... URL in pairing. Quote relay URLs in shell commands because the ?token=... query string is glob syntax in shells like zsh.

After deploying, validate the public endpoint from a network outside the Mac LAN:

RELAY_URL="wss://relay.example.com/ws?token=..." npm run relay:public-smoke

The public smoke checks /health token gating, unauthenticated WebSocket rejection, authenticated WebSocket upgrade, and opaque frame routing between two test devices.

Use the public wss://.../ws?token=... relay URL in the sidecar --relay value and in the Android pairing payload. The relay token only gates WebSocket admission; the sidecar/mobile secret still provides end-to-end encryption for Codex requests and responses. Android debug builds allow private cleartext ws:// for local emulator development; release builds reject cleartext pairing URLs and disable cleartext traffic.

In another terminal, build and run the Node sidecar with the mock adapter. --print-pairing generates an ephemeral secret, prints the Android pairing payload, and leaves the sidecar connected. Add --pairing-qr pairing.png to also write a scan-ready QR code for the release app deep link. This is the same JavaScript sidecar used by the Androidex skill, so users do not need a prebuilt, signed, or notarized Mac helper binary:

npm run build:sidecar
node sidecar-node/sidecar.mjs \
  --relay ws://127.0.0.1:8787/ws \
  --realm local \
  --print-pairing \
  --pairing-qr pairing.png

Use the printed JSON as the Android pairing payload, scan pairing.png from the app's Pair Mac screen, or open the pairingUri field on Android to prefill the pairing screen, review the redacted relay/realm/Mac summary, and then tap Connect. The QR code contains the same androidex://pair?... URI and therefore includes the pairing secret; treat it like a credential. For repeatable scripted runs, provide your own secret and reuse it:

SECRET="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"
node sidecar-node/sidecar.mjs \
  --relay ws://127.0.0.1:8787/ws \
  --realm local \
  --secret "$SECRET" \
  --print-pairing

For long-running setups, prefer file-backed credentials so relay tokens and pairing secrets do not appear in process arguments:

printf '%s\n' "wss://relay.example.com/ws?token=..." > relay-url
SECRET="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"
printf '%s\n' "$SECRET" > pairing-secret
chmod 600 relay-url pairing-secret
node sidecar-node/sidecar.mjs \
  --relay-file relay-url \
  --realm local \
  --secret-file pairing-secret \
  --print-pairing

Use real local Codex threads via codex app-server:

node sidecar-node/sidecar.mjs \
  --relay ws://127.0.0.1:8787/ws \
  --realm local \
  --adapter app-server \
  --codex-url ws://127.0.0.1:17654 \
  --print-pairing

The sidecar launches codex app-server by default for the supplied --codex-url. Add --no-launch-codex-app-server if you started it yourself. The app-server adapter persists sidecar project aliases, hidden project/thread ids, and per-thread settings in ~/Library/Application Support/Codex Remote/sidecar-state.json. Mobile-added projects and global default settings are written to the user's Codex config via app-server when available, with the sidecar state file kept as a fallback for older app-server builds. Pass --state-file /path/to/state.json to choose another location, or --no-state-file for an ephemeral sidecar session.

For an always-on Mac setup with an existing public relay URL, use Androidex with that relay:

/androidex --relay "wss://relay.example.com/ws?token=..." --realm codex-remote

The installer checks the Node sidecar entry, creates ~/Library/LaunchAgents/com.openai.codexremote.sidecar.plist, stores the pairing secret in ~/Library/Application Support/Codex Remote/pairing-secret with user-only permissions, stores the Android relay URL in ~/Library/Application Support/Codex Remote/relay-url with user-only permissions, writes pairing.json and pairing.png for Android pairing, and loads the LaunchAgent with launchctl. The generated wrappers pin the Node executable that launched the installer, so /androidex uses Codex's bundled Node runtime instead of depending on a user-installed node in launchd's PATH. In Cloudflare mode, the sidecar uses a separate protected sidecar-relay-url file that points at the local loopback relay, so Mac DNS never gates startup. The generated plist and wrapper do not contain the pairing secret or relay admission token; the wrapper passes protected file paths to the sidecar instead of placing those credentials in LaunchAgent or transient process arguments. Pass --dry-run to preview paths, --no-load to write files without loading the service, or --rotate-secret to invalidate an old Android pairing. Remove the LaunchAgent with:

npm run mac:sidecar:uninstall

Android

The Android package/application id is com.openai.codexremote.

Install the latest debug APK by downloading androidex-v0.1.0-debug.apk from the latest GitHub release and opening it on the phone. For a connected development device, install from source with:

npm run android:assemble
adb install -r android/app/build/outputs/apk/debug/app-debug.apk

Build the debug APK:

npm run android:assemble

Build release APK/AAB artifacts:

npm run android:release

Unsigned release artifacts are enough for local smoke checks and are written to android/app/build/outputs/apk/release/app-release-unsigned.apk and android/app/build/outputs/bundle/release/app-release.aab. To produce signed release artifacts, provide a keystore through environment variables before running the release command:

export CODEX_REMOTE_RELEASE_STORE_FILE="$HOME/.codex-remote-signing/codex-remote-release.jks"
export CODEX_REMOTE_RELEASE_STORE_PASSWORD="..."
export CODEX_REMOTE_RELEASE_KEY_ALIAS="codex-remote"
export CODEX_REMOTE_RELEASE_KEY_PASSWORD="..."
npm run android:release

Set -PcodexRemoteVersionCode=... -PcodexRemoteVersionName=... after ./gradlew if you need to override the default 1 / 0.1.0 version for a release train.

Run Android unit tests:

npm run android:test

Run connected device/emulator tests:

npm run android:connected

Run the background notification smoke on a connected device/emulator:

npm run android:background-smoke

The smoke installs the debug APK, opens the real androidex://pair deep link, confirms the prefilled pairing screen, uses adb reverse to connect Android to the local mock relay, verifies the debug autostart receiver can restart the stopped background observer, backgrounds the app, starts a mock sidecar turn, verifies that Android posts a Codex turn started or Codex turn completed notification, then taps a pending approval notification action and verifies the sidecar receives the session-scoped approval. It clears com.openai.codexremote app data before and after the run unless you pass -- --keep-app-data. Use -- --device SERIAL when more than one device is attached.

For an emulator talking to a relay on the Mac host, use ws://10.0.2.2:8787/ws in the pairing payload. If your relay URL already has query parameters, such as wss://relay.example.com/ws?token=..., Android preserves them when it adds realmId, deviceId, and role. Release builds parse androidex://pair?v=1&relay=...&realmId=...&secret=...&macDeviceId=mac deep links and QR scans directly into pairing. Release pairing requires wss://; debug builds can use private ws:// LAN/emulator relays with an admission token and also accept test-only pairing_payload and pairing_payload_b64 intent extras. The Android app saves successful pairings through a Keystore-backed AES-GCM store and auto-reconnects on future launches. Use the forget pairing button in the connected toolbar, or on the pairing screen after a saved-pairing connection failure, to clear the stored payload and key. Clearing the pairing also stops the background relay observer. Use the Background relay switch to pause/resume always-on listening while keeping the pairing. Android asks for notification permission on Android 13+ after pairing when background relay is enabled, so background sessions can surface approval and turn-completion events without interrupting the initial pairing screen. If notifications remain off, the Background relay panel shows an Allow action that opens the app notification settings. The app declares an Android foreground service with the remoteMessaging type to keep the encrypted relay observer active when the app is backgrounded. If background relay is enabled and a pairing is saved, Android restarts that observer after device boot and after app package replacement.

Verification

Run the core suite:

npm test

Run everything including Android instrumentation when a device/emulator is available:

npm test
npm run android:connected
npm run android:background-smoke

Or run the complete release gate plus connected device/emulator flows:

npm run launch:check:device

Run the launch gate before publishing a build:

npm run launch:check

This runs the core relay/sidecar/e2e/Android unit tests, the installed-Codex smoke, Android release packaging, and a final artifact/manifest/config check that verifies release cleartext policy, release pairing rejection for insecure relay URLs, background-relay boot recovery declarations, debug-only smoke actions staying out of release, and static TLS relay config invariants. For a Play-publishable build, export the Android release signing variables and run:

npm run launch:check:publish

The publish gate also rejects unsigned APK metadata, the Android debug signing alias, debug.keystore, repo-local keystore paths, and the default local version (versionCode=1 or versionName=0.1.0) unless --allow-default-version is passed for a local signed smoke. It verifies the release APK and AAB signatures. When a device or emulator is attached, use npm run launch:check:publish:device to add the connected Compose tests and background relay notification smoke to the signed publish gate.

For the automated production launch gate, run from a network that can reach the deployed public relay and has a connected Android device:

export RELAY_URL="wss://relay.example.com/ws?token=..."
export RELAY_TOKEN="..."
export CODEX_REMOTE_SUPPORT_EMAIL="[email protected]"
export CODEX_REMOTE_PRIVACY_POLICY_URL="https://your-real-domain.com/privacy"
export CODEX_REMOTE_SUPPORT_URL="https://your-real-domain.com/support"
export CODEX_REMOTE_PLAY_SCREENSHOT_DIR="/path/to/play-screenshots"
npm run launch:check:production

This combines signed publish verification, connected Android tests, background notification smoke, store-listing validation, Play screenshot validation, physical-smoke evidence validation, and public relay smoke. The physical evidence gate validates the recorded release-smoke fields, but it does not perform the manual phone steps for you.

For the production launch checklist, public relay validation steps, real-device smoke matrix, and Play Console metadata/privacy draft, see:

  • docs/user-setup.md
  • docs/android-launch-runbook.md
  • docs/launch-completion-audit.md
  • docs/play-store-metadata.md
  • docs/privacy-policy.md

Run the optional installed-Codex smoke without starting an LLM turn:

npm run test:real-app-server

Verified locally:

  • Relay unit tests: routing and offline queue replay.
  • Relay deploy smoke: compiled production entrypoint starts with RELAY_TOKEN, gates /health, and accepts token-authenticated WebSocket clients.
  • Node sidecar checks: JavaScript syntax/entrypoint validation for pairing, relay, mock, and app-server adapter modules.
  • End to end: Node mobile client -> encrypted relay -> Node sidecar -> mock Codex adapter, including QR pairing artifact generation, sidecar --secret-file startup, account/rate-limit read, project list/create/rename/clear, model list, thread create/resume/rename/archive/restore/delete, code review start, settings update, turn streaming, and thread readback.
  • Sidecar launch readiness: pairing-only mode writes pairing JSON/QR artifacts without opening a relay socket, and the macOS LaunchAgent installer keeps the pairing secret and relay token out of plist/wrapper process arguments.
  • App-server adapter E2E: fake codex app-server WebSocket exercises non-LLM reads, account/rate-limit reads and notifications, bounded thread resume/history loading with older-page pagination, read-only project file browsing, Git metadata parsing, thread goals, archived thread clear/hide, project clear hiding active project threads, code review start, collaboration mode and config profile option listing, structured turn-start/steer transport including uploaded Android image persistence, project config writes, global default config writes including advanced model/provider/profile/instruction/tool options, per-thread override reset, memory mode/reset, token usage notifications, persistent sidecar project/settings/hidden-thread state, command output deltas, reasoning deltas, turn diff updates, file-change patch/output updates, image-generation artifact notifications, plus command, file-change, and permission approval server requests including session-scoped approval through the encrypted relay.
  • Event subscription E2E: a second Android-style client subscribes with events.subscribe and receives another device's thread lifecycle, review start, thread goal, settings, turn.completed, turn.steered, and turn.interrupted events through encrypted fan-out; when it disconnects, sidecar presence cleanup prevents future events from being queued for that offline subscriber.
  • Android unit tests: pairing parser and Android AES-GCM/HKDF round trip.
  • Android connected test: Compose pairing screen on Medium_Phone_API_35.
  • Android connected secure-store test: Keystore-backed pairing payload save/read/clear.
  • Android live smoke: paired emulator to relay + mock sidecar, rendered project/thread/history UI, and sent a prompt through encrypted streaming.
  • Android background smoke: installed debug APK, paired by deep link, kept the foreground relay observer alive after HOME, triggered a sidecar turn, verified the posted Codex turn notification through dumpsys notification, then triggered a pending approval, tapped the notification Session action in the emulator shade, and verified the sidecar received approved_for_session.
  • Approval E2E: a pending turn emits approval.requested, Android-style client steers it with turn.steer, replies with approval.respond while turn.start is still open, and the turn completes; a separate pending turn is stopped through turn.interrupt.
  • Real Codex smoke: npm run test:real-app-server launches the installed codex app-server through the sidecar and verifies thread list, thread resume when an active thread exists, model list, settings read, and collaboration mode read calls.