Skip to content

ventaquil/appcli-template

Repository files navigation

appcli-template

Rust MSRV License: MIT CI CD Docker

Production-ready Rust template for Linux daemons.

Use this template

  1. Click "Use this template" on GitHub (or fork / clone) this repository

  2. Find-and-replace globally (case-sensitive):

    From To
    appcli-template, appcli your app name (lowercase)
    appclid your daemon binary name
    appclictl your control binary name
    APPCLI your app name (UPPERCASE)
    ventaquil/appcli-template your repository URL

    The repository slug (username/reponame) is also used as the Docker image name — the CD workflow derives it automatically from github.repository.

  3. Update Cargo.toml (version, description, repository, authors, etc.)

  4. Add your domain-specific commands to src/protocol/command.rs

  5. Add your daemon logic to dispatch_command in src/daemon/mod.rs

Everything else — Unix socket IPC, config layering, signal handling, graceful shutdown, daemonization — is already done and battle-tested.

What's included

Feature Implementation
Unix socket IPC Newline-delimited JSON over a Unix socket
Config layering env vars > CLI > YAML > hardcoded defaults
Runtime log-level Change log level without restarting the daemon
SIGINT / SIGTERM Graceful shutdown, removes socket + PID file
SIGHUP Live config reload from disk
Daemonize -b / --background flag to detach from terminal
PID file Written on start, removed on clean exit
Pre-flight check Won't start if daemon is already running
Typed errors Structured error handling throughout

Docker

docker pull ghcr.io/ventaquil/appcli-template:latest

Run the daemon:

docker run --rm -it --name appcli ghcr.io/ventaquil/appcli-template
# or with custom flags
docker run --rm -it --name appcli ghcr.io/ventaquil/appcli-template appclid --log-format pretty

Control it from another terminal:

docker exec -it appcli appclictl ping
docker exec -it appcli appclictl config show
docker exec -it appcli appclictl shutdown

See docs/DOCKER.md for available image variants, build and run instructions.

Quick Start

make

Daemon:

bin/appclid --config /etc/appcli/config.yaml        # foreground
bin/appclid -b --config /etc/appcli/config.yaml     # background

Control:

bin/appclictl ping                           # is it alive?
bin/appclictl config show                    # dump active config
bin/appclictl config reload                  # hot-reload from config file
bin/appclictl config reload /new/path.yaml   # reload from different file
bin/appclictl shutdown                       # graceful shutdown

Signals:

kill -HUP  $(cat /var/run/appclid.pid)   # reload config
kill -TERM $(cat /var/run/appclid.pid)   # graceful shutdown

See docs/DAEMON.md and docs/CONTROL.md.

Configuration

Config file (YAML)

An annotated example config lives at config/config.yaml:

# /etc/appcli/config.yaml
log:
  format: compact
  level:  info
pid-file:    /var/run/appclid.pid
socket-file: /var/run/appclid.sock

All fields are optional. Every value can be overridden via env vars or CLI flags.

See docs/CONFIG.md.

Documentation

Document Description
docs/ARCHITECTURE.md Module layout, data flow, extension points
docs/CONFIG.md YAML config fields, accepted values, defaults, live reload
docs/PROTOCOL.md IPC wire-format spec, JSON examples, Rust type definitions
docs/DAEMON.md appclid flags, startup sequence, signal handling
docs/CONTROL.md appclictl commands, flags, and examples
docs/DOCKER.md Image variants, build and run instructions
docs/MAKEFILE.md All make targets for build, lint, test, and Docker
docs/ACTIONS.md CI/CD workflows, jobs, triggers, and permissions
config/config.yaml Annotated example configuration file

Design Principles

  • No panics — every error is handled, logged, and exits with a meaningful exit code
  • Single source of defaults — defaults live in exactly one place; CLI flags and env vars are always explicit overrides
  • Type-safe config — fields are optional during parsing and fully resolved at runtime
  • Correct priority chain — env vars beat CLI, CLI beats YAML, YAML beats defaults; no layer can accidentally win over a higher one
  • Safe IPC — Unix socket with newline-delimited JSON; no raw bytes, no length prefixes
  • Reactive signals — SIGINT and SIGTERM shut down cleanly; SIGHUP hot-reloads config without a restart (pid-file and socket-file are locked at startup and require a restart to change)
  • Clean shutdown — socket and PID file are always removed on exit, even after a signal
  • Structured logging — format and level are runtime-configurable without restarting

License

MIT

About

Production-ready Rust template for Linux daemons

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors