Host agent
Probes check your services from the outside. The agent checks the machine itself, which is the only way to see a full disk, a dead process, or a host that is up but no longer doing its job. It is deliberately narrow: it measures and reports, and it executes nothing on your behalf.
What it measures
Section titled “What it measures”Every 15 seconds, on the host:
| Signal | Detail |
|---|---|
| CPU | Total utilisation, 0 to 100 |
| Load average | 1, 5 and 15 minutes (Unix only) |
| Memory and swap | Used, total, percentage |
| Disk | Every mounted filesystem, used and total and percentage |
| Uptime | Seconds since boot |
| Services | For each watched process: running, process count, CPU, resident memory |
No network counters, no per-core breakdown, no temperatures. Nothing about the host that is not in that table.
Install
Section titled “Install”Create an enrolment token in the app under Host agents, New agent. It hands you a ready-made command:
PERSTAT_TOKEN=psag_… sh -c "$(curl -fsSL https://agent.perstat.io/install.sh)"The environment assignment keeps the token out of ordinary process arguments and ps output.
A literal command pasted into an interactive shell can still be stored in shell history; use
your secret manager or a shell-specific hidden-input/history policy, then unset the variable.
Supported today: Linux on x86_64 and aarch64 (static musl builds, no runtime dependencies) and macOS as a universal binary. Windows is not shipped yet.
The installer detects OS and architecture, downloads the matching binary, and checks SHA-256. With an Ed25519-capable OpenSSL 3 it also verifies the release signature against the key in the script. Without that capability, including common macOS LibreSSL and older distributions, it warns and falls back to TLS transport plus SHA-256. Because installer and key come from the same origin, the first install still depends on that origin being trusted. The agent’s later self-update uses a compiled key and is fail-closed, as described below.
On macOS it installs a LaunchDaemon instead. Set PERSTAT_NO_SERVICE=1 if you want the
binary without a service.
Re-running is safe. If the host is already enrolled, the installer switches to upgrade mode: it refreshes the binary and the service, keeps the existing identity, and needs no token. Running the same line from your configuration management on every host, repeatedly, is the intended use. For more than a handful of machines, see agents on a fleet.
Enrolment tokens
Section titled “Enrolment tokens”| Property | Default | Range |
|---|---|---|
| Lifetime | 24 hours | 1 to 720 hours |
| Single use | yes | can be made reusable |
The token is shown once and stored only as a hash. Single use is right for one machine; a reusable token is right for a fleet roll-out. Tokens cannot be withdrawn before they expire, so prefer a short lifetime over a long one.
The token itself is opaque. Which organization and project it belongs to is resolved on the server, never parsed by the agent.
Monitors you can build on it
Section titled “Monitors you can build on it”An agent reports; a monitor decides what is worth an incident. Create monitors of type
agent and bind them to the agent. One monitor watches one signal:
metric |
Fields | Fires when |
|---|---|---|
availability |
grace_seconds (default 180, range 60 to 3600) |
The host stopped reporting for longer than the grace |
cpu |
threshold (default 90) |
CPU above the threshold |
mem |
threshold (default 90) |
Memory above the threshold |
disk |
threshold (default 90) |
The fullest filesystem above the threshold |
service |
service_name, grace_seconds (default 120, range 60 to 3600) |
The process has been absent for longer than the grace |
Two settings apply to all of them. breach_severity is down (opens an incident, pages
on-call, shows on status pages) or degraded (an in-app notice only). notify_push
toggles the push notification.
One disk monitor covers every mount point, because the threshold is evaluated against the fullest filesystem. Note what that does and does not catch: it sees a filesystem filling up, not a single file growing. A log file that adds 700 MB to a 25 GB disk moves the figure by three points and will not trip a 90 percent threshold.
Agent monitors are evaluated on our side roughly every 30 seconds. They take no check regions and no quorum, so a single breaching evaluation opens the incident once the grace has passed.
Watching services
Section titled “Watching services”service_name is a process name, not a systemd unit. The agent scans the process
table and matches three ways: the exact process name, the exact basename of the
executable (which is what makes postgres and postmaster both work), and the Linux
15-character name truncation. Matching is case sensitive on Linux.
That has a consequence worth knowing before you configure it. A service that starts as a
script shows up in the process table as python3, sh or node, so two such services
cannot be told apart by name. Compiled daemons and anything that sets its own process
name are fine.
To see the real names, either run ps -eo comm= | sort -u on the host, or switch on the
process inventory for that agent. It is opt-in, off by default, and transmits process
and executable names only, deduplicated and capped, never command lines, paths, users or
PIDs. With it on, the monitor form suggests names instead of asking you to type them.
The agent only scans the process table when at least one service monitor exists for it.
Network and firewall
Section titled “Network and firewall”Outbound only. The agent never opens a listening socket. There is no inbound rule to write and no port to expose, and the systemd unit restricts address families and system calls to match.
Two destinations over HTTPS on port 443:
| Host | Purpose |
|---|---|
api.perstat.io |
Enrolment, measurements, configuration polling |
agent.perstat.io |
Installer, binaries, self-update downloads |
Both need to resolve. On a machine that runs an authoritative nameserver rather than a resolver, make sure a usable resolver is configured.
Timing
Section titled “Timing”Measurements every 15 seconds, sent in a batch every 60 seconds, configuration polled about every 5 minutes. The first measurement is sent immediately after enrolment, so a new host appears within seconds.
When a push fails, measurements queue in memory (about six hours’ worth) and are sent when the connection returns, so a short outage does not leave a hole in your history. The queue does not survive a restart of the agent.
One consequence of the 5 minute configuration poll: after you add a service monitor, it can take a few minutes before the agent is watching that process. Until real data arrives the monitor stays pending rather than firing, so a newly created monitor never raises a false alarm.
Self-update
Section titled “Self-update”The agent keeps itself current. Releases are ed25519-signed, the signing key stays offline, and the agent verifies the signature against a key compiled into its own binary before swapping anything. It is fail-closed: an unverifiable release is not installed, and a lower version never qualifies. The swap happens inside the agent’s own directory and needs no root helper.
Set DATARGO_AGENT_NO_SELFUPDATE=1 in the service environment if you would rather drive
versions yourself.
Removing an agent
Section titled “Removing an agent”Remove the identity with the trash icon on the agent. This revokes its token, archives the monitors attached to that agent, and resolves their open incidents. Archived monitors free their plan slots while their historical records remain subject to the applicable retention rules.
Remove the software on the host:
curl -fsSL https://agent.perstat.io/uninstall.sh | sudo shIt stops and removes the service, deletes the binary, state and service user, and deregisters the host. If the machine is already gone, removing the identity in the cockpit is sufficient.
When an agent goes quiet
Section titled “When an agent goes quiet”Worth understanding precisely, because it decides what you see.
The availability monitor fires: silence past its grace period opens an incident. This is the monitor that tells you a host is gone, and it is the reason to give every agent one.
The other monitors are not evaluated at all once the last report is older than 180 seconds. They write no checks, so they neither open nor resolve anything, which is why a dead host produces one incident rather than one per metric. The flip side: those tiles keep displaying their last reading, which is usually green. Read the availability monitor, not the tiles, when a host is silent.
One distinction we do not yet draw: a dead host and a healthy host that cannot reach us produce the same signal, because the timestamp we work from is when the report arrived. If that difference matters to you, pair the availability monitor with an external check against the same machine.
Data minimalism
Section titled “Data minimalism”The agent never collects command lines, environment variables or usernames. Process inventory is opt-in and limited to names. It measures the host and reports; it is not an inventory or forensics tool, and its narrow scope is the point.
It also executes nothing. There is no remote command channel, no script hook and no way for us to run something on your machine. That is a deliberate design limit rather than a feature we have not built yet.
Limits today
Section titled “Limits today”- Windows is not shipped. It lands on the changelog when it is real.
- systemd unit state is not read. The check answers “is a process of this name alive”, so a failed unit with a lingering process, a wedged process, and restart flapping inside the grace window all read as healthy.
- Your own measurements cannot be reported through the agent. If you need to alert on
a number only the host knows, a heartbeat monitor covers it: each one
has a healthy endpoint (
/ping/<token>) and a failure endpoint (/ping/<token>/fail), and a timer on the host decides which to call. Calling the failure endpoint breaches at the next evaluation rather than waiting out the period. That covers what a percentage threshold cannot, such as a count that dropped or a directory that grew. - One monitor per signal. Watching four processes on a host means four monitors.