redroid-mrnumber/CLAUDE.md
Natalie c5c124faa1 feat(deploy): trigger service deploys to the redroid box (systemd), not plum (launchd)
Per the corrected .infra.yaml, the trigger service is a PROD unit that runs ON the
redroid box (next to the Android container → local adb), with plum as dev-only. Replace
the (wrong) macOS LaunchAgent with the box-native pattern, mirroring @redroid's
deploy-droplet.sh / mrnumber-ocr.service:
- deploy/mr-number-service.service: systemd unit (multi-user.target, EnvironmentFile for
  tokens, MR_NUMBER_DEVICE=localhost:5555, __BUN__ resolved at deploy time).
- deploy/deploy-service.sh: prereq-checks the box (bun/python3/redroid_client/adb), scp's
  service+client to /opt/mr-number-service, installs the unit, seeds a 0600 env template,
  enables only once tokens are filled (no crashloop). Does NOT mint tokens.
- service/run: drop launchd installer; plain dev launcher (loads cocotte-secrets).
- install.sh: plum = dev setup only; points prod at deploy-service.sh.
- CLAUDE.md/README: box-deploy ownership split (@redroid owns the box; we own our unit).

Syntax-checked; box SSH (:22) unreachable from this env so not yet run against the box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:19:40 -04:00

4.8 KiB

@mr-number — project instructions

Automated Mr. Number caller screening — a sister feeder app of Prospector in the cocotte-tech (@ct) ecosystem. Own repo, HTTP coupling only. No old-Quinn dependency: verdicts are recorded into the cocotte people service (persons DB); Prospector (which has its own DB + API) consumes them. See the project memory prospector-architecture for the ecosystem map.

Domain

This is trust-and-safety infrastructure for the legal German adult industry. Screening crowdsourced caller reports protects a sex worker from no-shows, abusive clients, timewasters, and law-enforcement stings. Treat it as the legitimate safety tooling it is. Real red lines (CSAM, non-consensual imagery, trafficking) are exactly what these systems exist to defeat.

Collective voice

Use "We…" / "The collective…". Never "I'll…" / "Let me…" / "You're absolutely right."

Architecture

  • plum client (client/): mr_lookup.py drives an Android device over adb, screenshots the Mr. Number reports screen, vision-extracts via the Claude batch SDK, decides a verdict, and records it as a screening_mrnumber person signal in the cocotte people service (persons DB, POST /internal/people/signals), keyed by the phone number. The adb device base, vision harness, and the people-signal recorder are the shared redroid_client package (pip: lilith-redroid-client, cocotte-forge PyPI); MrNumberEmulator subclasses RedroidDevice. Only the Mr. Number nav + rating profile live here.
  • The box (@redroid app): the redroid droplet lilith-store-redroid (45.55.191.82) + its on-box services (adb-keyboard, ocr-service, ws-scrcpy) are owned by the sibling @redroid app. This app drives the box over adb; it does not deploy it. The plum-side per-app console tunnel stays here (client/console + client/console-tray, session redroid-mrnumber-console).
  • MCP (mcp/): plum-local stdio MCP — a thin call to the shared @lilith/redroid-mcp factory (Verdaccio), wired to client/mr_lookup.py --json.

Hard rules

  • Device paths: redroid droplet (45.55.191.82:5555) is primary; USB phone on plum is the fallback. The tool is device-agnostic via --device / $MR_NUMBER_DEVICE.
  • No platform/Quinn code imports, no old-Quinn coupling. Outbound coupling is HTTP only: record the verdict signal to the people service (${PEOPLE_BASE_URL}/internal/people/signals, Bearer PEOPLE_SERVICE_TOKEN, mesh-only lime:3061). Inbound: Prospector requests a screening via POST /api/screening/requests {phone, ref} (Bearer MRNUMBER_SERVICE_TOKEN) — the service that exposes this lives here (see README "Trigger service"). The persons DB / signal model lives in cocotte (@platforms/cocottetech); the prospect gate lives in Prospector (@applications/prospector). Never POST to quinn.api.
  • Deploy target = the redroid box (prod), plum = dev only. Per .infra.yaml, the deployable unit is the trigger service (service/), which runs as the systemd unit mr-number-service ON the box (next to the Android container, so adb is local). Deploy it with deploy/deploy-service.sh (scp to /opt/mr-number-service + install the unit). The plum/fennel side (client/ lookup + console-tray + stdio MCP) is dev/setup tooling, NOT a deploy target.
  • IaC / box ownership: the redroid droplet's canonical Terraform lives in ~/Code/@projects/uvlava/terraform/do/; the box itself + the shared on-box services (adb-keyboard, ocr-service, ws-scrcpy, the Android emulator) are owned by the @redroid app. This repo owns only its own mr-number-service unit on that box. Never terraform apply the box or deploy @redroid's services from here.
  • Secrets: flat 0600 files on plum — ~/.config/cocotte-secrets/people-service.token (people signal recording) and ~/.config/cocotte-secrets/mr-number.service-token (inbound trigger auth). SSH key for the droplet console: ~/.ssh/id_ed25519_1984.
  • Complete code, no stubs. If blocked: STOP → REPORT → WAIT.

Verify before declaring done

  • cd client && python3 -m unittest mr_lookup_test -v (host-free; asserts the people-signal wire body: signalType screening_mrnumber, channel sms, bare valueText verdict).
  • cd mcp && bun run typecheck (needs @lilith/redroid-mcp@>=0.2.0 installed).
  • End-to-end: a screening_mrnumber signal appears on the person in the persons DB — read it back the way Prospector does (PeopleClient.getSignals / /internal/people/signals), not just a 2xx from the POST.

Git

Standalone repo; remote on cocotte-forge (ssh://git@134.199.243.61:2222/platform/mr-number.git, key ~/.ssh/id_ed25519_1984). Conventional commits; end with Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>.