barto - A job scheduling system
Overview
barto is a distributed, WebSocket-based job scheduling system composed of four components:
bartos— Central scheduling server (Actix-web + MariaDB). Owns all schedule definitions and persists every job's output and exit status.bartoc— Remote worker client. Connects tobartosvia WebSocket, receives schedule initializations, executes the configured commands, and streams results back.barto-cli— Command-line interface for querying and managing a runningbartosinstance.libbarto— Shared library providing the message protocol,Realtimescheduler, config types, TLS support, and tracing initialization.
How it works: bartos triggers scheduled commands at the configured times and sends them over WebSocket to the matching bartoc instance by name. bartoc executes each command, streams stdout/stderr output and exit status back to bartos, which persists everything to MariaDB for later querying via barto-cli.
All services are configured via TOML files located at ~/.config/<service>/<service>.toml by default, with BARTO* environment variables available to override any TOML value.
MSRV
1.95.0
bartos - The barto server
Configuration
bartos configuration is controlled via a toml file. By default this is located in the bartos directory rooted at the dirs2 config directory, i.e. /home/<user>/.config/bartos/bartos.toml on a Linux machine. The full path to the configuration file can also be specified as a command-line argument to bartos. See the
help output bartos --help for more details.
Format
# Actix Configuration
[]
# The number of actix worker to launch (REQUIRED)
= 8
# The ip address to listen on for the actix server (REQUIRED)
= "0.0.0.0"
# The port to list on for the actix server (REQUIRED)
= "20000"
# Actix TLS Configuration (OPTIONAL)
[]
# The ip address to listen on for a TLS connection (REQUIRED)
= "0.0.0.1"
# The port to listen of for a TLS connection (REQUIRED)
= "20000"
# The full path to the Certificate PEM file (REQUIRED)
= "/path/cert.pem"
# The full path to the Private Key PEM file (REQUIRED)
= "/path/key.pem"
# MariaDB Configuration (REQUIRED)
[]
# The hostname of the database (REQUIRED)
= "localhost"
# The port of the database, default 3306 (OPTIONAL)
= 3307
# The username for the database (REQUIRED)
= "user"
# The password used to access the database (REQUIRED)
= "pass"
# The database name (REQUIRED)
= "db"
# An & separated list of database directives (OPTIONAL)
= "ssl=true"
# stdout Tracing Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
# File Tracing Configuration (REQUIRED)
[]
# The quiet level (more is less verbose output) (REQUIRED)
= 0
# The verbose level (more is verbose output) (REQUIRED)
= 3
# File Tracing Layer Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
# An array of schedules for barto clients (REQUIRED)
# This is [schedules.<bartoc name>].
# This should match the name defined in your bartoc.toml.
[]
= [
{ = "echo", = "*-*-* 10:R:R", = [ "echo -n \"barto\"" ] }
]
The on_calendar format is outlined at Realtime
Command Line Usage
A bartos server records information from bartoc instances and serves as a central hub for job scheduling
Usage: bartos [OPTIONS]
Options:
-v, --verbose...
Turn up logging verbosity (multiple will turn it up more)
-q, --quiet...
Turn down logging verbosity (multiple will turn it down more)
-e, --enable-std-output
Enable logging to stdout/stderr
-c, --config-absolute-path <CONFIG_ABSOLUTE_PATH>
Specify the absolute path to the config file
-t, --tracing-absolute-path <TRACING_ABSOLUTE_PATH>
Specify the absolute path to the tracing output file
-h, --help
Print help
-V, --version
Print version
Ed25519 Message Signing
bartos can sign every outgoing BartosToBartoc message with an Ed25519 private
key. bartoc verifies the signature before acting on any message — a bartoc
instance that receives an unsigned or incorrectly-signed message drops it and logs
a warning. This protects against a compromised network path even when TLS alone
might be bypassed.
The wire format is [64-byte Ed25519 signature][bincode-encoded message]. When
signing_key is not configured on bartos, messages are sent unsigned (current
behaviour). When server_public_key is not configured on bartoc, verification is
skipped.
Generating an Ed25519 keypair
# Generate a 32-byte Ed25519 private key seed (base64-encoded)
| | |
# → paste output as signing_key in bartos.toml
# Derive the corresponding public key (base64-encoded)
| |
Or generate both in one step and capture each:
# Write private key to file
# Extract 32-byte private seed (base64) → signing_key for bartos
| |
# Extract 32-byte public key (base64) → server_public_key for bartoc
| |
Configuring bartos (server)
# bartos.toml
= "base64encodedEd25519PrivateKey..."
Configuring bartoc (client)
# bartoc.toml
= "base64encodedEd25519PublicKey..."
Keep bartos-signing.pem (and the signing_key value) secret and only on the
bartos host. The server_public_key value is safe to distribute to every bartoc
instance — it is a public key.
HMAC-SHA256 Message Authentication & Replay Protection
bartos can wrap every outgoing BartosToBartoc message in an HMAC-SHA256
authenticated envelope. bartoc verifies the MAC before acting on any message
and rejects messages with duplicate nonces or timestamps outside a configurable
window (default ±60 s). This provides:
- Message integrity — any in-transit tampering with the payload is detected
- Authentication — only a peer that knows the shared secret can produce valid messages
- Replay protection — each message carries a random 64-bit nonce;
bartoctracks seen nonces within the replay window and drops duplicates
The authenticated envelope is prepended to the bincode payload (inside any Ed25519 signature when both are enabled):
[8-byte timestamp BE][8-byte nonce BE][32-byte HMAC-SHA256][bincode payload]
When hmac_key is not configured on either side, messages are forwarded without
authentication (backward-compatible). If only one side has the key configured,
jobs will not run — both sides must use the same key.
Generating an HMAC key
# Generate a 32-byte random key (base64-encoded)
# → paste the output as hmac_key in both bartos.toml and bartoc.toml
Keep this value secret. Unlike the Ed25519 public key, it must never be distributed publicly — anyone who knows it can forge authenticated messages.
Configuring bartos (server)
# bartos.toml — top-level, not under any section
= "your-shared-secret-here"
Configuring bartoc (client)
# bartoc.toml — top-level, not under any section
= "your-shared-secret-here"
# Optional: replay window in seconds (default: 60).
# Messages whose timestamp differs from the current time by more than this value
# are rejected, regardless of MAC validity.
# replay_window_secs = 60
Layer ordering: when both Ed25519 signing and HMAC are enabled, the HMAC envelope wraps the bincode payload first (inner layer), then the Ed25519 signature wraps the result (outer layer). On
bartoc, Ed25519 is verified first, then the HMAC envelope is unwrapped. Either layer can be enabled independently of the other.
Pre-Shared Token / Bearer Authentication
bartos supports a pre-shared API token that all clients must present on the
WebSocket upgrade request (Authorization: Bearer <token>). Connections with a
missing or incorrect token are rejected with HTTP 401 before the WebSocket
handshake completes. This provides connection-level authentication independent
of TLS or message-layer signing.
When api_key is not configured, all connections are accepted (backward-compatible).
Generating an API key
# Generate a 32-byte random token (base64-encoded)
# → paste the output as api_key in bartos.toml, bartoc.toml, and barto-cli.toml
Keep this value secret. Anyone who knows it can connect to bartos.
Configuring bartos (server)
# bartos.toml — top-level, not under any section
= "your-secret-token-here"
Configuring bartoc and barto-cli (clients)
# bartoc.toml or barto-cli.toml — under [bartos]
[]
= "your-secret-token-here"
TLS & Certificate Pinning
bartos supports TLS for all WebSocket connections. bartoc and barto-cli
support certificate pinning — trusting only a specific CA certificate rather
than the full system/Mozilla root CA store. This prevents MITM attacks via a
compromised or malicious public CA.
What needs to change when clients are added or removed?
Nothing on the server certificate. The SANs in the bartos server cert list
the server's own hostnames and IP addresses — they say nothing about clients.
Adding a new bartoc instance only requires generating a new client certificate
for that instance (see Mutual TLS below). Removing a client
just means decommissioning its cert; the server cert is untouched.
You only need to recreate the server certificate when:
- bartos moves to a new hostname or IP address
- The cert expires
- The CA key is compromised
The CA certificate (bartos-ca.pem) is the most stable artifact — valid for
10 years in the examples below. Clients pin this CA cert, not the server cert
itself, so they automatically trust any new server cert signed by the same CA
when the server cert is rotated.
Generating a CA and server certificate
Two options are shown: openssl (ubiquitous) and step from
Smallstep (simpler API for PKI work).
Using openssl
# 1. Generate the CA key and self-signed CA certificate (valid 10 years)
# 2. Generate the bartos server key and a certificate signing request (CSR).
# The CN and SANs are the bartos SERVER's own hostname/IP — not the clients.
# 3. Sign the server CSR with the CA (valid 1 year).
# The subjectAltName extension is required by modern TLS clients (rustls).
# List every hostname and IP that bartos itself listens on.
# Client hostnames/IPs are NOT listed here.
Using step (Smallstep CLI)
# 1. Generate the CA key and self-signed CA certificate
# 2. Generate the bartos server certificate signed by the CA.
# --san flags list the SERVER's own hostname(s) and IP(s), not clients.
Configuring bartos (server)
Point [actix.tls] at the signed server certificate and key:
[]
= "0.0.0.0"
= "20000"
= "/etc/bartos/bartos.pem"
= "/etc/bartos/bartos.key"
Configuring bartoc and barto-cli (clients)
Set prefix = "wss" and pin the CA certificate. Only connections whose server
certificate is signed by this CA will be accepted:
[]
= "wss"
= "bartos.example.com"
= 20000
= "/path/to/bartos-ca.pem"
Distribute bartos-ca.pem to every bartoc and barto-cli host. Keep
bartos-ca.key and bartos.key private and only on the bartos host.
Tip: set restrictive permissions on key files:
Mutual TLS (mTLS) — bartos server side
Mutual TLS additionally proves each client's identity to the server — bartos will reject any connection that does not present a valid certificate signed by a trusted client CA.
Add client_ca_cert to [actix.tls]. bartos will now require every connecting
bartoc and barto-cli to present a certificate signed by this CA:
[]
= "0.0.0.0"
= "20000"
= "/etc/bartos/bartos.pem"
= "/etc/bartos/bartos.key"
= "/etc/bartos/bartos-ca.pem"
See the bartoc TLS & mTLS section for how to generate and
configure client certificates on each bartoc instance.
bartoc - The barto client
Configuration
bartoc configuration is controlled via a toml file. By default this is located in the bartoc directory rooted at the dirs2 config directory, i.e. /home/<user>/.config/bartoc/bartoc.toml on a Linux machine. The full path to the configuration file can also be specified as a command-line argument to bartoc. See the
help output bartoc --help for more details.
Format
# The name of the bartoc instance (REQUIRED)
= "vader"
# The number of attempted re-connection attempts (REQUIRED)
# after a disconnect
= "10"
# Optional connection timeout in seconds (OPTIONAL)
# client_timeout = 30
# How to handle missed scheduler ticks (OPTIONAL)
# Values: Burst (default), Delay, Skip
# missed_tick = "Burst"
# The bartos configuration (REQUIRED)
[]
# The websocket prefix, i.e. ws or wss. (REQUIRED)
# NOTE: wss requires TLS support on bartos
= "wss"
# The hostname of the bartos instance (REQUIRED)
= "localhost.ozias.net"
# The port of the bartos instance (REQUIRED)
= 21526
# stdout Tracing Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
# File Tracing Configuration (REQUIRED)
[]
# The quiet level (more is less verbose output) (REQUIRED)
= 0
# The verbose level (more is verbose output) (REQUIRED)
= 3
# File Tracing Layer Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
Command Line Usage
A bartoc instance runs scheduled jobs and reports results back to a bartos instance
Usage: bartoc [OPTIONS]
Options:
-v, --verbose...
Turn up logging verbosity (multiple will turn it up more)
-q, --quiet...
Turn down logging verbosity (multiple will turn it down more)
-e, --enable-std-output
Enable logging to stdout/stderr
-c, --config-absolute-path <CONFIG_ABSOLUTE_PATH>
Specify the absolute path to the config file
-t, --tracing-absolute-path <TRACING_ABSOLUTE_PATH>
Specify the absolute path to the tracing output file
-r, --redb-absolute-path <REDB_ABSOLUTE_PATH>
Specify the absolute path to the redb database file
-h, --help
Print help
-V, --version
Print version
TLS & mTLS
Certificate pinning
Set prefix = "wss" and ca_cert in [bartos] to pin the bartos CA. Only
connections whose server certificate is signed by that CA are accepted — see the
TLS & Certificate Pinning section for generating the
CA and server certificate.
[]
= "wss"
= "bartos.example.com"
= 20000
= "/path/to/bartos-ca.pem"
Mutual TLS (mTLS) — client certificates
If bartos is configured to require client certificates (client_ca_cert in
[actix.tls]), each bartoc instance must present its own signed certificate.
Each instance gets its own cert — adding a new worker means generating one new cert and signing it with the CA. No other certs change.
Generating a client certificate
Using openssl:
# Generate a client key and CSR (CN can be anything descriptive)
# Sign with the same CA used for the server cert
Using step:
Configuring bartoc
Add client_cert and client_key to [bartos]:
[]
= "wss"
= "bartos.example.com"
= 20000
= "/path/to/bartos-ca.pem"
= "/path/to/my-worker.pem"
= "/path/to/my-worker.key"
Note: if the server does not request client auth, the client cert is silently not sent and the connection succeeds. This means client certs can be configured on all
bartocinstances before enablingclient_ca_certon the bartos server — allowing a gradual, zero-downtime rollout.
Each bartoc instance should have its own unique certificate so that a
compromised instance can be identified and its certificate revoked independently.
HMAC-SHA256 Authentication
If bartos is configured with an hmac_key, each bartoc instance must be
configured with the same key to accept messages. Set the key and, optionally, the
replay window at the top level of bartoc.toml:
# bartoc.toml — top-level, not under any section
= "your-shared-secret-here"
# Optional: replay window in seconds (default: 60)
# replay_window_secs = 60
See the HMAC-SHA256 Message Authentication & Replay Protection
section under bartos for key generation instructions and a full description of
the wire format and layer ordering.
Bearer Token Authentication
If bartos is configured with an api_key, each bartoc instance must present
the same token on the WebSocket upgrade or the connection will be rejected (HTTP
401). Set the key under [bartos] in bartoc.toml:
[]
= "your-secret-token-here"
See the Pre-Shared Token / Bearer Authentication
section under bartos for token generation instructions.
barto-cli - The barto command line client
Configuration
barto-cli configuration is controlled via a toml file. By default this is located in the barto-cli directory rooted at the dirs2 config directory, i.e. /home/<user>/.config/barto-cli/barto-cli.toml on a Linux machine. The full path to the configuration file can also be specified as a command-line argument to barto-cli. See the
help output barto-cli --help for more details.
Format
# The name of the barto-cli instance (REQUIRED)
= "vader-cli"
# The bartos instance configuration (REQUIRED)
[]
# The websocket prefix, i.e. ws or wss. (REQUIRED)
# NOTE: wss requires TLS support on bartos
= "wss"
# The hostname of the bartos instance (REQUIRED)
= "localhost.ozias.net"
# The port of the bartos instance (REQUIRED)
= 21526
# stdout Tracing Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
# File Tracing Configuration (REQUIRED)
[]
# The quiet level (more is less verbose output) (REQUIRED)
= 0
# The verbose level (more is verbose output) (REQUIRED)
= 3
# File Tracing Layer Configuration (REQUIRED)
[]
# Should the target be included in tracing output (REQUIRED)
= true
# Should thread ids be included in the tracing output (REQUIRED)
= false
# Should thread names be included in the tracing output (REQUIRED)
= false
# Should line numbers be included in the tracing output (REQUIRED)
= false
# Should the output level be included in the tracing output (REQUIRED)
= true
# An comma separated list of tracing directives (OPTIONAL)
= "actix_server=error,actix_tls=error"
Command Line Usage
A command line tool for requesting information from a bartos instance
Usage: barto-cli [OPTIONS] <COMMAND>
Commands:
info Display the bartos version information
updates Check for recent updates on a bartoc client
cleanup Perform cleanup of old database entries
clients List the currently connected clients
query Run a query on bartos
list List the output for the given command
failed List the jobs that failed
cmd Display output for the given command name across all clients
help Print this message or the help of the given subcommand(s)
Options:
-v, --verbose...
Turn up logging verbosity (multiple will turn it up more)
-q, --quiet...
Turn down logging verbosity (multiple will turn it down more)
-e, --enable-std-output
Enable logging to stdout/stderr
-c, --config-absolute-path <CONFIG_ABSOLUTE_PATH>
Specify the absolute path to the config file
-t, --tracing-absolute-path <TRACING_ABSOLUTE_PATH>
Specify the absolute path to the tracing output file
-h, --help
Print help
-V, --version
Print version
Info
Display the bartos version information
Usage: barto-cli info [OPTIONS]
Options:
-j, --json Output the information in JSON format
-h, --help Print help
Updates
Check for recent updates on a bartoc client
Usage: barto-cli updates --name <NAME> --update-kind <UPDATE_KIND>
Options:
-n, --name <NAME> The name of the bartoc client to check for recent updates
-u, --update-kind <UPDATE_KIND> Check for updates of the given kind
-h, --help Print help
Cleanup
Perform cleanup of old database entries
Usage: barto-cli cleanup
Options:
-h, --help Print help
Clients
List the currently connected clients
Usage: barto-cli clients
Options:
-h, --help Print help
Query
Run a query on bartos
Usage: barto-cli query --query <QUERY>
Options:
-q, --query <QUERY> The query to run on bartos
-h, --help Print help
List
List the output for the given command
Usage: barto-cli list --name <NAME> [-c <CMD_NAME>]
Options:
-n, --name <NAME> The name of the bartoc client to check for recent updates
-c, --cmd-name-opt <CMD_NAME> The name of the command to list the output for
-h, --help Print help
Failed
List the jobs that failed
Usage: barto-cli failed
Options:
-h, --help Print help
Cmd
Display output for the given command name across all clients
Usage: barto-cli cmd <CMD_NAME>
Arguments:
<CMD_NAME> The name of the command to display output for
Options:
-h, --help Print help