2026-06-18 08:29:08 +02:00

4.4 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 two release targets: 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 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 two release targets from a shared base stage:

Target Tag suffix Contains Modes Platforms
jre latest, X.Y.Z 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 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 both jre and native targets.
  • Release versions are published via publish.sh triggering GitHub Actions (dev vs stable tags, with -native suffix for the native variant).