Community-powered radio monitoring for Yukon, Oklahoma and beyond. Run a hub, add a recorder, and share trusted local signals without towers or gatekeepers — including off-grid cells that never phone home to the cloud.
Real traffic from the hosted SignalForge hub. Tap LIVE ON in the console below to hear calls as they land — same embeddable player operators share from any radio set.
Browsers require a click inside the player to start audio — use LIVE ON.
This started with a simple idea: Yukon deserved a public GMRS repeater — a reliable community radio hub that would keep neighborhoods connected when cell towers go dark and power grids fail. We put together the proposal, found the tower, reached out to the city.
The city didn't answer. The tower owner went quiet. The project stalled.
SignalForge Hub is what came next — a software-defined radio monitoring platform where community members contribute scanner, repeater, SDR, or streamed audio sources. No tower lease. No $5,800 equipment budget. No waiting on a committee. Every person who runs a recorder expands the network.
Distributed architecture. Feed audio from a radio, scanner, SDR setup, or existing stream.
Every contributor shapes the network. No single point of control.
Built for the moments when conventional systems go silent.
SignalForge CLI is the new one-binary recorder path for Windows, macOS, and Linux. Point it at an audio folder, validate your hub and source key, and upload calls without installing a separate desktop recorder console.
brew tap CptPlastic/signalforge
brew install signalforge
scoop bucket add signalforge https://github.com/CptPlastic/scoop-signalforge
scoop install signalforge
sf onboard
sf rec check --source-key sk_live_REPLACE_WITH_SOURCE_KEY
sf rec inspect --input ./Input
sf rec w --input ./Input --source-key sk_live_REPLACE_WITH_SOURCE_KEY
sf update check
Pick one mode when you run sf rec w (folder watch). Profile settings live in
~/Library/Application Support/signalforge/profile.json on macOS.
Watch your ingest folder and upload new audio as calls land. No heartbeat clips.
sf rec w --input ./Input
Upload an audible pip on an interval so the hub knows the recorder is alive. Minimum interval is 30s.
sf rec w --canary --canary-interval 2m
Real traffic from the folder plus a periodic heartbeat. Use sf rec stop to end a watch session cleanly.
sf rec w --input ./Input \
--canary --canary-interval 2m
Re-upload a fixed audio clip on a schedule (separate from the canary pip). Handy for scheduled check-ins.
sf rec w --beacon \
--beacon-file ./beacon.wav \
--beacon-interval 30m
Use the hosted SignalForge hub if you want to listen, contribute a recorder, or try the network before running your own hub.
The recommended install path is plain Docker Compose with official SignalForge images. No single-platform package, no hosted template, no lock-in: one generated environment file, one compose stack, and a PostgreSQL volume you can back up or move.
For a local test, install Docker Desktop, make sure it is running, and use http://localhost:3000 as the public hub URL when the helper asks.
git clone https://github.com/CptPlastic/signalforge-node.git
cd signalforge-node
SIGNALFORGE_PUBLIC_URL=http://localhost:3000 make init-env
make install-up
curl http://localhost:8080/api/v1/health
Put HTTPS in front of the web port with Caddy, nginx, Traefik, Portainer, or your hosting panel's reverse proxy. The web service handles public traffic and proxies API and WebSocket requests to the api service inside the stack.
Call audio lives inside PostgreSQL. High-traffic hubs can log a million calls in a month — without a retention policy the database volume fills up and the hub stops accepting new traffic.
Set CALL_RETENTION_DAYS and CALL_ARCHIVE_DIR in the stack environment. The hub archives on a six-hour schedule — no cron job required.
Hub admins open Account → Call Storage & Retention in the web console. Archive Now runs in batches until the backlog is cleared, with live progress.
Point CALL_ARCHIVE_S3_URI at an S3-compatible bucket. Day folders sync via s3cmd before rows are deleted from the database.
Each archived call becomes a JSON manifest plus audio file under
YYYY-MM-DD/call-{id}.mp3 — easy to browse, back up, or replay outside the hub.
Minimal retention setup for a Compose stack:
# Keep 14 days in Postgres; export older calls to a mounted volume
CALL_RETENTION_DAYS=14
CALL_ARCHIVE_DIR=/data/call-archive
# Optional: DigitalOcean Spaces (bucket name is the Space, not a subfolder)
CALL_ARCHIVE_S3_URI=s3://your-space/signalforge-hub/call-archive
SPACES_ACCESS_KEY=your-key
SPACES_SECRET_KEY=your-secret
SPACES_ENDPOINT=ams3.digitaloceanspaces.com
CALL_ARCHIVE_DELETE_LOCAL_AFTER_S3=true
Mount a spacious volume at CALL_ARCHIVE_DIR if you are not offloading to object storage immediately. Use DRY RUN in the Account panel first to see how many calls and how much audio would move before anything is deleted.
Not every deployment should depend on Mailjet, a public directory, or an update manifest on the internet. SignalForge hubs can run as closed off-grid cells — a local PostgreSQL stack, password sign-in, recorder ingest, public radio-set players, and optional on-box transcription, with no outbound cloud services required.
Bootstrap an admin with AUTH_BOOTSTRAP_EMAIL and AUTH_BOOTSTRAP_PASSWORD. Enable AUTH_PASSWORD_LOGIN_ENABLED so the web console and mobile app sign in without magic links.
Set AUTH_AUTO_APPROVE_USERS=true for small trusted cells, or keep approval on and manage accounts locally from the hub console.
Leave Mailjet blank, set UPDATE_CHECK_URL= and HUB_DIRECTORY_URL= empty, and keep HUB_FEDERATION_ENABLED=false until you deliberately peer with another hub.
Radio sets can follow talkgroup groups instead of hand-picked TG IDs — useful when your recorder tags traffic by agency or discipline and you want a share link that stays current automatically.
The optional transcriber worker runs faster-whisper on your hardware. Audio never leaves the cell.
Clients call GET /api/v1/auth/capabilities to learn whether password login, email codes, or both are available before showing a sign-in screen.
Minimal off-grid environment for a Compose stack:
# Bootstrap admin (created or updated on API startup)
AUTH_BOOTSTRAP_EMAIL=admin@local.signalforge
AUTH_BOOTSTRAP_PASSWORD=change-me-strong
AUTH_PASSWORD_LOGIN_ENABLED=true
AUTH_AUTO_APPROVE_USERS=true
# Stay local — no cloud callbacks
UPDATE_CHECK_URL=
HUB_DIRECTORY_URL=
HUB_FEDERATION_ENABLED=false
# Mailjet can stay blank; magic-link sign-in is simply unavailable
After the stack starts, open the hub console Account tab and sign in with the bootstrap email and password. The mobile app reads the same capabilities endpoint and switches to password mode when email delivery is not configured.
SignalForge Hub ships with an optional self-hosted transcription worker that turns recorded calls into searchable text — no third-party API key, no audio leaving your infrastructure. It runs faster-whisper inside a Docker container and pulls jobs from the hub's internal queue.
Runs entirely on your hardware. Audio is never sent to an external service.
Choose the Whisper model size that fits your hardware. small is the recommended default — meaningfully better than base while still practical on CPU.
Set a domain prompt to prime the model with scanner vocabulary — ten-codes, callsigns, local streets — before it touches a single call.
Key environment variables for the transcriber service:
# Model size — tiny · base · small · medium · large-v3
TRANSCRIPTION_MODEL=small
# Comma-free phrase list that primes the model for your traffic
TRANSCRIPTION_INITIAL_PROMPT=Police and fire dispatch radio traffic. Units responding. 10-4. Copy. Dispatch. Requesting backup. Officer down. Units on scene. Negative. Affirmative. Stand by. All units. Channel.
# Force a language or leave blank for auto-detect
TRANSCRIPTION_LANGUAGE=en
# Run on CPU (default) or cuda if you have a GPU
TRANSCRIPTION_DEVICE=cpu
Larger models produce better accuracy but require more RAM and CPU time. small is a good starting point for most deployments. medium or large-v3 are worth trying if you have the hardware and want the best results on noisy radio audio.
Hubs can carry more than just received radio traffic. Authorized users in a hub can press-and-hold a button — in the web client or a per-set "PTT mode" screen — to record a short audio message that is delivered to every listener of that radio set, alongside the real radio. Each PTT call gets a distinct amber badge, a Nextel-style chirp before playback, and the sender's identity in the call log, so listeners always know they're hearing a person, not the radio.
Every radio set gets its own PTT talkgroup (9_000_001+) auto-allocated on creation. PTT calls land on that channel so they fan out only to that set's listeners.
Press and hold the PTT button — or hold spacebar on a dedicated PTT screen — to record. On release, the clip uploads, lands as a call, and plays for everyone on the radio set in seconds.
Users with the dispatcher_enabled flag can key multiple radio sets at once, delivering a single transmission across many talkgroups — useful for coordinated alerts across a hub's listener groups.
Every PTT call plays a short two-tone chirp before the audio so listeners instantly know it's a person keying, not a scanned transmission. The call log labels the sender by email.
Clients generate a UUID per transmission. Network retries return the same call without creating duplicates — important for mobile PTT on spotty connections.
SignalForge Mobile v1.0.1 — iOS and Android with live monitor, PTT, dispatcher broadcast, and background playback. App Store & Play coming soon; TestFlight and internal builds available now.
Endpoints surfaced by the PTT subsystem:
# Single-set PTT (held button on one radio set)
POST /api/v1/radio-sets/{id}/ptt
multipart: audio, duration, clientId
# Multi-set dispatcher broadcast (one keying, N talkgroups)
POST /api/v1/ptt/broadcast
multipart: audio, duration, clientId, radioSetIds=id1,id2,id3
Both endpoints require an active session with tx_enabled (and dispatcher_enabled for the broadcast endpoint). Guests cannot transmit.
SignalForge web, hub console, and mobile app share a tactical display cycle — DARK → NITE → NVG — modeled after field coordination tools like SchedKit. The cycle never passes through full brightness, so you won't flash-blind NVG or night-adapted eyes mid-op.
Default amber phosphor on CRT black — console monitoring and PTT.
Dim red palette for naked-eye dark adaptation between screen checks.
Ultra-low luminance blue-grey — minimum software glow for Gen III tubes.
Daylight paper terminal — click ☀ LIGHT in the nav (or long-press DARK on touch).
Use the mode bar in the nav on any page, or read DISPLAY-MODES.md for palette tokens and per-product implementation notes.
signalforge-node is the public, buildable source for the hub stack: server, web client, recorder clients, compose files, operator docs, and SignalHub federation code. The public repo stays buildable, documented, and free of local secrets or deployment-only clutter.
Yes, the clients belong in the mirror. A hub is not just the Go server. Operators need the React console, recorder tools, and container recipes to run the whole stack without reverse-engineering any projectseven deployment.
Go API, database migrations, ingest endpoints, auth, hub identity, and federation routes.
React client for monitoring calls, managing sources, radio sets, peers, and updates.
Desktop and CLI tools that turn local scanner, SDR, or audio feeds into signal sources.
SignalHub is the next layer: a peer-to-peer pub/sub network for community scanner hubs. Each SignalForge Hub can publish local sources, subscribe to trusted remote sources, and keep control of what it shares downstream.
SignalForge is peer-to-peer first. Operators run their own hubs, connect by invite, and choose which local sources they share with trusted peers.
Local scanner, SDR, repeater, or stream sources announce live calls, metadata, and health.
Trusted hubs can pull selected sources or talkgroups without depending on one central server.
SignalForge can list known-good hubs while still allowing direct peer-to-peer trust.
The directory is a public trust list for known SignalForge hubs. It separates discovery from federation: operators can still peer directly by invite, while listed hubs can publish a directory status and trust level that local consoles can refresh on demand.
Default local trust. The hub exists, but the directory has not vouched for it.
The hub is known to the directory and can be shown in public operator surfaces.
The operator and public URL have been checked by the SignalForge directory issuer.
A known stable operator with useful community signal sources and clean behavior.
Infrastructure operated by projectseven or SignalForge.
A listed hub that should not currently be used for trust or discovery.
SignalForge is intentionally layered: run a cell today, list it in the directory when you are ready, federate with peers when you want shared sources. These are the active platform tracks.
Monitoring mode docs, password/off-grid onboarding, admin user management, and hub registration wizard in the console.
Public hubs.json feed, mobile directory picker, trust levels, and the register-hub intake flow.
Peer invites, shared sources, imported remote calls — optional mesh between cells without a central tower.
Custom RSS/JSON feeds, multi-protocol ingest, API key scoping, export tooling, and operator monitoring dashboards.
Want to help shape priority? Reach out — especially if you are running a hub cell and want directory listing or federation with Yukon.
The original goal was a repeater at every Yukon landmark — a cohesive signal network stitched across the city. The hardware approach hit walls. The software approach has no walls.
Every SignalForge Hub instance can stand on its own. Every recorder running is a signal source. Contributors in Yukon, in OKC, anywhere — each one extends the reach of the network without a single piece of shared infrastructure.
If you want to contribute a scanner source or run your own hub, install the SignalForge CLI and reach out. SignalForge is community infrastructure — and you're the infrastructure.