Amateur radio emergency communications. From the makers of ARS Suite.
GoKit is a standalone, cross-platform application for emergency communications operators — APRS situational awareness, Winlink radio email, AX.25 packet, and the workflow glue (ICS forms, net logging, go-kit profiles) an ARES / RACES or served-agency operator actually needs in the field.
It is its own product. It is not part of ARS Suite and does not require it — an emergency operator should not have to install a contest logger and a learning library to pass a message. If ARS Suite's J-Hub happens to be running, GoKit can optionally surface there and reuse the station configuration; otherwise it runs entirely on its own.
This is alpha software. It has never been validated against a real radio or TNC. Do not rely on it for actual emergency communications. The full stack is implemented and passes its software test suite — the AX.25 frame codec and connected-mode engine; the KISS, AGW, telnet, AX.25-packet, ARDOP and VARA transports; the APRS engine; the Winlink B2F client; and the emcomm workflow (ICS-213, net logging, profiles) with a CLI and a local web UI — but on-air validation against real radios/TNCs is the remaining and as-yet incomplete step. Expect bugs. Use at your own risk.
Status:
0.1.0-SNAPSHOT, in active development. SeeARCHITECTURE.mdfor the design and roadmap.
GoKit never depends on the Linux kernel AX.25 stack (removed from mainline in
2026) and never opens an AF_AX25 socket. All packet I/O is userspace: KISS or
AGW over TCP to a software TNC such as Direwolf. The same code runs on Linux,
macOS, and Windows.
Requires JDK 21 and Maven 3.8+.
mvn clean install
The runnable application jar is produced at gokit-app/target/gokit.jar. Run it
with java -jar; the examples below assume a shell alias:
alias gokit='java -jar gokit-app/target/gokit.jar'
gokit --help # list commands
gokit --version
GoKit speaks to standard software TNCs / modems over TCP — it does not drive a sound card itself. Run one of these alongside GoKit:
| Transport | Needs |
|---|---|
kiss / agw (AX.25 packet) |
a KISS or AGW TNC, e.g. Direwolf |
telnet |
a Winlink CMS / RMS Telnet gateway (TCP) |
ardop |
an ARDOP TNC (piardopc / ardopc / ARDOP_Win), default ports 8515/8516 |
vara |
the VARA HF/FM modem, default ports 8300/8301 |
GoKit reads a small JSON config (there is no YAML anywhere in the project). A
sample is in gokit-app/gokit.example.json:
{
"station": "WM3J-10",
"grid": "FM19",
"mailboxDir": "mail",
"profiles": [
{ "name": "vhf-kiss", "type": "kiss", "host": "localhost", "port": 8001, "channels": { "main": 0 }, "timeoutMs": 30000 },
{ "name": "cms-telnet", "type": "telnet", "host": "cms.winlink.org", "port": 8772, "channels": {}, "timeoutMs": 60000 },
{ "name": "hf-ardop", "type": "ardop", "host": "localhost", "port": 8515, "channels": {}, "timeoutMs": 90000 },
{ "name": "hf-vara", "type": "vara", "host": "localhost", "port": 8300, "channels": {}, "timeoutMs": 90000 }
]
}station— your callsign (with optional SSID).grid— Maidenhead grid square (optional).mailboxDir— directory for the mailbox, net logs, and profiles.profiles— named transports;typeiskiss,agw,telnet,ardop, orvara.
Every command takes -c/--config <file>.
The quickest path is run-web.sh: it builds the image, starts the
container, waits for the UI, and opens it in your browser. On first run it
bootstraps data/gokit.json from the example (edit it afterwards to set your
callsign) and, on a Linux desktop, installs a GoKit entry with an icon into
your applications menu so you can relaunch it from there.
./run-web.sh
To remove the menu entry: rm ~/.local/share/applications/gokit.desktop ~/.local/share/icons/hicolor/scalable/apps/gokit.svg.
A multi-stage Dockerfile builds the jar and runs it on a JRE; the
image entrypoint is the gokit CLI, so the same image serves the web UI and the
one-off commands. To run it by hand instead, put your gokit.json and mailbox
under a ./data directory that is mounted at /data — set
"mailboxDir": "/data/mail" in the config.
mkdir -p data && cp gokit-app/gokit.example.json data/gokit.json # then edit it
docker build -t gokit .
# web UI on http://localhost:8080/
docker run --rm -p 8080:8080 -v "$PWD/data:/data" \
gokit web -c /data/gokit.json --host 0.0.0.0
# a one-off CLI command
docker run --rm -v "$PWD/data:/data" gokit mail -c /data/gokit.json --box inbox
Or use docker-compose.yml — docker compose up --build
starts the web UI on http://localhost:8080/. A minimal file:
services:
gokit:
build: .
image: gokit:latest
command: ["web", "-c", "/data/gokit.json", "--host", "0.0.0.0", "--port", "8080"]
ports:
- "8080:8080" # host:container — change the host side to remap, e.g. "9090:8080"
volumes:
- ./data:/data # holds gokit.json, the mailbox, net logs and profiles
restart: unless-stopped
# network_mode: host # uncomment (and drop `ports:`) to reach a TNC on the host — Linux onlyWhat to change for your setup:
./datacontents — put yourgokit.jsonthere with"mailboxDir": "/data/mail"and your own"station"callsign; create it before the firstup(see the caveats below). Pick a different host path if you keep config elsewhere.ports— the left number is the host port; change it (e.g."9090:8080") if 8080 is taken. Leave the right number8080unless you also change--port.--portincommand— only if you want the container to listen on a port other than 8080; keep it in sync with the right-handportsnumber.network_mode: host— uncomment and remove theports:block if a profile dials a TNC/modem on the host (Direwolf, ARDOP, VARA); otherwise leave it off. See "Reaching a TNC" below.- Run a CLI command instead of the UI:
docker compose run --rm gokit mail -c /data/gokit.json --box inbox.
Container caveats and troubleshooting:
- Bind to
0.0.0.0. The UI defaults to127.0.0.1, which is unreachable from outside the container; passweb --host 0.0.0.0and publish the port. - Create the config first.
web -c /data/gokit.jsonrequires a readable config and exits immediately if it is missing, so the container dies with nothing listening — looking like the build "ran but the UI never came up". Copy the example intodata/before the firstdocker run. If you start the container first, Docker auto-creates./dataowned byroot; remove it (sudo rm -rf data) and recreate it as above. - Make
data/writable by the container. The image runs as a non-root user (uid 1001), so the bind-mounteddata/must be writable by it for the mailbox, net logs, and ICS-213 forms. The simplest fix for a single-user test box ischmod -R 777 data. - Diagnose startup. Run the first time without
-dso any error (missing config, unwritable mailbox, port in use) prints to the console. A healthy start logsGoKit web UI for <station> on http://0.0.0.0:8080/. - Reaching a TNC. Transports connect out to a TNC/modem. A
hostoflocalhostin the config means the container itself, not your machine. To reach Direwolf/ARDOP/VARA running on the host, run the container with host networking (--network hoston Linux, ornetwork_mode: hostin compose), or point the profilehostathost.docker.internal(Docker Desktop).
GoKit is a command tree (gokit <command>). Each command has --help.
# queue a plain Winlink message in the outbox (body from -b or stdin)
gokit compose -c gokit.json -t W1AW -s "Status" -b "All stations operational."
# fill an ICS-213 General Message (also carries a Winlink form-data attachment)
gokit ics213 -c gokit.json -t W1AW --to-name "Logistics" --subject "Water request" \
--incident "Field Day" -m "Send 10 cases of water to staging."
# list a mailbox and read one message by its MID
gokit mail -c gokit.json --box outbox
gokit read -c gokit.json <MID>winlink connects to a station over the named transport profile, sends the
outbox, receives inbound mail into the inbox, and files sent messages:
# over AX.25 packet / ARDOP / VARA — TARGET is the remote station callsign
gokit winlink -c gokit.json -p vhf-kiss W1AW
gokit winlink -c gokit.json -p hf-vara W1AW
# over a Winlink CMS via telnet (with the CMS password if required)
gokit winlink -c gokit.json -p cms-telnet WL2K --password XXXXgokit net start -c gokit.json "Sunday ARES Net"
gokit net checkin -c gokit.json "Sunday ARES Net" W1AW --name "J. Doe" \
--location "Hartford CT" --notes "1 message for EOC"
gokit net show -c gokit.json "Sunday ARES Net"
gokit net list -c gokit.jsongokit profile save -c gokit.json field-vhf --description "VHF field go-kit" \
--transport vhf-kiss --frequency "146.520 FM" --notes "Spare battery, log book."
gokit profile list -c gokit.json
gokit profile show -c gokit.json field-vhfA local, server-rendered web console for the mailbox, net logs, profiles, an ICS-213 compose form, and (optionally) a live APRS heard list:
# serves on http://127.0.0.1:8080/ by default
gokit web -c gokit.json
# also monitor APRS on a KISS/AGW profile for a live heard list
gokit web -c gokit.json --monitor vhf-kiss --port 8080| Module | Purpose |
|---|---|
gokit-core |
Shared model and interfaces — transports, events, station, platform SPI |
gokit-ax25 |
Userspace AX.25 frame encode/decode + connected-mode engine |
gokit-testkit |
Shared test contracts (TCKs) and fixtures — test-scope only |
gokit-transport-kiss |
KISS-over-TCP packet transport |
gokit-transport-agw |
AGW-over-TCP packet transport |
gokit-transport-telnet |
Session transport over TCP (Winlink telnet) |
gokit-transport-packet |
Session transport over AX.25 connected mode |
gokit-transport-ardop |
Session transport over ARDOP |
gokit-transport-vara |
Session transport over VARA |
gokit-aprs |
APRS parse / encode, iGate, beaconing, heard list, monitor |
gokit-winlink |
Winlink B2F client and message store |
gokit-hub-link |
Optional ARS Suite J-Hub discovery and integration |
gokit-glue |
Emcomm workflow — ICS forms, net logging, go-kit profiles |
gokit-ui |
Local web UI (embedded Jetty, server-rendered HTML) |
gokit-app |
Application assembly and gokit command-line entry point |
GoKit is free software, licensed under the GNU General Public License,
version 3 or (at your option) any later version. See LICENSE.