A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer answers technician calls, records both call legs as separate channels, and a Ruby backend transcribes them through Whisper and files an AI summary against the caller. Squashed to a single commit for sharing. No credentials are included; secrets live outside the repo in /etc/helpdesk/env on the server or a gitignored .claude/env.local locally. See .claude/env.local.example for the shape. Start at README.md, then docs/architecture.md. |
||
|---|---|---|
| .claude | ||
| ci | ||
| components | ||
| deploy | ||
| docs | ||
| resources | ||
| .editorconfig | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| CLAUDE.md | ||
| LICENSE.txt | ||
| README.md | ||
Helpdesk
A phone helpdesk for field technicians. A technician calls a stationary GrapheneOS Pixel in the office; before the operator picks up, the caller's card pops up on the operator's screen. The call is recorded, transcribed, and summarised, and filed against the caller as an event. Operators work in a web console; the phone talks to the backend over its own signed channel.
The backend is one Ruby process: WEBrick and the standard library, plus the pg and sequel gems when it
runs on PostgreSQL. In production it runs on moje.al.army - operators reach the console over mutual
TLS on 443, the phone posts to its own TLS door on 8443.
Run it locally
Ruby 3.2+ and nothing else. The default mode stores everything in a JSON file, so there is no database to set up:
ruby components/backend/server.rb
That starts the console and the device API on http://127.0.0.1:4000 in dev mode: operator auth off, a few demo contacts seeded. Open http://127.0.0.1:4000 for the console.
To run on PostgreSQL instead, point HELPDESK_DATABASE_URL at a database and the backend switches
stores:
createdb helpdesk_dev
psql helpdesk_dev -f components/backend/db/migrate/001_init.sql
HELPDESK_DATABASE_URL=postgres://localhost/helpdesk_dev ruby components/backend/server.rb
Tests run from components/backend: make test, or any file directly (ruby test/test_domain.rb).
To watch a whole call go through without a phone, start the server and run ruby sim/simulator.rb.
Layout
components/backend- the deployed service: operator console, operator API, device API, storage, the AI pipeline. Start reading atserver.rb.components/backend/lib/helpdesk- the domain core:domain.rb(the Store seam and the Service, including the call state machine),pg_store.rb(PostgreSQL),ledger.rb(the resolutions ledger),business_hours.rb,reporting.rb.components/backend/wiki- wiki grounding for summaries: GraphQL client, embedder, cosine index, build script.components/transcription-worker- recording to speaker-tagged transcript:remote_transcriber.rb(hosted Whisper, what production uses) andtranscriber.rb(local WhisperX fallback).components/dialer-patch- the GrapheneOS Dialer patch: a Java overlay plus nine source patches. Built only on the build box (seedocs/runbooks/), never in CI.components/sepolicy-patch- one SELinux patch so the patched Dialer can read its*.helpdesk.*config properties.deploy/- reference copies of the production config: systemd units, nginx vhosts, the deploy and backup scripts.ci/- the end-to-end script the pipeline runs.docs/- the human docs, listed below.resources/- fetch scripts for the (huge, git-ignored) GrapheneOS sources, and the local Whisper CLI the fallback transcriber drives.
Docs
docs/architecture.md- how the pieces fit: the two auth planes, a call's path through the system, storage, the AI subsystem.docs/operations.md- the production server: deploy, roll back, logs, backups, secrets, CI.docs/device-api.md- the wire contract between the phone and the backend.docs/phone-connectivity.md- how the patched Dialer finds, authenticates to, and talks to the backend, with troubleshooting.docs/onboarding.md- accounts, certificates, SSH, first run.docs/runbooks/- building and flashing the Pixel:graphene-build.md,pixel10a-flash-manual.md,windows-wsl2-build.md. Pluscert-renewal.md, for the vmin certificates, which do not renew themselves.