Docs / Contact / protocols/nano-agent
Nano Agent
The Tendrl Nano Agent is a lightweight, language-agnostic messaging gateway that runs locally on your device or server. It exposes a Unix socket that any application can write JSON to, no SDK required.
Why use the Nano Agent?
- Language agnostic: Any language that can open a Unix socket can send messages. Python, C, Rust, shell scripts, anything.
- Single API key: The agent authenticates once. Local applications connect to the socket without managing credentials.
- Batching and backpressure: Messages are batched dynamically based on system load (CPU, memory, queue depth) and sent to Contact in bulk.
- Retry with backoff: Failed batches are retried automatically with exponential backoff.
- Cross-platform: Runs on Linux, macOS, and Windows (10 1803+) using AF_UNIX sockets.
AF_UNIX Socket Requirements
Windows
- Minimum Version: Windows 10 version 1803 (April 2018 Update) or later
- Windows Server: 2019 or later
- Driver: AF_UNIX support via
afunix.syskernel driver - Verification: Run
sc query afunixto verify the driver is available
Unix/Linux/macOS
- Native AF_UNIX support (all modern versions)
The tendrl Group and Socket Access
The agent runs on Windows, Linux, and macOS. Access to the socket is restricted by group membership on all platforms.
Unix/Linux (and macOS): The tendrl group is required for socket security. The agent runs as user/group tendrl, and the socket directory (/var/lib/tendrl) and socket file are owned by that group with restricted permissions (e.g. 770 for the directory, 660 for the socket). Only root or users in the tendrl group can connect. Add application users with: sudo usermod -aG tendrl your-app-user. Creating the group and setting these permissions during installation is mandatory for correct and secure operation.
Windows: The same idea is enforced using a local group named tendrl and a directory ACL. On first run, the agent creates the group (if missing) and sets the ACL on C:\ProgramData\tendrl so that only the tendrl group has access. Only members of that group (and administrators) can use the socket. Add application or service accounts to the group so they can connect: net localgroup tendrl YourUser /add (run in an elevated prompt). The service account running the agent should also be in tendrl so it can create and use the socket.
Installation
One command on any platform — the installer detects your OS and architecture, verifies checksums against the release manifest, and puts tendrl-agent on your PATH:
macOS / Linux
curl -fsSL https://app.tendrl.com/api/public/tools/nano-agent/v1/latest/install.sh | sh
On Linux, also create the socket directory and access group once:
sudo mkdir -p /var/lib/tendrl
sudo groupadd tendrl
sudo chown :tendrl /var/lib/tendrl
sudo chmod 770 /var/lib/tendrl
(On macOS, or to run without root, set TENDRL_SOCKET to a user-writable path instead.)
Windows (x86_64)
powershell -c "irm https://app.tendrl.com/api/public/tools/nano-agent/v1/latest/install.ps1 | iex"
# Create the socket directory (or let the agent create it on first run; it will also create the "tendrl" local group and set ACL so only that group can access the socket)
mkdir "C:\ProgramData\tendrl"
Starting the Agent
# Using a flag
./tendrl-agent -apiKey=YOUR_API_KEY
# Using an environment variable
export TENDRL_KEY=YOUR_API_KEY
./tendrl-agent
The agent creates a Unix socket and begins listening for messages:
| Platform | Socket Path |
|---|---|
| Linux/macOS | /var/lib/tendrl/tendrl_agent.sock |
| Windows | C:\ProgramData\tendrl\tendrl_agent.sock |
CLI Client
The tendrl binary is a command-line wrapper around the socket protocol. It is useful for debugging, install verification, and shell scripts, especially on Windows where nc -U may not be available.
Download tendrl-* from the same tool downloads listing alongside tendrl-agent. No API key is required on the client.
tendrl ping
tendrl publish -data '{"temperature": 22.5}' -tags sensor
tendrl check -limit 5
tendrl state read
See CLI Client for the full command reference.
Configuration
| Flag | Env | Default | Description |
|---|---|---|---|
-apiKey |
TENDRL_KEY |
— | Entity API key (required) |
-appURL |
TENDRL_APP_URL |
https://app.tendrl.com/api |
API base URL |
-minBatchSize |
— | 10 | Minimum messages per batch |
-maxBatchSize |
— | 200 | Maximum messages per batch |
-maxQueue |
— | 1000 | Maximum queued messages before backpressure |
-targetCPU |
— | 70.0 | Target CPU % for dynamic batch sizing |
-targetMem |
— | 80.0 | Target memory % for dynamic batch sizing |
-flushInterval |
— | 250ms | Maximum time between flushes |
Sending Messages
Connect to the socket and write JSON. Every message needs a msg_type. The data field accepts a JSON object or a string.
Publish a Message
{
"msg_type": "publish",
"data": {
"temperature": 22.5,
"unit": "celsius"
},
"context": {
"tags": ["sensor", "building-a"]
}
}
Messages are queued and batched automatically. To wait for the server response instead, set "wait": true in the context:
{
"msg_type": "publish",
"data": { "temperature": 22.5 },
"context": { "wait": true }
}
Send to a Specific Entity
{
"msg_type": "publish",
"data": { "command": "reboot" },
"dest": "control-panel-01"
}
Send a Heartbeat
Heartbeats are sent directly (not batched) and require system metrics:
{
"msg_type": "heartbeat",
"data": {
"mem_free": 1024.0,
"mem_total": 4096.0,
"disk_free": 50000.0,
"disk_size": 100000.0
}
}
State Messages
Create or update your entity's state table:
{
"msg_type": "state_new",
"data": { "firmware": "1.2.0", "mode": "active" }
}
{
"msg_type": "state_update",
"data": { "mode": "standby" }
}
Read State Table
Retrieve your entity's current state table:
{
"msg_type": "state_read"
}
Response:
{
"statusTable": {
"firmware": "1.2.0",
"mode": "standby"
}
}
Checking for Messages
Poll for messages sent to your entity:
{
"msg_type": "msg_check",
"context": { "limit": 5 }
}
Response is an array of messages, or 204 if none are pending:
[
{
"msg_type": "publish",
"data": { "command": "reboot" },
"tags": ["maintenance"],
"source": "123456:us-1:entity:control-panel",
"timestamp": "2024-01-15T10:30:45Z"
}
]
Quick Start Examples
Python
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/var/lib/tendrl/tendrl_agent.sock")
message = {
"msg_type": "publish",
"data": {"temperature": 22.5, "humidity": 65},
"context": {"tags": ["sensor"]}
}
sock.sendall(json.dumps(message).encode())
sock.close()
C
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
int main() {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strncpy(addr.sun_path, "/var/lib/tendrl/tendrl_agent.sock", sizeof(addr.sun_path) - 1);
connect(fd, (struct sockaddr *)&addr, sizeof(addr));
const char *msg = "{\"msg_type\":\"publish\",\"data\":{\"temp\":22.5}}";
write(fd, msg, strlen(msg));
close(fd);
return 0;
}
Bash
echo '{"msg_type":"publish","data":{"temperature":22.5}}' | \
nc -U /var/lib/tendrl/tendrl_agent.sock
Running as a Service
systemd (Linux)
[Unit]
Description=Tendrl Nano Agent
After=network.target
[Service]
Type=simple
Environment=TENDRL_KEY=your_api_key
ExecStart=/usr/local/bin/tendrl-agent
Restart=always
User=tendrl
Group=tendrl
[Install]
WantedBy=multi-user.target
sudo cp tendrl-agent.service /etc/systemd/system/
sudo systemctl enable --now tendrl-agent
Windows
nssm install TendrlAgent "C:\Program Files\Tendrl\tendrl-agent.exe"
nssm set TendrlAgent Environment "TENDRL_KEY=your_api_key"
nssm start TendrlAgent
Context Fields
| Field | Type | Description |
|---|---|---|
tags |
string[] | Tags for routing and fanout fan-out (max 10) |
wait |
boolean | Wait for server response instead of batching |
limit |
integer | Number of messages to retrieve (msg_check only) |
entity |
string | Entity identifier |
Error Responses
{
"status": "error",
"message": "Queue full, try again later"
}
| Error | Cause |
|---|---|
Queue full, try again later |
Message queue at capacity. Reduce send rate or increase -maxQueue. |
Too many tags provided; maximum is 10 |
Context has more than 10 tags. |
Unknown message type |
msg_type is not one of: publish, heartbeat, state_new, state_update, state_read, msg_check. |
Troubleshooting
Windows AF_UNIX Issues
- AF_UNIX Not Supported
# Check if AF_UNIX driver is available
sc query afunix
# If not available, ensure Windows 10 1803+ or Windows Server 2019+
winver
- Socket Permission Denied
Only the tendrl local group (and administrators) have access to C:\ProgramData\tendrl. Add the user or service account that needs to connect:
# Run in an elevated (Administrator) prompt
net localgroup tendrl YourUser /add
Then check that the directory ACL includes the tendrl group:
icacls "C:\ProgramData\tendrl"
Unix/Linux Issues
- Permission Denied
The socket is only accessible to root and members of the tendrl group (see The tendrl group and socket access). Ensure the socket and directory are owned by tendrl and add your application user to the group if it needs to connect:
# Fix socket ownership
sudo chown :tendrl /var/lib/tendrl/tendrl_agent.sock
sudo chmod 660 /var/lib/tendrl/tendrl_agent.sock
# Allow your app user to use the socket
sudo usermod -aG tendrl your-app-user
- Connection Refused
# Check if agent is running
systemctl status tendrl-agent
# Check socket exists
ls -l /var/lib/tendrl/tendrl_agent.sock
Common Issues
- Message Queue Full
# Check agent logs
# Unix: journalctl -u tendrl-agent -f
# Windows: Check Event Viewer or agent console
# Increase queue size
./tendrl-agent -maxQueue=20000
Logging
Unix/Linux: The agent logs to systemd journal by default:
# View all logs
journalctl -u tendrl-agent
# Follow new logs
journalctl -u tendrl-agent -f
# View errors only
journalctl -u tendrl-agent -p err
Windows: Check Windows Event Viewer under Applications or run agent in console mode for direct output.
Security Considerations
Socket Security
- Socket files created with restricted permissions
- Directory access controls prevent unauthorized access
- AF_UNIX provides better security than TCP for local IPC
API Key Protection
- Store API key in environment variable
- Use service environment configuration
- Don't pass key on command line
Network Security
- Agent uses HTTPS for API communication
- Certificate verification enabled by default
- AF_UNIX eliminates network-based local attacks
Tendrl