2026-06-21 13:12:13 +02:00

4.8 KiB

AGENTS.md

Project Overview

Go-based REST API wrapping signal-cli for Signal Messenger. Runs exclusively inside Docker; there is no standalone go run dev server for the full API. The Go app orchestrates signal-cli (a Java binary) or signal-cli-native (GraalVM precompiled), communicating via CLI args in normal/native mode or JSON-RPC in daemon mode.

Architecture

  • src/ — Go source (the REST API server)
    • main.go — entrypoint; sets up Gin router, routes, cron, plugin loader
    • api/api.go — all HTTP handlers
    • client/ — signal-cli interaction layer; three modes: Normal, Native, JsonRpc (see client.go constants)
    • datastructs/datastructs.go — shared structs
    • utils/ — helpers, plugin config, text-style parser
    • docs/ — Swagger docs (auto-generated by swag init)
    • scripts/jsonrpc2-helper.go — daemon manager for json-rpc mode
  • plugin_loader.go — Go plugin system using Lua scripts (v1/v2 plugin API)
  • plugins/ — example Lua plugins and persistence plugin
  • Dockerfile — multi-stage build with three release targets: all, jre, and native
  • entrypoint.sh — container entrypoint; validates MODE against available binaries, handles UID/GID, chown, supervisor for json-rpc mode

Build & Run

  • Build & test (local): All commands run from src/
    cd src
    go test ./client -v
    go test ./utils -v
    go build -o signal-cli-rest-api main.go
    
  • Build & run (Docker, the primary workflow):
    # Edit docker-compose.yml: change image to build: "."
    docker compose build
    docker compose up
    
  • Build specific variant (Docker):
    docker build --target all .     # all-in-one (all four modes)
    docker build --target jre .     # JRE variant (normal + json-rpc)
    docker build --target native .  # native variant (native + json-rpc-native)
    
  • No linter or typecheck config exists — standard Go tooling only (e.g., go vet).

Swagger / API Docs

Docs are auto-generated from swag annotations in main.go and api/api.go.

cd src
go run github.com/swaggo/swag/cmd/swag@v1.16.6 init --requiredByDefault --outputTypes "go,json"

The receive V1 schemas require an extra step (add_v1_receive_schemas.go); see src/docs/README.md. CI checks that generated docs are up-to-date (workflow: check-docs.yml).

Image Variants

The Dockerfile produces three release targets from a shared base stage:

Target Tag suffix Contains Modes Platforms
all latest, X.Y.Z headless JRE + signal-cli Java dist + signal-cli-native normal, json-rpc, native, json-rpc-native amd64, arm64, arm/v7
jre latest-jre, X.Y.Z-jre headless JRE + signal-cli Java dist normal, json-rpc amd64, arm64, arm/v7
native latest-native, X.Y.Z-native signal-cli-native only (no JRE) native, json-rpc-native amd64, arm64

The all target is the backwards-compatible default — it contains both runtimes so all four modes work, matching the original monolithic image.

The entrypoint.sh validates that the requested MODE matches binaries available in the running image variant and exits with a clear error if mismatched.

The JRE variant uses openjdk-25-jre-headless (not the full openjdk-25-jre) to avoid ~280 MB of GUI libraries that a CLI tool never uses.

Key Environment Variables

Variable Default Purpose
MODE normal normal, native, json-rpc, json-rpc-native
PORT 8080 Listen port
ENABLE_PLUGINS false Enable Lua plugin system
AUTO_RECEIVE_SCHEDULE Cron expression; incompatible with json-rpc mode
SIGNAL_CLI_CMD_TIMEOUT CLI timeout; incompatible with json-rpc mode
RECEIVE_WEBHOOK_URL Webhook on receive; json-rpc mode only
LOG_LEVEL info debug, info, warn, error
DEFAULT_SIGNAL_TEXT_MODE normal normal or styled

Gotchas

  • The Dockerfile pins SIGNAL_CLI_VERSION and LIBSIGNAL_CLIENT_VERSION as build args. After bumping these, verify the libsignal-client-*.jar filename still matches.
  • Multi-arch builds: the jre target covers linux/amd64, linux/arm64, linux/arm/v7; the native target covers linux/amd64, linux/arm64 only (no armv7 native binary).
  • AUTO_RECEIVE_SCHEDULE and SIGNAL_CLI_CMD_TIMEOUT cause a fatal error in json-rpc mode.
  • RECEIVE_WEBHOOK_URL is only valid in json-rpc mode; fatal in other modes.
  • CI uses Podman for multi-arch builds, not Docker Buildx. Each CI/release workflow builds all three targets (all, jre, native).
  • Release versions are published via publish.sh triggering GitHub Actions (dev vs stable tags, with -jre and -native suffixes for those variants; all variant gets the plain version/latest tags).