ManageLM Documentation

Manage your Linux and Windows servers with natural language — securely, instantly, at scale.

Deployment mode:

Overview

ManageLM is a remote server management platform. Instead of SSH-ing into servers and running commands manually, you describe what you want in plain English and ManageLM takes care of the rest.

You are running the self-hosted version. The portal runs on your own infrastructure via package installer or Docker.

You are using the SaaS version hosted by ManageLM.

The three components:
  • Portal — The control plane (this web app). Manages accounts, agents, skills, and bridges communication.
  • Agent — A lightweight daemon on each managed Linux or Windows server. Receives tasks, uses an LLM to interpret them, executes commands, and reports back.
  • Claude — Connects via MCP (Model Context Protocol) to the portal. You talk to Claude, Claude talks to your servers.

How It Works

Architecture diagram
  1. You ask Claude to do something on a server, e.g. "Restart nginx on web-01".
  2. Claude calls a tool on the portal that maps to the agent's assigned skills.
  3. The portal forwards the task to the target agent.
  4. The configured LLM (local Ollama/LM Studio, or a cloud provider) interprets the task and generates the shell commands.
  5. Commands are validated against the skill's allowlist before execution — only explicitly permitted commands can run.
  6. Results flow back through the agent → portal → Claude → you.
Key security principle: Agents only initiate outbound connections. No inbound ports are needed on your servers. Commands are validated against a strict allowlist defined by each skill.

What you can do

Just describe what you need in plain English. Here are examples across skills:

CategoryExample prompt
Services"Restart nginx on web-01 and show me the last 20 log lines"
Packages"Update all packages on production servers"
Users"Add SSH access for Charly on user deploy on pocmail"
Security"Run a security audit on all servers and email me a summary"
Access"Who has sudo on production servers?"
Activity"Run an activity audit on dev and show who logged in today"
Files"Add a server block for api.example.com to nginx on web-01"
Firewall"Open port 8080 on staging servers"
Containers"List all running Docker containers on docker-01 and show which ones use more than 1GB memory"
Certificates"Check TLS certificate expiry on all web servers"
Backups"Show me the last backup status for every agent and which ones are failing"
Database"Show the slow query log for MySQL on db-01"
Monitoring"Which servers have disk usage above 85%?"
Multi-server"Check if chrony is running on all servers, install it where it's missing"
LLM"Pull llama3.2 on the Ollama server and test it with a simple prompt"

These are not templates — you can phrase requests however you want. The agent interprets intent and adapts to each server's OS (Linux or Windows), package manager, and configuration.

Quick Start

From zero to managing a server with natural language — in under 10 minutes.

What You'll Need

  1. Create an account — Register on the portal and verify your email.
  2. Configure the LLM — Go to Settings → Account. Choose Local LLM (install Ollama and run ollama pull qwen3.5:9b) or Cloud LLM (enter a provider API key).
  3. Import Skills — Go to Agent Skills → Catalog and import the skills your agent will need. Start with system, files, services, packages, and users.
  4. Install the agent — Click Add Agent in the dashboard, copy the install command, and run it on your server.
  5. Approve the agent — The portal detects the enrollment automatically. Verify the hostname and click Approve.
  6. Assign skills — Click on the agent, scroll to Assigned Skills, and assign the skills you imported.
  7. Connect Claude — Copy the MCP connector details from Settings → MCP & API into Claude Desktop or Claude Code.
  8. Run your first task — Ask Claude: "Show me the system info on web-01", or use the portal's Run Task button directly.
That's it! Your agent is running, skills are assigned, and you can manage your server with natural language — either through Claude or the portal UI. Read on for detailed instructions on each step.

Create an Account

  1. Navigate to the portal and click Register.
  2. Enter your first name, last name, email, and password.
  3. Check your email for a verification link and click it.
  4. Log in to the portal. You're now the owner of your account.
As the account owner, you have full access to all features. You can invite team members later from the Users & Roles page.

Install an Agent

Agents are installed on any Linux or Windows server you want to manage. The install is a single command.

  1. Log in to the portal and go to My Agents.
  2. Click Add Agent.
  3. Optionally select one or more groups. The agent is automatically placed in the site you have selected in the sidebar (or stays unassigned if you're viewing "All sites" — see Sites).
  4. Copy the install command and run it on your server:

Linux

curl -fsSL "https://your-portal/install.sh?token=..." | sh

The Linux installer will:

Linux requirements: Python 3.9+, curl, and root/sudo access. The install script supports both apt-based and dnf-based distributions.

Windows

On Windows, the portal provides a PowerShell install script. Copy it from the Add Agent modal (Windows tab) and run it in an elevated PowerShell session. The Windows installer performs the same enrollment steps and registers the agent as a Windows service.

Windows requirements: Python 3.9+, PowerShell 7+, and Administrator access.

Approve the Agent

After the install script runs, the agent appears in the portal as pending approval.

  1. The portal's Add Agent modal will automatically detect the new enrollment and show an approval prompt.
  2. Verify the hostname and click Approve.
  3. The agent receives its access token and connects via WebSocket.
  4. A green Connected indicator appears in the agent list.

You can also approve agents from the agent list by clicking the Approve button on any pending agent.

Set Up the LLM

Each agent uses an LLM to interpret tasks and generate commands. Configure from Settings → Account.

Option 1: Local LLM (Recommended)

Install Ollama or LM Studio for full data privacy — your commands and data never leave your infrastructure. The LLM can run on the agent server itself or on a dedicated machine accessible by your agents.

# Install Ollama
curl -fsSL https://ollama.com/install.sh | sh

# Pull a recommended model
ollama pull qwen3.5:9b

Ollama listens on http://localhost:11434 by default. If Ollama runs on a separate server, set the LLM API URL to its address (e.g. http://llm-server:11434) in Settings → Account.

Recommended local models

ManageLM agents need an LLM that reliably follows structured output formats (<cmd> tags, <done/> markers). For IT agent workloads — generating shell commands, managing services, parsing logs — models with strong instruction following perform best. On consumer GPUs we recommend Mixture-of-Experts (MoE) models as the preferred default: gemma-4-26b-a4b (Gemma 4, 3.8B active) and qwen3.6:27b-a3b (Qwen 3.6, 3B active). Both deliver near -dense quality at a fraction of the per-token cost, and Gemma 4 adds native multimodal support and a 256K-token context for large log / config analysis. Dense models (Gemma 4 31B, Qwen 3.6 27B, Qwen 3.5 35B, Mistral, Llama 3.3) remain the recommended choice on high-end hardware where the extra VRAM and throughput are available.

All VRAM figures below assume 4-bit quantization (Q4), which is the default for Ollama/LM Studio and keeps quality within ~2–5% of full precision while cutting memory by roughly 60%. Add 1–3 GB of overhead for the runtime, KV cache, and typical context — more for long contexts on dense models.

CPU-only servers (not recommended)

ModelSizeRAMNotes
qwen3.5:9b9B~7 GBBest balance of speed and accuracy for CPU-only servers.
qwen3.5:4b4B~4 GBLightweight option for constrained servers or simple skills.
gemma-4-e4bE4B (4B effective)~5 GBGemma 4 edge model — native multimodal (text, image, audio, video), 128K context. Runs on modest CPU or 8 GB class GPU.
ministral-3:8b8B~6 GBMistral’s edge model with strong function calling and 128K context. Good alternative to qwen3.5:9b when Mistral’s instruction style fits your skills better.

GPU servers (min 16–24 GB VRAM)

ModelSizeVRAMNotes
qwen3.6:27b-a3b27B MoE (3B active)~17 GBQwen 3.6 Mixture-of-Experts — ~3B active parameters give near-4B latency with quality close to a dense 27B. Strong tool-use and structured output for agent skills. Fits RTX 3090/4090.
qwen3.5:35b-a3b35B MoE (3B active)~22 GBQwen 3.5 Mixture-of-Experts — larger expert pool than the 27B variant for higher peak quality, while keeping ~3B active parameters for near-4B latency. Fits 24 GB GPUs (RTX 4090, A5000).
gemma-4-26b-a4b26B MoE (3.8B active)~18 GBMixture-of-Experts — only 3.8B active parameters at inference, so tokens-per-second are close to a 4B model while quality is close to a 26B. 256K context (memory stays modest: ~18 GB at 4K → ~23 GB at 256K). Fits RTX 3090/4090.
gpt-oss:20b20B MoE (3.6B active)~13 GBOpenAI open-weights Mixture-of-Experts — strong tool-use and structured output with very fast tokens-per-second. Different model lineage from Qwen/Gemma/Mistral, useful as a second opinion or fallback. Fits comfortably on 16 GB GPUs.
mistral-small3.224B~16 GBMistral’s small model with strong function calling and instruction following.
ministral-3:14b14B~10 GBMid-tier Mistral model — fast tokens-per-second on consumer GPUs (RTX 3080/4070+) with solid tool-use. Leaves headroom for long contexts or parallel skills.
Tip: You can assign different models per skill using LLM Model Override in the agent detail page — for example, use a larger model for complex skills like containers or kubernetes, and qwen3.5:9b for simple skills like system or users. This optimizes both quality and throughput.

Option 2: Cloud LLM

Use an external cloud provider instead of running a local LLM. Supported providers:

ProviderExample models
Anthropic (Claude)claude-opus-5, claude-sonnet-5, claude-haiku-4-5
OpenAI (ChatGPT)gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna
Google (Gemini)gemini-3.7-flash, gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite
xAI (Grok)grok-4.6, grok-4.5, grok-4.3
Groqllama-3.3-70b-versatile, llama-3.1-8b-instant, openai/gpt-oss-120b, openai/gpt-oss-20b
Mistralmistral-large-3-25-12, mistral-medium-3-5-26-04, mistral-small-4-0-26-03, ministral-3-14b-25-12
DeepSeekdeepseek-v4-pro, deepseek-v4-flash
OpenRouteranthropic/claude-opus-5, anthropic/claude-sonnet-5, anthropic/claude-haiku-4.5, openai/gpt-5.6-sol
Together AImeta-llama/Llama-3.3-70B-Instruct-Turbo, deepseek-ai/DeepSeek-V4-Pro, deepseek-ai/DeepSeek-V4-Flash-0731, openai/gpt-oss-120b
Fireworks AIaccounts/fireworks/models/llama-v3p3-70b-instruct, accounts/fireworks/models/llama-v3p1-405b-instruct
Perplexitysonar, sonar-pro, sonar-reasoning-pro, sonar-deep-research

Select the provider and model from the dropdown, enter your API key, and click Test to verify the connection before saving.

Privacy note: With cloud LLM, task data (commands, parameters, outputs) is sent to the provider for processing. For production workloads with sensitive data, use a local LLM instead.

LLM Access Mode

In self-hosted mode, you can choose how agents access the LLM:

  • Direct (default) — Each agent calls the LLM directly. The API key is sent to the agent.
  • Proxied — Agents route LLM calls through the portal. The API key stays on the portal server and is never sent to agents. This is useful for centralized key management or when agents should not have direct network access to the LLM provider.

Set the access mode from Settings → Account using the Direct / Proxied toggle. Agents with per-agent LLM overrides always use direct access regardless of this setting.

Proxied badge: When an agent uses proxied access, the dashboard shows an orange PROXIED badge next to the LLM status.
LLM detection: When an agent connects, it probes the LLM endpoint and reports the service type and reachability status in the portal dashboard.

Assign Skills

Skills define what an agent is allowed to do. Without skills, an agent can only perform read-only operations.

  1. Go to Agent Skills in the sidebar.
  2. Click Catalog to browse the built-in skills.
  3. Import the skills you need (e.g. "Systemd Service Management", "Package Management").
  4. Navigate to your agent's detail page.
  5. In the Assigned Skills section, click the skill buttons to assign them.

Built-in Skills (31 total)

Skills are available for both Linux and Windows agents. On Linux, skills use shell commands (bash); on Windows, skills use PowerShell-based equivalents. The skill catalog includes platform-appropriate commands for each OS.

SkillWhat it can do
baseCore read-only utilities (file reading, search, system info, resource usage, network diagnostics). Auto-assigned to all agents.
systemSystem info, performance, hostname, timezone, kernel, reboot.
filesCreate, read, write, move, copy, delete files. Permissions, compression, upload/download.
servicesStart, stop, restart services. Systemd on Linux, Windows Services on Windows. Cron jobs, timers, scheduled tasks, process management.
packagesInstall, update, remove packages. Linux: apt, dnf, yum, pacman, zypper, snap. Windows: Chocolatey, winget, MSI.
usersCreate/manage system users, groups, SSH keys, and sudo access.
networkConfigure interfaces, routes, DNS, diagnose connectivity and ports.
firewallManage firewall rules. Linux: UFW, firewalld, iptables, nftables. Windows: Windows Firewall (netsh/PowerShell).
storageDisks, partitions, filesystems, LVM, RAID, mounts, and swap.
securityAuditing, hardening. Linux: fail2ban, SELinux/AppArmor, SSH config. Windows: Windows Defender, BitLocker, Group Policy, Windows Firewall. Intrusion detection.
certificatesSSL/TLS certificates, Let's Encrypt, CAs, Java keystores, trust stores.
logsView, search, and analyze system and application logs (read-only).
monitoringSystem health, resource usage, disk/network I/O, service checks.
containersDocker, Podman, Buildah, images, volumes, networks, Compose.
webserverNginx, Apache, Caddy, Tomcat — sites, configs, SSL, reverse proxy.
webappsNode.js, Python, PHP, Ruby, Java apps — PM2, Gunicorn, Supervisor.
databaseMySQL, PostgreSQL, SQLite — queries, schemas, users, backups.
nosqlMongoDB, Redis, Elasticsearch — data operations, backups, clusters.
gitGit repositories — clone, pull, push, branches, deployment workflows.
backupBackup and restore with rsync, tar, cron — files, dirs, databases.
dnsBIND, Unbound, dnsmasq — zones, records, resolver configuration.
emailPostfix, Dovecot, queues, aliases, DKIM, SPF, spam filtering.
vpnWireGuard, OpenVPN, IPsec — tunnels, peers, keys.
virtualizationKVM/QEMU, libvirt, LXC/LXD, Proxmox, Vagrant.
kubernetesPods, deployments, services, Helm, scaling, troubleshooting.
proxySquid, Varnish, HAProxy — reverse proxy, caching, load balancing.
messagequeueRabbitMQ, Kafka, NATS, ActiveMQ — queues, consumers, messages.
filesharingNFS, Samba/SMB, FTP/SFTP, WebDAV.
ldapOpenLDAP, FreeIPA, SSSD — directory services, centralized auth.
automationAnsible, Terraform, cloud-init — infrastructure as code.
llmOllama, vLLM, llama.cpp — local LLM server and model management.
Security note: Each skill has a strict command allowlist. For example, the services skill on Linux can only run systemctl and journalctl; on Windows, only Get-Service, Restart-Service, etc. The agent rejects any command not on the list. An agent with no skills can only run read-only commands.

Choose Your Interface

ManageLM is not tied to a single tool. You can manage your servers from Claude, ChatGPT, your terminal, the web portal, VS Code, Slack, or n8n — pick whatever fits your workflow.

ScenarioClaude MCPChatGPTShellPortalVS CodeSlackn8n
Natural language tasksSlash cmdsStructured
Multi-step reasoning✓ BestWorkflows
Scheduled & automated tasksVia portalVia portal✓ Cron✓ Built-inWebhooks✓ Native
Security audits & reports✓ + PDF
Fleet operations✓ Bulk select
CI/CD & scripting✓ Best✓ APIAlerts✓ Best
Team collaborationPer userPer userPer user✓ RBAC + auditPer user✓ Shared channels✓ Shared
Offline / air-gapped✓ Self-hosted✓ Self-hosted
Summary: Use Claude MCP or ChatGPT for complex, conversational tasks. Use the Shell for scripting and cron jobs. Use the Portal for dashboards, RBAC, and PDF reports. Use VS Code to manage servers from your editor. Use Slack for team alerts and approvals. Use n8n for automation pipelines.

Connect Claude

ManageLM integrates with Claude via the Model Context Protocol (MCP). Claude sees your servers as tools it can call.

There are two ways to connect Claude to ManageLM. Pick based on whether Claude can reach your portal directly:

Option A: Custom Connector (OAuth)

Available on every Claude plan (Free is limited to one connector). Uses OAuth 2.0 with PKCE, the standard MCP authentication method.

  1. Go to Settings → MCP & API in the portal — you'll need the four fields shown there: Name, Remote MCP URL, OAuth Client ID, OAuth Client Secret.
  2. In Claude Desktop: Customize → Connectors → Add custom connector. Paste the four fields and save.
  3. On Claude Team plans, the org admin adds the connector once under Organization Settings → Connectors → Add → Custom → Web (on claude.ai), and each member then enables it under Customize → Connectors with their own ManageLM credentials.

Option B: Local bridge (mcp-remote)

Requires Node.js installed locally. The same JSON snippet works for both Claude Desktop and Claude Code — only the config file location differs.

  1. Go to Settings → MCP & API in the portal, expand MCP Connector (JSON), and copy the snippet (it embeds your credentials).
  2. Paste it into the relevant config file:
    • Claude Desktop on macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Claude Desktop on Windows: %APPDATA%\Claude\claude_desktop_config.json
    • Claude Code: use claude mcp add, or paste the same snippet into the project's .mcp.json or your user-level Claude Code config.
  3. Restart Claude Desktop (or reload Claude Code).

The snippet looks like this:

{
  "mcpServers": {
    "ManageLM": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://your-portal/mcp",
        "--header", "X-MCP-Id: your-client-id",
        "--header", "X-MCP-Secret: your-secret"
      ]
    }
  }
}

macOS gotcha: apps launched from Finder or the Dock don't inherit your shell PATH, so plain npx may fail with "command not found". If that happens, replace "npx" with its absolute path (run which npx in a terminal to find it).

What Claude sees

Once connected, Claude gets one tool per skill slug (e.g. system, services, files). Each tool takes two parameters:

For example, Claude calls the services tool with target: "web-01" and instruction: "restart nginx", or with target: "Frankfurt" to fan out to every agent in that site.

Claude also gets built-in meta-tools:

Note: The tool list is fetched at connection time. If skills are added or removed during a session, Claude won't see the changes until you reconnect (restart Claude Desktop or re-open Claude Code).

Run Tasks

You can run tasks in two ways:

Via Claude (MCP)

Just describe what you want in natural language:

Via the Portal UI

  1. Click on an online agent in the dashboard.
  2. Click the Run Task button.
  3. Select a skill from the dropdown.
  4. Type a natural-language instruction describing what you want.
  5. Click Execute.

Task results appear in the Command History section on the agent detail page and in the Request Log page.

Agent CLI Tools

Three on-host commands ship with the agent and talk to the local daemon over a Unix socket — no network, no portal round-trip. They reuse the same skill gate, command validator, and kernel sandbox as portal tasks, and work offline whenever the local LLM is configured. All three are installed in /opt/managelm/bin/ (Linux) or C:\ProgramData\ManageLM\bin\ (Windows) and also exposed on the PATH.

Security model: These tools run as root / LocalSystem on the managed host. They bypass portal user identity (no per-user RBAC) but still go through the skill's allowed-commands validator and the kernel sandbox, and every task is forwarded to the portal's audit log with source shell.

managelm-shell — Interactive terminal

A natural-language REPL on the managed server. Type what you want, the agent auto-routes it to the best skill, runs it through the sandbox, and streams the answer back.

# Interactive REPL
managelm-shell

# One-shot
managelm-shell -c "install htop and verify"

# Force a specific skill
managelm-shell
> @services restart nginx

Shell tasks show up in the Audit Log (Agent Activity tab) and webhooks just like portal tasks.

managelm-fixit — Diagnose & fix one file

Point it at any misbehaving file. The agent classifies the content, picks the right skill, diagnoses the issue, and proposes a full-file replacement as a colored diff. Apply on y, reject on N.

# Diagnose, show diff, y/N to apply
managelm-fixit /etc/nginx/nginx.conf

# Diagnosis only, no diff
managelm-fixit --explain /etc/postfix/main.cf

# Auto-apply without prompting
managelm-fixit --yes /var/www/app/config.yaml

# Force a skill and add a hint
managelm-fixit @webserver -c "502 after upgrade" /etc/nginx/nginx.conf

managelm-review — Read-only review

Where fixit writes, review only reads. Point it at a file or a directory and get a short summary plus a list of findings grouped by severity. Nothing is written to disk.

# Review a single file
managelm-review /etc/ssh/sshd_config

# Review a directory (walks recursively, skips .git, node_modules, …)
managelm-review ./src/

# Only warning + critical
managelm-review --severity warning ./src/

# JSON for CI
managelm-review --format json ./src/

Inside a Terminal Console

Two more tools work only where there is a browser at the other end — inside a Terminal Console. Run either over plain SSH and it says so rather than doing something surprising.

managelm-copy /var/log/syslog     # send a file to your browser's downloads
managelm-copy /etc/nginx          # a folder arrives as nginx.zip
managelm-copy app.conf web-01:/etc/   # or straight to another server
managelm-sync ./conf   web-01:/etc/app/   # keep a folder in step

managelm-edit /etc/nginx/nginx.conf   # open it in an editor over the terminal

See Moving files in and out and Editing a file.

Quick Reports

Quick reports are one-click diagnostic commands available on the Agent Assets page. They let you run common checks on any online agent without writing instructions.

How it works

  1. Open the Agent Assets page.
  2. Each agent card shows small icon buttons below the OS info line — one per available report.
  3. Click an icon to run the report. A modal opens showing a spinner while the agent executes.
  4. When complete, the modal displays the LLM summary (a readable interpretation) and the raw terminal output.
  5. Click Copy to copy both summary and output to your clipboard.
Requirements: The agent must be online and you need admin/owner role or the agents permission. Reports only appear for skills that are assigned to the agent (directly or via a group).

Available reports

Nine built-in skills include quick reports. Each report runs a pre-built instruction on the agent:

SkillReportWhat it checks
systemSystem SummaryHostname, OS, kernel, uptime, load, memory and disk usage
systemTop ProcessesTop 10 processes by CPU and memory
servicesService InventoryAll services with status and enabled state (systemd on Linux, Windows Services on Windows)
servicesFailed ServicesServices in failed state
packagesAvailable UpdatesPackages with pending updates
usersUser AccountsAll users and groups with UID, GID, home, shell
networkListening PortsAll listening TCP/UDP ports with their process
securitySecurity OverviewListening ports, SSH config, fail2ban status
containersContainer StatusAll containers with name, image, status, ports
storageDisk UsageDisk usage for all mounted filesystems
logsRecent ErrorsErrors and warnings from the system journal (Linux) or Windows Event Log (last 30 min)

Active task indicators

Agent cards on both the My Agents dashboard and the Agent Assets page display a red badge with a spinning icon when the agent has tasks currently running. The badge shows the number of active tasks (pending, sent, or executing).

Portal UI Guide

PagePurpose
My AgentsDashboard showing all agents, their status, LLM info, skills, active task indicators, and a 7-day task activity chart. Add, approve, search, and bulk-manage agents.
Agent DetailConfigure an agent: display name, LLM settings, tags, groups, assigned skills, member access. Run tasks and view command history.
Agent AssetsVisual server map with agents organized into collapsible zones — by group, tag, site, subnet or operating system, whichever you pick (the choice is remembered) — click-to-expand agent cards with 24h metrics and cloud provider metadata, quick report buttons, security audit, system inventory, SSH & sudo access, certificate discovery, activity audit, service dependencies, scheduled tasks, and bulk select operations.
Agent Skills & RulesetsImport skills from the built-in catalog, create custom skills or rulesets, or import/export skill JSON files. Two tabs: Skills (per-skill commands and prompts) and Rulesets (cross-skill policy text). Attachment counts on each row reflect the active site when one is selected.
Agent Groups & SitesTwo tabs: Groups (logical organization — e.g. "production", "staging" — carry skills, rulesets, SIEM, and member access) and Sites (physical/logical location — datacenters, offices — carry an optional Local LLM endpoint and feed the global site filter). See Sites for the full picture.
Users & RolesInvite team members, assign roles (admin/member), and configure granular permissions.
MonitorsService monitors — track availability and response time of 43 service types (HTTP, TCP, DNS, SMTP, databases, message brokers, VPNs, and more). Sparkline charts, status badges, alert toggles, categorized catalog, test-before-create.
CertificatesCertificate management — issue, renew, and revoke TLS certificates via internal CA or Let's Encrypt. Deploy to agents automatically. CRL generation. Daily auto-renewal sweep.
CredentialsCredential rotation — generate and rotate passwords, SSH keys and Entra client secrets on a schedule, then deliver them to a vault, a file your scripts read, an application's own database, a local account on other hosts, the Windows registry or a pipeline. Local accounts, LDAP, Active Directory, Entra, databases and Redis.
KeystoreKSM Keystore — RSA, EC, post-quantum ML-DSA, AES and HMAC keys held by the portal and used by applications on your servers through a PKCS#11 module, without the key ever reaching the host. Per-application credentials, Unix account allowlists, certificates served over PKCS#11, and a per-day record of what every key was used for and what was refused.
System BackupsSystem Backups — end-to-end encrypted filesystem backups to your own S3 storage (OVH, AWS, R2, B2, Exoscale, Wasabi, Scaleway, Hetzner, DigitalOcean, Google Cloud, Infomaniak, MinIO/Ceph, or any S3-compatible endpoint). Streaming downloads, restore to any agent, detach-on-delete, optional service quiesce for consistent database snapshots.
PentestsAutomated penetration testing for public-facing agents using nmap, nuclei, testssl.sh, ffuf, subfinder. Credit-based scans with domain verification. Results feed into the Compliance page. Pro/Business plans.
ComplianceCompliance framework mapping — automatically projects security audit and pentest results onto CIS Level 1, CIS Docker, SOC 2, PCI DSS, ISO 27001, NIS2, NIST CSF, and HIPAA. Drift detection with in-app and email alerts. Per-framework evidence PDFs.
ConnectorsExternal integrations split into three kinds: Hosting Integration (Azure, AWS, Google Cloud, VMware, Proxmox, OpenStack — credentials, test connections, sync resources, browse discovered hosting inventory with agent matching), SIEM Integration (Splunk HEC, Elasticsearch _bulk, generic JSON webhook — agents forward task-completion events directly to the destination, per-agent or inherited from an agent group), and Notifications & Ticketing (Slack messages, ServiceNow and Jira tickets — per-category routing for monitor / cert / backup / security / threat / report / pentest / agent / task events with severity-aware defaults).
Audit LogFour-tab viewer of everything that happened in your account: Agent Activity (task log per agent with AI summary in the expanded row, Changes-only toggle, and PDF export — replaces the standalone Reporting page), Threat Alerts, Admin Actions, and Geolocation (world map of admin connection origins, when GeoIP is configured). Account-wide visibility requires the logs permission; otherwise the view is scoped to the agents you are assigned to.
SettingsProfile (name, timezone, System Username), Security (passkeys, MFA, SSH public keys, verified domains, sessions), MCP & API (credentials, IP whitelist, API keys, webhooks), PKI & CA (internal CA setup, Let's Encrypt account, DNS-01 providers, certificate defaults), S3 Backups (provider, bucket, credentials, orphan cleanup), Account (plan, LLM defaults, danger zone).

Skills

Skills are the core security and capability model. Each skill defines:

PowerShell modules need agent 1.5.0 or newer. Older agents ignore the field, so a Windows skill that lists its capabilities as modules loses those commands on that host until it is updated. The portal names the affected agents when you upgrade a catalog skill.
Hard security boundary: The allowed_commands list is enforced in code, not just in prompts. Even if the LLM generates a command not on the list, the agent will reject it. Empty allowed_commands = read-only mode (only safe commands like ls, cat, grep).

Management Hints

Each skill assignment (on an agent or a group) supports management hints — free-text contextual instructions passed to the LLM alongside the task. Use hints to provide server-specific or group-wide context that helps the LLM do its job:

Hints can be set at two levels:

LevelWhere to setScope
Per-agentAgent detail → expand skill → Management HintsThis skill on this specific agent
Per-groupAgent Groups → expand skill → Management HintsThis skill on all agents in the group

Direct per-agent skill assignments take priority over group-inherited ones (including their hints).

Skill Definition Example

Below is an example of a Linux skill definition. Windows skills follow the same structure, listing PowerShell cmdlets in allowed_commands and whole modules in allowed_modules.

{
  "description": "Manage systemd services",
  "operations": [
    {
      "name": "restart",
      "description": "Restart a systemd service"
    },
    {
      "name": "status",
      "description": "Get status of a service including recent logs"
    }
  ],
  "allowed_commands": ["systemctl", "journalctl"],
  "system_prompt": "You are a Linux sysadmin..."
}

Operations are instruction-based — each operation has only a name and description. They describe capabilities for documentation and AI context, not structured parameter schemas. The agent LLM interprets the user's natural-language instruction to determine what commands to run.

Skill Combinations

Many real-world management tasks span multiple skills. Each skill controls a specific domain — when an operation touches several domains, you need all the relevant skills assigned to the agent.

How it works: When you ask Claude to perform a multi-step task, it will call the appropriate skill tools one after another. If a required skill is missing, that step will fail with a "skill not assigned" error. Plan ahead by assigning all the skills an agent needs for its role.

Foundation skills

These five skills are used by almost every management workflow. Consider assigning them to all agents as a baseline:

SkillWhy it's foundational
systemSystem info, hostname, timezone — needed to understand what you're working with.
filesRead/write config files, set permissions — almost every change touches a file.
servicesStart/stop/restart daemons, manage cron — most installations end with a service reload.
packagesInstall software — any new capability starts with installing a package.
usersCreate accounts, manage SSH keys, sudo — many services need a dedicated user.

Common multi-skill workflows

Below are typical management tasks and the skills they require. Each example shows what you'd ask Claude and which skills are involved.

Create a new system user with SSH access

"Create user deploy with a home directory, add their SSH key, and set them up with sudo access for systemctl"

StepSkill needed
Create user account and groupusers
Create home directory and set ownershipfiles
Add SSH authorized keyusers
Configure sudoers entryusers

Skills: users + files

Install and configure Nginx with SSL

"Install nginx, create a site for example.com with Let's Encrypt SSL, and open port 443 in the firewall"

StepSkill needed
Install nginx packagepackages
Create site config filewebserver
Obtain SSL certificate via certbotcertificates
Enable the site and reload nginxwebserver
Open ports 80/443 in the firewallfirewall

Skills: packages + webserver + certificates + firewall

Deploy a Node.js application

"Clone the repo from GitHub, install dependencies, set up a PM2 process, and configure nginx as a reverse proxy"

StepSkill needed
Create app user and directoryusers + files
Clone the Git repositorygit
Install Node.js and npm dependencieswebapps
Start the app with PM2webapps
Create nginx reverse proxy configwebserver
Set up SSL certificatecertificates

Skills: users + files + git + webapps + webserver + certificates

Set up a PostgreSQL database server

"Install PostgreSQL 16, create a database and user for my app, configure backups, and open port 5432 only from 10.0.0.0/24"

StepSkill needed
Install PostgreSQL packagespackages
Start and enable the serviceservices
Create database and DB userdatabase
Edit pg_hba.conf for network accessfiles
Set up a pg_dump cron jobbackup
Open port 5432 for the subnetfirewall

Skills: packages + services + database + files + backup + firewall

Docker Compose deployment

"Create a docker-compose.yml for my app stack, start it, and check the container logs"

StepSkill needed
Create project directory and compose filefiles
Start compose stackcontainers
View container logscontainers
Open ports in firewall (if needed)firewall

Skills: files + containers + firewall

Security hardening

"Harden SSH (disable root login, key-only auth), set up fail2ban, and configure the firewall to allow only SSH and HTTPS"

StepSkill needed
Edit sshd_configsecurity
Restart sshdservices
Install and configure fail2bansecurity
Set firewall rules (allow 22, 443 only)firewall
Review auth logslogs

Skills: security + services + firewall + logs

Set up WireGuard VPN

"Install WireGuard, generate keys, configure a tunnel to 10.0.1.0/24, and open UDP port 51820"

StepSkill needed
Install WireGuard packagepackages
Generate keys and create configvpn
Enable IP forwarding (sysctl)network
Open UDP 51820 in firewallfirewall
Start and enable the WireGuard serviceservices

Skills: packages + vpn + network + firewall + services

Skill assignment strategies

Use agent groups to assign skill sets by server role, so you don't have to configure each agent individually:

Server roleRecommended skills
Web serversystem, files, services, packages, users, webserver, certificates, firewall, logs, monitoring
App serversystem, files, services, packages, users, webapps, git, logs, monitoring
Database serversystem, files, services, packages, database, backup, firewall, storage, logs, monitoring
Docker hostsystem, files, services, packages, containers, network, firewall, storage, logs, monitoring
Minimal / read-onlysystem, logs, monitoring (no write skills — agent can only read)
Least-privilege: Only assign the skills each server actually needs. A database server doesn't need webserver. A web server doesn't need database. Fewer skills = smaller attack surface.

Policy Rulesets

Rulesets are short markdown policy snippets attached to agents (directly or via groups). Every attached ruleset applies to every task on that agent, regardless of which skill runs.

Where management hints are advisory context scoped to a single skill ("PostgreSQL data dir is /data/pg16"), rulesets are cross-skill constraints that stay in force for the whole task ("Never restart services between 09:00 and 18:00 UTC", "Never edit files under /etc/pam.d without prior approval"). The prompt includes an explicit refusal rule: if a request would violate a listed policy, the agent refuses instead of executing.

Managing Rulesets

Go to Agent Skills → Rules. Each ruleset has:

Attaching Rulesets

LevelWhereScope
Per-agentAgent detail → RulesetsThis agent only
Per-groupAgent Groups & Sites → Groups tab → RulesetsAll agents in the group

Rulesets accumulate across attachments — an agent gets the union of everything attached directly plus everything inherited from every group it belongs to (deduplicated by ruleset id). Changes push to affected agents immediately over WebSocket; no restart required.

Permission: Managing rulesets requires the skills permission (same gate as creating custom skills).
Rulesets are guidance, not a hard sandbox. They instruct the LLM to refuse out-of-policy requests, but hard security boundaries (allowed_commands, kernel sandbox, skill operation gates) still live in the agent itself. Use rulesets for organizational policy; use skills and the kernel sandbox for enforcement that cannot be prompted around.

Agent Groups

Groups let you organize agents logically (e.g. by environment or role) and apply policy in bulk.

Create and manage groups from the Agent Groups & Sites page (Groups tab). Assign agents to groups from the agent detail page or the groups page. Sites live next to groups under the Sites tab on the same page — groups carry policy (skills, rulesets, SIEM), sites carry physical/logical location.

Group-level skill configuration

When assigning skills to a group, you can configure per-skill settings that apply to all agents in the group:

Click the chevron next to a skill in edit mode to expand the configuration panel.

Sites & Datacenters

Sites give every agent a physical or logical home — a datacenter, office, branch, or cloud region. They're a different axis from groups: groups are policy bags (skills, rulesets, SIEM, member access), sites are about where the server lives. Most teams won't create any sites and that's fine; they're optional and only worth turning on once a fleet spans multiple locations.

What sites do

LLM resolution chain

The LLM endpoint an agent uses is resolved field-by-field in this priority order:

PrioritySourceWhen to use
1 (highest)Per-agent override (Agent detail → Edit)One agent needs a specific endpoint
2Per-site override (Sites tab → expand row → LLM)One LLM appliance close to a whole datacenter's worth of agents
3Account default (Settings → Account)Default for everything else
4Local default (http://localhost:11434, llama3.2)Nothing configured

An explicit URL anywhere in the chain bypasses Trial LLM and Proxied LLM — if you point a site at a local appliance, agents in that site go direct.

On the agent edit page the toggle reads "Inherit from site" when the agent's site has its own LLM, otherwise "Inherit from account". The "Currently:" line shows the resolved endpoint regardless of source.

Creating and managing sites

Sites are admin-only. From the Agent Groups & Sites page (Sites tab):

Detached resources under a specific-site filter

Some resources can become "detached" when their agent is deleted — backups (S3 data survives) and certificates (the cert remains until expiry for the CRL). Under "All sites" or "None", detached items are visible. Under a specific-site filter, they hide — they don't belong to any specific site, so a site view doesn't include them. Switch back to "All sites" to see and reassign or delete them.

Site vs group at a glance

 GroupSite
ConceptPolicy bagPlace
MembershipMany-to-manyOne-to-one (an agent is in 0 or 1 site)
Carries skills / rulesetsYesNo
Carries SIEM destinationYesNo
Carries Local LLM defaultsNoYes
Filters the sidebar selectorNoYes

Secrets

Each agent has a local secrets.txt file (/opt/managelm/secrets.txt on Linux, C:\ManageLM\secrets.txt on Windows). This file stores sensitive values that commands might need.

# Example secrets.txt
DB_USER=myapp
DB_PASS=s3cret
API_KEY="my-api-key"
How secrets work: Values are injected as environment variables into command subprocesses. The LLM only sees variable names ($DB_PASS), never the actual values. Secrets never leave the server.

LLM Configuration

The LLM is configured from Settings → Account:

For both Local and Cloud LLM, you can choose the access mode:

  • Direct — Agent calls the LLM directly (default).
  • Proxied — Agent routes LLM calls through the portal. The API key stays on the portal and is never exposed to agents.

Configuration hierarchy

LLM settings can be overridden at multiple levels (highest priority first):

LevelWhere to setUse case
Per-skill overrideAgent detail → expand skill → LLM Model OverrideUse a specific model for complex skills
Per-agent overrideAgent detail → Edit → "Override for this agent"Agent needs a different LLM (local or cloud)
Per-site overrideGroups & Sites → Sites tab → expand site → "Override for this site"One LLM appliance close to all agents in a datacenter (see Sites)
Account defaultSettings → AccountDefault for all agents

The per-skill config panel also includes management hints for providing contextual instructions to the LLM.

Per-agent overrides offer Local LLM or Cloud LLM options and always use direct access. Agents inherit from the account default unless explicitly overridden.

Default values if nothing is configured:

Users & Roles

ManageLM supports team collaboration with role-based access control.

Roles

RoleAccess
OwnerFull access. Cannot be removed. One per account.
AdminFull access. Can invite users, manage permissions, edit settings.
MemberLimited access based on permissions. Only sees assigned agents and groups.

Member Permissions

PermissionGrants access to
agentsApprove, delete, configure agents and assign skills. Does not grant a terminal console — that is not a permission at all, but a grant made per server
groupsCreate, rename, delete groups and assign agents
skillsCreate, import, edit, and delete skills
logsView task logs and MCP activity
reportsRun and view security audits, system inventory, SSH/sudo access scans, activity audits, compliance dashboards
connectorsCreate and manage hosting connectors (AWS, Azure, GCP, VMware, Proxmox, OVH…) for resource discovery and SIEM forwarding
hostingAct on the infrastructure a hosting connector exposes — start, stop, reboot and snapshot VMs. Separate from connectors, which only covers configuring the integration itself
monitorsCreate, edit, delete service monitors; toggle alerts; run ad-hoc tests
certificatesIssue, renew, revoke, and deploy TLS certificates (Internal CA + Let's Encrypt)
backupsConfigure backups, run on-demand, restore snapshots, manage account S3 settings
pentestsLaunch penetration tests (active attack scans against public agents)
credentialsCreate, edit, rotate, test and delete managed credentials and their delivery targets

Several of these gate changing things rather than seeing them: every member can view Monitors, Certificates, Backups and Credentials read-only, and the permission unlocks the buttons. Credential pages never show a secret — there is none stored to show.

The terminal console is not in this table, and is not a permission. It is granted per server, beside SSH Root and Sudo Root, in that server’s Assigned Users list or on a group — see Terminal Console. Nothing in this table opens a console, and neither does being an owner or an admin: everyone needs the grant on the server they want a shell on.

Disabling a user

Each user has a toggle beside the delete button. Disabling blocks sign-in and immediately cuts everything that person currently holds — browser sessions, API keys they created, MCP connections — while keeping the account itself, along with their group access, site grants and SSH keys. Re-enable them and they carry on where they left off.

Prefer it to deletion when you are responding to something rather than off-boarding: deleting a user takes all of that with them. The Panic Button disables every member at once.

You cannot disable yourself, and the account owner can never be disabled — there always has to be a way back in.

MCP Visibility

All users (including owners and admins) only see agents via MCP that are:

This ensures MCP access is always explicitly granted, regardless of role.

Skill Restrictions

For delegated admin members, you can optionally restrict which skills they can invoke by maintaining a per-member allowlist. On the Users & Roles page, expand the Skill Restrictions row under a member's permissions and click Edit to add skills to the member's allowlist.

Use permissions to gate management actions (creating agents, editing groups) and skill restrictions to gate operational ones (running sensitive skills on agents). Rejected tasks return the same error as “skill not assigned to agent”, so a restricted user can't tell whether the skill is missing or simply forbidden for them.

Site Admin Grants

For delegated members, you can optionally grant admin permissions on specific sites — on top of (not in place of) any global perms the member already holds. On the Users & Roles page, expand the Site Admin Grants row under a member and pick one or more sites.

Which permissions can be elevated: the seven that act on individual agents — agents, monitors, backups, certificates, pentests, reports, logs. Not elevatable: groups, skills, connectors — these manage account-wide catalogs that have no per-site axis, so only the global perm can grant them.

The terminal console is not on this list and cannot be site-granted. It is handed out one server at a time, in that server’s Assigned Users list or on a group.

Read access is independent of these grants. A member still sees every agent they're assigned to (directly or via group / site member access); grants only affect write/admin actions on those agents.

Enforcement is uniform across the portal UI, the API, and the MCP scan tools. Action buttons, agent pickers in “New Monitor”, “New Certificate”, “New Backup”, “New Pentest”, the copy-to-agents modals, bulk action toolbars, and per-row management buttons all filter to agents the member can actually admin (global perm or matching site grant).

Inviting Users

  1. Go to Users & Roles.
  2. Click Invite User.
  3. Enter their name and email, select a role, and set permissions.
  4. They'll receive an email with an invitation link.

Passkeys & MFA

ManageLM uses WebAuthn passkeys for multi-factor authentication. The rule is simple: having a passkey is having MFA — there is no separate on/off switch.

Require MFA for all users (account owners)

Owners can enforce MFA account-wide from Settings → Security → Passkeys & MFA with Require MFA for All Users. When on, every member must clear a second factor at login:

The same applies when connecting MCP clients: a connector login with a passkey does the passkey step; without one, the emailed-code page appears.

SSH key as MFA fallback (account owners)

Owners can also enable SSH Key as MFA Fallback in the same section. When on, any member who has registered an SSH public key may sign the login challenge with their SSH private key as a recovery alternative to their passkey (portal login only).

API Keys

API keys allow programmatic access to the portal API for automation and integrations.

  1. Go to Settings → MCP & API.
  2. Enter a name, select permissions (any subset of the ten member permissions: Agents, Groups, Skills, Logs, Reports, Connectors, Monitors, Certificates, Backups, Pentests), and optionally set an expiration (30, 90, 180, or 365 days).
  3. Click Create Key and copy the key (starts with mlm_ak_). It's only shown once.

Use the key in the Authorization header:

Authorization: Bearer mlm_ak_...

Each key's effective permissions are the intersection of the key's permissions and the creating user's permissions. If a user is later downgraded, their keys lose access accordingly. Expired keys are automatically cleaned up.

Disabling a key

Each key has a toggle beside the delete button. Disabling stops the key working immediately but keeps it, so you can switch it back on with one click instead of re-provisioning whatever holds it — a plugin, an n8n workflow, a GPT Action. A disabled key shows a Disabled badge and its toggle turns amber.

Use disable when you are not sure a key is compromised, and delete when you are. The Panic Button disables every key at once.

A key also stops working if the user who created it is disabled — a key is only as live as its owner.

OAuth App Credentials (OpenAI GPT, etc.)

For integrations that require OAuth 2.0 (like OpenAI GPT Actions), set OAUTH_APP_CLIENT_ID and OAUTH_APP_CLIENT_SECRET in your .env file. These identify the application — each user still authenticates individually with their own ManageLM credentials. See the Self-Hosted Docker guide for details.

Security Model

Defense in depth

  • Command allowlist — Skills define exactly which commands an agent can run. Enforced in code, not prompts.
  • Destructive command guard — Even for allowed commands, the agent blocks catastrophically dangerous argument combinations: rm targeting protected root directories (/, /etc, /usr, etc.), dd writing to block devices, mkfs, --no-preserve-root, and find -delete.
  • Kernel sandbox (opt-in, Linux only)Landlock + seccomp-bpf confine command subprocesses at the kernel level. Even if a command passes all Python-level checks, the kernel blocks writes outside allowed paths and dangerous syscalls.
  • Read-only by default — Agents with no skills (or skills with empty allowlists) can only run safe read-only commands.
  • Outbound-only connections — Agents connect to the portal. No inbound ports needed.
  • Ed25519 task signing — Every task dispatched to an agent is cryptographically signed. Agents verify the signature before execution.
  • Secrets isolation — Secrets stay on the server. The LLM only sees variable names, never values.
  • Hash-only storage — Passwords, tokens, and API keys are stored as hashes.
  • Rate limiting — Login, registration, and password reset endpoints are rate-limited.
  • IP whitelist — Optional CIDR-based IP whitelist for MCP connections.
  • Execution limits — Max 10 LLM turns per task, 120s timeout per command, 8000 char output limit.

Always-allowed commands (read-only)

The base skill is auto-assigned to every agent and provides a broad set of read-only commands:

cat head tail less more ls tree grep egrep fgrep find locate wc sort uniq
awk sed cut tr diff comm column paste tac xargs file stat md5sum sha256sum
sha1sum readlink basename dirname realpath uname hostname whoami id uptime
date timedatectl lsb_release arch nproc getconf dmesg last lastlog w who
df du free lsblk lscpu lsmem vmstat iostat top ps pgrep lsof fuser
ip ss netstat dig nslookup host ping traceroute curl wget nc
echo printf which type test true false yes seq sleep cd pwd

Even if the base skill is somehow missing, agents fall back to a minimal safe set: cat head tail ls grep find wc sort echo printf test true false cd pwd which.

Sandbox

The sandbox confines the commands an agent runs, so that even a command which passes every check above cannot do more than it is allowed to. There are two ways in:

How it works

When enabled on a skill, every command runs inside the sandbox. The agent itself stays unrestricted — only the command is confined. Commands pass through these layers in order:

  1. Injection blocking — rejects shell tricks like $(…), backticks, eval.
  2. Binary allowlist — the command must be on the skill's allowed_commands list.
  3. Destructive argument guard — blocks combinations like rm -rf /, dd of=/dev/sda.
  4. Privilege drop — the command runs as the configured system user, not as root.
  5. Filesystem confinement (Landlock) — restricts which paths the command can read, write, and execute from.
  6. Syscall blocklist (seccomp-bpf) — blocks dangerous kernel calls (mount, reboot, ptrace, etc.).

Run as user (privilege drop)

Drops privileges to a system user (e.g. apache, mysql, postgres) before executing each command. The agent itself runs as root to manage the host, but with run-as enabled the skill's commands inherit only the target user's permissions — so a misuse of a database-admin skill can't, for example, write to /root.

Fail-closed: if the configured user does not exist on the host, every command for that skill fails with a clear error rather than silently running as root.

Landlock (filesystem confinement)

Restricts which filesystem paths the subprocess can read, write, and execute from. Uses Linux Landlock LSM (requires kernel 5.13+).

AccessDefault pathsPurpose
Read/ (everything)Commands can read system state
Write/etc, /var, /tmpConfig edits, logs, temp files
Execute/ (everything)allowed_commands is the binary gate

Everything outside the configured write paths is read-only at the kernel level — no userspace bypass possible. File uploads also enforce write paths via Python-level path validation using the same config.

seccomp-bpf (syscall filtering)

Blocks dangerous syscalls that no legitimate agent task should need. Returns EPERM (not kill) for graceful error handling.

CategoryBlocked syscalls
Filesystem rootmount, umount2, pivot_root, chroot, move_mount, fsopen, fsconfig, fsmount, fspick, open_tree
System controlreboot, kexec_load, kexec_file_load
Kernel modulesinit_module, finit_module, delete_module
Swapswapon, swapoff
Exploit primitivesptrace, bpf, userfaultfd, perf_event_open
System identitysettimeofday, clock_settime, sethostname, setdomainname

Read-only AI Access

A switch on an agent — or on a server group, where it applies to every agent in it and cannot be turned off host by host. When it is on, the AI can inspect that server as thoroughly as ever and cannot change it.

It is enforced by the operating system rather than by asking the model nicely. On Linux every command runs under Landlock with no writable path except /tmp, behind a syscall filter that also blocks the ways a file can be changed without being written to — its permissions, owner, timestamps and extended attributes — along with mounting, rebooting and loading kernel modules. On Windows every command runs with a low-integrity token: Windows checks integrity before it checks permissions, so the command cannot write to anything — not even where its own account has full control. File edits are refused outright, and so are file uploads through the files skill.

The model is told, so it spends its turns answering rather than discovering the wall: a task that would need a change comes back with what would need to be done instead of a string of failed attempts. Claude sees the flag too, on the server list and in the task result.

What it does not affect

Everything you drive from the portal yourself — restarting a service, rotating a credential, installing a certificate, syncing SSH keys, restoring a backup, a Panic Button containment action. None of those involve the AI, and all of them still work on a read-only server.

Two limits worth knowing. The sandbox governs the host: a command that asks a service to change something (a SQL statement against a local database, or a service restart requested over its socket) is not a filesystem write and is not blocked by it. And if a server cannot provide the sandbox at all — a Linux kernel older than 5.13, or a Windows agent not running as LocalSystem — the agent refuses to run the task rather than running it unprotected.

Enabling the sandbox

  1. Open the Skills page and edit a skill.
  2. Go to the Sandbox tab.
  3. Toggle any combination of Run as user, Landlock, and seccomp-bpf.
  4. Fill in the system user, write paths, or blocked syscalls as needed.
  5. Click Save.

The sandbox is pushed to agents automatically on save. Agents on kernels older than 5.13 (Landlock) or 3.17 (seccomp) gracefully degrade — those layers are skipped with a log warning. Run-as requires the agent to run as root (the default).

Skill configuration (JSON)

{
  "sandbox_run_as": "apache",
  "sandbox_landlock": {
    "read_paths": ["/"],
    "write_paths": ["/etc", "/var", "/tmp", "/opt/myapp"],
    "exec_paths": ["/"]
  },
  "sandbox_seccomp": ["mount", "reboot", "ptrace", "init_module", "..."]
}

Each key is independent — use any combination. Absent key means that layer is off. Catalog skills include recommended sandbox templates that you can use as a starting point.

Requirements

Panic Button

When you believe you are being attacked, the Panic Button cuts off access across your whole fleet in one step. It is the red entry at the bottom of the sidebar, and only an account owner or admin can see or use it.

Nothing here is new capability. Every action is one the Credentials, Certificates, Backups or Users pages already performs — the Panic Button fans them out across many servers at once and reports what passed and what failed, so you are not clicking through pages while an incident is running.

These actions take effect immediately and affect everyone. People will be signed out, integrations will stop working, and services that hold a rotated password will need the new one. That is the point — but decide deliberately, and read what each action says before ticking it. You confirm by typing EXECUTE.

Choosing a scope

Pick all servers, a site, a group, or a single host. The scope covers the server actions only. Portal actions are always account-wide, because an attacker holding a stolen session or API key is not confined to one site — the modal separates the two groups so this is never in doubt.

Portal actions

Server actions

Watching it run

The page shows the run live: who fired it, when, over what scope, and a row for each action on each server with its own result — ok, failed or skipped. Servers that are offline are skipped rather than retried, and a single failure never stops the rest of the run. Results refresh every couple of seconds until it finishes.

Only the most recent run is kept, and it is discarded after seven days. It is a live view, not an archive — the permanent record is in the Audit Log, alongside the history each feature keeps for itself (rotation history, snapshots, certificates).

Afterwards

Most of what the Panic Button does is designed to be undone once you know what happened: re-enable users from Users & Roles, re-enable API keys from Settings, reconnect MCP clients by signing in. Rotated credentials and reissued certificates stay rotated — that is the containment you asked for.

Encryption at Rest

Every secret the portal stores is encrypted with AES-256-GCM under a single master key, ENCRYPTION_KEY. That covers cloud connector credentials, agent signing keys, LLM API keys, the SMTP relay password, the S3 backup secret, webhook signing secrets, and PKI private keys (internal CA, Let's Encrypt account, DNS provider credentials).

Back the key up with your database. The two are useless apart: without the key, every encrypted value is unrecoverable. It lives in .env, which is not regenerable.

Each stored value carries a short identifier of the key that encrypted it, so the portal can always tell which key opens a given row. That is what makes the key replaceable without downtime.

Rotating the encryption key

Because values are tagged with their key, a rotation does not have to be atomic. The portal reads old and new keys side by side, so it keeps working while secrets are still being moved — you can sit in that state for as long as you like and finish when it suits you.

Never change ENCRYPTION_KEY during a rolling restart. A node that has restarted writes secrets a node that has not restarted cannot read. Update every node's .env first, then restart.
  1. Set ENCRYPTION_KEY to the new key and ENCRYPTION_OLD to the outgoing one, in the .env of every node. Both files must match — ENCRYPTION_OLD is what lets a node still read secrets on the old key, and a matching ENCRYPTION_KEY is what lets the move finish.
  2. Restart the nodes. Each logs both key identifiers at startup, so you can confirm they agree before continuing.
  3. Run the rewrap tool on one node and let it finish:
    bin/recrypt              # move every stored secret onto the new key
    bin/recrypt --dry-run    # show what would move, write nothing
    bin/recrypt --audit      # check no encrypted column is unaccounted for
    It shows what it will do, asks for confirmation, then reports progress per category. A value it cannot read is skipped and named rather than stopping the run, and re-running is always safe — it picks up wherever it left off.
  4. When it reports nothing left on a retired key, remove ENCRYPTION_OLD everywhere and restart. Until then, every startup tells you how many secrets still need it.

If a secret keeps failing to move, its stored value is corrupt — re-enter it in the portal and it is rewritten under the current key.

Email threat-action links are signed with the same key and are accepted from either key during a rotation, so links already sitting in an operator's mailbox keep working until the old key is removed.

Terminal Console

The Terminal Console gives you an interactive shell on a managed host, in the browser. Open it from the terminal icon on any online agent in Agents or Assets, or from the console list; it opens in its own window, one per host.

The browser never talks to the agent. Keystrokes go to the portal, the portal forwards them to the agent over the connection it already has, and output comes back the same way — so the agent still listens on nothing and no port has to be opened.

The console is the most privileged thing the portal hands out. The shell runs as the agent’s own identity — root on Linux, the service account on Windows — and, unlike a task, it does not go through a skill’s allowed-commands validator, the kernel sandbox, or the change journal. Nothing typed in a console can be reverted from the portal — the one exception being a file changed with managelm-edit, which does go through the change journal.

Who can open one

One thing, and it is per server: the Console grant on that server. Turn it on beside SSH Root and Sudo Root, either in the server’s Assigned Users list (agent detail) or on a group the server belongs to — a group grant reaches every server in it.

There is no Console permission and no role shortcut. An account owner needs the grant exactly as a member does, and being assigned to a server is not enough on its own: an assignment lets someone chat with a host and read its tasks, which is a different thing from a root shell on it.

Revoking closes a console that person already has open, within a minute — turn the grant off on the server, turn it off on the group that reached it, unassign them, or disable the user, and the shell goes with it. A running root shell cannot be quietly downgraded, so revocation ends it outright.

Changed in 1.5.6. The console was a member permission paired with an assignment; that meant root on every server that person happened to be assigned to, with no way to hand out a console on one server alone, and owners and admins had it everywhere on role. It is now a per-server grant like SSH Root and Sudo Root. Nobody has a console after the update — owners and admins included — until it is granted on a server or on a group. A root shell is not something that should arrive already granted.

API keys and MCP tokens cannot open a console. It is a person at a keyboard, so it requires a signed-in browser session.

Passkey required, every time

A passkey is confirmed at the moment the console opens, even though the same passkey was used to sign in. That is what stops a stolen session from becoming a root shell. There is no way to skip it: an account with no passkey enrolled cannot open a console at all — add one under Settings → Security first.

Idle screen lock

After 10 minutes without a keystroke the screen locks: output stops being forwarded and input is refused until you confirm your passkey again. Your work is not lost — the shell keeps running, and output produced behind the lock is replayed when you unlock. Locking is enforced by the portal, not drawn over the page, so it holds even if the browser is tampered with.

Terminal chatter the browser sends on its own (focus changes, mouse reports) does not count as activity — only real typing holds the lock open.

While the screen is locked nothing new may leave the server through it: a managelm-copy or a managelm-edit that starts behind the lock is refused and says why at the prompt. An editor that was already open is left alone, with whatever you had typed in it, because nothing can be saved from behind the lock either.

The console list

/console/ is a page of its own: every console you may open, and nothing else. It is meant to be bookmarked — open the bookmark, sign in if your session has gone, and pick a host. Unlike a link to one shell, it keeps working when a server is rebuilt or when today’s work is on a different machine.

Each row shows the server’s name and address, its platform and operating system, its site, its tags and the agent version, with a bookmark of its own in the corner for a link straight to that shell. A server that is offline, or whose agent is too old to have a console, is still listed — with the reason — because a host being down is usually why you are looking. Clicking one opens the console in its own window; the list stays where it is, so the next host is one click away. When your servers are organised into sites, the list is grouped by site.

The list keeps itself up to date — a server that goes down, or comes back, changes on the page within seconds, so a list left open in a window stays true without a reload.

The list shows what you may open. It is the same test the console itself applies — the Console permission, plus your assignment to that server — so it is a shortcut to what you already have, never a way in.

Moving files in and out

Drag a file onto the terminal and it is copied to the server, into whatever directory the session is standing in — cd somewhere else and the next file goes there instead. Drop a folder and the whole tree is copied, keeping its shape. A file that would land on top of one already there is renamed rather than overwriting it (report (1).pdf), and a folder dropped onto one of the same name merges into it.

On Windows there is no equivalent of the live directory, so files land at the root of the system drive (C:\), which is also where a Windows console opens. Dropped files there are locked to administrators, so a certificate or a configuration file is not left readable by everyone with an account on the machine.

To take a file the other way, run managelm-copy in the console and it downloads in your browser:

managelm-copy /var/log/syslog
managelm-copy /etc/nginx          # a folder arrives as nginx.zip
managelm-copy *.conf              # several at once

It only works inside a portal console — that is where the browser is. Run it over plain SSH and it says so.

Copying straight to another server

Name a server at the end and the files go there instead of to your browser. The two machines never talk to each other — everything passes through the portal — so this works between servers that cannot reach one another at all:

managelm-copy nginx.conf web-01:/etc/nginx/
managelm-copy /etc/nginx  web-01:/opt/        # a folder goes as a tree, not a zip
managelm-copy a.conf b.conf web-01:/etc/      # several at once

The server is named by its hostname or the name shown in ManageLM, in any case you like; quote it if that name has spaces ("Web Server 01:/tmp/"). Nothing is overwritten on the far side — a name already taken gets the next free one.

You can only send to a server you already have the Console permission on. The portal decides that, not either server: it knows who opened the console, because you confirmed a passkey to do it. The bar is deliberately “you could have opened a shell there and written the file by hand”, so this is a shortcut and never a way around a permission. Being assigned a server is not enough, and neither is having root on it by SSH key or sudo alone.

Keeping a folder in step: managelm-sync

managelm-sync makes a folder on another server match one on this host, sending only what is new or has changed:

managelm-sync ./site-config web-01:/etc/app/
managelm-sync /etc/nginx web-01:/etc/nginx/ --dry-run
managelm-sync ./dist web-01:/var/www/site/ --delete

The destination is made to match the folder rather than to contain it: syncing ./conf to /etc/app puts conf’s files directly in /etc/app. Run it twice and the second run sends nothing, because a file’s modification time travels with it. “Changed” means a different size or time — the same quick check rsync makes — so it never has to read a file it is not going to send.

By default it only adds and replaces: a file you deleted here stays on the destination, and the run tells you how many such files it left alone. --delete removes them, and because that is the one thing here you cannot undo, it prints every file it would remove and asks before doing any of it. --dry-run shows the whole plan without touching anything, and the receiving server refuses a --delete outright in a directory like / or /etc, where a mistyped destination would be a restore from backup rather than a mistake.

Between Linux and Windows

Both work in either direction. Paths keep their shape, so a folder copied from Windows arrives as a tree on Linux and the other way round, and names Windows will not accept are adjusted on the way in. For a Windows destination, forward slashes are easier than backslashes from a Linux shell:

managelm-copy app.conf  win-01:C:/inetpub/wwwroot/
managelm-sync ./dist    win-01:C:/inetpub/wwwroot/

There is no limit on how big a file you can drop onto a console. On the hosted service transfers run at about 1 MB per second, so a large one takes a while and a small one is instant; a self-hosted install is limited only by its own network. A transfer shows its progress along the top of the terminal, and closing the console stops it.

Coming the other way there is a ceiling of 1 GB, because your browser has to hold the file before it can save it. A bigger one is refused straight away rather than after the wait — move it with scp instead.

If the screen lock falls while a file is on its way out, the transfer is stopped rather than finished — a download that completed itself would land on a machine you have walked away from. What had already crossed is on the timeline, marked interrupted. A managelm-copy that starts while the screen is locked is refused for the same reason, and says so at the prompt.

Transfers are recorded. If the session is being recorded, every file that moves — in or out — appears on the replay’s timeline with its name, its size and where it went. The file itself is not stored in the recording; what is kept is the fact that it moved.

Editing a file

To change a file without leaving the browser, run managelm-edit in the console and it opens in an editor over the terminal:

managelm-edit /etc/nginx/nginx.conf

Saving does not close the editor. Ctrl+S writes the file to the server and you carry on typing, the way any editor behaves; the header says what the save did until you change something again. Closing the panel is what ends the edit and gives your prompt back, and the shell then reports the net change across every save you made. Closing with unsaved typing asks first.

A file is written back with the permissions and ownership it had, so a config a service owns still belongs to it afterwards. The command waits while the panel is open — the shell behind it is parked on it.

Ctrl+S saves, Ctrl+Q or Esc closes, Ctrl+D downloads a copy, and Ctrl+C at the prompt closes it too — anything already saved stays saved.

Beside Save is a download button, which puts what is currently in the editor into your own downloads — a copy of the file before you change it, or of your version when a save has been refused. It is your browser writing to your machine, so it works whether or not the file was ever saved.

It is meant for the config file you came to fix, not for development: it opens one text file at a time, up to 64 KB, and refuses anything binary. For a whole workspace on a host, point an editor at it over SSH instead — ManageLM already syncs the keys.

Over a plain SSH login it opens your own editor instead. There is no browser to draw a panel in, so the file is put in a private scratch copy, $VISUAL or $EDITOR (or whichever of editor, vim, vi, nano is installed) is handed the terminal, and what you save is written back through the same path a browser save takes. Quit without saving and nothing is touched. Run it with sudo there — the agent socket is root-only:

sudo managelm-edit /etc/ssh/sshd_config

That is the whole reason to use it rather than vi: the file is replaced atomically keeping its owner and mode, the change is journalled and revertable, and it is reported to the portal. vi gives you none of that.

An edit can be undone. A file inside a tracked directory (/etc and its neighbours) becomes a change like any other, so managelm-shell lists it under changes and rollback #N puts it back. Elsewhere a .bak copy is written beside the file before it is replaced. That makes the editor the one thing in a console that is reversible — nothing typed at the prompt is.

If the file changes on the server while you have it open, the save is refused rather than applied: you would be writing over somebody else’s change with a copy of what the file used to be. Nothing is lost — the panel stays up with your version in it.

Edits are recorded, and listed. A recorded session gets a timeline entry for every file opened this way, saying whether it was saved and by how much it changed — and one for a file opened and closed without saving, which is otherwise the one thing a replay would not show, since nothing about the panel is typed into the terminal. Every save also appears under Tasks with its file list and its diff, whether it came from the browser panel or from $EDITOR over SSH — recording is optional, so a change to a server should not exist only inside a replay somebody may have switched off.

Bookmarks

Every console has its own address, so the bookmark button in the terminal header hands you two links: this console, and the console list. No browser lets a page create a bookmark for you, so the button copies the link and shows it ready to be dragged to your bookmarks bar — press Ctrl+D (⌘D on a Mac) and it is saved.

A bookmarked console asks you to sign in first if you are not, then lands on the server you asked for. The link carries no authority of its own: the permission, the assignment and the passkey are all still checked when the shell is opened, and no server name appears in the address.

Closing a console

The × in the terminal header ends the session. A console the portal opened in its own window is closed — the window exists only to hold that shell. A console you opened yourself, from a bookmark or a pasted link, is a tab of yours to keep: that one goes to the console list instead, so the next host is one click away.

Session lifetime

Ask the assistant

Under the terminal there is an input where you can ask about what is on screen — why a command failed, what a log line means, what to check next. Your question goes up together with the last of your terminal, so you do not have to paste or explain anything: it already sees what you see.

The assistant answers in words, and sometimes offers one command. It runs nothing itself — it has no shell and no access to the host, and a suggested command does nothing at all until you act on it:

Read a suggested command before you run it. The assistant reasons about text your host printed — logs, file contents, a login banner — and that text is not always trustworthy. A file crafted by someone else can contain wording aimed at the assistant rather than at you. This is why nothing it suggests ever runs on its own, and why Insert is there: on a root shell, one glance at the line costs nothing.

The assistant uses the same LLM the agent already uses for tasks — per-agent, per-site, or your account default — so a model on your own network works, and there is nothing extra to configure. Questions are answered one at a time per console, and Stop ends an answer in progress.

What is sent is the last of what was displayed (about 8 KB), never your keystrokes — so a password typed at a sudo prompt, which the shell does not echo, is not part of it. Obvious secrets that were printed, such as token= lines or a private key, are masked before the text leaves your browser. The conversation lives only in that window and disappears with the session; nothing is stored.

The panel collapses when you click back into the terminal, and Ctrl+Shift+A jumps to it from the shell.

What gets recorded

Opening and closing a console are both written to the Audit Log — who, which host, from which address, how long it lasted and how it ended. Both also fire as console.opened and console.closed to webhooks and notification connectors, so a root shell on a production host can reach your SIEM or chat channel as it happens.

Acting on a command the assistant suggested is recorded too, as console.ai_command — the host, the command, and whether you ran it or only inserted it. What a model proposed and what a person chose to run are different things, and the Audit Log records the second.

Sessions are only recorded if you turn it on. By default a console is relayed, not stored — there is no transcript and nothing to replay. Switch on Admin Sessions for a server and every console session on it is kept and replayable. Either way, a task remains the option that gives you a reviewable, revertable record of a change.

Requirements

Graphical Desktop

The Graphical Desktop gives you a full Windows desktop on a managed host, in the browser. Open it from the monitor icon that sits beside the terminal icon on any online Windows agent in Agents, Assets or the Consoles launcher; it opens in its own window, one per host.

There is nothing to install — not on your machine, not a plugin, not an RDP client. The desktop is drawn on an ordinary web page. And there is nothing to open on the server: the connection travels out through the link the agent already holds, exactly as the terminal console does, so the host still needs no inbound port and no VPN.

A desktop is as privileged as a console. It signs in as an administrator of the host, and nothing typed or clicked in it goes through a skill’s allowed-commands validator, the sandbox or the change journal. Nothing done in a desktop can be reverted from the portal.

Who can open one

The same Console grant, on that same server — there is no separate Desktop permission, grant or switch to find. Turn Console on for someone beside SSH Root and Sudo Root, in the server’s Assigned Users list or on a group, and on a Windows host they get both icons: a terminal and a desktop. On Linux they get the terminal alone.

A passkey is confirmed when the desktop opens, the same step-up the console requires, and for the same reason: a stolen session must not become an administrator desktop. Revoking Console closes a desktop that person already has open, within a minute.

Signing in without a password

You are never asked for Windows credentials, and none are stored. Windows will not reveal an existing account’s password to anybody — so rather than reuse one, the agent keeps an account of its own on the host, MANAGELM, and gives it a fresh random password at the start of every session. That password is handed straight to the RDP gateway and is never sent to your browser.

The account it uses is called MANAGELM — the same name the agent’s own system account carries on a Linux host. An agent updating from an earlier build removes the account that build used, along with its profile, so a host is never left carrying a privileged account nothing looks after any more.

Between sessions the account is disabled and its password scrambled to a value nobody — not you, not the portal, not the agent — ever learns. So there is never a usable standing credential on the host, but the account itself stays, which is deliberate: its Windows profile survives, so only the very first connection waits for a profile to be built, and it gives you one stable name to recognise in the host’s own user list and audit events instead of a different one each time. Removing the agent deletes the account and its profile.

On an ordinary server or workstation it is a local administrator of that one machine, with no rights anywhere else. On a domain controller there is no such thing as a local account, so it is necessarily a domain account with administrative rights on the controller — added to Administrators rather than Domain Admins, which keeps it off every member server, but it is still domain-wide. Open a desktop on a controller only if that is what you intend.

If Remote Desktop is switched off

A freshly installed Windows refuses Remote Desktop until it is turned on. Rather than fail, the window says so and offers Enable Remote Desktop and connect. That switches on the Remote Desktop listener and nothing else — no firewall rule is opened, because the connection arrives over the agent’s own outbound link on the machine’s loopback address, not from the network. The setting stays on afterwards.

One desktop at a time

A host serves one desktop session at a time. Because every session signs in as the same account, Windows would reconnect a second person into the first person’s session rather than giving them their own — two operators would silently share one screen. A second attempt is refused with a clear message instead. The terminal console is unaffected: shells and a desktop can be open on the same host together.

Moving a file onto the desktop

Drag a file onto the desktop and it is copied onto the desktop of the session — it appears among the icons you are looking at, ready to open. Drop a folder and the whole tree is copied, keeping its shape. Nothing is installed in the session to make this work, and the file never touches anything but the host you dropped it on.

It lands on the desktop of the MANAGELM account the session is signed in as, wherever Windows keeps that — a desktop redirected by group policy or moved into OneDrive is followed rather than guessed at. If a brand-new account is still building its profile the file goes to the root of the system drive (C:\) instead, which is where a Windows terminal console’s drops land.

There is no limit on how big a file you can drop. On the hosted service transfers run at about 1 MB per second, so a large one takes a while and a small one is instant; a self-hosted install is limited only by its own network. A transfer shows its progress along the top of the window, and closing the desktop stops it. Files that arrive this way appear on a recorded session’s timeline, like a terminal console’s.

Copying a file back to your browser

A Copy to Browser folder sits on the desktop of the session. Copy a file into it — drag it there, or right-click and Send to — and it downloads in your browser, then disappears from the folder. Copy a folder in and it arrives as a single .zip. There is nothing to type and nothing to install: a desktop has no prompt, so this folder is the gesture that stands in for the terminal console’s managelm-copy.

It is an outbox, not a place files pile up. What reaches your browser is taken out of the folder, so anything still sitting in it has not been sent — and the window says why. A file the browser cannot take stays put: a download has to be held in memory before it can be saved, so 1 GB is the ceiling in that direction, where dropping a file onto the desktop has no limit at all.

Whatever is already in the folder when you open a desktop is left alone. The account and its profile survive between sessions, so a file somebody left behind stays where it is rather than arriving in the next person’s browser unasked; copy it in again if you want it. Copies out appear on a recorded session’s timeline, exactly as files coming in do.

Session lifetime

What gets recorded

Opening and closing a desktop are both written to the Audit Log — who, which host, from which address, how long it lasted and how it ended — and both fire as desktop.opened and desktop.closed to webhooks and notification connectors, beside the console’s own events.

Sessions are only recorded if you turn it on. By default a desktop is relayed, not stored. Switch on Admin Sessions for the server and the session is kept and replayable. Either way, a task remains the option that gives you a reviewable, revertable record of a change.

Requirements

Admin Sessions

Console, desktop and direct SSH sessions can be recorded and replayed. For the portal's own consoles nothing is installed on the server to make this work — the portal already relays every byte you see, so it records what it is already carrying. Direct SSH logins are recorded by the agent on the server itself, since those never pass through ManageLM.

Turning it on

Recording is decided per server, not account-wide: open a server and switch on Record Admin Sessions, or set it on a group to cover every server in it. A group can only switch it on — an individual server cannot turn it back off — which is what makes it usable as a policy rather than a preference. Servers being recorded carry a REC badge in the Agents list, and the operator sees one in the console window too, so nobody is recorded without knowing.

Recordings are written to your own S3 bucket — the one configured under Settings → Account & LLM → S3 Storage, shared with system backups. They are encrypted before they leave your infrastructure, so the bucket holds nothing readable, and ManageLM keeps no copy. Without storage configured nothing can be recorded, and the session opens as normal.

Direct SSH logins

The same switch also records people who connect straight to the server with ssh, without going through ManageLM. It works by putting the recorder in front of the keys ManageLM manages for that server, so those logins are captured on the host and uploaded to the same bucket a few seconds after the session ends. They appear in the same list, marked SSH, with an Account column showing which local account was used — root and charly are different sessions even when the same person opened both, and the list tells them apart.

Attribution comes from the key that opened the session, not from the account, which is what lets a shared root login still name the person — provided that key is one ManageLM manages.

What this does not cover, and it is worth knowing before relying on it:

Recording never costs anyone their access: if it cannot start for any reason, the login proceeds unrecorded — unless you have switched on Refuse sessions that cannot be recorded, which turns that into a refused login instead.

Replaying

Recorded sessions are listed under Audit Logs → Console Sessions, newest first, with the operator, the server, the account the session ran as (a desktop names the throwaway administrator it signed in with), how long it lasted and how big it is. The buttons above the list narrow it to Terminal, Desktop or SSH. Expand one to replay it in place: play and pause, drag the scrubber, and change speed on a terminal replay. Long pauses where nothing happened are shortened, so the replay is the session's activity rather than its wall clock. Beside the player a timeline lists the moments worth jumping to — when the session started and ended, when the screen locked itself and was unlocked again, any command the console assistant proposed with whether it was run or only inserted, every file that moved in or out, and every file edited with managelm-edit. Each kind has its own colour, so a long session can be read at a glance. A transfer that did not finish is listed as interrupted, with how much of it had crossed.

Open Viewer takes the replay into its own window, sized to the terminal the operator actually had and resizing with it as the session resizes, so it plays back at its true size instead of scaled into a row. Download gives you the file: a terminal or SSH recording is an asciinema cast (.cast), which plays with asciinema play on any machine and needs nothing from us — useful for handing a session to an auditor who has no portal account. A desktop recording is a Guacamole instruction stream (.guac), Apache Guacamole’s own recording format; guacenc, which ships with guacamole-server alongside the guacd you already run, turns it into an ordinary .m4v video. Both come out decrypted — what sits in your bucket is encrypted, and only ManageLM holds the key.

A terminal replay is real text, not video: you can select and copy from it.

What is and is not kept

Retention

Settings → Security → Admin Sessions sets how long recordings are kept before they are deleted from your bucket automatically. The maximum is your audit log retention: a recording should not outlive the audit entries that say who opened the session and who replayed it.

The same panel has Refuse sessions that cannot be recorded. Off (the default) a server set to record still opens its console when storage is unreachable, and the gap is written to the audit log — an object-storage outage does not become a console outage. On, the session is refused instead, for teams that need the recording to be a guarantee.

Locking an idle session

Settings → Security → Admin Sessions → Lock idle sessions after is one number, anywhere from five minutes to an hour, and it governs every kind of admin session. A session left untouched for that long locks itself. Set it to Off and they stop locking, with one exception noted below for desktops.

A shell left open on an unattended laptop is the same exposure as a stolen session, and the passkey you gave at the start buys nothing if walking up to the machine an hour later is enough. What “lock” means depends on the session, because the three are not the same thing:

Idle means no typing. Output does not count — a command printing to a screen nobody is watching is exactly the case worth locking.

If the lock cannot be lifted — ManageLM is unreachable, or the agent on the server is down — the session stays locked and says so, rather than telling you the password was wrong. Press Ctrl-Q to end the session and log in again; a fresh login depends on neither, so this never leaves you locked out of the server. Nothing you were running is lost.

Existing accounts start at ten minutes, which is what the terminal console has always used, so nothing that already locked stops locking. Turning it on takes effect on your servers within moments; setting it back to Off does the same.

Who can watch

Replaying a session needs the same reach as opening one. Account admins and holders of the Audit permission see every recording in the account; everyone else sees only recordings from servers where they hold the Console grant — watching a shell and opening one are the same secret. Watching a recording is itself written to the audit log, and recordings cannot be read with an API key at all.

Security Audits

ManageLM includes a built-in security audit and compliance engine that scans your agents for misconfigurations, vulnerabilities, and hardening issues. Audits run read-only on the agent and are fully deterministic — no LLM required.

How it works

  1. Trigger — From the Agent Assets page (per agent), the Compliance dashboard (fleet-wide), or via MCP.
  2. Scan — The agent runs a set of read-only checks on the host.
  3. Report — Each finding includes a severity, an explanation of the risk, a suggested fix, and a mapping to compliance frameworks (CIS, PCI DSS, HIPAA, ISO 27001, NIS2, NIST CSF, SOC 2). A compliance score (0–100) reflects the overall posture. Installed packages are also matched against known vulnerabilities (see below).
  4. Results — Findings appear in the Agent Assets audit view and the Compliance dashboard. You receive an in-app notification when the audit completes.

Server context

Each compliance rule has separate severity ratings for public and private servers:

What is checked

CheckWhat it inspects
SSH & RDP configRoot login, password vs. key authentication, retry limits, X11 forwarding, RDP Network Level Authentication.
Listening portsOpen TCP and UDP sockets on all interfaces.
FirewallHost firewall status and rules (UFW, firewalld, nftables, iptables, or Windows Firewall profiles).
User accountsLogin-enabled users, UID 0 / local administrators, guest account, service accounts.
Password policyMinimum length, complexity, lockout threshold.
Windows hardeningUAC enabled, cleartext credential storage disabled (WDigest), automatic login disabled.
File permissionsWorld-writable files, SUID binaries, shadow file readability.
Password hashingPassword hashes flagged if they use weak algorithms (MD5 or older).
Patch posturePending security updates, automatic-update service enabled, pending reboot after kernel or library updates.
Installed packagesFull package inventory feeding the vulnerability scan.
Authentication eventsFailed login attempts in the last 24 hours.
Audit & event loggingAudit daemon (Linux) or Advanced Audit Policy (Windows); PowerShell script-block logging.
Endpoint protectionMandatory access control (SELinux / AppArmor) or Windows Defender antivirus including signature freshness.
Time synchronizationSystem clock synchronized via NTP.
Kernel hardeningIP forwarding, ICMP redirect handling, reverse-path filtering, ASLR, SUID core dumps.
Brute-force protectionFail2ban status and active jails.
TLS/SSLWeak protocols (SSLv3, TLSv1.0/1.1) and weak ciphers (RC4, DES, NULL, EXPORT, MD5) rejected on all listening services.
CertificatesTLS certificate expiry with days remaining.
SMB hardeningSMB signing required, legacy SMB1 protocol disabled.
Network exposureLLMNR (legacy name resolution) disabled on Windows.
Disk encryptionBitLocker protection on OS and fixed data volumes (Windows).
Scheduled tasksSystem and per-user cron jobs.
SSH authorized keysSSH key-based access across all users.
DockerPrivileged containers, socket exposure, containers running as root.
Vulnerability scanInstalled packages matched against known CVEs (see next section).

Vulnerability scanning

As part of every security audit, ManageLM checks each agent's installed packages against a public vulnerability database and reports any known CVEs that apply to the installed versions. Nothing to install, nothing to configure.

Severity levels

LevelMeaning
CriticalImmediate action required — actively exploitable or dangerous misconfiguration.
HighSignificant risk — should be addressed promptly.
MediumModerate risk — recommended to fix.
LowMinor issue or informational finding.
PassCheck passed — no issue found.

Findings

Each finding includes:

Automated remediation

You can select one or more findings and click Remediate to have the agent automatically fix them. This requires:

Remediation creates a task that uses the security skill and the agent's LLM to intelligently apply the recommended fixes. The agent backs up configuration files before making changes and validates them before restarting services.

Review before remediating. Always review the recommended fixes before clicking Remediate. Security changes (e.g. SSH hardening, firewall rules) can lock you out if applied incorrectly.

PDF export

Click the Security button at the top of the Agent Assets page to download a fleet-wide security audit report. The PDF includes a summary bar with issue counts by severity, detailed findings with explanations and remediation steps, and a list of passed checks.

Use the Scheduled Tasks popover in the Agent Assets toolbar to set the audit schedule for the whole fleet at once (Daily / Weekly / Monthly), so the report you export always reflects fresh data. Reports are exported on demand — ManageLM does not email them.

Scheduled audits

You can configure automatic recurring audits per agent. Open the Security Audit modal and use the schedule selector in the top-right corner to choose a frequency:

The scheduler checks every 15 minutes and triggers audits for agents that are overdue. Agents that have never been scanned are prioritized. A yellow badge (D, W, or M) appears on the agent card to indicate an active schedule.

Constraints

Service Monitors

Monitor the availability and response time of services running on your agents. Monitors run directly from the agent's network, so they can check internal services (localhost, LAN) as well as public endpoints.

How it works

  1. Create — Open the Monitors page and click Add Monitor. Pick a type from the catalog (48 types across 10 categories), select an agent, and configure the check parameters.
  2. Check — The agent runs the check locally on the configured schedule (1m, 5m, 15m, 30m, or 1h). Two kinds of check are supported: network probes (TCP, UDP, HTTP, DNS) and resource checks (filesystem, memory, CPU, process, custom command).
  3. Report — The agent only sends results to the portal on status transitions (up→down, down→up) and as periodic summaries, not on every check.
  4. Alert — When alerts are enabled, an email is sent to all users assigned to the target agent after a configurable number of consecutive failures (default: 3). A recovery email is sent when the service comes back up. Wording adapts per flavor: network monitors talk about a service being “down”; resource monitors talk about a “critical condition”.

Service catalog

The monitor catalog defines 48 types organized in 10 categories:

CategoryServices
WebHTTP / HTTPS, REST API, HAProxy, Squid Proxy
NetworkTCP Port, Ping (ICMP), DNS, NTP
EmailSMTP, IMAP, POP3
DatabaseMySQL / MariaDB, PostgreSQL, SQL Server, Redis / Valkey, MongoDB, Elasticsearch, Memcached, ClickHouse, InfluxDB, Cassandra, CouchDB
MessagingRabbitMQ, Kafka, NATS, MQTT
File SharingFTP / SFTP, SMB / CIFS, NFS, AFP, MinIO / S3, WebDAV
Remote AccessSSH, RDP, WinRM, OpenVPN, IPsec / IKEv2
InfrastructureLDAP / LDAPS, Kerberos, Docker API, Consul, Vault, etcd
MonitoringPrometheus, Grafana, Zabbix
SystemFilesystem Usage, Memory Usage, CPU Usage, Process Running, Command / Script

Each entry maps to one of the agent's check types: tcp, udp, http, dns (network), or filesystem, memory, cpu, process, command (resource). TCP and HTTP support an SSL/TLS toggle for TLS handshake validation and optional certificate expiry warnings (works with self-signed certificates). Resource checks use warning/critical thresholds (e.g. 80 %/90 % memory) instead of binary up/down.

Custom command / script monitor

The Command / Script type runs an arbitrary shell command on the agent and maps the result to a monitor status. It exists for the cases the built-in checks don't cover — application-specific health endpoints, SaaS API probes, custom Python or Bash check scripts, plugins from your existing monitoring stack, etc.

Convention — Nagios-compatible exit codes:

Exit codeStatusMeaning
0OK (up)Service is healthy
1Warning (degraded)Service is degraded but functional
2Critical (down)Service is in a critical state
otherCritical (down)Treated as critical so a misbehaving script never silently reports OK

Output format: stdout up to the first | is the user-facing detail, shown in the test modal and the “Last error” column when the status isn't OK. Anything after | is parsed as Nagios-style perfdata label=value[unit] ...; the first numeric value goes into the metric column, so charts work out of the box. Stderr is appended to stdout when it adds information.

Example — an existing Nagios plugin:

check_disk -w 80% -c 90% /
# stdout: DISK OK - free space: / 412 GB (84% inode=99%);| /=87GB;90;100;0;512
# exit:   0
# → status = up, value = 87 (the first perfdata number)

Example — a custom one-liner:

curl -fsS http://localhost:8080/healthz | grep -q '"ok":true' && echo "API healthy" || (echo "API failing" && exit 2)

Configuration:

Security note — this is unrestricted execution. The command runs as the agent process (typically root on Linux, SYSTEM on Windows). There is no skill gate — whoever has the monitors permission can have the agent run anything the agent can run. Treat command monitors with the same care you'd treat task execution: only grant monitors to operators you'd trust to open a shell on the host.

Alerts

Each monitor has an alert toggle and a configurable consecutive failure threshold (default: 3).

Test before creating

The Test button in the create/edit modal sends an ad-hoc check to the agent and shows the result immediately (up/down, response time, error) without creating or saving the monitor.

Data & charts

Permissions

MCP integration

One MCP tool is available for AI assistants:

Per-Plan Limits

The number of monitors per account is limited by your plan (Free: 20, Pro: 100, Business: 200, Enterprise: unlimited). The Monitors page shows your usage against the limit. The Add Monitor button is disabled when the limit is reached.

Certificates & PKI

Manage TLS certificates for your agents directly from the portal. Two certificate sources are supported:

Setup

  1. Configure a CA or LE account — Go to Settings → PKI & CA. Create a new internal CA, import an existing sub-CA, or register a Let's Encrypt account. Optionally add DNS-01 providers for DNS-based certificate validation.
  2. Set defaults — Configure default certificate validity (14–365 days), key type (ECDSA P-256, RSA-2048, RSA-4096), and renewal window (7–90 days before expiry).
  3. Issue certificates — Go to Certificates, click New Certificate, pick a target agent, and fill in the common name, file paths, and optional SANs.

Certificate Lifecycle

CRL & Public Endpoints

The portal serves two public endpoints (no authentication required):

Both URLs are embedded in issued certificates as the CRL Distribution Point and Authority Information Access extensions.

Auto-Renewal Sweep

A daily background task handles certificate lifecycle:

Permissions

Per-Plan Limits

The number of certificates per account is limited by your plan (Free: 10, Pro: 50, Business: 100, Enterprise: unlimited). The Certificates page shows your usage against the limit. The New Certificate button is disabled when the limit is reached.

MCP Tools

Credential Rotation

ManageLM can own the lifecycle of a credential: generate a new value, set it wherever the account lives, and deliver it everywhere it is consumed — on a schedule or on demand. On by default; turn it off under Settings → Optional Features if you do not use it.

The value is never stored. ManageLM holds the plaintext only for the seconds a rotation takes, then discards it. No page shows it, and no API returns it — there is nothing to return. If a rotation fails, the next attempt simply generates a fresh value rather than recovering the old one, so nothing has to be kept.

Switching a key off, and alerts

Each key has two switches on the Keys list. Enabled is a reversible way to stop a key without destroying it: switch it off and it disappears from what applications can see and every operation on it is refused, from the very next call. Nothing else changes — its grants, its name and the key itself are all still there, so switching it back on restores what was there before. Reach for this rather than Delete during an incident: deletion is final. Alert decides whether that key's events reach webhooks and notifications; with it off, the events are still recorded, they just do not leave the portal.

Running the same application on several hosts

The copy button beside an application in a key's list replicates it onto other hosts — same name, same account allowlist, the same keys granted, and the same credential. One application deployed to twenty servers is one secret in your configuration management, not twenty to distribute, so there is nothing new to write down.

Each copy is still its own registration: you can disable, rotate or delete one without touching the others, and the activity log tells you which host did what. A host that already has an application of that name is skipped rather than failing the whole copy, and a Windows host is skipped when the application has an account allowlist, because Windows cannot report the calling account.

Who can see and change them

Every member can read the Credentials page — names, accounts, hosts, schedules and rotation history — the same as Monitors, Certificates and Backups. That is safe precisely because no value is stored to leak. The credentials permission unlocks the buttons: creating, editing, rotating, testing and deleting. API keys are stricter and need the permission even to read.

What can be rotated

Targets

A credential has one list of targets, added from a single form. They answer one question — where does this credential take effect:

A password is defined in one place — the account the credential names — and delivered from there. It has no authorized-key list, which is an SSH idea: to give a second account the same password, add an Account on agent target, and to hand the value to software that reads it, deliver it to a file, a database or a vault.

A target added later starts out empty. ManageLM keeps no copy of the current value, so a target you add after the last rotation receives nothing until the next one — and a credential with no rotation interval has no next one. The form offers Rotate now for that: it generates a new value and delivers it everywhere, so the new target is filled in straight away. It is off by default, because a rotation also rewrites every other target and restarts the services they list. Leave it off if you would rather wait for the next scheduled rotation.

Every target on a host — both file kinds and a script — can name services to restart: a comma-separated list, restarted there once the new value has landed and any script has finished. A restart, not a reload: a service that opened its connection at startup is still holding the old password, and re-reading its configuration will not change that. Write an entry as docker:name to restart a container instead of a system service — a containerised application picks up a new secret only when its container is replaced. If a restart fails, the delivery is reported as failed — the file is written, but what reads it has not picked the value up yet.

At least one target is required. A value generated and delivered nowhere is simply lost, so ManageLM refuses to rotate without one.

Setting one up

  1. Grant the Credentials permission to whoever should manage them. The feature itself is on by default — if it was switched off, turn it back on under Settings → Optional Features.
  2. For an LDAP, database or Entra credential, add the connector first — under Connectors → Directories for LDAP, Active Directory and Entra, or Connectors → Databases for PostgreSQL, MySQL, MS SQL Server, Oracle, MongoDB, Redis/Valkey and Couchbase.
  3. On the Credentials page choose New Credential, pick the type, and name the account it belongs to.
  4. Add your targets, then set the generation options and the rotation interval (default 30 days), and create it.

With an interval set, the first rotation runs automatically within the hour — which does change the account's password. Leave the interval empty for manual-only, and nothing changes until you press Rotate.

Where an SSH private key goes

An SSH credential already names the account and host that hold the key, so it does not ask again: leave Private key path empty and the key lands in that account's own .ssh, written the way ssh-keygen would — the directory created at 0700 if it does not exist, the private key 0600 and the public key beside it at 0644, all owned by the account. The filename follows the algorithm you picked (id_ed25519, id_rsa or id_ecdsa), because those are the only names ssh looks for with no -i and no configuration.

The path can be changed later on the credential, or on the target itself — they are the same thing, and clearing the field puts it back to the account's .ssh. A file is delivered with the owner you name and that account's own group unless you name a different one.

Set the path when a job reads the key from somewhere specific — a cron that connects out with ssh -i /etc/backup/id_ed25519, say. The file is still 0600 and owned by the account you named; no public key is written beside it, since nothing there is looking for one. Anything more (a different owner or group, a vault as well) is a target like any other.

Changing one afterwards

Everything the form shows can be edited later, including what the credential rotates: the account and host of a local credential, or the connector and distinguished name of a directory one. A mistyped DN, an account moved to another OU, or a service relocated to another host is a correction — not a reason to delete the credential and rebuild its targets.

Two things do not change. The type is fixed, because it decides which fields exist at all, and a connector can only be swapped for one of the same kind — a directory for a directory, a database for a database. Moving between them would change what the account name even means.

Changing what a credential rotates clears its rotation state: the rotation on record happened against the old account, and leaving "last rotated" on screen would claim the new one already holds that value. The rotation history is kept — it records what happened.

How the value is generated

For everything except an Entra application secret, ManageLM generates the value:

An Entra application secret is the exception: Entra mints it and returns it once, so there is no length or complexity to choose. An Entra user password is generated here like any other, and does honour both.

Before you rotate: what uses this account?

The mechanics of rotation are the easy part. What makes one safe is knowing what depends on the credential first — and neither a passwd entry nor a directory record can tell you that. ManageLM does not ship a separate scanner for it, because your agents already answer questions about their own hosts: ask "what would break if I change the password for svc_app on these servers?" and each agent looks at its own running services, unit files, cron entries and configuration. That reaches places a fixed list never could — a compose file, a CI credential, an application's own settings table.

Ask about connection poolers by name. pgbouncer, Odyssey, pgpool and ProxySQL each keep their own copy of a database credential, in a file nowhere near the application's configuration. Rotating a database password without updating the pooler is the most common way a rotation causes an outage, and it is the one place worth naming explicitly in what you ask.

History

Expanding a credential shows its last five rotations — outcome, when, and what failed — with View all for the rest. An entry marked redeliver is ManageLM having caught up the targets that missed an earlier rotation, without changing the password again. A rotation record never holds the value. History is kept for 90 days by default (CREDENTIAL_RETENTION_DAYS on self-hosted installs).

How a rotation behaves when something goes wrong

There is deliberately no rollback. Restoring a password is not possible — ManageLM never knew the old one — and would not help if it were. Recovery is automatic: if some targets took a new password and others did not, ManageLM retries just the ones that missed it over the next few minutes, with the same password, so the targets that already have it are left alone and their services are not restarted again. If that does not fix it, the whole rotation is retried with a fresh value, up to five consecutive attempts. You are alerted once ManageLM has given up, rather than for a target that comes back on its own a few seconds later. What differs is how much is at risk in between:

Scheduled rotations do not start at all while a host they need is unreachable — the server, a target account's host, or a host receiving a file. An offline machine is not a failed rotation, and for a password there is no overlap window, so starting one that cannot be delivered would change the account and then have nowhere to put the result.

LDAP and database rotations can also verify themselves by signing in as the account with the new password — "the server accepted it" and "the account can use it" are different claims. For a database that check is a real connection, exactly what the consuming application will do. Turn verification off for an account that is not meant to sign in.

MCP Tools

Requirements and limits

Databases

Entra

Per-Plan Limits

Switching a credential off, and alerts

Each credential has two switches on the list. Enabled stops it rotating — the schedule skips it and Rotate now is refused — while keeping its targets, its schedule and its history, so switching it back on resumes exactly where it was. Alert decides whether its rotation results reach webhooks and notifications; the rotation still happens and is still in the history either way.

Skipping one destination

Each destination in a credential's Targets list has its own switch. Turning one off stops the next rotation deploying to it, without deleting it and losing how it was configured. The usual reason is a host that is off for maintenance or being decommissioned: while every destination has to be reachable for a rotation to run at all, a destination that is switched off is not counted, so one retired server no longer blocks the credential from rotating. The list column shows how many are on out of the total, and turns amber when any is off.

One thing to know before switching off a password destination. A rotation changes the password at the source first and then delivers it. A destination that is skipped therefore keeps the old password, which will no longer work — and nothing is recorded as an error, because the rotation did what you asked. The portal says so before it happens. An SSH key is different and safe: the old key is not withdrawn until the new one has been published, so a skipped host simply does not receive the new key.

A credential whose destinations are all switched off is not rotated at all, rather than having its password changed and delivered nowhere.

The number of managed credentials per account is limited by your plan (Free: 10, Pro: 50, Business: 100, Enterprise: unlimited). The Credentials page shows your usage against the limit. The New Credential button is disabled when the limit is reached. Every credential counts, whatever its state — one whose last rotation failed still occupies a slot until you delete it.

KSM Keystore

The Keystore holds private keys in the portal and lets applications on your servers use them without ever having them. An application loads a standard PKCS#11 module, asks it to sign or decrypt, and gets the answer back — the key itself stays in the portal. On by default — though it does nothing until you create a key and register an application, and managing either needs the Keystore permission. Turn it off under Settings → Optional Features if you do not use it.

This is not an HSM. Keys are held in software and encrypted at rest with the portal's encryption key, the same as every other secret. There is no tamper-resistant hardware and no FIPS or Common Criteria certification. What the Keystore gives you is central custody, per-application authorisation and a complete audit trail — not a hardware security boundary.

What it is for

Signing and decryption, not TLS termination. Every operation is a round trip to the portal. That is nothing for a code signature, a document, a JWT or an S/MIME message, and far too much for a busy web server — a full TLS handshake is one private-key operation, so a server doing hundreds of connections a second would be doing hundreds of round trips a second. TLS server certificates belong in Certificates & PKI, where the key is generated on the agent and stays there.

It follows that if the portal is unreachable, the keys are unusable. For occasional signing that is a failed job you retry; it is another reason not to put a web server's certificate here.

Key types

KindAlgorithmsUsed for
AsymmetricRSA 2048 / 3072 / 4096Signing, decryption, or both
AsymmetricEC P-256 / P-384 / P-521Signing only — a curve key cannot decrypt
Post-quantumML-DSA-44 / 65 / 87Signing only — see below
SymmetricAES 128 / 256Wrapping other keys, and encrypting small payloads
HashingHMAC SHA-256 / 384 / 512Message authentication — webhook signatures, API request signing

Post-quantum signatures use ML-DSA (FIPS 204), the NIST standard for signatures that stay secure against a quantum computer. Three strengths are offered; ML-DSA-65 is the usual choice. Two differences from RSA and EC are worth planning for. ML-DSA signs only — it is a signature scheme and cannot decrypt, so replacing an RSA key that does both means two keys. And it signs the message itself rather than a digest of it, so the whole message travels to the portal and is capped at 1 MB: it suits documents, manifests, tokens and attestations rather than firmware images or container layers. Signatures are also much larger — 2.4, 3.3 or 4.6 KB — so check that whatever stores or transmits them has room.

The signing application has to support ML-DSA through PKCS#11 as well. The mechanism comes from the 3.2 revision of the standard, which is newer than most tools; if yours does not offer it, an EC key remains the safe choice today.

Older digests. SHA-1 and MD5 signatures are accepted for interoperating with systems that cannot be changed — an old signing chain, an appliance, a protocol that predates SHA-2. Neither is safe against anyone who can influence what is being signed, and neither should be chosen for anything new. They are allowed here rather than pushing you to a tool outside the platform, because every use is recorded on the Activity tab — so “what still signs with MD5” is a question you can actually answer. Note that RHEL-family servers block SHA-1 signatures at the operating-system level, so an application there may refuse one even though the portal produced it.

A symmetric key here is a key-encryption key, not a data-encryption key. The case it exists for is wrapping: generate a data key on the host, have the portal-held key wrap it, and store the wrapped blob beside the data — so the key that protects everything else never exists outside the portal. Symmetric operations are capped at 64 KB, because every byte crosses the network twice and bulk encryption through this path would be a misuse rather than merely a slow one.

Keys and clients

Two things are managed on the Keystore page, and they are many-to-many:

You then grant a key to a client. A key with no clients exists but nothing can use it; a client is reused across every key it holds, which is why it is created on its own tab rather than inside a key.

How an application is authorised

Two independent things must agree before a key can be used:

  1. The credential — the PKCS#11 PIN, held in the application's own configuration. It is shown once when the client is created or rotated and never again; only a hash is stored.
  2. The calling process's account — read by the agent from the kernel, not claimed by the application. This one is optional per client: leave the allowlist empty and the credential alone authorises, fill it in and it is enforced strictly. Available on Linux agents only.

The credential is bound to the hosts that carry that client. Copied out of one machine's configuration it works on those and nowhere else — a client created on its own has a credential unique to it, and a client copied onto other hosts shares one with its copies, which is the point of copying: one application deployed to a fleet is one secret in your configuration management. Revoking a shared credential means rotating each copy; rotating any one of them gives that copy a new secret and leaves the others alone.

Every refusal reaches the application as an undifferentiated error — it is never told why, so an application that can reach the socket cannot map out which credentials exist or which account would have worked. The real reason is on the Usage tab — expand a line with refusals to read what the caller was not told.

Setting one up

  1. Turn the feature on under Settings → Optional Features, and grant the Keystore permission to whoever should manage it.
  2. On the Keystore page choose Add Key: name it, pick an algorithm, and check the handle it will be known by.
  3. Choose Add Client: pick the agent, name the application, and on a Linux agent optionally list the accounts allowed to use it. Copy the credential — it is shown once.
  4. Open the key and Grant to a client.
  5. Point the application at the module. The agent installs it at /opt/managelm/pkcs11/managelm-p11.so, fetching it from the portal the first time a key is granted on that host.
  6. If the application needs a certificate — anything on the JVM, and the code-signing tools do — create a CSR from the key, have it signed, and upload the answer. See Certificates below.

Configuring an application

The token is ManageLM Keystore, the PIN is the client's credential, and the object label is the key's handle.

# What this application may use
pkcs11-tool --module /opt/managelm/pkcs11/managelm-p11.so -O --login

# OpenSSL 3, through pkcs11-provider
openssl dgst -sha256 -sign "pkcs11:object=release-signing;type=private?pin-value=$PIN" file

Java's SunPKCS11 takes the same module path and the credential as its PIN. Supported mechanisms are RSA PKCS#1 v1.5 (raw and with SHA-256/384/512), RSA OAEP, ECDSA (raw and hashed), AES-GCM, AES key wrap and HMAC. Key generation, wrapping to new token objects and symmetric key creation are deliberately absent — those happen in the portal, where there is an operator, a policy and an audit trail.

Linux and Windows, with one difference. On Linux the agent reads the calling application's account from the kernel, which is what makes the account allowlist possible. Windows provides no equivalent, so a client on a Windows agent is authorised by its credential alone — the same assurance a hardware PKCS#11 token gives, since the PIN is the identity there too. The allowlist fields are simply unavailable when a Windows agent is selected, rather than accepted and quietly ignored.

How many keys you can hold

The number of keys per account is limited by your plan (Free: 10, Pro: 25, Business: 50, Enterprise: unlimited). The Keystore page shows your usage against the limit, and the Add Key button is disabled when the limit is reached. Only keys count — applications and grants are unlimited, since a grant simply gives an application access to a key that already occupies a slot. Self-hosted installs are uncapped: the keys live in your own database.

Who can see and change them

Every member can read the Keystore page — keys, applications, grants and usage — the same as Credentials, Monitors and Certificates. That is safe because no key material and no credential can be read back by any route. The keystore permission unlocks the buttons: creating, editing and deleting keys and clients, granting, and rotating credentials. API keys are stricter and need the permission even to read.

Revoking access

Four levels, each taking effect on the very next operation because nothing is cached:

Prefer any of these to deletion during an incident: all four are reversible with one click, and none of them loses configuration.

Deleting a key is final. It cannot be exported, recovered or regenerated — anything it signed can still be verified, but nothing new can be signed with it.

Usage

The Usage tab shows what every key was used for and what was refused, counted per key, per application, per mechanism, per day. Each line carries how many operations succeeded and how many were turned down; a line with refusals expands to show the most recent reason, the Unix account that asked and when — the reason the application itself was never told.

Counts rather than a line per signature, deliberately. A key signing a million times a day costs the same single row as one signing twice, so the record cannot grow with your traffic and a busy application cannot crowd out the rest of the history. It also means the numbers stay useful far longer: usage is kept for a year.

What you give up is the individual event — you can see that a key signed 4,312 times on Tuesday from one host, not the timestamp of each. If you need a per-signature trail for compliance, stream it to your own SIEM under Webhooks. Deleting a key or an application also removes its usage, so the record only ever describes things that still exist; the deletion itself stays in the Audit Log. Two events can be pushed off the portal — a refused access and a deleted key — under the Keystore category in Webhooks and notifications.

Certificates

A key can sign on its own, but most consumers will not use one without a certificate saying who the signature belongs to. Java's SunPKCS11 will not present the key at all, and the code-signing tools need the chain to build a signature. Each key holds one certificate chain, shown on its row.

  1. Expand the key and choose Create CSR. Fill in the subject — for code signing the common name is your organisation's legal name, exactly as your CA has it — and send the request to your CA.
  2. When the certificate comes back, choose Upload certificate. PEM, DER, PKCS#7 (.p7b) and PKCS#12 are all accepted, and you can send the whole chain: the root is dropped, the rest is put in order, and the certificate is checked against the key it claims to belong to. One for a different key is refused.

The key row then shows the certificate's state at a glance — valid, expiring within 30 days, or expired — and expanding it shows the chain, the expiry and downloads. Replace installs a renewal; applications read the token when they start, so a long-running one picks up a replaced certificate at its next restart.

Not for a publicly-trusted code-signing certificate. Since 2023 the CA/Browser Forum requires those keys to be generated inside certified hardware, so no public CA will issue against a key held in software — here or anywhere else. The Keystore's certificates are for your internal CA, a private-trust chain, S/MIME, document signing and tokens.

System Backups

End-to-end encrypted filesystem backups from your agents to your own S3 storage. ManageLM never sees your data — the agent encrypts every archive locally before uploading, and only the ciphertext transits via your S3 bucket. Restore to any online agent at any time.

Providers

The S3 bucket is configured once per account in Settings → Account & LLM → S3 Storage, and is used for both backups and session recordings. Provider-agnostic — one set of credentials, any S3-compatible storage:

The list is a convenience, not a limit: a preset only pre-fills the endpoint URL and region, so any other S3-compatible endpoint works by picking Custom / Other. The Test button validates credentials via HeadBucket before saving. Secret keys are stored AES-256-GCM encrypted at rest.

Encryption

Every backup has its own randomly generated 32-byte master key, stored wrapped server-side. Before each run, the portal sends the key to the agent over the existing mTLS WebSocket channel — never over HTTP, never logged.

Pure-Python implementation on the agent via oscrypto — no cryptography package, no native build dependencies.

Schedule & Retention

Each backup has its own cadence and retention:

ScheduleConfigurable Fields
Every hour
Every 6 hours
DailyRun time (HH:MM, agent-local)
WeeklyDay of week + run time
MonthlyDay of month (1–31, clamped) + run time

FIFO retention — specify how many snapshots to keep (1–90). Older snapshots are automatically rotated out by the cleanup cron, which best-effort deletes the S3 object then the DB row.

Quiesce services during backup

For a consistent snapshot of databases and stateful apps, list one or more services to stop during the backup (comma-separated, e.g. postgresql, docker:redis). The agent:

  1. Stops each listed service via systemctl stop (Linux) or net stop (Windows) — or docker stop for an entry written docker:name, which stops that container instead. 30-second timeout per entry.
  2. Runs the tar → encrypt → upload pipeline.
  3. Restarts every service that was successfully stopped — in a try/finally so a backup failure (or the agent being killed mid-run) never leaves services down.

Run flow

  1. Agent requests a presigned PUT URL from the portal; portal pre-inserts a pending snapshot row.
  2. Agent tars the source path (with optional excludes), encrypts the archive, uploads directly to S3 — never through the portal.
  3. Agent reports size, file count, duration, SHA-256 via backup_status.
  4. Portal flips the snapshot to ok / failed; the cleanup cron reaps stuck pending rows after 6 hours.

Download & Restore

Detach on agent delete

When you delete an agent that has backups, the backups are not deleted — their agent_id is cleared instead. The S3 data and snapshot history survive the hardware replacement. A purple Reassign button appears in the backup row; clicking it opens the edit modal with an Agent picker so you can attach the backup to a new agent and continue the schedule. The UI also warns you about the detached count before confirming the agent deletion.

S3 orphan cleanup

The S3 Cleanup button in Settings → S3 Backups scans your bucket under the account prefix and deletes objects that have no matching snapshot row in the portal. Useful when the bucket was deleted externally, credentials were rotated mid-run, or you want to reclaim storage after manually removing backups.

Alerting

Per-backup toggle for alert-on-failure emails. ManageLM also detects stalled backups: if a scheduled backup is missed because its agent is offline, you receive a single consolidated alert per agent rather than one alert per missed run.

Permissions

Per-Plan Limits

The number of backups per account is limited by your plan (Free: 20, Pro: 100, Business: 200, Enterprise: unlimited). Detached backups still occupy a slot — delete them explicitly to free the slot.

Constraints

Pentests

ManageLM includes automated penetration testing for your public-facing agents. Pentests scan your servers from the outside — testing what an attacker would see. Available on Pro and Business plans.

How it works

  1. Select — Open the Pentests page and click New Pentest. Choose one or more public agents, select the tests to run, and optionally add target URLs.
  2. Validate — The portal sends a one-time token to the agent. The agent validates with the pentest service from its public IP, proving it controls the target.
  3. Scan — The pentest service runs tools sequentially: nmap (port discovery), nuclei (vulnerability scanning), testssl.sh (TLS audit), and more depending on selected tests.
  4. Report — An LLM generates a human-readable report with findings, severity ratings, and a security score (0–100). Results appear in the Agent Assets audit modal (Pentest tab) and the Pentests dashboard.

Available tests

TestWhat it scansCredits
Basic ScanPort discovery (nmap), vulnerability scan (nuclei), TLS quick check (testssl)3
Full Port ScanAll 65,535 TCP ports3
Vulnerability ScanExtended nuclei templates (critical/high/medium)3
SSL/TLS AuditFull testssl.sh analysis (per URL)1
Web App ScanNuclei web templates (per URL)3
DNS AuditSPF, DMARC, DKIM, MX records (per URL)1
HTTP HeadersSecurity headers analysis (per URL)1
Directory ScanCommon path discovery with ffuf (per URL)2
Subdomain EnumSubdomain discovery with subfinder (per URL)1

URL-based tests run once per target URL. Credit cost is calculated as: IP-based test credits + (URL-based test credits × number of URLs).

Credits

Pentests consume credits. Credits are deducted after a successful scan — failed scans are not charged.

Domain verification

Before scanning URLs, you must verify domain ownership. The pentest service generates a DNS TXT record that you add to your domain. Once verified, the domain stays valid for 24 hours before requiring re-verification.

Compliance integration

Pentest results automatically feed into the Compliance page. Each tool produces a pass/fail rule that maps to framework controls (CIS, PCI-DSS, SOC 2, ISO 27001, NIS2, NIST CSF, HIPAA). Pentest rules appear alongside security audit rules in framework coverage views.

Constraints

Compliance & Frameworks

The Compliance page maps your security audit results to industry compliance frameworks. ManageLM evaluates your fleet against each framework's controls and shows which pass, fail, or are not covered by the current rule set.

Supported frameworks

FrameworkVersionDescription
CIS Level 1v8.0Center for Internet Security — essential security hygiene for servers
CIS Dockerv1.6CIS Docker Benchmark — container runtime security
SOC 22017Trust Services Criteria — Security principle technical controls
PCI DSSv4.0Payment Card Industry Data Security Standard
ISO 270012022ISO/IEC 27001 Annex A — information security controls
NIS2 Directive2022EU Directive 2022/2555 — network and information security measures
NIST CSFv2.0NIST Cybersecurity Framework — Protect, Detect, Identify functions
HIPAA Security Rule201345 CFR §164.312 — technical safeguards for protected health information

How controls are evaluated

Each framework control is backed by one or more checks from security audits, pentests, and vulnerability scans. A control passes only when every backing check passes on every agent. If any check fails on any agent, the control fails. Controls with no data yet (no agents scanned) show as not covered.

Compliance dashboard

The Compliance page has two tabs:

Agents tab

Frameworks tab

Security drift notifications

When a security audit completes and a rule that previously passed now fails, ManageLM detects this as drift. Drift is shown in the Compliance dashboard as an alert. Optionally, admins can enable the Security Drift email notification in Settings > Email Notifications to receive an email with the new issues.

Drift detection only triggers when there is audit history — the first scan for an agent never generates drift alerts.

Evidence PDF export

Each framework has an Evidence PDF button (enabled when compliance is ≥ 50%). The generated PDF is designed for auditors and includes:

The fleet-wide Export PDF button on the Compliance page generates a summary report covering all frameworks.

Adding custom frameworks

Self-hosted operators can add a custom framework by dropping a JSON file into the install's frameworks/ directory and restarting the portal — the file lists which existing rule slugs map to each control.

System Inventory

ManageLM discovers all running services, installed packages, and system components on your agents. Checks are read-only and no skill assignment is required.

How it works

  1. Trigger — Open an agent's detail panel on the Agent Assets page. Click the clipboard icon to open the System Inventory modal, then click Run Inventory.
  2. Scan — The agent collects information about the system using a read-only set of checks.
  3. Structure — The portal turns the collected output into inventory items, categorising each one and joining service names to their installed package versions. No LLM is involved, so the result is the same on every run and does not depend on your model configuration.
  4. Results — Inventory items appear in the modal, grouped by category.

What is collected

CheckWhat it inspects
System InfoOS, kernel, uptime, CPU count, memory, disk usage
Running ServicesAll active services (systemd on Linux, Windows Services on Windows)
Enabled ServicesServices enabled at boot
Listening PortsTCP listening sockets with associated processes
Installed PackagesPackage list from rpm or dpkg (Linux), or installed programs list (Windows)
Package VersionsExplicit version extraction for common packages (nginx, PostgreSQL, Redis, Docker, etc.)
ContainersDocker/Podman containers with image, status, and ports
Cron JobsSystem and per-user cron jobs
Network InterfacesAll network interfaces with addresses
Mounted FilesystemsNon-virtual mounted filesystems
Hardware InfoCPU model, memory, disks
Web ServersRunning web servers (nginx, Apache, Caddy, HAProxy)
DatabasesRunning databases (PostgreSQL, MySQL, MongoDB, Redis, Valkey, Memcached, Elasticsearch)
Login UsersNon-system user accounts with shell and group membership

Categories

Each inventory item is classified into one of these categories:

CategoryExamples
systemOS version, kernel, CPU, memory, disk
webNginx, Apache, Caddy, HAProxy
databasePostgreSQL, MySQL, Redis, Valkey, MongoDB, Elasticsearch
mailPostfix, Dovecot, OpenDKIM
containerDocker containers, Podman containers
networkNetwork interfaces, listening ports
storageMounted filesystems, disks
securityFail2ban, SELinux, firewall
monitoringMonitoring agents, metrics collectors
logRsyslog, journald, logrotate
userLogin user accounts
schedulerCron jobs, systemd timers

PDF export

Click the Inventory button at the top of the Agent Assets page to download a fleet-wide inventory report covering all agents with completed inventories. The PDF includes categorized service lists with versions and status for each server.

Like security reports, use the Scheduled Tasks popover to set the inventory scan schedule across all agents at once.

Scheduled inventories

You can configure automatic recurring inventories per agent. Open the System Inventory modal and use the schedule selector in the top-right corner to choose a frequency:

The scheduler checks every 15 minutes and triggers inventories for agents that are overdue. A yellow badge (D, W, or M) appears on the agent card to indicate an active schedule.

Constraints

SSH & Sudo Access

ManageLM includes a built-in access scanner that discovers SSH authorized keys and sudo privileges across your infrastructure. Checks are read-only and run on the agent — fully deterministic, no LLM involved. Discovered SSH key fingerprints are matched against ManageLM user profiles for identity resolution.

How it works

  1. Trigger — Open an agent's detail panel on the Agent Assets page. Click the SSH & Sudo button to open the access scan modal, then click Scan Access.
  2. Collect — The agent enumerates each user's authorized SSH keys (with SHA256 fingerprints) and parses sudoers files, including group-based rules. No LLM is involved.
  3. Results — The combined data is returned to the portal and displayed in the modal. SSH key fingerprints are matched against public keys registered in ManageLM user profiles (Settings → Security → SSH Public Keys) — matched keys show the user's name in a green badge, unmatched keys show as "Unknown".

What is collected

DataSourceDetails
SSH authorized keys~/.ssh/authorized_keysKey type, SHA256 fingerprint, comment, full public key, line number
Sudo user rules/etc/sudoersTarget host, runas user, commands, NOPASSWD flag, source file
Sudo group rules/etc/sudoers + /etc/groupGroup rules (e.g. %wheel) expanded to individual users via group membership

Identity mapping

ManageLM users can register their SSH public keys in Settings → Security → SSH Public Keys. When the access scan discovers a key on a server, its SHA256 fingerprint is matched against registered keys to identify the owner. This creates a complete map of who has access to what and what they can do (SSH + sudo).

Register your SSH keys. For identity resolution to work, each team member should add their SSH public key(s) in Settings → Security → SSH Public Keys. Without registered keys, all discovered keys will appear as “Unknown” in scan results.

Sudo rules with NOPASSWD are highlighted in red as a security concern.

Key comments are not used for identity. The user@host comment in authorized_keys is unreliable — identity is resolved exclusively via SHA256 fingerprint matching against registered profiles.

MCP integration

The access scan powers natural-language access management via Claude:

PDF export

Click the SSH & Sudo button at the top of the Agent Assets page to download a fleet-wide access report. The PDF includes SSH keys and sudo rules per user per server, with NOPASSWD rules highlighted.

Scheduled scans

Configure automatic recurring scans per agent via the schedule selector in the modal header, or for all agents via the Scheduled Tasks popover in the Agent Assets toolbar. Frequencies: Manual / Daily / Weekly / Monthly.

Constraints

Certificate Discovery

ManageLM includes a built-in certificate scanner that discovers the x509/TLS certificates already installed on each host — in system stores, web-server config directories, Let's Encrypt live directories, and other well-known locations. Checks are read-only and run on the agent (fully deterministic, no LLM involved), and only public certificate metadata is collected — private key material is never read, transmitted, or stored. Discovered certificates are cross-referenced against the certificates ManageLM itself issues (see Certificates & PKI) so you can tell at a glance which are already managed.

Discovery vs. management. This scan inventories certificates that already exist on your servers, whatever their issuer. To issue, renew, or revoke certificates, see Certificates & PKI.

How it works

  1. Trigger — Open an agent's detail panel on the Agent Assets page. Click the Certificates button to open the discovery modal, then click Scan Certificates.
  2. Collect — The agent walks the known certificate locations, parses each certificate's metadata (no key material), and returns it to the portal.
  3. Results — Each certificate is shown with its subject, issuer, expiry, key type/size, and signature algorithm. Health flags surface certs that are expired, expiring soon (≤ 30 days), weak (RSA < 2048 or SHA-1/MD5 signature), or self-signed. Certs whose fingerprint matches a ManageLM-issued certificate show a green Managed badge.

What is collected

DataDetails
Certificate metadataSubject (CN + full DN), issuer, SANs, validity dates, serial, SHA-256 fingerprint
Key & signatureKey type (RSA / EC), key size, signature algorithm; CA vs leaf
LocationFile path (Linux) or store name (Windows)
Private-key hygieneWhether a matching key file sits beside the cert, and whether its file mode is world-readable — a serious misconfiguration. The key contents are never read.

Trust-store bundles (hundreds of public root CAs) are excluded, so results focus on the server certificates actually deployed on the host. Linux discovery covers /etc/ssl, /etc/pki, and the config directories of nginx, Apache, HAProxy, Postfix, Dovecot, and others; Windows discovery reads the LocalMachine\My and WebHosting certificate stores.

MCP integration

The certificate scan powers natural-language certificate auditing via Claude:

PDF export

Click the Certificates button at the top of the Agent Assets page to download a fleet-wide certificate report, grouped per server with expiry, health flags, and managed status.

Scheduled scans

Configure automatic recurring scans per agent via the schedule selector in the modal header, or for all agents via the Scheduled Tasks popover in the Agent Assets toolbar. Frequencies: Manual / Daily / Weekly / Monthly.

Constraints

SSH Key & Sudo Sync

Push a user's stored SSH public keys to managed Linux and Windows hosts so they can log in directly with their keys — no manual editing of ~/.ssh/authorized_keys (or administrators_authorized_keys on Windows) on each server. On Linux, separate grants can also put a user's keys in /root/.ssh or give their account passwordless sudo. Sync is event-driven: every relevant change (toggle flip, new key uploaded, user removed, group membership change) immediately updates the affected agents.

How It Works

Three things can be turned on, and they are independent of one another. Only the first has a master switch:

  1. Keys into each user's own account — the "Sync Admin SSH Keys" master switch on the agent (and on the group). If it is on at the agent or on any group it belongs to, every assigned user with a System Username gets their keys pushed to that local account — most-permissive wins. There is no per-user toggle for this one: the System Username field is itself the participation flag, since admin-set targeting is what makes the push safe. With every switch off, the agent strips those managed blocks.
  2. SSH Root — a per-user grant, set on a direct assignment or on a group membership; if either grants it, the user has it. Puts the user's keys in /root/.ssh/authorized_keys. It needs no System Username and does not consult the master switch: root's file is nobody's account, so there is nothing to map, and the host's consent to fill people's own accounts has no bearing on it. A user with no key on file simply contributes nothing.
  3. Sudo Root — a per-user grant with the same OR-union rule. Writes a passwordless NOPASSWD: ALL line for the user's local account into a managed /etc/sudoers.d/managelm drop-in. It does need a System Username, because the sudoers line names an account — but it does not consult the master switch either. A sudoers rule works for any login method (AD, Kerberos, a password, a jump host) and never needed a key to exist.

All three are orthogonal: a user can have their own keys pushed, root-key access, sudo-to-root, any combination, or none.

Changed in 1.5.6. SSH Root and Sudo Root used to ride on the master switch, so a host could only have its sudoers or its /root/.ssh managed if it was also having keys written into its users' own accounts. That excluded ordinary cases — a host whose people sign in through AD and wants sudo managed but authorized_keys untouched, or an operator who should hold root on a box where they have no account of their own. Existing grants keep working; the switch now means only what its name says.

Local-Account Matching: System Username

To participate at all, a user must have a System Username set on their profile (e.g. charly). This is the local account name on managed hosts. On Linux, LDAP / SSSD / NIS-managed accounts are visible alongside /etc/passwd. On Windows, local accounts are supported (domain-only accounts are not yet).

The field is admin-set: regular members can't change their own System Username (or anyone else's), but admins and owners can edit theirs and others'. This prevents a member from redirecting their own keys onto another local account by relabeling themselves. Configure it in Users & Roles → (member) → System Username, or at invite time via the optional field on the invite modal.

Sudo Root (Linux only) requires System Username — the sudoers line has to name a local account. SSH Root does not: those keys go to root's own file, so there is no account to map, and an operator can hold root on a host where they have no login of their own. What SSH Root does need is a key on file, since without one there is nothing to push. Either way, a grant whose prerequisite is missing shows as a disabled switch that still reflects what is stored, with the reason on hover — it is never silently hidden or flipped off.

Where to Toggle

How the Agent Reconciles

SSH keys (Linux). The agent maintains a managed block inside each user's authorized_keys. Lines outside that block are preserved verbatim — existing keys aren't touched. Updates are safe against partial writes and against symlink tricks. Accounts that drop out of coverage (user removed from the agent, sync toggle off, user deleted) get their managed block stripped on the next reconcile.

SSH keys (Windows). Windows OpenSSH treats accounts in the local Administrators group specially — it reads their authorized keys from a single shared file (%PROGRAMDATA%\ssh\administrators_authorized_keys) instead of the per-user ~\.ssh\authorized_keys. The agent picks the right file automatically per user based on live group membership: per-user file for non-admins, shared admin file for accounts in Administrators. Be aware that any key in the shared admin file authenticates as any admin account on the host — this is a Windows OpenSSH default, not something we introduce; operators who need stricter scoping must customise their sshd_config. SSH Root and Sudo Root have no Windows analog — there is no /root and no sudoers — so those two columns are not drawn on a Windows agent at all. Console is, and works there — and on Windows the same Console grant also provides the graphical desktop, so a Windows host shows both a terminal and a desktop icon.

Sudo grants (Linux only). The agent owns /etc/sudoers.d/managelm end-to-end and writes one passwordless NOPASSWD: ALL line per granted user. Each update is syntax-validated before being installed; if validation fails, the previous file stays in place — a broken sudoers can never lock you out. When the grant list is empty, the file is removed entirely — clearing every grant is how you turn sudo management off on a host, since it has no master switch of its own.

FIDO / Hardware-Backed Keys

SSH FIDO keys generated with ssh-keygen -t ed25519-sk are accepted at upload time and synced just like any other key. sshd will require a physical touch on the YubiKey at login time. This is a separate credential from any passkey you've registered for portal MFA — same hardware, different credentials.

Triggers

The portal updates affected agents immediately whenever the effective state changes. A single update covers both SSH keys and sudo grants. Triggers include:

Safety Notes

Activity Audit

ManageLM includes a built-in activity audit that tracks user activity on your servers. The audit collects login history, sudo activity, file changes, and package events on the agent in a read-only scan. On Linux it works without any extra dependencies (no auditd needed); on Windows it uses the Windows Event Log. Fully deterministic, no LLM needed.

How it works

  1. Trigger — Click the Activity tab on an agent card in the Agent Assets page, then click Run Activity Audit.
  2. Scan — The agent collects activity for the configured time window.
  3. Parse — Events are normalized, deduplicated, and system accounts are filtered out.
  4. Identity — Full names (including LDAP/SSSD users) are matched against ManageLM users — matched users appear as green badges.
  5. Results — Displayed in the Activity Audit modal with dashboard cards and detail tables.

What the report shows

Time windows

Each audit collects data for a rolling time window:

PDF export

Click the Activity button at the top of the Agent Assets page to download a fleet-wide activity audit report as PDF. Use the Scheduled Tasks popover to set the audit schedule across all agents.

Constraints

Threat Detection

Continuous, LLM-narrated runtime threat detection on Linux hosts. The agent watches what's happening on the host in real time and the LLM turns anything that looks compromising into a human-readable alert in the portal — with a severity rating, a plain-English explanation of what happened, and one-click actions to stop it.

Two independent modes — one for services and daemons, one for human login sessions — can be enabled together or separately, per agent or per group. Both toggles are Linux only and can cascade from a group to every Linux agent in it (same model as Sync Admin SSH Keys).

Service Threat Detection

Watches services, daemons, and workloads — non-human activity. Related events are correlated before a verdict is formed, so an incident produces one alert with a short explanation of why the activity matters — not a stream of disconnected ones. Examples of what gets caught:

The LLM judges each batch against the host's installed skills — the same skills you assigned to the agent (e.g. Web Server Management, Database Management, Email Server Management). Behavior that fits the host's role is dismissed silently (a PHP site making outbound HTTP on a web-server host is normal; the same behavior on a host with no web role is flagged). Batching also means a flapping service can't storm the inbox — one alert per incident, not one per event.

Session Threat Detection

Watches interactive SSH and sudo sessions for the ManageLM users that map to local accounts on the host. The LLM gets the user's permitted scope — built from the skills they're allowed to use on that host plus their optional free-text role description — together with a structured transcript of what they did, and decides whether the activity fits that scope. A session is judged as activity builds up, again when the user logs out, and after 10 min of inactivity — so a risky session can be flagged (and stopped) while the user is still connected, not only after they leave.

This isn't a fixed rule-list — the LLM judges holistically against the user's scope. Examples of what typically gets flagged:

Activity that the user explicitly reverses (stop a service, work on it, restart it) is not flagged — the LLM evaluates the whole session arc, not isolated events. Every mapped user is monitored — there is no per-user opt-out. A user with no assigned skills and no role description is judged as a standard, non-privileged account, so administrative actions (installing packages, editing auth files, changing services) will be flagged. A login whose user doesn't map to a ManageLM user is skipped, and the full session content never leaves the host.

Alert Severity

The LLM grades every batch on three levels; only the top two ever reach you:

Where to Toggle

Roles & Skills

Session Threat Detection judges every mapped user. What counts as “in scope” for a user is built from two things:

A user with neither skills nor a role description is treated as a standard, non-privileged account — routine work is fine, but administrative or privileged actions are out of scope and will alert. Linux sessions are matched to ManageLM users via the same System Username field used by SSH Key Sync; a login that doesn't map to a ManageLM user is skipped.

Where to See Alerts

Audit Logs → Threat Alerts tab. The row+expand layout matches the other Audit Logs tabs (Agent Activity, Admin Actions, Geolocation) and respects the same shared From / To pickers and global Site selector. Each row shows the time, the actor (the user for session alerts, or the offending process/daemon for service alerts), agent, kind, severity, the rule that fired, and a status badge (Unhandled, Discarded, Stopped, or Ended). Clicking expands the row in place to show the full event context, the role description used for judgment, and any action history — and, for admins on unhandled alerts, the same Kill / Discard actions offered in the alert email (below).

Email & One-Click Actions

Each alert offers these actions — from the alert email, and inline on unhandled alerts in the portal (admins):

Alert kindAction buttonWhat it does
Session Kill Session The agent terminates the flagged user's login session on the host.
Both Discard Alert Marks the alert a false positive and tells the agent to stop alerting on this same activity (rule + service/user) on that host.

Email actions go through a mandatory confirmation screen, and each link expires in one hour and can be used once; in-portal actions are admin-only and confirm in a dialog. Critical system processes (init, sshd, the agent itself, container runtimes) are never affected regardless of what the alert says.

Service alerts cover a batch of events from potentially several processes, so they don't carry a single process to kill — only Discard Alert is offered. Session alerts offer Kill Session only while the login is still active; once the user has logged out, only Discard remains.

Email Recipients

Privacy

For Session Threat Detection, the session details — commands, file paths, network destinations — stay on the host. Only the LLM's verdict and a short excerpt are stored in the portal alert. Where the LLM call itself runs depends on your deployment:

Deployment modeLLM call destinationRecommended for sensitive workloads
SaaSTrial LLM (Anthropic)Acceptable under the standard SaaS terms.
Self-hosted, proxied LLMManageLM proxy → configured upstreamSame exposure as the SaaS path.
Self-hosted, local LLMStays on the customer hostRecommended. Session content never leaves your infrastructure.
Linux only. Threat Detection requires a modern Linux kernel (RHEL 9, Ubuntu 22.04+, Debian 12+ all qualify). Windows and macOS hosts are not supported in this release. The first time a host's toggle is turned on, the agent fetches its detection engine from the portal — this can take a moment on slow links; subsequent toggle changes are instant.

Service Dependencies

The Service Dependencies scan discovers cross-server service dependencies across your infrastructure. It shows what each server provides, what it depends on, and highlights connections between managed agents.

How it works

  1. Trigger — Click the Service Dependencies button at the top of the Agent Assets page.
  2. Scan — The portal triggers a scan on every online agent simultaneously. A progress modal shows each agent's scan status in real time.
  3. Collect — Each agent runs a fully deterministic scan (no LLM needed):
    • Provides — discovers all listening TCP services.
    • Depends on — discovers outbound connections (established TCP) plus config-file parsing for intermittent dependencies.
    • All hostnames are resolved to IPs locally on the agent before reporting.
  4. Report — The portal matches dependency IPs against known agent IPs to identify managed vs external connections, and displays a per-agent report.

What is scanned

SourceWhat it finds
Established connectionsAll active outbound TCP connections to non-local IPs
Nginx configsproxy_pass, upstreams, fastcgi_pass, uwsgi_pass, grpc_pass
Apache configsProxyPass, ProxyPassReverse, RewriteRule [P]
HAProxy configBackend server definitions
Caddy configreverse_proxy targets
.env filesDATABASE_URL, REDIS_URL, DB_HOST, SMTP_HOST, and many more
Docker ComposeEnvironment variables with connection strings
WordPressDB_HOST in wp-config.php
Database replicationMySQL master-host, PostgreSQL primary_conninfo, Redis replicaof
Mail configsPostfix relayhost and lookup tables, Dovecot auth backends
LDAP configsldap.conf, sssd.conf, nslcd.conf URI/host directives
NFS/CIFS mountsNetwork mounts in /etc/fstab
Systemd unitsEnvironment variables with connection strings in service files
PrometheusScrape targets in prometheus.yml
DNS resolvers/etc/resolv.conf nameservers
NTP serversntp.conf, chrony.conf, timesyncd.conf
Syslog targetsRemote syslog destinations in rsyslog configs
SNMP trapsTrap sink destinations in snmpd.conf
Backup clientsBacula, Bareos, Borg, Restic server addresses
Zabbix agentServer= directive in zabbix_agentd.conf
Generic /etc sweepURLs with host:port and raw IP:port patterns across all /etc files

Report format

Each agent's section shows:

Constraints

Connectors

Connectors wire ManageLM up to external systems. They come in three kinds, selectable as tabs in the Add Connector modal:

All three kinds share the same permission (perm_connectors), the same encryption-at-rest (AES-256-GCM, requires ENCRYPTION_KEY), the same storage table, and the same CRUD pages. What differs is the data flow: hosting connectors pull on a schedule, SIEM connectors push task events from each agent, notification connectors push platform events from the portal.

Hosting Integration

Sync your hosting resources (VMs, volumes, networks, security groups) from cloud providers and hypervisors, and auto-match them to ManageLM agents by IP address and hostname.

Supported providers

How it works

  1. Go to Connectors in the sidebar and click Add Connector.
  2. On the Hosting tab, select a provider, enter a name, and fill in your credentials.
  3. Click Save — the connector syncs automatically on creation.
  4. Expanding a connector shows what depends on it: a cloud connector lists the resources it discovered, a SIEM the agents forwarding to it, and a directory, database or vault the credentials it is part of — the accounts rotated there, or the items each rotation writes into.
  5. Test is available while you are still filling the form, not only after saving, and it checks what is on screen rather than what was last saved — so you can try a different URL or turn off certificate verification for a self-signed server and see the result before committing to it. Nothing is written until you save. When editing, a password you do not retype is taken from the stored connector.
  6. Hosting resources appear in the connector's expanded view and on agent cards in the Agent Assets page.

What is synced

Agent matching

After each sync, ManageLM automatically matches hosting VMs to agents by comparing IP addresses and hostnames. Matched agents show a provider badge (e.g. AWS, Azure) on their card in the Agent Assets page. Expanding an agent card shows the full provider metadata (instance type, zone, IPs, disks, security groups, tags).

Reaching a private endpoint (hosted platform)

Public cloud APIs (AWS, Azure, GCP) are reachable from the portal directly. An on-premises Proxmox or vCenter usually is not — and publishing a hypervisor API to the Internet just to use ManageLM is not a reasonable ask. On the hosted platform you can instead point the connector at one of your agents: it makes the API call on your own network and returns the result over the connection it already holds open. No inbound firewall rule, no VPN.

  1. Set API Access to Through an agent on the connector.
  2. Pick the relay agent — any agent that can reach the hypervisor endpoint.
  3. Save. Sync and any write actions now travel through that agent.

The relay is scoped to the connector's own endpoint: the agent refuses any URL outside it, only permits standard HTTP methods, never follows redirects, and caps response size. Every relayed call is logged on the agent so the machine's owner can audit what it was asked to reach. Because a self-hosted portal already runs inside your network, it connects directly and the option is not offered there.

Write mode — acting on VMs

A connector is read-only until you say otherwise. Turning on Write Mode lets the portal (and Claude) act on the VMs it discovered:

ModeWhat it allows
Read onlyInventory sync only. The default.
Safe actionsStart a VM, create a snapshot — nothing that interrupts a running workload.
Full actionsAlso shut down, force stop, reboot, and roll back to a snapshot.

Deleting VMs, disks and snapshots is not reachable from either mode.

Four independent gates apply to every action, and all of them must pass:

Actions run from the connector's expanded view in Connectors, on each discovered VM. Disruptive ones ask for confirmation first. Proxmox actions are asynchronous on the hypervisor side, so ManageLM waits for the underlying task to finish and reports its real outcome — an action that was accepted but has not completed yet is reported as still running rather than as a success.

Proxmox API token permissions: a token that syncs fine can still be refused for writes. Power actions need VM.PowerMgmt and snapshots need VM.Snapshot, plus an ACL granting them unless privilege separation is disabled on the token.

Action history

Every write attempt is recorded — who ran it, from the portal or from Claude, the resource, the outcome, and the state before and after. Refused attempts are recorded too, so “who tried to stop that VM, and were they allowed to?” is answerable and not just “who succeeded”. Open Action history at the bottom of the connector's expanded view. Entries are kept for 180 days.

MCP integration

Claude can query your hosting inventory using three built-in tools:

The read tools are hidden until at least one hosting connector exists — a SIEM-only tenant will not see them in Claude's tool catalog. cloud_action is hidden further, until a connector actually has write mode enabled.

When Claude uses cloud_action it must name exactly one VM — if the name matches several, it is told to ask you which rather than choose — and any disruptive action requires an explicit confirmation before it will run.

Sync schedule

Each connector syncs on a configurable interval: every 1 hour, 6 hours, 12 hours, or 24 hours. Manual sync is available from the connector list (refresh icon). Syncs are distributed across portal instances using Redis locks to prevent duplicates.

Security

SIEM Integration

Forward task-completion events from your agents directly to an external SIEM. Useful for compliance, centralized security monitoring, and audit trails outside ManageLM's own database. Forwarding is additive — the portal's own task log and audit trail are unchanged.

Agent-direct delivery. Events travel from the agent straight to the SIEM over HTTPS. The portal never sees the event stream in flight — it only distributes the SIEM config (endpoint + credentials) to the agents. This is what lets ManageLM SaaS forward into private / on-prem SIEMs behind NAT: the SIEM only has to be reachable from the managed server, not from our cloud.

Supported destinations

What gets forwarded

One event per completed task — the same rows you see in the Command History panel of an Agent's detail page. Nothing else is forwarded: no heartbeats, no config pushes, no LLM traffic.

{
  "ts": "2026-04-17T14:23:11Z",
  "agent": { "hostname": "prod-web-01" },
  "task": {
    "id": "...",
    "skill": "firewall",
    "instruction": "block 1.2.3.4",
    "status": "completed",
    "output": "...",
    "error": null,
    "files_changed": ["/etc/nftables.conf"]
  }
}

Splunk wraps this in {"event": <envelope>, "sourcetype": "...", "index": "...", "host": "..."}. Elasticsearch sends it as an NDJSON _bulk body (action line + doc line). Webhook sends a JSON array of envelopes per batch.

How it works

  1. Go to Connectors in the sidebar and click Add Connector.
  2. Switch to the SIEM Integration tab, pick a type, enter a name, fill in the endpoint and credentials, and save. A Test Connection runs automatically on create.
  3. Open an Agent detail page — or a Server Group — and pick the new SIEM from the SIEM Forwarding dropdown.
  4. From that point on, every task completed by that agent fires a POST to the SIEM, in parallel with the normal task-result report to the portal.

Assignment and inheritance

Each agent has at most one SIEM destination. It resolves as:

  1. If the agent itself has a direct override → that destination wins.
  2. Else if its group(s) point at a single destination → inherit that one.
  3. Else → no forwarding.

If an agent belongs to several groups whose SIEM settings differ, the portal refuses to guess — the agent gets a red SIEM CONFLICT badge on the Agent Assets list until you set an explicit per-agent override to resolve the conflict.

Agent groups show their SIEM destination as a small → <connector name> pill on the group card (read-only view).

Transport and reliability

Security

Permissions

Creating, editing, or deleting a SIEM connector requires the Connectors permission (perm_connectors) — the same gate as hosting connectors. Assigning a SIEM destination to an agent also requires the Agents permission; assigning one to a group requires the Groups permission.

Notifications & Ticketing

Route platform events to Slack, ServiceNow, or Jira so the people who need to know are paged in the channels they already watch — without writing custom webhook receivers. Notifications are an additive fan-out: in-app notifications, email, user webhooks, and SIEM forwarding all continue to work unchanged.

Supported destinations

Adding a new destination type (PagerDuty, Teams, Zendesk, ...) is a single-file extension — the dispatcher and call sites are provider-agnostic, and the dispatcher discovers new providers from the connector schema automatically.

What gets forwarded

Every platform event that fires a webhook today is also eligible to fire a notification, plus two channels that webhooks do not carry: threat alerts and security drift. The complete category list:

Subscription routing

Each connector has its own per-category routing, configured in the expanded view on the Connectors page. The column adapts to what the destination can do:

Either way, untouched = no events (safe default: a new connector ships nothing until you opt in). One Slack connector for chatty ops alerts and a separate ServiceNow or Jira connector for ticket-worthy events is a common shape — tick all categories on Slack, tick only critical categories on the ticketing destination.

Severity and tickets

The dispatcher assigns a default severity (info / warn / critical) and a default ticket flag to every event. Sensible starting points:

For Slack, the severity default decides whether an event renders as a plain message or a ticket-styled one. For ticket-only destinations (ServiceNow / Jira), every event in a subscribed category opens a ticket regardless of its default severity.

Correlation id

Every ticket carries a stable correlation_id derived from the event name + the most-identifying payload fields — for example managelm:monitor.down:<monitor_slug>:<agent_id>, so the same monitor flapping on the same agent shares one trackable id while different monitors stay separate (ServiceNow stores it in the correlation_id field; Jira attaches it as a label). Note: in this version ManageLM does not itself de-duplicate — each fire opens a new ticket. The id is provided so you can collapse re-fires on your side (a ServiceNow business rule / transform-map coalesce, or a Jira automation rule), and so a future release can add update-in-place.

Transport and reliability

Security

Permissions

Creating, editing, or deleting a notification connector requires the Connectors permission (perm_connectors) — the same gate as cloud and SIEM connectors.

Permissions (shared)

The Connectors permission (perm_connectors) covers both kinds. Owners and admins have full access. Members need the permission toggled on in Users & Roles.

Change Tracking

ManageLM automatically tracks file changes made by every mutating task. Each agent maintains a local git repository that snapshots tracked directories before and after task execution, producing a precise record of what changed, when, and by which task.

How it works

  1. Pre-snapshot — Before a task executes, the agent syncs all tracked files into its local git repo and commits a baseline.
  2. Task execution — The task runs normally (LLM-driven commands).
  3. Post-snapshot — After the task completes, the agent syncs again, commits the delta, and computes the list of changed files.
  4. Report — Changeset metadata (files changed, commit hashes, summary) is sent to the portal and stored in the database. The full diff stays in the agent’s local repo.

What is tracked

AspectDetail
Tracked directories/etc/ — covers SSH, nginx, firewall, cron, sudoers, sysctl, network config, and more
Skipped contentBinary files, files > 512 KB, symlinks, and noisy directories (ssl/certs, pki/ca-trust, firmware, kernel, selinux/targeted/policy)
Git implementationdulwich (pure Python) — no git CLI needed on the host
Repo location/opt/managelm/git/ on each agent
Retention30 days — older commits are automatically pruned daily

Viewing changes

When a task modifies tracked files, a changeset badge appears on the task in the task log (in the Agent Detail page and the MCP Log). The badge shows the number of files changed.

With MCP (Claude), use the built-in get_task_changes tool to inspect what a task modified:

get_task_changes(task_id="...", full_diff=true)

This returns:

Reverting changes

If a task made unwanted changes, you can revert them to restore the previous file state. Expand the task — in a server’s own task list or in the Agent Log — and the files it changed are listed with two buttons: View diff fetches the change from the agent and shows it inline, and Revert puts the files back after confirming. The revert is itself recorded, so it can be undone in turn.

Reverting needs the Agents permission; viewing a diff does not. The same thing is available to an MCP client as the revert_task tool:

revert_task(task_id="...")

This fetches the diff from the agent’s local git repo and applies a reverse patch, restoring the files to their pre-task state. The revert is tracked as a separate changeset.

Requirements: The agent must be online for full diffs and reverts (the data lives in the agent’s local repo). The changeset must be within the 30-day retention window. Changeset metadata (file list, summary) is always available in the portal database regardless of agent status.

Non-mutating tasks

Tasks classified as read-only (non-mutating) by the LLM skip the snapshot process entirely — no changeset is created. This keeps the git history clean and avoids unnecessary I/O for read-only operations like status checks and log queries.

Audit Log

The Audit Log gives you a single chronological view of everything that happened in your account — both who ran what on which agent, and who changed which setting in the portal. Open it from the Audit Logs entry in the sidebar.

The page is organised into five tabs, all sharing one From / To date picker and one site-scope filter:

Agent Activity tab

Every task executed against an agent — from the portal, MCP, or shell. Each row shows when it ran, who submitted it, which agent and skill, and the outcome. The expanded row carries the full operation detail, including:

The toolbar adds two Agent-Activity-only controls when the tab is active:

Threat Alerts tab

Alerts from the agent's Threat Detection layer (Linux only). Both Service alerts (a batched LLM verdict over a window of daemon behaviour, judged against the host's installed skills) and Session alerts (LLM judgement of admin SSH/sudo sessions against the user's permitted scope) land here.

Console Sessions tab

Recorded terminal, desktop and SSH sessions — who, on which server, as which account, how long and how big — each expanding into a player you can replay in place or open in its own window. See Admin Sessions for how to turn recording on and how long recordings are kept. Admins also get an S3 Cleanup button here, which removes recording files from the bucket that no longer have a session in ManageLM.

Admin Actions tab

Every administrative change in the portal:

CategoryActions
AuthenticationLogin, logout
UsersInvite, update role/permissions, delete, transfer ownership
AgentsApprove, delete, update settings, bulk actions
SkillsCreate, import, update, delete, document upload/delete
GroupsCreate, update, delete, member changes
WebhooksCreate, update, delete
API KeysCreate, delete
MCPConfiguration changes (IP whitelist, etc.)
AccountSettings changes, license activation/removal

Each entry records timestamp (in your timezone), user (name and email), action type (e.g. agent.approved, skill.created), target resource, and the client IP.

Geolocation tab

World map of admin connection origins with numbered pins linked to a side legend. Appears when GEOIP_DATABASE is configured on the portal.

Access control

Webhooks

Get notified when things happen in your account.

Available events

EventFires when
agent.enrolledA new agent requests enrollment
agent.approvedAn agent is approved
agent.onlineAn agent connects
agent.offlineAn agent disconnects
task.completedA task finishes successfully
task.failedA task fails
report.completedA security audit or inventory scan completes
report.failedA security audit or inventory scan fails
monitor.downA service monitor goes down (after consecutive failure threshold)
monitor.upA service monitor recovers from down
cert.issuedA new certificate is issued and deployed to an agent
cert.revokedA certificate is revoked (CRL updated, LE notified for LE certs)
cert.renewedA certificate is automatically renewed by the daily sweep
cert.renewal_failedAutomatic certificate renewal failed
cert.reactivatedA revoked certificate is reactivated (internal CA only)
cert.deletedA certificate is soft-deleted from the portal

Configure webhooks from Settings → MCP & API. Enter a URL, select events, and optionally provide an HMAC secret. Payloads are signed with HMAC-SHA256 via the X-Webhook-Signature header when a secret is configured.

Delivery retries up to 3 times with exponential backoff. After 10 consecutive failures, the webhook is automatically disabled. Re-enabling it resets the counter. Maximum 25 webhooks per account.

In-App Notifications

The portal includes a real-time notification system accessible from the Notifications bell in the sidebar. Notifications are delivered alongside email alerts for key events.

Notification triggers

Failures are also emailed. Task Failed is the one email notification that is on by default, under Settings → Profile → Email Notifications — every other one tells you something changed, and this one tells you something is broken. A credential rotation that fails halfway is the clearest case: the password has already changed at the source, so a target that did not receive it is a service holding one that no longer works. You get at most one email per host and task every six hours, so a host that is simply offline does not mail you hourly until you filter it.

How it works

Storage: Notifications are stored in Redis and self-expire 12 hours after they are created (max 50 per user). They are ephemeral and do not persist across Redis restarts.

Deployment & .env

The portal is configured via environment variables in a .env file. Below is a reference of all available settings.

Core

VariableRequiredDefaultDescription
DATABASE_URLYesPostgreSQL connection string
SERVER_PORTNo3000HTTP listen port
SERVER_URLYesFull public URL (e.g. https://portal.example.com)
ACCESS_TOKEN_TTLNo86400Access token lifetime in seconds (24h). Tokens are opaque random strings stored in Redis — no signing secret.
REFRESH_TOKEN_TTLNo2592000Refresh token lifetime in seconds (30d).
DEFAULT_TIMEZONENoUTCDefault timezone for new users
TASK_TIMEOUT_SECONDSNo300Max duration for synchronous task execution (seconds)
FILE_TRANSFER_MAX_BYTESNo26214400Max file transfer size (default 25 MB)
LOG_LEVELNoinfoLog verbosity: trace, debug, info, warn, error, fatal, silent
CLUSTER_WORKERSNo2Number of Node.js cluster workers. Set to 1 to disable clustering.
SERVER_MODENoselfhostedsaas = hosted SaaS (trial LLM available), selfhosted = Docker/on-prem (proxied LLM available).
NOTIFY_EMAILNoEmail address for platform operator alerts (account created/deleted notifications).
ENCRYPTION_KEYNoAES-256 master key for every secret stored at rest — connector credentials, agent signing keys, LLM API keys, SMTP and S3 passwords, PKI private keys. Required to use Connectors. 64-character hex string; generate with openssl rand -hex 32. See Encryption at Rest.
ENCRYPTION_OLDNoPrevious encryption key(s), comma-separated — decrypt-only. Set while rotating ENCRYPTION_KEY, remove once the rotation is finished.

SMTP & DKIM

VariableRequiredDefaultDescription
SMTP_HOSTNoSMTP server hostname. When empty, emails are sent directly to recipient MX servers (no mail server required).
SMTP_PORTNo25SMTP server port
SMTP_FROMYesFrom address for all emails
SMTP_SECURENononenone = plain (localhost:25), starttls = upgrade via STARTTLS (587), tls = implicit TLS (465)
SMTP_USERNoSMTP auth username (for external relays)
SMTP_PASSNoSMTP auth password
DKIM_DOMAINNoDomain for DKIM signing (e.g. example.com)
DKIM_SELECTORNodefaultDKIM selector (matches DNS TXT record)
DKIM_PRIVATE_KEY_PATHNoPath to PEM private key file
DKIM_PRIVATE_KEYNoInline PEM private key (use \n for newlines)
DKIM setup: When DKIM_DOMAIN and a private key are set, all outgoing emails are signed with DKIM (RSA-SHA256). You also need to publish a DNS TXT record at {selector}._domainkey.{domain} with the matching public key.

Redis (required)

VariableRequiredDefaultDescription
REDIS_URLYesRedis connection URL (e.g. redis://localhost:6379). Supports redis://, rediss://, valkey://, valkeys:// schemes.
REDIS_TLSNoautoauto = TLS if URL uses rediss:// or valkeys://, on = force TLS, off = no TLS
REDIS_DBNo0Logical database number (0–15). Useful when sharing a Redis instance.

Redis is a mandatory component used for:

Database

VariableRequiredDefaultDescription
DB_POOL_MAXNo20Max PostgreSQL connection pool size
DB_SSLNononenone = no SSL, require = SSL (skip cert verify), verify = full CA verification, verify-ca = custom CA cert
DB_SSL_CANoPath to CA certificate file (used with DB_SSL=verify-ca)
TASK_LOG_RETENTION_DAYSNo30Days to keep task log entries
AUDIT_LOG_RETENTION_DAYSNo90Days to keep audit log entries
TASK_LOG_MAX_PER_ACCOUNTNo5000Max task log entries per account
AUDIT_LOG_MAX_PER_ACCOUNTNo10000Max audit log entries per account
LOGIN_SESSION_RETENTION_DAYSNo30Days before inactive sign-in sessions are deleted (was SESSION_RETENTION_DAYS, still honoured)
PENDING_AGENT_RETENTION_DAYSNo14Days before unapproved agent enrollments are deleted
EMAIL_VERIFY_RETENTION_DAYSNo7Days before stale email verification tokens are cleared
MONITOR_RETENTION_DAYSNo90Days to keep monitor events. Rollups are kept 4× longer for trend charts.
CREDENTIAL_RETENTION_DAYSNo90Days to keep credential rotation history. Outcomes only — a rotation record never holds the value.

Performance notes

The portal includes several built-in performance optimizations for high-load deployments:

For high-traffic deployments, increase DB_POOL_MAX and configure REDIS_URL for session persistence and horizontal scaling.

Account Migration

Move an entire account between deployments — for example from the hosted SaaS to a self-hosted install, or between two self-hosted servers — without re-creating everything by hand. The owner exports one encrypted file and imports it on the destination.

From Settings → Account → Account Migration (owner only):

  1. Export (available on SaaS and self-hosted): choose a passphrase and download managelm-account-<name>-<date>.json. The payload is encrypted with your passphrase (scrypt + AES-256-GCM). Keep both the file and the passphrase safe — the file contains your account's secrets (LLM keys, connector credentials, agent credentials).
  2. Import (self-hosted only): register a fresh account on the destination portal, then upload the file and enter the same passphrase. Your current login becomes the owner of the imported account.

What moves: agents (with their credentials preserved), sites, agent groups, skills and their uploaded documents, policy rulesets, connectors, rotated credentials and their delivery targets, Keystore keys with their clients and grants, webhooks, service monitors, certificates & PKI, and the whole team — users, roles, permissions and access grants, with passwords carried over. Every item keeps its identity, so all the links between them stay intact.

Keystore keys move as key material, as the internal CA's signing key does. The export is decrypted under the source's encryption key and re-encrypted under the destination's, so the plaintext exists only inside the transfer — and a key cannot be recovered any other way, so leaving them behind would destroy them.

What does not move: history and scan results (security audits, inventory, activity, monitor history, threat alerts, task logs, credential rotation history and Keystore usage — these record what happened on the source deployment), login sessions, and passkeys/MFA (these are tied to the portal's web address, so team members re-enroll on the new instance). The license is not included in the file either.

After importing: each agent only needs its SERVER_URL repointed at the new portal — it then reconnects automatically with its existing credentials and resumes work. Re-enter your license key from the same Account tab; a paid key activates on the new instance and its entitlement follows the most recently activated server (the previous instance reverts to Free).

Import requires a fresh account. The destination account must have no agents, skills or sites yet — import does not merge into an account that already contains configuration. Register a new account for it.

Background Maintenance

The portal automatically cleans up stale data using three background tasks. Each runs on a distributed Redis lock, so only one portal instance executes per interval — no external cron is needed.

TaskIntervalWhat it does
OAuth cleanupEvery 30 minDeletes expired MCP OAuth tokens and authorization codes
Log purgeEvery 1 hourAge-based and count-based pruning of task history and the audit log
MaintenanceEvery 6 hoursCleans all other stale resources (see table below)
Scheduled scansEvery 15 minTriggers security, inventory, certificate, access and activity scans for agents with a configured schedule (daily/weekly/monthly), dispatches due pentests, and purges expired audit history

All tasks also run once on portal startup.

Maintenance targets

ResourceCleanup ruleConfigurable
Login sessionsNo activity in LOGIN_SESSION_RETENTION_DAYS (default 30)Yes
Expired invitationsPast expires_at and not accepted
Expired API keysPast optional expires_at
Password reset tokensPast password_reset_expires_at
Email verification tokensUnverified accounts older than EMAIL_VERIFY_RETENTION_DAYS (default 7)Yes
WebAuthn challengesUser inactive > 6 hours (abandoned registration flow)
Pending agent enrollmentsUnapproved for PENDING_AGENT_RETENTION_DAYS (default 14)Yes
Monitor eventsOlder than MONITOR_RETENTION_DAYS (default 90)Yes
Monitor rollupsOlder than 4× MONITOR_RETENTION_DAYS (default 360 days)Yes
PKI certificatesSoft-deleted certs after natural expiry, expired certs after 7 days, stale failed/pending after 7 daysYes

Configurable retention values can be set via environment variables in .env. See the Deployment & .env section for details.

Reinstalling an Agent

You can reinstall an agent without losing its configuration (skills, groups, members).

  1. Go to the agent's detail page.
  2. Click the Reinstall button.
  3. Copy the install command and run it on the server.
  4. Approve the re-enrollment when prompted.

The agent gets a fresh access token and signing key while keeping all its existing configuration intact.

Custom Skills

You can create your own skills to extend what agents can do.

  1. Go to Agent Skills and click Create Skill.
  2. Define the skill's slug, name, and description.
  3. Add operations (name and description for each capability).
  4. Set the allowed commands (and, for Windows skills, any PowerShell modules).
  5. Write a system prompt that guides the LLM.

Tips for custom skills

Import / Export

Skills can be exported as JSON files and imported into other accounts. Use the export button on any skill, or import from the skills page.

Skill Documents (RAG)

You can upload reference documentation to any skill. When a task is dispatched, relevant sections are automatically retrieved and injected into the LLM prompt — giving the agent knowledge about products, tools, or APIs that the LLM wasn't trained on.

No external dependencies. Document search needs no embedding API, vector database or other third-party service. It works out of the box on both SaaS and self-hosted installations, including air-gapped ones.

How it works

  1. Upload — Drop .txt, .md, .pdf, .html, .doc, or .docx files onto the skill's edit form. Text is extracted automatically and chunked for indexing.
  2. Retrieve — When a task matches, the portal searches document chunks using the task instruction and retrieves the top matching sections.
  3. Inject — Matching sections are supplied to the agent as reference material, ahead of the task instructions.

Uploading documents

  1. Go to Agent Skills and click the Edit (pencil) icon on a skill.
  2. Below the Detailed Description field, you'll see the Reference Documents section with a drag-and-drop zone.
  3. Drop one or more files (.txt, .md, .pdf, .html, .doc, .docx), or click the zone to browse.
  4. Each uploaded file is shown with its filename, size, chunk count, and upload date.
  5. To remove a document, click the trash icon next to it.

Chunking

Text is extracted from the uploaded file, then split into sections of roughly 1000–1500 characters so the most relevant parts can be retrieved:

Retrieval at task time

When a task is sent to an agent, the portal searches the skill's documents for the sections that match the instruction. The best matches (up to 10 sections / 30,000 characters by default) are supplied to the agent. If nothing matches, nothing is added.

Limits

LimitSaaS DefaultEnvironment Variable
Max file size2 MBSKILL_DOC_MAX_SIZE_BYTES
Max documents per skill10SKILL_DOC_MAX_PER_SKILL
Max total size per skill10 MBSKILL_DOC_MAX_TOTAL_BYTES
Max chunks per task10RAG_MAX_CHUNKS
Max chars per task30,000RAG_MAX_CHARS

The three upload limits apply to the SaaS platform only. On self-hosted installs they are unlimited by default — set the corresponding environment variable to enforce a limit. The two retrieval settings (chunks/chars per task) apply in both modes.

Use cases

Cleanup: Documents and their chunks are automatically deleted when the parent skill is deleted (CASCADE). No manual cleanup needed.