Help & Documentation
What is Octotor?
IT information lives scattered across independent systems — Active Directory, Microsoft 365, network equipment, and the machines themselves — making it hard to get a quick read or run a deep investigation in one place. Octotor solves both: it gathers information from any script-capable system and presents it through a single, friendly web interface. And it doesn't just collect — it acts: scripts run directly on remote computers, switches, and firewalls, manually, on a schedule, or automatically when an alert fires.
Octotor is agentless: built on industry-standard protocols — WinRM, SSH, and SNMP — it talks to almost any system straight out of the box, with nothing to install on the target. Deployment is fast and simple.
See everything in one place
Every asset — person, computer, switch, firewall, cloud account — has one page holding everything Octotor knows about it: identity, attributes, linked accounts, relationships, history. For the help desk this turns support into a one-glance operation: the moment a call comes in, the caller's full picture is already on screen, and the technician can act immediately — running pre-built toolkit scripts in real time with a single click.
Act on what you see
Select one or several assets, pick a script, and run it instantly — without ever seeing the target's credentials, which stay securely stored in Octotor. The Scheduler runs the same scripts on a clock — a routine AD sync to keep the inventory current, an SNMP query to check switch port status — or triggered by a detected condition instead of time, driving automatic remediation (for example, resetting a VPN tunnel the moment a connection loss is detected).
Know the moment something changes
Alerts fire on a wide range of conditions — an asset going offline or coming back, an attribute crossing a threshold (like low disk space), a system event, a locked account, a failed logon, and more — delivered by email, Telegram, or webhook. An alert can also trigger a remedy: a script that runs on the asset that fired it (or any other asset), so routine problems are handled before anyone files a ticket. See Alert Center.
The right command on the right machine
Before executing actions, Octotor's Identity Verification confirms the target on the other end is genuinely the one you intended — not a stale record, a reassigned IP, or a renamed machine. And permissions run through every layer: which group a user belongs to, which toolkit scripts they may run, which customers they can view or manage, whether their rights are read-only or read-write, and whether sensitive actions require an extra per-action password before anything executes. See Permissions and Security.
Everything on the record
Every action taken through Octotor — and every piece of information it collects — is tracked. Whether a script ran manually, on schedule, or as an alert-triggered remedy; whether a setting changed or a user signed in — nothing goes unrecorded. The Investigate page is the single timeline where you can reconstruct what changed, who or what triggered it, when, and what the outcome was.
AI, your way
Octotor's toolkit is built to expand: with AI assistance, you can write tailor-made PowerShell or shell scripts for exactly what you need and save them to the Toolkit for manual or scheduled use. Operators can also work in plain language through the AI assistant — ask "which servers haven't rebooted in over 30 days?" or say "restart the DNS service on DC01". You choose where the AI runs: a fully local model, entirely offline and air-gapped — no data ever leaves your network — or an external cloud provider for the full power of the latest large language models. Either way, it's your call, and Octotor adapts.
How it fits together
Page Overview
| Page | Purpose | Who can access |
|---|---|---|
| Dashboard | System health overview, recent activity | Admin, Operator, Viewer |
| Assets | Manage devices, people, accounts, attributes, relationships | Admin, Operator, Viewer (read-only) |
| Run | Execute scripts and protocols on assets in real time | Admin, Operator |
| Toolkit | Manage the script library | Admin |
| Scheduler | Recurring and condition-triggered tasks | Admin |
| Investigate | Unified events timeline with AI queries | Admin, Operator (if group allows) |
| Alerts | Live alert center — acknowledge, resolve, investigate | Admin, Operator, Viewer (if group allows) |
| Alerts Admin | Alert rules, notification channels, maintenance windows | Admin |
| Goose | AI agent chat — run scripts, investigate, manage via natural language | Admin, Operator (if group includes 'goose') |
| Services | Background service status and health | Admin |
| Settings | System configuration, users, groups, credentials, tokens, AI | Admin only |
Notifications (Toast System)
Octotor uses non-blocking toast notifications for feedback on every user action. Toasts appear briefly in the top-right corner and never block the UI the way classic pop-up dialogs do. All frontend feedback uses this system — there are no native pop-up dialogs in the app.
| Color | Meaning | Default duration |
|---|---|---|
| Green (success) | Action completed — a record was saved, a job started, a password was changed | 4 seconds |
| Green — persistent | Security-critical confirmation (master action password saved / changed / removed; VACUUM or maintenance results with row counts) | Until you click it |
| Red (error) | Action failed — form preserved so you can retry | 4 seconds |
| Amber (warn) | Validation problem — fill required fields, check format | 4 seconds |
| Blue (info) | Informational update | 4 seconds |
Click a toast to dismiss it immediately. Persistent toasts (security-critical confirmations and VACUUM/prune result counts) will remain on screen until you click — this is intentional so you can read important numbers or confirmations without them flashing away.
Content Security Policy (CSP)
Octotor ships with a hardened CSP that disallows inline scripts and disallows eval() / runtime JS compilation. If you see console messages like "Refused to execute inline script" in the browser devtools, that is expected — the browser is enforcing the policy. This significantly reduces the reflected-XSS-to-RCE attack surface; it does not affect normal use of any page. If a feature appears to misbehave after a Chrome/Firefox update, open devtools > Console and send the full CSP error text when reporting.
Dashboard
The Dashboard is your landing page. It provides a quick overview of system health and recent activity at a glance.
What You See
- Asset Status Tiles — count of online, offline, warning, and unknown assets
- Recent Jobs — the last 5 script executions with status and timing
- Active Protocols — any multi-step protocols currently running
- Recent Events — last 10 audit log entries (logins, changes, errors)
- System Status (admin only) — host health, container resources, monitoring load, recent errors. Auto-refreshes at a configurable interval (15s/30s/60s/off) with a manual "Update Now" button.
Actions
- Ping All Assets — triggers a connectivity check on all monitored assets
You open the Dashboard and the Asset Status tiles read Online 142 Offline 3 Warning 1 Unknown 6.
- Click the Offline 3 tile → you land on Assets pre-filtered to those 3. Open each to see the last successful ping and run a fresh check.
- Unknown 6 = never-pinged or monitoring-off assets — turn on autoping for any you expect to be up.
- Recent Events shows a red job failed line — click it to open Investigate at that entry and read the output.
Dependencies
None — the Dashboard reads from all other modules but doesn't require any setup to display.
Assets
The Assets page is the central inventory of everything Octotor manages — computers (workstations and servers), switches, firewalls, and users (AD-synced or manual).
Guided tours
The Tour button in the top-right of the Assets page runs a guided walkthrough on the real page. It dims the screen, highlights one control at a time, and explains what it is for. Where a step needs a click, an arrow points at exactly what to click — make the click yourself and the tour follows you, or press Next and it does that click for you.
The Assets page ships with these tours:
- View computer and user info — 20 steps, the whole page end to end: the list, the filters, a device record and its tabs, then a person record and what each connected directory says about them.
- Which switch port is this machine on? — the answer in two clicks.
- Add a device by hand and Add a person — for what discovery does not bring in. The device tour walks the fields that matter later: the customer, the OS family that decides which scripts can run, the monitoring options, the default protocol, the alert templates, and why the machine still needs a credential before Octotor can act on it. Both stop on the form; neither creates anything for you.
- Add a switch — a switch is not a computer with a different icon. The tour covers the type and OS family that give it a Port Map and an SNMP panel, the SNMP community credential it needs on its Credentials tab, switching on SNMP monitoring and the MAC-table walk, saving them, and using Test to prove the poll works rather than waiting for the schedule.
- Filter by any attribute — opens the Attr Filter panel and picks the first attribute for you, so you can see what it reaches that the top filters do not. An attribute needs a value beside it before the list narrows, and filters stack with + Add.
- What the search box matches — and what it does not: devices and people have separate search boxes that look for different things.
- What the Alerts button does and What the Monitoring button does — the two filter panels on the toolbar, how to find the machines nobody is watching, and how to change alert flags or switch monitoring on across many machines at once from the bulk action bar.
- Run a command on a machine — three clicks, and where the output goes. This one follows you to the Run page: it carries on there, finds the
collect-infoscript and stops on the Run button without running anything. - Give a machine a credential — the usual reason a job fails immediately.
- What changed on this machine? — Changes versus Timeline, and expanding a single timeline entry to see its source, detail and reference.
Tours that would create or modify something stop one step short of the Save button, so taking a tour never changes your data. That includes the bulk actions: a tour will point at Enable Monitor or Apply and tell you what it would do, but it never presses one.
Every step has a Next button, so you are never stuck. Stop any tour with End tour or the Esc key, and start one again whenever you like from the Tour button. Ending a tour leaves the page exactly as you left it.
The first tour runs automatically on your first visit, once per browser. After that, every tour waits to be chosen from the Tour button.
Worked example — finding a machine's switch port
A user reports slow file transfers on TRI-LT007 and you want to know which switch port it is plugged into, and at what speed.
- Open Assets and click Tour (top-right, next to Import CSV).
- Choose Which switch port is this machine on? from the menu.
- The tour highlights the first row of the Devices table and says "Open the machine you are chasing." Click the machine's name —
TRI-LT007. - The record opens and the tour highlights the Attributes tab. Click it.
- The tour points at the Network group, which holds
connected_switch_ip(for example10.40.10.2),switch_port(for exampleGigabitEthernet1/0/14) andswitch_port_speed.
What this tells you: if switch_port_speed reads 100 Mbps on a gigabit port, the link has negotiated down — almost always a bad cable or a damaged socket. You have the port number in hand, so the fix can be dispatched without anyone walking to the comms room.
Note: these values come from SNMP polling of the switch itself, so they appear only for machines whose switch is registered as an asset and polled. On an unpolled switch the Network group has no switch fields, and the tour says it has lost its place rather than pointing at nothing.
Creating an Asset
Asset Detail Tabs
| Tab | What it shows |
|---|---|
| Overview | Name, type, hostname, IP, OS, status, monitoring toggle, related assets |
| Attributes | Custom fields — email, disk space, RAM, network info, etc. Editable by admins/operators |
| Credentials | SSH/WinRM credentials linked to this asset. Link or unlink credentials here |
| Relations | Links to other assets (belongs-to, has-user, connected-to) |
| Jobs | Execution history — scripts run on this asset, with status and output |
| Changes | Full attribute change history for this asset (every old → new value), with filters by source (manual, collector, import, bulk), user, and time range. Deep-link via assets.html?open=<id>&tab=changes |
| Timeline | Unified chronological view across the asset's lifetime: every offline/online status flip, every alert (fired/resolved), every job run, and every manual action. Filter chips: All / Status / Alerts / Jobs / Manual. Date range: Last 24h / 7 days / 30 days / 90 days / 1 year. Each row is click-to-expand for source/detail/ref. Source data: alert_transition_log (status flips), alerts (lifecycle), action_log (manual), jobs (runs). Read-only. |
| Identity | IP validity score, DNS resolution chain, verification history, locked IP toggle. See Identity Verification below |
Identity Verification
Octotor verifies that each asset's IP address actually belongs to the expected hostname. This prevents mismatched mappings in DHCP environments where IPs rotate between devices.
How It Works — Verification Flow
AUTOPING CYCLE (runs every N seconds for each monitored asset)
│
├─ 1. CHECK LOCKED IP
│ └─ IP locked? ──▶ Skip DNS, score = 5, ping stored IP
│
├─ 2. CHECK CUSTOMER DNS CONFIG
│ └─ No DNS configured? ──▶ Skip DNS, score unchanged, ping stored IP
│
├─ 3. FORWARD DNS LOOKUP (hostname + domain → DNS server)
│ │ Example: "salespc1" + "contoso.com" → query DNS at 10.5.5.10
│ │
│ ├─ DNS server not responding ──▶ Score = 0, reason: "DNS server not available"
│ │ ⚠ Admin alert raised
│ ├─ No A record found ──▶ Score = 2, use stored IP
│ └─ Got IP (e.g. 10.5.5.96)
│ └─ Different from stored IP? ──▶ Update stored IP automatically
│
├─ 4. PING (using resolved or stored IP, with fallback chain)
│ ├─ OFFLINE ──▶ Stop here. Score is NOT changed (avoids penalizing offline devices)
│ └─ ONLINE ──▶ Continue to step 5
│
├─ 5. REVERSE DNS LOOKUP (IP → hostname, optional)
│ │ Queries: "What hostname owns 10.5.5.96?"
│ │
│ ├─ No reverse zone / no PTR record ──▶ Score = 3 (Medium)
│ │ Forward lookup OK but unconfirmed by reverse
│ │
│ ├─ Reverse returns MATCHING hostname ──▶ Score = 4 (High)
│ │ Both forward and reverse agree
│ │
│ └─ Reverse returns DIFFERENT hostname ──▶ Score = 1 (Stale!)
│ The IP belongs to a different device — record is stale
│
└─ 6. STORE RESULT
Update asset: ip_validity_score, ip_validity_reason, ip_validated_at
SSH IDENTITY GATE (runs before every job/script execution)
│
├─ 1. SSH CONNECT to resolved IP
│
├─ 2. RUN HOSTNAME PROBE
│ │ Linux: "hostname" | Windows: "[System.Net.Dns]::GetHostName()"
│ │
│ ├─ MATCH ──▶ Score = 5 (Verified — highest possible)
│ │ Proceed with job execution
│ │
│ └─ MISMATCH
│ ├─ Strict mode ──▶ ABORT job, flag asset, self-heal IPs
│ └─ Warn mode ──▶ Log warning, run job anyway, self-heal IPs
│
└─ 3. SELF-HEALING (on mismatch)
├─ Search for the actual hostname in customer assets
├─ Found? ──▶ Reassign IP to correct asset automatically
└─ Not found? ──▶ Log "unknown host" for admin review
When Is Reverse DNS Used?
Reverse DNS (PTR lookup) runs during the autoping scoring phase (step 5 above) — after a successful forward lookup and only for online assets. It asks: "What hostname does this IP map to?"
- If reverse matches the forward result → higher confidence (score 3 → 4)
- If reverse returns a different hostname → the A record is stale (score drops to 1)
- If no reverse zone exists → forward-only scoring (score stays at 3)
Reverse DNS is not required. Without it, DNS verification caps at score 3 (Medium). SSH verification can still reach score 5 regardless of reverse DNS.
5.5.10.in-addr.arpa for 10.5.5.0/24) and enable dynamic updates. DHCP will then register PTR records automatically.DNS Server Alerts
If a customer's DNS server is unreachable (timeout or connection refused), Octotor:
- Sets validity reason to "DNS server not available"
- Raises an admin alert in the Investigate page (category: identity, requires action)
- Falls back to the stored IP for pinging (does not break monitoring)
IP Validity Score (0-5)
| Score | Label | Meaning |
|---|---|---|
| 5 | Verified | SSH hostname probe confirmed identity, or IP is locked |
| 4 | High | DNS forward + reverse lookup both match |
| 3 | Medium | DNS forward lookup OK, no reverse (PTR) record available |
| 2 | Low | DNS lookup failed, using stored IP |
| 1 | Stale | DNS or SSH mismatch detected — IP may belong to a different device |
| 0 | Unknown | No DNS configured for customer, no verification done |
Attribute Locking
Any attribute on an asset can be locked by an admin. Locked attributes cannot be overwritten by automated sources (collectors, DNS, imports). Only an admin can change a locked value manually.
- Lock IP: The "Lock IP" checkbox next to the primary IP in the Overview tab prevents DNS and collectors from changing the stored IP. Score is set to 5. Use this for devices with static/reserved IPs (servers, network gear).
- Lock attributes: Each attribute card in the Attributes tab shows a lock icon. Click to lock — the icon changes to solid and a "locked" badge appears. Click again to unlock.
- Manual edit does NOT auto-lock. Changing a value manually does not lock it. The value can still be overwritten by collectors on the next cycle unless explicitly locked.
[192.168.2.3, 192.168.2.14] and the next [192.168.2.14, 192.168.2.3]. Octotor's DNS resolver uses the first record returned, so with the IP unlocked, autoping rewrites asset.ip on every cycle to whichever record DNS handed back first. The asset visibly flaps between online and offline as the alternate address is reached or unreachable, and a status alert fires on every offline transition. Locking the IP is the fix: autoping skips DNS resolution entirely, the operator's chosen IP is preserved, and the ping fallback chain still verifies reachability via asset.ip → secondary_ip → wifi_ip → hostname. For genuinely dual-homed hosts, set the primary as asset.ip, add the second interface as the secondary_ip attribute, and lock — autoping then pings both candidates per cycle and reports online if either responds.
Per-Component Settings
Each identity verification step can be independently enabled or disabled in Settings > Monitoring > Identity Verification:
| Setting | Options | What it controls |
|---|---|---|
| DNS Resolution | On / Off | Autoping DNS lookup and IP scoring |
| SSH Identity Gate | On / Off | Hostname probe before job execution |
| Require Successful Probe | On / Off | Abort job if SSH probe fails (timeout, auth error). Only active when SSH gate is on. |
| Collector Identity Check | On / Off | Hostname comparison after script execution |
| Mismatch Behavior | Strict / Warn | What happens when any enabled check finds a mismatch |
| Validity TTL | Minutes (0 = never) | Score expires after this many minutes and resets to 0 on the next autoping cycle. Default: 60 minutes. |
With all checks off, Octotor connects to the stored IP and runs commands without any identity verification. These settings can be overridden per scheduled task — see Scheduler > Identity Override.
NetMap Compatibility
DNS verification works correctly with per-customer NetMap (Tailscale SNAT translation). DNS server IPs are automatically translated through NetMap before queries are sent. The two systems operate at different layers:
- DNS server access — if the customer's DNS server (e.g.
192.168.0.11) is behind a NetMap translation, Octotor automatically uses the translated IP (e.g.10.99.0.11) to reach the DNS server - DNS results use real IPs — the customer's DNS server returns the actual LAN address (e.g.
10.155.155.50) - NetMap translates at ping/SSH time only — converts the real IP to a Tailscale-routable address (e.g.
10.18.0.50)
The asset always stores the real IP. If an asset was accidentally stored with a translated (NetMap) IP, DNS resolution will correct it to the real IP automatically.
Example: TRIPLEOR-LAB asset on WiFi segment
Real IP: 10.18.18.50 (what DNS returns, what the asset stores)
NetMap: 10.18.18.0/24 → 10.18.0.0/24
Translated IP: 10.18.0.50 (used ONLY for ping/SSH via Tailscale)
Reverse lookup: queries 10.18.18.50 (real IP) → hostname ✓
Verification Mode (Settings > Monitoring)
| Mode | Behavior on Mismatch |
|---|---|
| Strict (default) | Abort job, flag asset as ip_mismatch, trigger self-healing |
| Warn | Log warning, continue with job execution, still trigger self-healing |
| Off | No identity check |
Customer DNS Setup
To enable DNS-based verification, configure DNS for each customer in Settings > Customers > Edit:
- DNS Domain — the Active Directory domain (e.g.
contoso.com). Appended to bare hostnames for lookups. - DNS Server 1 & 2 — the customer's DNS servers (typically the domain controllers).
Key Features
- Search & Filter — filter by type, status, customer, Last Seen (1h/24h/7d/30d/never), and IP Validity score (0-5). The Status filter applies server-side, so selecting e.g. "online" returns matching assets across all pages — not just the current page. Search applies within the active filters (e.g. search "helpdesk" with customer "TRIPLEOR" selected shows only TRIPLEOR's HELPDESK-01). Searching a MAC address works in any notation —
00:0a:fc:ff:ff:0e,00-0A-FC-FF-FF-0E,000a.fcff.ff0eor bare hex, full or partial (6+ hex chars) — and also finds devices Octotor only knows from the network: a MAC learned on a switch port returns the mapped computer (or the switch that learned it, if unmapped), and a MAC present in a Check Point firewall's DHCP leases returns that firewall. Example: searching00-0A-FC-FF-FF-0Efinds the computer plugged into the switch port where that MAC was learned, even when no asset carries the MAC as an attribute. - Status Since vs Last Seen — two different timestamps. Status Since (table column and drawer Overview row) is when the asset's current status began — it updates on every status change, in both directions. Last Seen (drawer Overview row, and the Last Seen sort/filter) is the last time Octotor successfully reached the asset — live while the asset is online (it tracks the most recent good check), frozen at the last good ping once it goes offline. Worked example: a server is up and pinged OK every 5 minutes for a week, then goes down at 07:44 — its row shows Status Since = today 07:44 (when it went offline) and Last Seen = today 07:39 (the last good ping before the outage). While it stays down, Status Since keeps holding 07:44; when it recovers at 09:10, both move — Status Since = 09:10 (online since) and Last Seen starts tracking again. Assets that existed before this feature show "—" for Status Since until their first status change.
- Type filter — "Users & Computers" vs "All" — the Type dropdown opens on Users & Computers, which lists the real-world things you manage (people, machines, switches, firewalls) but hides account sub-objects (AD / M365 / etc. accounts), since those belong to a person or computer and are viewed through its drawer. Choose All to list literally everything, account sub-objects included — or pick a specific provider (e.g. Active Directory) to list just those accounts.
- Adaptive columns — in a mixed list (Users & Computers or All) the two middle columns (Identity and Detail) plus the Status column adapt to each row's type, so every row shows data that is actually relevant to it instead of empty computer-only columns:
- Computer — Identity = active IP, Detail = OS, Status = online/offline.
- User (person) — Identity = email, Detail = job title.
- AD user account — Name shows the UPN, Identity = the leaf OU (e.g.
OU=LAPTOPS), Detail = last logon, Status = Enabled/Disabled. - AD computer (machine) account — Identity = the leaf OU, Detail = last logon, Status = Enabled/Disabled.
- Attribute filter — filter the list by any attribute value (e.g.
account_state= Disabled). The attribute dropdown is the shared global attribute set (the sameasset_attribute_defsthe Alerts > New Rule dropdown uses). Caveat worth knowing: because several providers reuse the same attribute key, filtering or monitoring byaccount_statealone catches all of them (AD, M365, Google, …) — the attribute is matched by its key, not by provider. To scope to one provider, combine the attribute filter with the Type filter (e.g. Type = Active Directory +account_state= Disabled). This is true on both the Assets page and the Alerts rule page — a provider tag like[ad]in the Alerts dropdown labels which definition the entry came from; it does not by itself restrict monitoring to that provider. - Filter Pinning — click the 📌 pin button to persist your current filters across page navigation and refreshes. Pinned filters are stored in the browser session. Click again to unpin and clear.
- Live Monitor — real-time ping status grid. Toggle monitoring per asset in the detail panel
- CSV Import/Export — bulk import assets from CSV, or export the current view
- Pending Attribute Updates — when a collector script gathers data, attribute changes appear here for review and approval. Filter by asset name to review updates per asset. Use bulk approve/reject for efficiency
- Discovered Identities (Discovery queue) — when an account collector (e.g. AD user discovery) finds accounts that don't exist in Octotor yet, they appear in the Discovery panel for per-item approve/reject. Approving creates the account asset (and, when no owner matched, a new person asset) and links them. Rejecting suppresses that identity on later sweeps. Enable Auto-approve discovered identities in Settings > Attributes to skip the queue and create directly.
- Deciding approve vs reject — the queue helps you spot dead accounts before approving: the Last activity column shows how long ago the account was actually used (AD last logon / Entra last sign-in; amber > 90 days, red > 180 days), the search box filters by account name, UPN, or owner, and the "Inactive > X days" filter isolates provably-stale rows for bulk-reject — rows with no activity data from the source are not included (absence is not proof of staleness). The ⓘ details button on each row opens everything the collector saw — OU, groups, description, password dates, MFA, license, manager — so you can decide without leaving the queue. Worked example: filter "Inactive > 1 year", check the details of the handful that remain (an OU named "Disabled Users" or a password unchanged for 3 years confirms dead wood), select all, Reject Selected.
- Multi-Select — select multiple assets for bulk ping, run command, toggle monitoring, or lock/unlock all attributes across selected assets
- Lock All / Unlock All — in the Attributes tab, use the "Lock All" button to lock every attribute with a value on the asset. Also available in the multi-select toolbar to lock/unlock across multiple assets at once.
Collector updates & pending approval (who wins — collector, import, or you?)
Every attribute value has an owner: the last thing that set it — a collector, a CSV import, or a human edit. Whether a collector's update (or removal) applies silently or asks for your approval follows two simple rules:
| Situation | What happens |
|---|---|
| Def's Auto-approve is off (Settings > Attributes) | Every collector change goes to Pending Attribute Updates — values and removals alike. |
| Auto-approve on, value is collector-owned | Updates and removals apply automatically. A removal deletes the value and history records (cleared). |
| Auto-approve on, value was set manually or by CSV import | The value is protected: a collector removal is never applied silently — it goes to Pending once, even with auto-approve on. This is why you can see pending rows for an auto-approve attribute. |
- You imported computers from CSV in April; each row set
Last Logged-in User. Those values are now import-owned (protected). - Months later the collector runs on TRI-LAB-01 and reports the field is empty on the machine. Because the stored value is protected, a (cleared) proposal lands in Pending Attribute Updates instead of applying.
- You approve it. The value is removed, history records old → (cleared), and the attribute becomes collector-owned.
- From now on every collector update and removal for that attribute on that asset applies automatically — no more pending rows. If a human edits the value again (or a new import overwrites it), it becomes protected again and the next collector change asks once more.
Second example: a removed M365 license. The license value was collector-owned and the def is auto-approve, so when the tenant removed the license, the next sync cleared it silently — the empty card stays in the drawer and its history clock shows O365_BUSINESS_PREMIUM → (cleared), who and when.
Duplicate Detection
Octotor automatically detects possible duplicate assets during each auto-ping cycle. If two or more assets within the same customer share the same IP address and are both online, they are flagged as possible duplicates.
- Visual indicator — flagged assets show a ⚠ warning icon next to their name in the asset list and a "Possible Duplicate" badge in the detail panel.
- Auto-clear on verification — when an asset's identity is verified via SSH or WinRM probe (hostname matches), the duplicate flag is automatically cleared for that asset.
- Manual clear — use the "Clear Duplicate" button in the detail panel or right-click context menu to manually clear the flag. Note: the flag will reappear on the next ping cycle if the duplicate condition still exists. To permanently prevent re-flagging, lock the IP on the asset.
- Self-healing — if the assets' IPs diverge (e.g. DHCP reassignment), the flag is automatically cleared.
VM-TEST-01) whose AD/DNS address now belongs to a different live host (OFFICE365). Identity verification correctly flags it, but it recurs every cycle because DNS keeps resolving the stale name to that IP and the AD collector keeps refreshing the stale asset. Resolve it root-cause first:
- Fix the stale DNS record (root cause). Remove or correct the A record that maps the old name to the contested IP (e.g. delete
VM-TEST-01 → 192.0.2.103). Once it no longer resolves to that address, autoping stops pointing the stale asset at the live host and the mismatch clears on its own — regardless of anything else. - Keep the object in AD but exclude it from Octotor. Delete the stale asset (and its machine account); when the next collector sweep re-queues it, click Reject in the Discovery queue rather than Approve. A rejected entry is suppressed on later sweeps, so the AD object can stay in place without re-creating the asset.
- Lock the IP on the correct asset (belt-and-suspenders). Open the genuine owner of the address (here
OFFICE365) and lock its IP. Autoping then skips DNS for it and pins the address, so its identity never drifts even if a stale record reappears.
identity_mismatch noise until you address it via step 1 or 2 — and the AD computer collector will keep refreshing the stale asset (no duplicate is created, and it is not deleted — directory deletion-sync is a separate planned feature).
AD User Auto-Discovery
The windows/collect-ad-users.ps1 collector turns a Domain Controller asset into an identity source. Schedule it (or Run it) against a DC; it queries every AD user and emits one record per account (SAM, UPN, email, state Enabled/Disabled/Locked, OU, groups, last logon, password dates, SID, description).
- Known accounts refresh in place — matched by SAM/UPN within the DC's customer; attribute updates follow the normal auto-approve/lock rules and are logged to attribute history.
- New accounts queue for review — the Discovery panel on this page shows each new identity with its proposed owner. Owner matching tries UPN and email against your person assets' Email attribute; unmatched records propose a new person (name, email, job title, department, phone from AD).
- Rejected identities stay rejected — later sweeps skip them, so service accounts you don't want in Octotor only need to be rejected once.
- State changes drive alerts — the unified Account State attribute (Enabled/Disabled/Locked) feeds Alert Center status rules for accounts and users.
AD Computer Auto-Discovery & Machine Accounts
The windows/collect-ad-computers.ps1 collector does the same for AD computer objects. Run it against a DC; it emits one record per computer (name, DNS hostname, OS, OU, enabled state, last logon, and the ManagedBy owner when set).
- Computers mirror the person model — directory state does not live on the computer asset itself. Instead each discovered computer gets a linked machine account: an Active Directory account asset shown under the computer's name (same as dsa.msc; the AD
NAME$sAMAccountName convention is kept on the SAM Account Name attribute) connected via the same account of relation used for people. The machine account carries Account State, OU, Description and the other directory attributes; the computer asset stays a clean device record. - Known computers refresh in place — matched by hostname/name within the DC's customer; the machine account is created or refreshed on every sweep (it heals automatically if deleted). Computers created from the Discovery queue start with auto-ping monitoring enabled, same as manually added ones.
- New computers queue for review — they appear in the Discovery panel marked "· computer". Approving creates the computer asset plus its machine account and links them; rejecting suppresses the computer on later sweeps.
- Owner auto-link — when the AD computer has ManagedBy set, the matched person is linked to the computer via an assigned to relation.
- Linked accounts on the computer drawer — open a computer asset to see its machine account(s) in the Linked accounts card on the Overview tab, with full attribute detail (provider sections, filter chips, history) on the Attributes tab — same experience as user assets.
- Directory-state alerts — Alert Center status rules with target type computer and trigger Enabled/Disabled/Locked fire on the machine account's Account State: when a sweep observes the state flip in AD (e.g. the computer object is disabled), the alert fires; when it flips back, the alert auto-resolves. Machine accounts do not count toward the computer-asset license limit.
Asset Enable / Disable
Assets can be administratively disabled via Asset > Edit > Account Status. A disabled asset:
- Is excluded from auto-ping monitoring
- Is excluded from TCP port monitoring
- Is excluded from scheduled task target resolution
- Cannot be targeted by Run Command (hidden from asset picker)
- Shows as "DISABLED" in the status column (grayed out row)
- Remains visible and editable in the Assets page for record-keeping
Customer Assignment
Every asset must belong to a customer. When creating or editing an asset, select the customer from the dropdown. The customer is shown in the asset list and detail panel. Assets can be filtered by customer using the toolbar dropdown.
SSH Port
Each computer, firewall, and switch asset has an SSH Port attribute (under Attributes tab). Default is 22. If the target listens on a non-standard SSH port, set this attribute and Octotor will use it for both connectivity checks and SSH connections.
Dependencies
- Customers — at least one customer must exist before creating assets (Settings > Customers)
- Credentials — assets need linked credentials before scripts can be executed on them
- Attribute Definitions — custom attributes are defined in Settings > Attributes
User Assets & Accounts
Octotor models people and their identities as first-class assets. A user asset (a person) owns one or more account assets — one per identity system the person has a presence in (Active Directory, Microsoft 365, Google Workspace, Slack, monday.com, Jira, local, other). Accounts are linked to their owner via the account of relation, so the person stays a single clean record while every directory keeps its own attribute set, state and history.
The model at a glance
- Person (user asset) — name, email, job title, department, phones, notes. Created manually (Add Asset > User), via CSV, or automatically by AD discovery when an unmatched account proposes a new person.
- Account asset — typed by its provider (e.g.
ad). Carries the provider's attributes: SAM Account Name, UPN, the unified Account State (Enabled/Disabled/Locked), OU Path, Group Membership, password dates, SID, Description. Collected attributes show the AUTO badge with per-attribute history. - Machine account — computers get the same treatment: each discovered computer is linked to its AD machine account (shown under the computer's name; the
NAME$sAMAccountName stays on the SAM Account Name attribute). See Assets > AD Computer Auto-Discovery. - Account State drives alerts — Alert Center status rules with target type user or computer fire when a linked account's state flips (e.g. an account is disabled or locked in AD) and auto-resolve when it flips back.
Working with a person
- Overview tab — User details card, linked-account cards (provider icon + state pill + Open), Relations, Notes. Unlink lives on the Relations tab.
- Attributes tab — search + All/Filled/Empty/Auto/Manual filter chips, set-progress bar, a read-only provider section per linked account (collected values, SYNCED pill), and the person's own attribute groups as mini-cards.
- Add account — from the person's Overview: pick a provider tile, fill the provider's fields, create. The account asset is created and linked in one step. The same modal has a Link existing mode — attach an account that already exists (perhaps mis-owned) to this person instead of creating a new one.
Setting or changing an account's owner
Discovery matches an imported account to a person by display name — so an account whose name doesn't match an existing person (common for firewall/appliance local logins, which carry only a username) lands on a freshly-created duplicate person. Three ways to fix or prevent that, all restricted to the correct kind (a user account can only be owned by a person; a machine/host account only by a computer):
- Change owner (after the fact) — open the account's own drawer > Overview. The OWNER row shows the current owner and a Change button. Search a person, pick them, confirm. If the previous owner is left with no accounts, Octotor offers to delete that now-empty duplicate in the same step.
- Set owner before approving — on Assets > Discovered Identities, the Owner column has a set-owner button. Pick the real person before clicking ✓ Approve, and the new account links straight to them — no duplicate is ever created.
- Link existing — from a person's Overview > + Add account > Link existing, search the account and attach it here (it moves off its old owner).
jsmith (email jsmith@tripleor.com) was imported and, because its name didn't match, created a duplicate person “jsmith” — while the real person Jamie Smith already owned the matching AD and Microsoft 365 accounts.
Fix: open the
jsmith account > Overview > OWNER row > Change > search “Jamie” > pick Jamie Smith > Change owner. When prompted “the previous owner ‘jsmith’ now has no accounts — delete it?”, choose OK.
Result: the Check Point login now sits under Jamie Smith alongside their AD and M365 accounts, and the duplicate person is gone. On the next firewall sync the link is preserved (an existing account is only refreshed, never re-matched). To stop it recurring, set the owner in the Discovered Identities queue before approving future imports.
Account Providers (Settings)
Settings > Account Providers is the registry of the identity systems Octotor can hold accounts for. Per provider: display name, icon (curated picker), enabled toggle, and a read-only view of its attribute schema with collected-by info. The enabled toggle is the master switch: a disabled provider disappears from the Assets page Type dropdowns (Devices and Users) and from the Add Account modal, but always stays visible here so it can be re-enabled. Fresh installs ship with Active Directory, Microsoft 365, Check Point, Local and Other enabled; Google Workspace, Slack, Monday and Jira start disabled — flip the toggle to use them. Example: to track Google Workspace accounts, enable Google Workspace here, then it appears in the Users Type filter and the Add Account modal. Provider attribute definitions themselves are managed in Settings > Attributes — pick the provider as the asset type. User accounts and machine accounts share one definition list per provider; attributes that don't apply to a kind simply stay "Not set". A provider can only be deleted when no live accounts use it and no collector targets it.
Filling accounts automatically
The AD collectors (windows/collect-ad-users.ps1 + windows/collect-ad-computers.ps1) sweep a Domain Controller and create/refresh accounts through the Discovery queue — see Assets > AD User Auto-Discovery for the full flow, owner matching and the auto-approve setting. Which providers a collector writes to is set per script via the COLLECTS tiles on the Toolkit page.
Two views: Devices & Users (and what “All” means)
On the Assets page the Type filter splits everything into two views: Devices (computers and device-side objects) and Users (people and their identities). Each view opens on a sensible default — Devices on Computers, Users on User (person) — so you first see the clean list of real machines and real people.
- All devices lists every device-side object and folds in all of their linked accounts — AD machine accounts, and Check Point host objects. “All” means every object, not just computers.
- All users lists every person and folds in all of their linked accounts — AD / Microsoft 365 / Google user accounts, and Check Point user objects.
- Pick a specific type (Computers, User (person), or a single provider such as Active Directory / Check Point) to narrow the list to just that kind.
Changing an asset's type
An asset's Type can be changed from its drawer: open the asset, click Edit on the Overview tab, pick the new type and click Save changes. Only the five generic types are available — computer, user, switch, firewall, other. Every applied type change is written to the audit trail (Investigate shows a type_changed entry with the old and new type and the operator).
- Account assets never change type. Accounts (Active Directory, Microsoft 365, Check Point, Local, … rows) are created and managed by their own flows — the Add Account modal, collectors and discovery — and the generic edit rejects any attempt to re-type them (or to re-type a device into an account type).
- Attribute values are kept, not deleted. Attributes are defined per type, so after a change the drawer renders the new type's attribute schema — but the values recorded under the old type stay stored. Change the asset back and they reappear untouched.
Worked example: a box was created as computer but is really a managed switch. Open its drawer → Edit → Type: switch → Save changes. The asset now shows the switch attribute schema (ports, SNMP fields); its old computer attributes (OS build, CPU, …) are retained invisibly and would return if it were ever re-typed to computer. Investigate shows type_changed: computer → switch.
Two freshness stamps on firewall assets
A firewall's Overview tab shows two separate timestamps, because two different pipelines feed the asset:
- Last Collector — when an attribute collector last ran against the box (the
checkpoint-spark/system-inforecipe or any collector job). This is the stamp that tells you how fresh attribute values like CP: License Expiry are. - Last Account Sync — when the hourly Check Point account sync last pulled user/host objects. This runs on its own schedule and never touches the collected attributes.
Worked example: the account sync ran an hour ago but no collector job has run for 12 days. Last Account Sync shows today; Last Collector shows the 12-day-old date — so a stale CP: License Expiry value is immediately explainable (the collector simply hasn't run), instead of the two freshness signals being blended into one misleading recent stamp. To refresh attributes, run the system-info recipe against the firewall.
Automatic user→computer mapping (primary-user linking)
Octotor links who a computer belongs to — a person→computer assigned to link — from the machine's primary user, automatically. The primary user is the account with the most interactive logons (local, unlock, RDP) on that machine over the last 14 days, read from the Windows Security log by the collector (Linux uses login history). This reflects who actually uses the box, unlike AD's ManagedBy, which usually names whoever joined the machine to the domain (often an IT admin). Octotor no longer uses ManagedBy for ownership — the primary user is authoritative.
Each machine reports three attributes on its next collection: Primary User (DOMAIN\user), Primary User Confidence (share of interactive logons that were the winner, 0–1), and Primary User Source (e.g. eventlog:14d).
What happens automatically
When a collection runs on a computer and its primary user resolves to a known person (via that person's AD account SAM Account Name), Octotor:
- Assigns the person to the computer if it has no owner yet.
- Corrects a wrong existing owner — it removes the incorrect link and sets the detected person. This self-cleans old bad links (e.g. an IT admin wrongly linked to many machines) as each machine is re-collected.
This only happens when the detected user accounts for at least a configured share of the machine's logins over the last 14 days (Settings → Collector → Auto-map users to computers, default 50%), or when you set the primary user by hand and lock it (a locked value always wins, at any confidence). Turn the whole behavior off with the Auto-map users to computers checkbox in the same place.
The "Suggest users" panel (fallback for exceptions)
Confidently-mapped machines are handled automatically and don't appear here. On the Assets page, Suggest users opens a panel that lists only the exceptions:
- Proposed — a low-confidence match with no current owner. Assign links it; Ignore dismisses it.
- Conflict — the detected user differs from the person already linked. Three buttons: Reassign (replace with the detected user), Unlink (remove the owner and stop auto-mapping this machine), Ignore (keep the current owner and stop auto-mapping this machine).
- No matching user — the primary user is a local account (or otherwise has no AD account in Octotor), so there's no person to link. Two buttons: Create local user makes a person (named after the username, reused across machines with that username in the same customer) plus a local account (username + host, marked as admin if it's in the machine's local Administrators group) and assigns it to the computer; Ignore dismisses the machine so it stops appearing (e.g. a shared kiosk or a local-admin-only box you don't want to track).
Bulk actions. Nothing is pre-selected — tick the checkbox on any rows (including conflicts) and use Assign Selected, Ignore Selected, or Unlink Selected to act on them all at once, or use the header checkbox to select every row shown.
Reviewing what you ignored. Click Show ignored to list every machine opted out of auto-mapping (via Unlink or Ignore), with its current owner and who opted it out. Restore (per row) or Restore Selected removes the opt-out, so the machine re-enters auto-mapping on its next collection.
WS-1042 and finds 10 interactive logons in 14 days, all TRIPLEOR\jsmith → it stores primary_user = TRIPLEOR\jsmith, primary_user_confidence = 1.0. Because 1.0 ≥ 0.5 and jsmith resolves to Jamie Smith, Octotor immediately creates the Jamie Smith → WS-1042 assignment during that collection — no clicks. If WS-1042 had previously been linked to the IT admin (from the old ManagedBy behavior), that wrong link is removed in the same step. You never see WS-1042 in the Suggest-users panel because it's already correct. A machine whose primary user has no AD account in Octotor shows No matching user in the panel and is left alone.
get_user_link_suggestions, read-only).Pinning an owner — lock the Primary User, not the owner
Auto-map keeps the owner in sync with the machine's detected Primary User. On the next collection it will overwrite a manually-assigned owner to match whoever logged in most — unless you tell it not to. There is no "lock the owner"; there is only "lock the Primary User field", and the owner always follows that field.
- To keep person X as the owner: open the computer's Attributes, set Primary User to X's username, then click the lock icon on it. Locked → the collector can't change it → X stays the owner.
- Just assigning X by hand is not enough — if Primary User is unlocked (or locked to someone else), the next collect replaces X.
- Other ways to stop changes on a machine: Unlink or Ignore it in the Suggest-users panel (opts it out entirely), or turn off Auto-map users to computers in Settings.
RECEPTION-PC should always belong to Morgan, even though the night cleaner logs in more. Open RECEPTION-PC → Attributes → set Primary User = TRIPLEOR\mreed → click the lock. From now on every collection leaves it as Morgan; the cleaner's logins no longer flip the owner. Remove the lock later and auto-map resumes.Local administrators on a computer
The collector script windows/win-user/usr-local-admins.ps1 (a JSON collector) records the membership of each computer's local Administrators group into the Local Administrators attribute (under the computer's Attributes, Software & Users group). Each entry shows the Name (DOMAIN\principal), Type (User/Group) and Source (Active Directory or Local).
HELPDESK-01 the attribute lists TRIPLEOR\jsmith (User, Active Directory), HELPDESK-01\Administrator (User, Local), and so on. To find every computer where a jsmith principal has local-admin rights, go to Assets → attribute filter → local_admins contains jsmith. It's a substring match across the whole list, so it finds both the AD and any local JSMITH entry.Linux computers report the same Local Administrators attribute — the members of the sudo and wheel groups — collected by linux/collect-info.sh (folded into the standard collection) or the standalone linux/local-admins.sh. The table, drawer render and local_admins filter are identical to Windows, so local_admins contains jsmith matches Linux and Windows machines together.
DHCP client & server (computers)
Every computer collection records whether the machine's primary network adapter gets its IP from DHCP and, when it does, which DHCP Server issued the lease. Both appear under the computer's Attributes → Network group: DHCP Client (Yes/No) and DHCP Server (the server IP). On Windows they come from the adapter's IP configuration; on Linux from NetworkManager / the DHCP lease file.
Yes, DHCP Server = 10.20.0.1. A server with a fixed address shows DHCP Client = No (and no DHCP Server). To list every statically-addressed machine, use Assets → attribute filter → dhcp_client equals false.Password Never Expires (AD accounts)
The AD user collector (windows/collect-ad-users.ps1) records the Password Never Expires flag on each Active Directory account (under the account's Attributes → Security section, Yes/No). It's a password-hygiene signal — accounts whose passwords never expire are worth reviewing.
password_never_expires equals true. A service account like svc-backup will typically show Password Never Expires = Yes.Run
The Run page is where you execute scripts on target assets and follow multi-step protocols. It has three tabs: Command, Protocol, and History.
Running a Script
Multi-Asset Execution
Select multiple assets using the checkboxes. Octotor runs the script on each asset in parallel. Each asset gets its own output tab showing individual results.
Max Job Output
Per-job stdout/stderr is capped to prevent runaway scripts (e.g. accidentally tailing a multi-GB log file) from saturating the worker container. The cap is configured in Settings > Instance > Max Job Output (MB), defaults to 10 MB, range 1–1024 MB.
When a job's output exceeds the cap, the worker appends a one-line truncation marker, broadcasts it to the live view, and stops appending further output. The script continues to run to completion — only the captured-output stream is bounded. Exit code, action-log entries, and any side effects on the target (file writes, state changes) are preserved.
... > C:\Temp\out.txt) and retrieve via SCP/SMB rather than streaming through Octotor.Running a Protocol
Credential Selection
| Priority | Source | Description |
|---|---|---|
| 1 | Manual selection | You pick a specific credential from the dropdown |
| 2 | Asset-linked | Credential directly linked to the target asset |
| 3 | Per-customer default | Credential set as default for this customer + OS family |
| 4 | Global OS default | Credential set as default for the asset's OS family (linux/windows/mac) |
| 5 | Fail | No eligible credential found — error shown |
History Tab
Browse past executions. Click any entry to view the full output, operator who ran it, timing, and status.
- Run page → Command tab → pick target
WIN-DB01(a Windows asset). - Script list → Windows folder →
disk-free.ps1. - Credentials auto-select the
ACME_WIN_ADMINwindows-OS default — leave it. - Click Run → confirm. Ping succeeds, WinRM port 5985 is open, the script executes.
- Live output streams:
C: 42.1 GB free of 120 GB (35%); exit code 0; status done.
Dependencies
- Assets — at least one asset must exist with a hostname/IP
- Toolkit — at least one script must be available
- Credentials — matching credentials must exist (linked to asset or set as OS default)
Toolkit
The Toolkit is the script library. It contains system scripts (built-in, read-only) and custom scripts (created by admins). Scripts are organized by folders: Linux, Windows, Mac, Network, and Custom subfolders.
Script Types
| Type | Badge | Who can edit | Location |
|---|---|---|---|
| System scripts | SYSTEM | No one (read-only, baked into the image) | linux/, windows/, mac/, network/ |
| Custom scripts | USER | Admin only | custom/, custom/group-name/ |
Supported Script Extensions
| Extension | Language | Typical OS |
|---|---|---|
| .sh | Bash / Shell | Linux, Mac |
| .ps1 | PowerShell | Windows |
| .py | Python | Any |
| .bat | Batch | Windows |
| .cmd | Command | Windows |
Creating a Custom Script
Script Properties
- Enabled/Disabled — disabled scripts are hidden from the Run page
- Collector — marks the script as a data collector. When enabled, the script's output is parsed and stored as asset attributes (subject to the Auto Attribute Updates setting in Settings > Attributes)
- Parse Mode — how collector output is interpreted (JSON or AI-assisted)
- OS Family — which operating systems this script targets
Writing a Collector Script
A collector script is just an ordinary toolkit script with the Collector flag turned on. After the job finishes, the runtime parses the script's stdout, matches every key in that output against Settings > Attributes (the asset_attribute_defs table), and writes the matching values onto the asset.
The contract
- Output a single JSON object on stdout. Keys must match the registered attribute
keyexactly (case-sensitive). Values must match the def'sdata_type. Anything that doesn't match is silently skipped. - One value per key. Numbers as numeric JSON literals (
3.5, not"3.5"). Booleans astrue/false. Dates parseable byDate.parse()(e.g."2026-05-03"). Objects/arrays (e.g. a NIC list) are stringified before storage. - Stdout-only. Lines starting with
[STDERR]or[octotor]are stripped before parsing — anything else outside the JSON object will break the parse. (Output from jobs run before the rename shows the historical[octopus]prefix; it is stripped the same way.) - Unknown keys are skipped, not errors. If you emit
"freeRam": 3.5but the def isram_free_gb, the runtime logsskipped: freeRam(unknown_key)and moves on. No alert. No retry. - Locked attributes are skipped. If an admin locked
ram_free_gbon this asset (Attributes tab → lock icon), the collector cannot overwrite it. - Pending vs auto-apply. If the def has
auto_approve=true, the value is written directly. Otherwise it goes to the pending-approval queue (Assets > Pending Attribute Updates) until an admin approves. - Removals (clear-on-removal contract). For a small, fixed set of fields the built-in collectors report removals: an empty-string value (
"license": "") means "I checked — this value is gone at the source", and Octotor clears the stored attribute (auto-approve on) or queues a (cleared) proposal for review (auto-approve off). An omitted key still means "not collected this run" and never touches the stored value. Values last set manually are never auto-cleared — a removal against a manual value always goes to the pending queue. Custom collector scripts cannot clear arbitrary fields: only keys in the built-in contract (api/services/collector-contract.js) are honored; empty values for every other key are skipped exactly as before.
Worked example — removed M365 license clears automatically
- User
tbrooks@tripleor.comshows License =O365_BUSINESS_PREMIUMon their m365 account asset (collected by the M365 sync). - The tenant admin removes Taylor's license in the Microsoft 365 admin center.
- On the next M365 sync, the collector reports
"license": ""for Taylor (evaluated, gone). Since thelicensedef ships with Auto-approve on, the attribute is cleared immediately — the drawer no longer shows a license, and the attribute history recordsO365_BUSINESS_PREMIUM → (cleared)with source collector. - If an operator had manually typed that license value earlier (source manual), the sync would instead add a (cleared) row to Assets > Pending Attribute Updates — approving it deletes the attribute, rejecting keeps the manual value.
Discovering the keys you can emit
Three ways to get the canonical key list — pick whichever fits your workflow:
- Browse — Settings > Attributes shows every key + label + type + auto-approve flag.
- API —
GET /api/attributes/defs?asset_type=computerreturns JSON for the current asset type. - Export —
GET /api/attributes/defs/exportdownloadsseed-attributes.jsonwith every def the system knows about.
Example — query RAM on a Linux/macOS asset (Bash)
Targets attribute keys ram_gb and ram_free_gb (both data_type=number; ram_free_gb is auto-approve).
#!/bin/bash
# check-ram.sh — emit RAM totals as JSON for the Octotor collector.
# Mark this script as Collector with parse_mode=json in Toolkit.
RAM_MB=$(free -m | awk 'NR==2{print $2}')
RAM_FREE_MB=$(free -m | awk 'NR==2{print $7}')
RAM_GB=$(awk "BEGIN{printf \"%.1f\", $RAM_MB/1024}")
RAM_FREE_GB=$(awk "BEGIN{printf \"%.1f\", $RAM_FREE_MB/1024}")
cat <<EOF
{
"ram_gb": $RAM_GB,
"ram_free_gb": $RAM_FREE_GB
}
EOF
Example — query RAM on a Windows asset (PowerShell)
Same two attribute keys, formatted as a numeric JSON object via ConvertTo-Json.
# check-ram.ps1 — emit RAM totals as JSON for the Octotor collector.
# Mark this script as Collector with parse_mode=json in Toolkit.
$os = Get-CimInstance Win32_OperatingSystem
$ramTotalGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
$ramFreeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
$payload = [ordered]@{
ram_gb = $ramTotalGB
ram_free_gb = $ramFreeGB
}
$payload | ConvertTo-Json -Compress
Add your own custom attribute — end to end (antivirus example)
Say you want every computer to show whether an antivirus product is installed, and you want to filter on it. Three steps, no code changes to Octotor:
- Define the attribute. Go to Settings > Attributes → Add attribute. Asset type
computer, Keyantivirus_installed, Label Antivirus Installed, Typeboolean, Auto-approve on (so it writes without a pending review). The key is the contract — your script must emit exactly this name. - Write a script that outputs that key. Anything on stdout that isn't the JSON object is ignored, so emit one JSON object. The value type must match the def (
booleanhere). See the copy-paste example below. - Flag it as a Collector. Upload/enter the script on the Toolkit page, open it, turn on Collector, set Parse Mode
JSONand OS Familywindows. Run it (or schedule it on the Scheduler) against your computers.
On the next run the collector writes antivirus_installed onto each computer. It then shows in the computer's Attributes, and you can filter it on the Assets page (attribute filter → antivirus_installed equals false to find unprotected machines) and ask the Goose agent about it.
# check-antivirus.ps1 — report whether a real antivirus product is registered.
# Mark this script as Collector with parse_mode=json in Toolkit.
# Requires the attribute def key `antivirus_installed` (boolean) to exist first.
$ErrorActionPreference = 'SilentlyContinue'
# Windows Security Center lists registered AV products (excludes Defender-only-off cases).
$av = Get-CimInstance -Namespace 'root/SecurityCenter2' -ClassName 'AntiVirusProduct'
$installed = [bool]($av | Where-Object { $_.displayName })
$names = ($av | ForEach-Object { $_.displayName } | Where-Object { $_ }) -join ', '
# Emit the exact attribute keys. `antivirus_installed` must be a registered boolean
# attribute; `antivirus` (text) is optional — add that def too if you want the names.
$payload = [ordered]@{
antivirus_installed = $installed
antivirus = $names
}
$payload | ConvertTo-Json -Compress
antivirus_installed but register av_installed and the runtime logs skipped: antivirus_installed(unknown_key) and writes nothing. Define the attribute first, then match the key.How to know it worked (no shell access needed)
- Save the script in Toolkit and toggle Collector ON (action password may be required).
- Run it once on a test asset via the Run page.
- Open that asset's drawer (Assets > click the row) and switch to the Jobs tab. Your run appears at the top with a
collected Nbadge — that N is exactly the number of attributes the runtime auto-applied from the script's output.collected 0means the script ran successfully but the runtime didn't accept any of the keys it emitted. - Expand the job row in the Jobs tab to see the script's full stdout — that's the JSON your script actually emitted. Compare it to the registered keys in Settings > Attributes: any key not on that list is treated as
unknown_keyand silently skipped, and any value that doesn't match the def'sdata_typeis treated astype_validationand skipped. - Switch to the Attributes tab — if a key landed and was auto-approved, the new value appears under its group (HARDWARE / NETWORK / etc.) with an AUTO badge and a "from collector script" subline.
- If the def has
auto_approve=false, the value goes to the pending queue instead — open Assets > Pending Attribute Updates and you'll see a row with old → new values waiting for an admin to approve or reject. - For a full audit trail of what changed and when, use the asset's Changes tab and filter by source = collector. Each row shows
old → new, the timestamp, and whichcollector:job#Nwrote it. - If your collector is wired into a scheduled task that drives an alert rule, the Alert Center detail panel Source row will read "Scheduled task · <your task name>" + "collector script <your script> updated <key> (job #N)". End-to-end chain complete.
unknown_key / type_validation / locked / value_too_long / empty_value) are recorded on the job row in the database but not yet surfaced in the UI — for now, the fastest way to diagnose collected 0 is to compare your script's stdout (visible in the expanded Jobs row) against Settings > Attributes by hand. A "collector dry-run + skip-reason inspector" UI is planned for a future release.Skip-reason vocabulary
| Reason | Meaning | Fix |
|---|---|---|
unknown_key | Emitted key has no matching def for this asset_type | Check Settings > Attributes for the exact key |
type_validation | Value didn't match the def's data_type | Number = numeric literal, boolean = true/false, date = ISO-parseable |
value_too_long | Value exceeds 1000 characters | Trim or split into multiple keys |
empty_value | Value is "", null, or undefined | Omit the key entirely instead of emitting a blank |
locked | Admin locked this attribute on this asset | Unlock from the asset's Attributes tab if intentional |
ai. The runtime sends the raw output plus the attribute-def schema to the local LLM (Ollama via LiteLLM), which extracts a matching JSON object. Trade-off: every collector run pays for an LLM call, and the result is only as good as the model — for fixed-format scripts, JSON parse mode is faster and deterministic.AI Validation
Octotor uses a local AI model to review scripts before saving. It checks for:
- Blocked patterns — destructive commands (rm -rf /, format disk, credential harvesting, reverse shells)
- Warnings — sudo usage, service restarts, registry modifications, network changes
Risk Classification
Every script is assigned a risk level based on AI validation. The risk level determines whether an action password is required to execute the script.
| Level | Badge | Meaning | Execution gate |
|---|---|---|---|
| High | HIGH | Destructive or privileged operations | Requires action password |
| Medium | MED | System modifications | Requires action password (if configured) |
| Low | LOW | Read-only or informational | No password required |
Risk levels are assigned automatically by AI during validation and displayed as colored badges in the script list and detail panel. Admins can change the risk level manually; downgrading requires the risk_downgrade action password (see Security).
Content Hash
Each script has a SHA-256 content hash (visible in the detail panel) that is recalculated on every save. This allows admins to verify a script hasn't been modified outside the UI.
Dependencies
- AI (optional) — Ollama + LiteLLM must be running for script validation. Without AI, scripts can be saved directly if "Skip AI Validation" is enabled
Uptime collection
Computer assets carry an uptime_seconds attribute (integer; seconds since last boot). Two paths populate it:
- Inside the full collectors —
windows/collect-info.ps1,linux/collect-info.sh, andlinux-embedded/collect-info-qnap.shemituptime_secondson every run. Same cadence as the rest of the collector data (usually 4 hours). - Dedicated one-shot scripts —
windows/uptime.ps1,linux/uptime.sh,linux-embedded/uptime-qnap.shemit JUST{"uptime_seconds": N}. Schedule these on a short cadence (e.g. every 5–15 minutes) when you want fast reactivity for "asset rebooted" or "uptime exceeded" alerts without paying for the full ~20-WMI-call collect-info run.
The Identity & Status row in the asset Overview tab renders the value adaptively: 15 seconds / 1 minute 15 seconds / 2 hours / 5 days 4 hours 22 minutes 15 seconds. Trailing zero components are trimmed; middle zeros are preserved (so a host up exactly 1 day and 15 seconds renders as 1 day 0 hours 0 minutes 15 seconds, not the misleading 1 day 15 seconds).
Threshold-rule conversion table
Alert rules compare against uptime_seconds directly. Common thresholds in seconds:
| Wall clock | Threshold value | Example rule |
|---|---|---|
| 1 hour | 3600 | uptime_seconds < 3600 — fires when an asset rebooted in the last hour |
| 1 day | 86400 | — |
| 7 days | 604800 | — |
| 30 days | 2592000 | uptime_seconds > 2592000 — warn that the asset is overdue for a reboot |
| 90 days | 7776000 | uptime_seconds > 7776000 — critical: patching cycle is missing |
| 1 year | 31536000 | — |
No default uptime rules are seeded — create your own under Alert Center > Rules > New Rule, pick the uptime_seconds attribute, choose a comparator and value from the table above.
Worked example rules
Two concrete examples for common uptime alert needs. Open Alert Center > Rules > New Rule and use the field values verbatim.
Rule 1 — Long uptime (reboot overdue)
Notifies on assets up for more than 3 months (90 days).
| Field | Value |
|---|---|
| Name | Long uptime — reboot overdue (>90d) |
| Severity | warning (orange — reboot reminder, not a crisis) |
| Category | availability |
| Rule type | threshold |
| Threshold attribute | Uptime (seconds since last boot) |
| Operator | > |
| Value | 7776000 (90 days × 86 400 s/day) |
| Dedupe window (min) | 1440 (24 h — fires once per day per asset while above threshold) |
| Cooldown (min) | 10080 (7 days — minimum gap between re-firings, weekly nag not daily) |
| Notify channels | Whatever you've configured (email / Telegram / Slack / webhook) |
| Target scope | Leave empty — uptime_seconds only exists on computer-type assets per the def |
After save, every asset that's been up > 90 days fires once. After a reboot, the rule auto-resolves on the next collector cycle (uptime crosses back below 7,776,000). If 30 days later it's back above 90 d, the rule fires again.
Rule 2 — Recently rebooted
Notifies on assets up less than 3 hours.
| Field | Value |
|---|---|
| Name | Asset recently rebooted (<3h) |
| Severity | info (or warning if you want it more prominent) |
| Category | availability |
| Rule type | threshold |
| Threshold attribute | Uptime (seconds since last boot) |
| Operator | < |
| Value | 10800 (3 h × 3 600 s/h) |
| Dedupe window (min) | 60 (1 h — surfaces each reboot, suppresses redundant fires within the rebooted window) |
| Cooldown (min) | 240 (4 h — slightly larger than the 3-h rule window so a re-fire only happens after the asset crosses 3 h and then reboots again) |
| Notify channels | Same as Rule 1 |
| Target scope | Leave empty |
Rule 2 cadence gotcha — schedule uptime.{ps1,sh} hourly
The uptime value on each asset only updates when a collector script runs. The full collect-info cadence is typically every 4 hours, so a 3-hour window can be missed entirely between two collector runs:
09:00 Asset reboots (uptime = 0) 10:00 Asset is at 1 h uptime (no collector running) 11:00 Asset is at 2 h uptime (no collector running) 12:00 Asset is at 3 h uptime (no collector running — exactly at the threshold) 13:00 collect-info runs (uptime = 4 h is what gets recorded) 13:00 Rule 2 checks "is uptime < 3 h?" → NO (it's 4 h) → rule doesn't fire
Result: asset rebooted, but you never get the "recently rebooted" alert. The 3-hour window came and went between two collector runs.
Fix: schedule the dedicated uptime.ps1 / uptime.sh scripts on a cadence shorter than the rule window. Configure at Scheduler > New Task.
Cadence trade-offs:
| Cron | Chances per 3-h window | Verdict |
|---|---|---|
*/15 * * * * | 12 | Overkill |
*/30 * * * * | 6 | Solid but more than needed |
0 * * * * | 3 | Recommended |
0 */2 * * * | 2 (worst case 1) | Tight — risky if one job misses |
0 */4 * * * | 1 max | Equivalent to full collect-info — dedicated script adds nothing |
Rule 1 doesn't have this concern — the default 4-hourly collect-info is plenty for a "uptime > 90 days" check.
Storm-cap awareness
If a maintenance window reboots 100 hosts at once, Rule 2 would fire 100 times within a short window. Octotor's per-rule storm cap (default 100/min, configurable per-rule) prevents the notification firehose — beyond the cap, alerts are recorded with storm_suppressed=true and the notification channel just gets a single "+97 more" summary instead of a flood. Consider setting storm_cap to e.g. 20 on Rule 2 if you're worried about mass-reboot churn.
Scheduler
The Scheduler runs scripts automatically on a recurring schedule. Tasks are defined using cron expressions and can target assets by type, attribute values, and customer scope.
Besides Script tasks, two non-asset task types exist: Goose Recipe (natural-language instruction executed by the AI agent) and M365 Sync (triggers a Microsoft 365 connector sync — see Help > M365 Connectors, Part 6). Non-asset types hide the target/execution sections; an M365 Sync task needs only a connector and a schedule.
Trigger: Time schedule vs On alert (auto-remediation)
Every task has a Trigger: Time schedule (the classic cron behavior) or On alert. An On-alert task carries no cron — it runs only when an Alert Center rule that links to it fires. This turns any monitoring Octotor does (offline/status, threshold, custom checks, events) into an automated response. Pro tier; attaching an action to a rule is admin-only.
To wire one up:
- Scheduler > New task → set Trigger = On alert. Pick the script, target, and credential as usual. Under Alert-trigger options choose Run on:
- The task's own target — runs against the assets the task's target filter selects (e.g. a specific firewall).
- The asset that fired the alert — runs against whichever asset tripped the rule. Because Octotor fires per asset, a rule matching 5 of 7 hosts runs the task on those 5 hosts individually.
- Set the guardrails: Cooldown (minimum minutes between runs) and Max runs / hour (after which Octotor stops and logs an "auto-remediation stopped — manual intervention needed" warning). These prevent a flapping alert from hammering the target or looping forever.
- Alert Center > Rules > New/Edit rule → under Run task on fire, pick your alert-triggered task. Save.
Now, whenever that rule fires, the task runs (subject to cooldown/cap). Dispatches, cooldown suppressions, and cap stops are all recorded in the action log (category alert) so you can see exactly when a remediation ran or was throttled. Creating or editing a rule never triggers the task — only real fires do.
Configuring the guardrails — worked examples
The two guardrails are set on the task (Scheduler ▸ task ▸ Alert-trigger options). They are independent:
| Field | What it does | Range | Default |
|---|---|---|---|
| Cooldown (minutes) | Minimum time that must pass after a run before the same task runs again. A fire inside the window is suppressed (logged, not run). 0 disables the cooldown. | 0–1440 | 10 |
| Max runs / hour | Ceiling on runs in any rolling 60-minute window. Once reached, further fires are suppressed and Octotor logs a single "auto-remediation stopped — manual intervention needed" warning. 0 would disable the cap (not recommended). | 1–100 | 3 |
| Verify after (seconds) | Post-fix verification: if the alert that triggered the task is still open this many seconds after the task ran, Octotor runs the task again automatically. Retries bypass the cooldown (a 10-minute cooldown would otherwise swallow a 5-minute verify window) but are bounded by Max retries. Alerts you have acknowledged are never retried — acknowledging means a human owns the incident. 0 turns verification off (the task runs once per fire). | 0, or 60–86400 | 0 (off) |
| Max retries | How many extra runs one alert may trigger through verification. The first run doesn't count — 2 means up to 3 runs total per alert. Every re-fire is recorded in the action log (category alert, "remediation re-dispatched"). | 0–10 | 2 |
Example 1 — VPN tunnel reset (steady, safe)
Cooldown 10 · Max/hour 3. The tunnel drops and the ping rule fires:
| Time | Rule fires? | Action |
|---|---|---|
| 10:00 | yes | Run — reset the tunnel (run #1) |
| 10:02 | yes (still flapping) | Suppressed — inside the 10-min cooldown |
| 10:11 | yes | Run — cooldown elapsed (run #2) |
| 10:22 | yes | Run (run #3) |
| 10:33 | yes | Suppressed — 3 runs already this hour → "auto-remediation stopped, manual intervention needed" alert fires once |
| 11:05 | yes | Run — the rolling hour has cleared the older runs |
Net effect: a real reset is attempted, brief flapping doesn't hammer the firewall, and if three resets in an hour don't fix it you get paged instead of an infinite loop.
Example 2 — restart a service, react fast but bounded
Cooldown 2 · Max/hour 6. Good when the remediation is cheap and you want a quick retry cadence but still a ceiling — up to 6 restarts an hour, no more than one every 2 minutes.
Example 3 — one-shot, never repeat automatically
Cooldown 1440 (24 h) · Max/hour 1. The task runs at most once per fire-storm per day — useful for a heavy or disruptive remediation you want to run once and then leave to a human until tomorrow.
remediation_dispatched / suppressed_cooldown / suppressed_cap / remediation_capped).Job History (per task)
Click Hist on any task (or the task name) to open its execution history. Each run lists its jobs with Job# · Asset · Customer · Asset type · Status · Exit · Started · Finished, plus skipped runs (e.g. "no credential available"). Click View on a job to see the full record — the same baseline the Investigate page uses (Triggered-by, Customer, Asset-type, Source/Dst IP) followed by the complete script output. Tasks that span multiple customers show which customer each job belonged to.
System Timezone
All scheduled tasks fire in the timezone set at Settings > Instance > System Timezone. On first save, the dropdown defaults to your browser's timezone (auto-detected) — operators in different regions can override. The Edit Task modal shows the current timezone below the cron expression input so you always know what wall-clock time your tasks will fire at.
Cron expression syntax
Cron expressions are five fields, space-separated, each with its own range:
| Position | Field | Range | Wildcards |
|---|---|---|---|
| 1 | Minute | 0–59 | * any, */N every N, A,B,C list, A-B range |
| 2 | Hour | 0–23 | same |
| 3 | Day of month | 1–31 | same |
| 4 | Month | 1–12 | same |
| 5 | Day of week | 0–7 (0/7=Sun) | same; 1-5 = Mon-Fri |
Worked examples
| Cron | Fires when |
|---|---|
*/5 * * * * | Every 5 minutes (00:00, 00:05, 00:10, …) |
17 * * * * | Every hour at minute 17 (00:17, 01:17, 02:17, …) |
0 */4 * * * | Every 4 hours starting at midnight (00:00, 04:00, 08:00, …) |
3 17 * * * | Daily at 17:03 |
0 6,18 * * * | Twice daily — 06:00 and 18:00 |
0 9-17 * * 1-5 | Every hour, Mon–Fri 09:00 through 17:00 |
0 8 * * 1-5 | Weekdays at 08:00 |
30 18 * * 5 | Fridays at 18:30 |
0 2 * * 0 | Sundays at 02:00 |
0 6 1 * * | 1st day of every month at 06:00 |
0 6 1,15 * * | 1st and 15th of every month at 06:00 |
0 6 1 1,7 * | 1st of January and 1st of July at 06:00 (semi-annual) |
Common gotchas
- Don't put colons inside a field.
0 17:03 * * *looks like "17:03" but in cron syntax that's minute=0, hour=17:03 (invalid). The right pattern for "daily at 17:03" is3 17 * * *— minute first, hour second, two separate fields. - Day-of-month and day-of-week are OR-ed, not AND-ed.
0 6 15 * 1fires on the 15th of any month or any Monday — not "Mondays that are also the 15th." If you mean "every Monday in March," use0 6 * 3 1. - Timezone is system-wide. Cron expressions are interpreted in Settings > Instance > System Timezone. The Edit Task modal shows the active TZ under the cron field.
- The cron has no "start time" memory. If you save
0 * * * *at 18:42, the first firing is 19:00 (the next minute=0). Cron doesn't track when you saved the task.
Creating a Scheduled Task
Common Cron Patterns
| Expression | Meaning |
|---|---|
| */5 * * * * | Every 5 minutes |
| 0 * * * * | Every hour |
| 0 6 * * * | Daily at 06:00 |
| 0 8 * * 1-5 | Weekdays at 08:00 |
| 0 0 * * 1 | Every Monday at midnight |
| 0 6 1 * * | First of every month at 06:00 |
Task Targeting
Tasks can narrow their scope using multiple filters that stack:
| Filter | Effect |
|---|---|
| Asset Type | Only run on assets of this type (e.g. "computer") |
| Attribute Filter | Only run on assets where a specific attribute contains a value (e.g. location contains "Warehouse") |
| Customer Scope | Only run on assets belonging to a specific customer |
| (none set) | Runs on all non-disabled assets |
Connectivity Check
Before each job runs, Octotor checks if the target asset is reachable:
Credential Resolution
For each target asset, the scheduler resolves credentials in this order:
| Priority | Source |
|---|---|
| 1 | Task-level credential (set in task configuration) |
| 2 | Asset-linked credential (linked in asset detail) |
| 3 | Per-customer default (set in Settings > Credentials for this customer + OS family) |
| 4 | Global OS default credential (set as default for the asset's OS family) |
| 5 | Skip — asset is skipped with a warning in the action log |
Task History
Click a task name or the clock button to view its execution history:
- Runs — each execution grouped by timestamp, showing per-asset job status (done/failed/cancelled), exit codes, and timing
- Skipped / Info — assets that were skipped (no credential available), or runs that found zero matching targets
Task Options
| Option | Effect |
|---|---|
| Enabled | Task fires on its cron schedule when enabled |
| Run Once | Task auto-disables after its first execution |
| Auto-proceed on ping fail | Skip connectivity check — attempt SSH even if ping and TCP port check fail |
| Timeout (sec) | How long one job of this task may run, in seconds (10 to 3600). Leave it empty to use the global value from Settings > Management Protocols (SSH or WinRM > Timeout (seconds); the SSH default is 30). Set it when the script needs longer than the global value, for example a backup collector that reads a long job history. Every job prints the limit it runs under (Timeout 240 s (the task's "Timeout (sec)" field)) and a job that is cut off says which field set the limit. |
| Override Identity Verification | When checked, the task uses its own identity settings instead of the global ones from Settings > Monitoring. All 5 settings (DNS, SSH gate, require probe, collector check, mismatch behavior) can be configured per task. |
Auto-Refresh
The "Auto" button in the page header enables 10-second auto-refresh of the task list. When you trigger a task manually, the list also auto-reloads after 2 and 5 seconds to show the updated status without requiring a manual page refresh.
Dependencies
- Toolkit — the script must exist in the toolkit
- Assets — at least one asset must match the target filters
- Credentials — matching credentials must exist for the target assets (task-level, linked, or OS default)
Investigate
The Investigation page provides a unified timeline of all system activity — audit logs and job executions merged into a single, filterable view. Use it to answer questions like "what happened to this asset?" or "what failed today?".
How It Works
Investigation merges data from three sources:
| Source | What it contains | Badge color |
|---|---|---|
| Logs | Audit events — logins, asset changes, config updates, scheduler skips, maintenance actions | Grey |
| Jobs | Script executions — queued, running, done, failed, cancelled. | Blue |
| Attribute changes | Attribute change history — every old → new transition of every asset attribute, including removals shown as (cleared). Triggered-by tells you whether a human edit (👤), a CSV import (📥) or a collector (📡) made the change. | Grey |
Attribute changes — investigating history
Pick Source → Attribute changes and two extra filters appear: Attribute (grouped by provider, same as the Assets page) and Value (old or new) — the value filter matches either side of a change, so you can find every place a value ever appeared.
production log on to?"
- Source → Attribute changes
- Attribute → Last Logged-in User (under Computer)
- Value (old or new) →
production, Customer → tripleor → Apply
Every row is one transition on one machine — e.g. DOMAIN\alice → DOMAIN\production on TRI-LAB-01 two weeks ago. The View modal shows the full record (old value, new value, change source). You can ask the AI Assist the same question in plain words, or ask Goose: "which computers did user production log on to at tripleor?"
The event line
Every row carries a consistent set of fields so any event is scannable at a glance:
| Field | What it shows |
|---|---|
| # | The row's own id — shown for every event (logs and jobs alike), never blank. Earlier this column only filled for jobs. |
| Triggered by | The mechanism that initiated the event: 👤 Operator (a human), ⏱ Scheduler (a scheduled task), ⚙ System (autoping / TCP monitor / alert engine / maintenance), 🤖 Goose AI, 🔔 Alert rule, or 🔑 API token. |
| Operator | The human behind the event, if any. Blank for pure system / scheduler / alert-rule events. (Available in the View modal; promote to a column via the chooser.) |
| Customer | Which customer the event belongs to. Resolved from the event's customer attribution, or from the target asset. |
| Asset type / Source IP / Dst IP | Shown when applicable (the event targets an asset / carries a source address). Always present in the View modal; optional columns via the chooser. |
Use the Columns ▾ button to promote any of the optional fields (Operator, Asset type, Source IP, Dst IP) into the table. Your selection is remembered in this browser.
Filters
All filters are optional and work together (AND logic). Results update immediately as you change filters. Use the 📌 pin button to persist filters across page navigation.
| Filter | What it does |
|---|---|
| Date range | From/To date pickers — narrow to a specific time window |
| Source | Show only Logs, only Jobs, or All |
| Category | auth, asset, job, scheduler, settings, sync, goose, ai, identity, maintenance |
| Status | ok, done, error, failed, warning, cancelled, running, queued, identity_mismatch |
| Operator | Username of who performed the action (includes "scheduler: task_name") |
| Asset name | Filter events related to a specific asset |
| Customer | Narrow to a single customer. The dropdown only lists customers you are scoped to, and the filter narrows within your existing access — it can never widen it. |
| Search text | Free text search across detail, script path, target name |
Attribute Cross-Filters
Click Attr Filter to filter events by asset attributes. You can add multiple attribute conditions (AND logic). Each filter has:
- Attribute — select from available attribute definitions (e.g., OS Family, Location)
- Mode — Include (show matching) or Exclude (hide matching)
- Comparison — contains, equals, > (greater than), < (less than)
- Value — the value to match against
View Details
Click View on any event row to see full details:
- Job events — opens the modal with the full record (id, triggered-by, customer, asset type, source/dst IP, status, exit code, duration) followed by the complete script output
- Log events — shows the full record (id, triggered-by, operator, customer, asset type, source/dst IP, target, timestamp, status) plus the complete, untruncated detail text
AI Investigation
When enabled, the AI query bar appears at the top of the page. Type a natural language question and the AI will:
- Translate your question into filter parameters (using knowledge of all asset attributes)
- Execute the query (respecting your permissions — customer scope, role, group)
- Fetch asset details for mentioned assets (IP, hostname, OS, all attributes)
- Summarize the results in plain language
The AI can answer both event questions ("what failed today?") and asset questions ("what is the IP of ast01?") because it has access to asset details during summarization.
Follow-up questions: The AI remembers your previous questions in the current session. You can ask "what jobs ran on it today?" after asking about a specific asset — the AI knows what "it" refers to. Use the Clear button to reset the conversation.
AI Conversation Logging: When enabled in Settings > AI Configuration, all AI queries and responses are logged to the action log for admin review.
AI Toggle
AI investigation has two levels of control:
| Level | Who controls | Effect |
|---|---|---|
| Admin setting | Admin (Settings > AI Configuration) | Enables/disables AI investigation for all users |
| User toggle | Each user (on the Investigation page) | Personal preference to show/hide the AI bar |
Export
Click Export CSV to download the current filtered results as a CSV file.
Permissions
| Role | What they see in Investigation |
|---|---|
| Admin | All events from all sources, all customers |
| Operator | Events for their assigned customers — both logs and jobs |
| Viewer | Log events for their assigned customers only — job events are excluded (no Run page access) |
Dependencies
- Activity to investigate — Investigate reads the
action_logand job history, so a brand-new instance shows little until logins, jobs, and collectors start writing events. - AI investigation (optional) — the AI summary bar needs AI enabled in Settings > AI Configuration and a reachable model (local
oct-litellm/oct-ollama, or an allowed external LLM).
Alert Center
The Alert Center surfaces operational events that need attention — asset outages, identity mismatches, threshold breaches — in a single dedicated page. Unlike the Investigate timeline (full audit log), the Alert Center shows only actionable items and supports acknowledge/resolve workflows.
Evaluation engine
A dedicated container, oct-alert-worker, runs the evaluation loop. It listens on the PostgreSQL channel alert_check and evaluates matching rules on every notification. The worker never calls oct-api over HTTP — all state flows through the database, consistent with the single-responsibility container model (see About).
What fires an alert
The rule engine is live end-to-end. Six rule types can raise alerts — create and scope them in Alerts Admin > Rules:
- status — an asset enters a watched state (e.g.
computer→offline). The built-in case is availability: when autoping detects an online→offline transition for an asset with Create alert when this asset goes offline enabled, an alert is raised and auto-resolves when the asset returns. - threshold — a numeric collector attribute crosses a bound (e.g.
disk_free_gb < 10). - os_event — a matching Windows / syslog event is ingested.
- ingest — an external webhook or email event matches.
- signin — a Microsoft 365 / Entra sign-in matches (e.g. a failed sign-in, or a sign-in from an unexpected country). Fed by the M365 connector's sign-in poll.
- custom — one of 9 check-types: run a script and check its result, Windows service state, TCP port reachable, HTTP(S) endpoint responds, process running, disk free space, file exists, LDAP bind, or AI analysis of output.
Watch every data disk on every server
The collect-info scripts report every data disk a server has — not only the system disk. Each disk gets its own attributes (size, free GB, free %, and the volume label), named by its drive letter on Windows (Disk Free D: (%)) or its mount path on Linux (Disk Free /data (%)). Two extra attributes summarize the whole server: Data Disk Free — Worst (%) holds the lowest free-space percentage across all of that server's data disks, and Data Disk With Least Free Space names which disk that is. When a disk is removed from the server, its attributes are cleared on the next collect run. The asset's Overview tab shows one usage line per data disk, fullest first.
This means ONE alert rule covers every data disk on every server. When it fires, the alert text names the disk (for example "disk: D: DATA").
- Open Alerts Admin > Rules and click New rule.
- Name:
Data disk low. Rule type:threshold. - Attribute key: pick
Data Disk Free — Worst (%). Operator:<=. Value:10. Data type:number. - Click Create rule.
Dependencies
oct-alert-workercontainer running — it listens on thealert_checkchannel and runs the evaluation loop. Confirm it on Services Status > Service Heartbeats.- Master alert toggle ON (Alerts Admin > Globals) — when off, rules stay visible but every fire is a no-op.
- autoping monitoring the asset — availability (status/offline) alerts are driven by autoping transitions, so the asset must be a monitored target.
- A notification channel (Alerts Admin > Channels) — only needed to push beyond the in-app Alert Center (email / Telegram / webhook).
computer / trigger offline rule — any implicit offline alert raised earlier can no longer auto-resolve and must be resolved manually in the Alert Center. New offline events from then on are handled by the explicit rule, which auto-resolves normally. A fix is planned.Enable offline alerts on an asset
- Open the asset on the Assets page and click Edit.
- Check Create alert when this asset goes offline and Save.
- To enable for many at once: select the assets on the Assets page, then click Enable Alerts in the bulk-action bar (Disable Alerts reverses it).
- Assets page → open
DB01→ Edit → check Create alert when this asset goes offline → Save. (Autoping must already be monitoring DB01.) - DB01 goes down. Within one autoping cycle the Alert Center shows a new critical row — title "DB01 is offline", category
availability. - Click the row title → the explain pane shows Status (open), Cause (autoping online→offline at the exact timestamp), and the available Actions (Ack / Resolve).
- DB01 comes back → within a cycle the alert auto-resolves with a ✅ "back online" note — no manual cleanup.
Acknowledge + resolve
Open alerts show Ack and Resolve buttons per row. Acknowledged means an operator is aware and working on it; Resolved marks the issue closed. Bulk operations (up to 1000 per batch) are available by selecting multiple rows. Viewers can browse the list but cannot ack or resolve.
Storm cap
To prevent flooding the table from misbehaving rules or genuine incidents affecting many assets, the engine caps alert creation at 100 per rule per minute by default. Events above the cap are merged into the first alert of that minute bucket — dedupe_count increments and a STORM badge is shown in the title cell. The cap is operator-configurable in Settings > Alerts > Alert Center (range 1–10000).
Nav badge
A badge next to the Alerts nav link polls /api/alerts/count every 30 seconds and tints by highest-open severity: red for critical, orange for warning, blue for info. It hides when there are no open alerts and caps at 99+.
Settings
- Master toggle — disables the evaluation engine entirely (rules still visible, fires become no-ops)
- Storm cap — see above
- Retention — days to keep resolved alerts before pruning by scheduled maintenance
Inline explain row + Enhanced view
Click an alert's title in the table — a second row slides in below it with a friendly explanation of what happened. The inline row has three sections:
- Status — what the alert's current state means in plain language. Wording varies per status: open, acknowledged by <operator> at <time>, auto-resolved (with rule-type-specific "back to normal" wording — back to online for status rules, back below threshold for threshold rules, etc.), resolved manually.
- Cause — what triggered the alert: process / script / task that detected it, the timestamp, and the key payload field. Built from the
alert_transition_logrow that fired this alert (linked via the newsource_transition_log_idcolumn from migration 078, so the Cause line is exact, not time-window-correlated). - Actions — buttons available at this status with a short explanation of what each does. Ack drops the open-critical badge count without resetting dedup; Resolve closes the alert and resets the dedup window.
The toolbar Enhanced view button (top-right of the page header) toggles a global mode where every alert renders the explain row automatically, no per-row clicking needed. The toggle persists for the lifetime of the browser tab via sessionStorage (closing the tab clears it).
Referring to a specific alert
Each alert row has a clickable #ID in the leftmost column (e.g. #285). Click the ID to:
- Update the URL to
/alerts.html?alert_id=285(no page reload — useshistory.pushState) - Expand that row's inline explain pane
- Copy the deeplink URL to your clipboard (a toast confirms)
Paste the URL into chat / email / a ticket — anyone with access to the Alert Center will land on that exact alert with the explain pane already open. The deeplink also clears the status filter so the alert is visible regardless of its current state (open / acknowledged / resolved).
Want to filter the table to a single alert? Type the ID number in the small # id input on the filter bar and press Enter. The page narrows to that one row.
Pin filter
Click the 📌 button in the filter bar to pin your current filter selections. They will persist across page reloads in the same tab — useful for parking a "show me only critical, last 24h, customer X" view while you switch to another page and come back. Pinning matches the existing pattern on the Assets and Investigate pages: pin survives navigation within the tab, dies when you close the tab. Click the Clear button to unpin and reset filters.
Sort columns
Most column headers are clickable. The default sort is Created descending (newest first). Click any sortable header (#, Severity, Category, Title, Asset, Customer, Created, Status) to re-sort by that column descending; click the same header again to toggle ascending. The active column shows ▼ (descending) or ▲ (ascending); inactive columns show a faint ↕. Sort preference persists for the tab via sessionStorage and is applied server-side so pagination stays correct.
Alerts Admin
The Alerts Admin page (/alerts-admin.html) is the rule-engine configuration surface for the Alert Center. It is admin-only by default; administrators may grant per-group access via Settings > Groups. Write actions (create/edit/delete rules, channels, maintenance windows, globals) remain admin-only regardless of group grant.
Five tabs
- Rules — list/create/edit/delete alert rules across all 5 rule types (status, threshold, os_event, ingest, custom with 9 check-types including AI-analysis). Scoped by customer.
- Channels — notification destinations (email SMTP / Telegram Bot API / webhook URL). Secrets are encrypted at rest (AES-GCM). Per-customer scope via junction table. Message templates support
{{...}}variables including{{phase_label}},{{alert_id}},{{alert_severity}},{{rule_name}},{{asset_name}},{{asset_ip}},{{customer_name}},{{category}},{{triggered_by}}(what initiated the alert — the rule, or availability monitoring) and{{asset_type}}. The default templates already include them. - Maintenance Windows — scheduled alert suppression (per-asset / per-customer / global; optional category filter). During an active window, matching events log to
action_logwithout firing. - Globals — master enable, storm cap (default 100/min/rule), retention days, notifications kill-switch, AI-alert settings (local model, external-AI allow, daily token budget).
- Audit — recent rule engine events (
notify_sent/notify_failed/rule_suppressed/action_deferred) plusoct-alert-workerheartbeat + queue depth.
Maintenance Windows
Scheduled, time-bounded alert suppression. While a window is active, any rule firing that matches its scope is logged to action_log as rule_suppressed_by_maintenance and no row is inserted into alerts — alerts don't backfill when the window ends.
Scope selection (all three knobs stack — leave all empty for global):
- Customer — the window suppresses alerts whose asset belongs to this customer. Leave empty to ignore customer scope.
- Asset IDs (comma-separated integers) — the window suppresses alerts only on these specific assets. Takes precedence over customer scope.
- Suppress categories — when "Suppress all" is OFF, list the rule
categoryvalues to suppress (e.g.availability, policy). Rules in other categories still fire.
The State column shows whether a window is currently active, upcoming, or past. Upcoming and past windows can be edited freely; editing an active window's end_at in the past ends it immediately.
Asset filter (rule scoping)
Every rule (any rule_type) carries an optional Asset filter that narrows which assets the rule applies to before any per-customer scope or per-asset override is consulted. Two independent knobs (both optional, stacked with AND):
- Asset type — only assets of this type (computer / user / switch / firewall / printer). Leave empty for any type.
- Attribute filter — pick an attribute key from the dropdown (sourced from Settings > Attributes), set Incl/Excl mode, type a substring to match the value (case-insensitive). Leave the key empty to disable. Same shape as the scheduler-task target query attribute filter — the operator UX is identical between the two pages.
The filter is stored as keys on alert_rules.target_query: type, attr_key, attr_value, attr_mode. It composes with all other axes (per-customer rule scope, per-asset overrides, deduplication, maintenance windows, flap detection, alert dependencies, action chains). Use Preview affected assets inside the rule modal to see exactly which assets the filter selects before saving.
Rule–asset coverage preview
Two complementary lookups answer the question "which rules touch which assets?":
- Lookup by asset (top of the Rules tab): type an asset name or IP, pick from the dropdown, and the list below shows every enabled rule that would fire on that asset — with a per-row match reason (e.g. "customer scope + has attribute
disk_free_gb"). Click Edit to jump straight into the rule modal. - Preview affected assets (button inside the rule edit modal, next to Save): before saving a new or edited rule, click it to see up to 20 assets that match — names, IPs, customer, match reason. If more than 20 match, the panel says so and points you back to Lookup by asset for targeted inspection. Works for both saved rules (
rule_id) and unsaved drafts (rule_draft).
A soft badge on a row means the match depends on runtime conditions the planner can't pre-compute — typically os_event rules (fire only when a matching event arrives) or custom rules with target_query.scheduled_task_id (asset inclusion depends on that scheduled task's own scope). Treat soft matches as "could apply" rather than "will apply."
Configuring a Telegram notification channel
Send Octotor alerts to a Telegram channel end-to-end. Steps 1–4 happen in Telegram / a browser; steps 5–8 happen in Octotor. One bot can serve many channels, and an existing bot can be reused.
| # | Step | Where | What you do |
|---|---|---|---|
| 1 | Create a bot | Telegram → @BotFather | Send /newbot, give a name + a username ending in bot. BotFather returns a bot token like 123456:ABC-DEF… — copy it. |
| 2 | Create the channel | Telegram | Menu → New Channel, name it (Private is fine). A group works too. |
| 3 | Add the bot as admin | Telegram | Channel name → Administrators → Add Admin → pick your bot → enable Post Messages. A bot can only post to a channel it administers. |
| 4 | Find the chat ID | Browser | Post any message in the channel, then open https://api.telegram.org/bot<TOKEN>/getUpdates. In the JSON find "chat":{"id":-100…} — that -100… number is the chat ID. (Public channel? use @channelname directly.) |
| 5 | Create the channel record | Octotor → Alerts Admin → Channels tab | Click + New Channel and fill the form (below). |
| 6 | (Optional) scope to a customer | Channels tab → Customers | Empty = global (all customers). Select customers to restrict. |
| 7 | Test send | Channels tab → Test send | A test message should land in Telegram within seconds; failures show the reason inline. |
| 8 | Attach to a rule | Rules tab → Edit a rule | In Notify channels type the channel name (comma-separate multiple, e.g. ops-email, oncall-telegram). |
The + New Channel form fields:
| Field | Value |
|---|---|
| Name | A short handle the rules reference, e.g. oncall-telegram |
| Type | telegram |
| Enabled | leave checked |
| Bot token | paste the token from step 1 |
| Chat ID | the -100… number (or @channelname) from step 4 |
| Parse mode | leave HTML (default) |
The token is encrypted at rest (AES-GCM) and never returned on read — when you edit the channel later, the field shows "(set — leave empty to keep)".
The token and chat ID below are fabricated placeholders — use the real values BotFather and getUpdates give you.
- @BotFather →
/newbot→ nameOctotor Alerts, usernameacme_octotor_bot→ token<BOT_TOKEN>(looks like111111111:AA…example…). - New private channel
ACME On-call; addacme_octotor_botas admin with Post Messages on. - Post "hi" in the channel, open
…/bot<BOT_TOKEN>/getUpdates→"chat":{"id":<CHAT_ID>}(a-100…number). - Alerts Admin → Channels → + New Channel: Name
oncall-telegram, Typetelegram, Bot token<BOT_TOKEN>, Chat ID<CHAT_ID>, Parse modeHTML→ Save. - Click Test send → "🔔 Test message from Octotor" appears in
ACME On-call. - Rules tab → edit the Host offline rule → Notify channels =
oncall-telegram→ Save.
ACME On-call Telegram channel, and auto-resolves with a ✅ message when the host returns.
{{…}} variables ({{alert_severity}}, {{rule_name}}, {{asset_name}}, {{asset_ip}}, {{customer_name}}, {{triggered_by}}, {{asset_type}}, …) are listed under Channels above.Goose Agent
Goose is an AI-powered IT operations agent that can manage assets, run scripts, investigate events, and execute scheduled recipes — all through natural language chat.
How It Works
Goose runs on the Octotor server and communicates via the MCP (Model Context Protocol). It has access to 43 tools that map to the Octotor REST API:
| Category | Tools | What they do |
|---|---|---|
| Assets | get_asset, list_assets, create_asset, update_asset, search_assets_by_attribute, ping_asset, get_user_link_suggestions | View, manage, and reach IT assets; suggest person→computer links from each machine's primary user |
| Jobs | run_script, run_command, get_jobs, get_job_output, wait_for_job | Execute scripts/commands on assets via SSH or WinRM |
| Batch Jobs | run_script_batch, wait_for_jobs, get_job_summaries | Run scripts on multiple assets at once, wait for all jobs to complete, and get a summary of results |
| Events | get_events, get_attribute_history | Query the unified events timeline; query attribute change history — who/what changed an asset attribute and when, including removals shown as "(cleared)" |
| Scheduler | get_scheduler_tasks, create_task, toggle_task, get_task_history | Manage scheduled tasks and inspect their run history |
| System | get_system_status, get_license, get_credentials, get_customers, list_users, list_scripts, get_update_status | System health, license state (tier / seat usage / expiry / feature limits), configuration, user directory, toolkit inventory, and software update status (current vs latest published version, last check result) |
| Identity | get_identity, get_identity_history | Resolve a person by name/email/UPN to their directory accounts (OU, last logon, group membership, account state); inspect identity-verification event history for an asset |
| Runbooks | list_runbooks, read_runbook | Read operational procedures from /opt/octopus/runbooks/ |
| SNMP | get_snmp_devices, get_switch_ports | List monitored switches and read a switch's port map (MAC/IP per port, link speed, effective status) |
| Backup | get_backup_state, get_backup_sessions | Backup state of protected computers (last success, last result, overdue, days without a successful backup) and the Veeam job run history of a backup server or one computer |
| Alerts | get_alerts, get_alert_counts | List alert rules with status and read open/auto-resolved alert counts |
| Check Point | get_firewall, list_jump_hosts, list_recipes, run_recipe, run_checkpoint_sync | Inspect Check Point firewalls and jump hosts, list and run CLI recipes, and trigger an account sync |
api/services/tool-definitions.js. If this table drifts from that file, api/services/tool-definitions.js is the source of truth.Navigation Safety
In-flight Goose requests survive page navigation. If you start a Goose chat and navigate to another page before the reply arrives, the pending request is persisted to sessionStorage; when you return to the Goose page the reply is re-attached automatically — no lost answers. This applies to both autonomous responses and those held in the Confirmation-Mode pending queue.
Chat Interface
The Goose page provides a chat interface where admins can type natural language requests:
- "Check disk space on all linux servers" — Goose runs collect-info on matching assets
- "What failed this week?" — Goose investigates the events timeline
- "Create a scheduled task to run backup.sh every night at 2am" — Goose creates the task
Confirmation Modes
Configured in Settings > AI Configuration > Goose Agent:
| Mode | Behavior |
|---|---|
| Autonomous | Goose executes all actions without asking |
| Confirm Writes | Read operations are automatic. Write operations (run script, create asset, etc.) require admin approval via the Pending Actions panel |
| Confirm All | Every action requires approval |
Pending Actions
When confirmation mode is active, Goose's write operations appear as pending actions on the Goose page and dashboard. Admins can approve or reject each action before it executes.
Goose Recipes (Scheduler)
Scheduled tasks can use type "Goose Recipe" instead of a script. The recipe is natural language text that Goose executes on the cron schedule:
Check disk usage on all linux assets for customer TRIPLEOR. If any disk is below 10% free, run linux/disk-cleanup.sh. Log results to action_log.
Recipes can reference toolkit scripts by name — Goose knows what's available.
Batch Tools
Goose can run scripts across multiple assets in a single operation using batch tools:
| Tool | Purpose |
|---|---|
| run_script_batch | Execute a script on multiple assets at once. Accepts a list of asset IDs, a script path, and optional credential. Returns a list of job IDs for tracking |
| wait_for_jobs | Wait for a list of jobs to complete. Polls until all jobs reach a terminal state (done, failed, cancelled) or a timeout is reached |
| get_job_summaries | Retrieve a compact summary of multiple jobs — status, exit code, asset name, and truncated output for each job. Useful for reviewing batch results at a glance |
Firewalls & CLI appliances
Goose can also work with Check Point / CLI-appliance firewalls and their jump hosts:
- Ask about a firewall's inventory — "what interfaces / VLANs / VPN tunnels / DHCP leases does the firewall have", "is 2FA required on the VPN", "what model and version is it". Goose reads the collected inventory (interfaces, site-to-site tunnels, DHCP leases, remote-access posture, linked account counts).
- Query synced accounts — a firewall's local user and host objects sync into Assets as accounts (like Active Directory / Microsoft 365); ask about them the same way you ask about any account.
- List & run diagnostic actions — Goose can list the appliance recipes available and run a read/diagnostic one (e.g. show VPN status, list DHCP) for you; it tunnels through the jump host automatically. Destructive actions (e.g. resetting a VPN tunnel) are never run from chat — Goose will point you to the Run page, where the action password is collected.
- Trigger an account sync and see the outcome in the events timeline.
Security
- Goose authenticates to the API via Bearer token — same permission boundaries as any API consumer
- Customer scoping, group credential access, and token scopes all apply
- All Goose actions are logged to the audit trail as
operator: "token:goose-agent" - Goose cannot see credential passwords (always masked)
- Access controlled by group permissions — operators can access Goose if their group includes the 'goose' page
Permissions
| Role | Goose Access |
|---|---|
| Admin | Full access — chat, approve/reject actions, configure |
| Operator | No access (unless group includes 'goose' page) |
| Viewer | No access |
Dependencies
oct-goosecontainer running — it runs the agent loop and calls the API under the Goose bearer token.- A reachable model — local
oct-litellm/oct-ollama, or an allowed external LLM; AI must be enabled in Settings > AI Configuration. - Data to reason over — Goose answers from assets, events, jobs and related tables, so it's most useful once collectors and activity have populated them.
- Page access — admin, or a group that includes the
goosepage.
Security & Action Passwords
Octotor provides a layered security system that protects sensitive operations with action passwords and optional TOTP verification. These controls prevent unauthorized changes even if an admin session is compromised.
Action Password System
Action passwords are a separate credential plane from login passwords. When configured, sensitive operations require entering the action password before they can proceed.
| Level | What it protects | Default |
|---|---|---|
| Master password | All operations below (unless overridden) | Not set |
| Per-action passwords | Individual operations (override master) | Inherit from master |
Setting the master action password
- Go to Settings > Security (admin only).
- In Master Action Password, enter a password and confirm it.
- Click Set. From now on every protected operation (table below) prompts for this password before it runs.
- (Optional) enable Require TOTP with every action prompt to add a second factor — first enrol TOTP for at least one admin (see the lockout rail below).
Configuring a per-action password
- In Settings > Security, find the operation in the Per-action list.
- Switch its mode from Inherit to Custom.
- Type the password for that specific action and click its Set button.
- That operation now requires its own password; everything still on Inherit keeps using the master.
- Settings > Security > set the Master Action Password to
Winter-Ops-2026!→ Set. All 13 protected operations now inherit it. - Find Create/modify scheduled tasks (
action_password_scheduler_create) → mode Custom → passwordoncall-sched-42→ Set. Repeat for Enable/disable and Run scheduled tasks manually. - Share
oncall-sched-42with the on-call team; keep the masterWinter-Ops-2026!with the senior admin only.
oncall-sched-42, but any attempt to open Access security settings or run a high-risk script still prompts for the master password they don't have — so scheduler work is delegated without handing over the keys to everything.
Protected Operations
| # | Action | Setting Key |
|---|---|---|
| 1 | Import scripts | action_password_script_import |
| 2 | Modify scripts | action_password_script_modify |
| 3 | Enable/disable scripts | action_password_script_enable |
| 4 | Delete scripts | action_password_script_delete |
| 5 | Move scripts between folders | action_password_script_move |
| 6 | Execute high-risk scripts | action_password_execution_high |
| 7 | Execute medium-risk scripts | action_password_execution_medium |
| 8 | Run ad-hoc commands | action_password_adhoc_command |
| 9 | Create/modify scheduled tasks | action_password_scheduler_create |
| 10 | Enable/disable scheduled tasks | action_password_scheduler_enable |
| 11 | Run scheduled tasks manually | action_password_scheduler_run_now |
| 12 | Downgrade script risk level | action_password_risk_downgrade |
| 13 | Access security settings | action_password_settings_security |
Per-Action Modes
| Mode | Behavior |
|---|---|
| Inherit | Uses the master password (default for all actions) |
| Custom | Uses a different password for this specific action |
TOTP Enforcement
When Require TOTP with every action prompt is enabled (Settings > Security), every action password prompt also requires a valid TOTP code. This provides two-factor protection: something you know (password) + something you have (authenticator app).
Rate Limiting & Lockout
| Protection | Limit | Effect |
|---|---|---|
| Rate limit | 5 attempts per minute per IP | HTTP 429 — try again after the window expires |
| Lockout | 10 consecutive failures | HTTP 423 — account locked, requires admin reset or 60-second cooldown |
Security Page Gate
The Security section in Settings is protected by a gate. When a master action password is configured, you must enter it (and optionally TOTP) before the security settings become visible. This prevents casual browsing of security configuration.
Changing the Master Password
When a master password is already configured, the Security page shows:
- Change Password — enter current password + new password
- Remove Password — enter current password to disable action password protection entirely
Script Risk Classification
Every script in the Toolkit has a risk level that determines the action password requirements when executing it.
| Level | Badge | Meaning | Action password |
|---|---|---|---|
| High | HIGH | Destructive or privileged operations (disk wipe, user management, service restart) | Uses execution_high password |
| Medium | MED | System modifications (package install, config change, file write) | Uses execution_medium password |
| Low | LOW | Read-only or informational (disk check, status query, log review) | No password required |
Risk levels are assigned automatically by AI validation when a script is saved, and can be adjusted manually by admins. Downgrading a risk level requires the risk_downgrade action password.
Content Hashing
Every script has a SHA-256 content hash that is recalculated when the script is saved. This hash is stored in the database and displayed in the Toolkit detail panel, allowing admins to verify script integrity.
Reset the Octotor admin login password
Use this when nobody can sign in as an administrator — the password was lost, or the only admin account is locked out. It is a host-level recovery procedure: it runs on the server that Octotor is installed on and requires sudo (or docker-group) access there. Anyone who can run it already controls the machine, so it grants no privilege they did not have; guard shell access to the host accordingly. If any administrator can still sign in, do not use this procedure — set the password from Settings ▸ Users & Access instead. The host-level route exists for the case where no administrator session is available, which the web interface cannot resolve by design.
Passwords are stored only as bcrypt hashes, so the old one cannot be read back — it can only be replaced. The procedure below never puts your new password into SQL: it is hashed first, and only the hash reaches the database.
- Sign in to the Octotor server over SSH as a user with
sudo. - Read the database role and name from the container so the commands below are correct even if this install did not use the defaults.
DBU=$(sudo docker exec oct-postgres printenv POSTGRES_USER); DBN=$(sudo docker exec oct-postgres printenv POSTGRES_DB)— on a default install both printoctopus. - Confirm the account name.
sudo docker exec oct-postgres psql -U "$DBU" -d "$DBN" -c "SELECT id, username, role, active FROM users ORDER BY id"— pick the administrator you want to recover. If the account showsactive = f, addactive=trueto the update in step 5. - Hash the new password.
H=$(sudo docker exec oct-api node -e 'console.log(require("bcrypt").hashSync(process.argv[1],12))' 'NewPasswordHere') - Apply it and force a change at next sign-in.
sudo docker exec oct-postgres psql -U "$DBU" -d "$DBN" -c "UPDATE users SET password_hash='$H', force_password_change=true WHERE username='admin'"— the command must answerUPDATE 1.UPDATE 0means the username did not match; re-check step 3. - Verify before you leave the shell.
curl -sk -o /dev/null -w '%{http_code}\n' -X POST https://localhost:8443/api/auth/login -H 'Content-Type: application/json' -d '{"username":"admin","password":"NewPasswordHere"}'—200means the reset worked,401means it did not. - Clear your shell history (
history -c) — step 4 leaves the password in it. - Sign in to the web interface as that user. Because force password change was set, Octotor immediately asks for a new password, so the value you typed in step 4 is only a temporary transit password and is never the one you keep.
Worked example. An install reachable at https://192.0.2.26:8443 has one administrator and nobody knows its password. Step 3 returns 1|admin|admin|t. The operator runs step 4 with 'Transit-9f2Kd!', then step 5, which answers UPDATE 1. Step 6 returns 200. The operator opens https://192.0.2.26:8443, signs in as admin with Transit-9f2Kd!, and is taken straight to the change-password screen, where the real password is set. Total time: under a minute.
Notes: substitute your own port if the install does not use 8443. If the container names differ from oct-api / oct-postgres, list them with sudo docker ps first. The reset is recorded in the database change itself but produces no Investigate entry, so note it in your own change log. If TOTP is enrolled for the account you will still be asked for the code after signing in — clear it with UPDATE users SET totp_enabled=false, totp_secret=NULL WHERE username='admin' in the same session if the authenticator is also lost.
Licensing
Every Octotor install — including Community — runs from a signed license file. Without a valid license the system starts in activation mode: nothing collects, no jobs run, and only the activation page is reachable until a license is applied. The License page (linked from Settings, or reached from the banner's Manage →) is where an admin views status, usage, and features, and applies or replaces a license. Licensing applies instantly — no restart.
Activating a new install
- Step 1 — Download the request. On the activation page, click Download license-request.json and send it to your Octotor vendor. It contains your instance ID and a machine fingerprint — the license is bound to this exact install.
- Step 2 — Apply the license. When you receive
license.oct, drop it on the activation page and click Apply license. The signature and machine binding are verified before it is accepted; a bad file is rejected without ever going live. On success the app loads. - Air-gapped? You can also copy
license.octto/opt/octopus/license/over SSH — it is picked up within a minute.
What the License page shows
- Status — tier, who it's issued to, license ID, expiry (with days remaining), and the machine fingerprint. Check now re-verifies immediately.
- Usage — live counts against each cap: seats, customers, M365 tenants, credentials, custom scripts, custom groups, operator users, scheduled tasks. Bars turn red at the limit. View → on Seats opens the exact list of seat-consuming assets.
- Features — which capabilities your license includes (Scheduler, Collectors, Full toolkit, Alert Center, SNMP, M365 and Backup collectors, Goose, …). The list of rows comes from the product itself, so every feature that has a license gate appears here; each row is on unless your license file sets it off. A row marked included by default means your license file was issued before that feature existed — such a key is not in the file, and the product treats it as included.
- Manage — Update license (renew / add seats / change tier), Download request, Redeem unlock code, Download diagnostics, Remove license.
Seats — how they're counted
A seat is one managed object: a user, a computer, or a managed network device (switch, firewall). Accounts (AD/M365/local directory accounts) and groups do not consume seats. This is why the Assets page can show far more rows than your seat count — it folds in accounts, which the seat meter excludes.
Emergency unlock (break-glass)
If an install is locked out — a license expired mid-renewal, or a disaster-recovery restore landed on a new machine so the license no longer matches — your vendor can issue a one-time unlock code. Paste it under Redeem unlock code (on the activation page or the License page). It grants temporary operation (up to 72 hours) at your licensed tier while a proper license is issued. Each code is single-use and bound to this install.
Worked example — renewing before expiry
Your banner reads "Your license expires in 9 days (2026-08-05)." You email your vendor and receive octotor-acme-2027.oct. On the License page you click Update license, choose the file, and click Apply. The page verifies the signature and that it matches this machine, then swaps it in. The Status card now reads Expires 2027-08-05 · in 365 days, the banner is gone, and no service restarted. If the file had been for a different company's install, the update would have been rejected and your current license left untouched.
Settings
Settings is the admin control center. It covers system configuration, user management, security, credentials, and integrations. Admin access only.
Sections
| Section | What you configure |
|---|---|
| Instance | Instance name, default customer, job timeout |
| Customers | Customer registry — add/edit/delete customers. Each asset must belong to a customer |
| Users & Access | Create/edit/clone/delete users, set roles, manage group memberships, assign customer access, TOTP setup |
| Monitoring | Auto-ping settings (write-on-change), live monitor refresh interval, "Mark asset as Unknown after (seconds)" — how stale an asset's last check may be before Assets/Live Monitor display it as Unknown; 0 = automatic (2× the ping interval). Example: with a 60-second ping interval but a check sweep that takes ~2.5 minutes, the automatic 120-second window makes healthy assets flip to Unknown for part of each cycle — setting 300 stops the flapping (display-only, alerting unaffected). Also: TCP monitoring (SSH/RDP/WinRM port checks), identity verification (DNS, SSH gate, WinRM gate, per-OS default gate, require probe, collector check, mismatch behavior, validity TTL) |
| Management Protocols | Global enable/disable per protocol (SSH, WinRM), execution defaults per OS family, SSH config (port, timeout), WinRM config (port, timeout, auth method). See WinRM Remote Management section. |
| Attributes | Define custom asset attribute fields (key, label, type, auto-approve) |
| Credentials | Create/edit/delete SSH and WinRM credentials, set OS defaults, per-customer defaults, sudo toggle, assign customer access. Groups can restrict which credentials operators see |
| Groups | Create custom permission groups, assign pages/scripts/protocols/credentials |
| Security | Master action password, per-action passwords, TOTP enforcement, script signing (coming soon). See the Security help section for details. |
| AI Configuration | LLM status (model name, RAM usage, loaded/unloaded), load/unload model, toggle AI features (script validation, override AI blocks, investigation, conversation logging), Goose agent settings (enable/disable, confirmation mode), Cloud AI Access (enable/disable, provider selection, encrypted-at-rest API key with last-4 preview) |
| API Tokens | Create/revoke Bearer tokens for API and Goose access. Each token has scopes, expiration, IP restriction, rate limit, and activity logging level |
| NetMap | Network address translation — map customer LAN subnets to Tailscale-routed subnets. Add, edit, or delete mappings. |
| Maintenance | Database maintenance — data retention policies, scheduled cleanup, backup freshness monitoring, vacuum, DB state monitoring. See Database Maintenance section. |
API Tokens — creating and using one
Settings > API Tokens issues Bearer tokens for programmatic access to the same API the web UI uses. Each token carries scopes, an expiry, an optional IP allow-list, a rate limit, and a log level. A token acts as the user who created it and is bound by that user's permissions and customer scope — a token can never do more than its owner. (This feature is licensed: if API Tokens is not in your license the Create button is disabled.)
- Create. Settings > API Tokens → + Create Token. Give it a name (e.g.
ci-inventory), pick scopes (e.g. read-onlyassets:read), set an expiry, optionally restrict to an IP. The raw token is shown once — copy it now; it is stored only as a hash and cannot be retrieved again. - Use. Send it as an
Authorization: Bearerheader:curl -H "Authorization: Bearer <your-token>" \ https://your-octotor/api/assets - Verify / revoke. The token list shows last-used time. Delete a row to revoke instantly (the next request with it returns 401).
TOKEN="oct_live_…" # created by an operator scoped to ACME
curl -s -H "Authorization: Bearer $TOKEN" \
"https://your-octotor/api/assets?customer_name=ACME" | jq '.[].name'
The same token used against a customer the owner can't see returns an empty set (scope is enforced server-side), and a write (POST /api/assets) is rejected unless the token's scopes include it.Cloud AI API Key (Anthropic)
Settings > AI Configuration > Cloud AI Access stores the cloud LLM API key encrypted at rest in the database (AES-256-GCM with the instance MASTER_KEY — same scheme as credentials and TOTP secrets). The key is decrypted only when oct-api writes the LiteLLM config file at toggle time, and the LiteLLM container reads it from there at startup. The full key never leaves oct-api: the UI shows only the last four characters once configured.
| Action | What happens |
|---|---|
| Set / Update | Inline password field appears; entering the key and clicking Save prompts for the master action password. On confirm, the key is encrypted and stored in settings.external_llm_api_key_claude_encrypted; the LiteLLM config file is rewritten with the literal key; oct-litellm restarts to pick it up. |
| Delete | Master action password required. The DB row is removed; the LiteLLM config falls back to the legacy EXTERNAL_LLM_API_KEY environment variable (if set in .env) or to no key at all. |
| View | Status row shows Configured: ••••XXXX (last four) or Not set. The full key is never returned by any API endpoint. |
EXTERNAL_LLM_API_KEY from .env as before. Migrating from the .env-only path is an opt-in that brings DB-dump safety and the lifecycle UI (rotate/delete/audit) above the host-filesystem baseline.Attribute Updates Flow
User Setup Flow
Credential Setup Flow
Sudo Support
Credentials can have a Sudo toggle. When enabled, scripts are wrapped in sudo -S bash -c '...' and the credential's password is piped to stdin. This can be overridden per-task in the Scheduler with the Sudo Override setting (force/never/default).
Per-Customer Default Credentials
In Settings > Credentials, you can set a credential as the default for a specific customer + OS family combination. This is useful when different customers have different service accounts.
Effective Permissions
In Settings > Users, click a user to see their Effective Permissions — a summary showing exactly which pages, scripts, credentials, and customers they can access, and which group grants each permission.
CLI Password Reset
If an admin forgets their login password, it can be reset from the host command line:
cd /opt/octopus && ./setup-prod.sh --reset-password
This prompts for a username and new password, then updates the bcrypt hash in the database directly. No login session is required.
To reset the master action password (if locked out):
docker exec oct-postgres psql -U octopus -c "UPDATE settings SET value='' WHERE key='action_password_master';"
SNMP Collector — switch port mapping
The SNMP collector (oct-snmp-collector) polls network gear (switches, routers, firewalls) over SNMP and builds a live picture of which device is on which switch port. It never changes anything on the gear — it only reads standard tables (SNMP GET/WALK, no SET). It is on by default — but it only sends packets once SNMP devices are configured: with an empty device list the collector idles and nothing is polled. Turn the master switch off in Settings > SNMP if you never want SNMP traffic from this box.
What it does
- Reads the switch MAC table — every MAC address the switch has learned, and which port it was learned on.
- Maps computers to ports — when a learned MAC matches a computer asset's
LAN MAC(orWiFi MAC), the collector sets that computer's Switch Port and Switch IP attributes, and creates a Connected to relation to the switch (visible in the Relations tab of both assets). - Flags unknowns — a MAC with no matching asset (and a resolved IP) can be surfaced as a discovery-pending device; MACs it can't resolve are counted, not queued.
Reading the "Switch Port" value
The Switch Port attribute stores the raw port description the switch itself reports (the SNMP ifDescr field). It is deliberately kept verbatim so it matches exactly what you'd see in the switch's own management UI — and because the format is vendor-specific, there is no single "clean" form to normalise to:
| Vendor / model | Example value | How to read it |
|---|---|---|
| HPE OfficeConnect 1820 | 3 Gigabit - Level | Physical port 3, a Gigabit port. - Level is HPE's fixed description text for the port on this model — it carries no per-port meaning (every port reads "N Gigabit - Level"); the actionable part is the leading number. The switch also exposes a bare ifName of just "3" for the same port. |
| Cisco IOS | GigabitEthernet0/3 | Port Gi0/3. |
| Generic | Port 12 / eth12 | Whatever the firmware names the interface. |
Rule of thumb: the leading number is the physical port; the rest is the vendor's speed/description text. If a value looks unfamiliar, compare it against the switch's own web UI or CLI (show interfaces description on Cisco) — the collector stores the same string those show.
The switch port map
Open a switch asset to see its Port Map: one row per active port, the MAC(s) learned there, and the asset each MAC resolves to (or unknown if nothing in inventory matches). A port that has learned many MACs is flagged as a likely uplink/trunk — that's normal for the link to a virtualization host or another switch (every downstream device's MAC appears there), so a trunk full of "unknown" entries is expected, not a fault.
Configuring a switch (on the asset)
SNMP monitoring is configured on the switch asset, exactly like SSH/WinRM on a computer — there is no separate device registry. Open the switch on the Assets page:
- Create an SNMP credential — v2c (a community string, e.g.
public) or v3 (user + auth/priv). Credentials are encrypted at rest under a dedicated key that only the collector can read; the community/keys are never shown back or logged. - On the switch's Credentials tab, link that SNMP credential (the same way you link an SSH or WinRM credential to a computer). The credential carries the SNMP version.
- On the Overview tab's SNMP Monitoring card: tick SNMP monitoring enabled, choose the roles — Walk MAC table (an access switch) and/or Walk ARP table (the VLAN's gateway, which maps MAC → IP) — set the port (default 161), and Save. These are stored as switch attributes.
- Test (poll now) on the same card confirms the collector can reach the switch and reads its system name.
- Turn on the master switch (Settings ▸ SNMP) and (optionally) schedule an SNMP Walk task for periodic polling.
Global settings (Settings > SNMP Collector)
Connection and tuning knobs live under Settings > SNMP Collector: the master enable toggle, default port (161), and the timers — response timeout (per SNMP request), walk deadline (max time for one full table walk), and per-device timeout (max budget per switch per cycle) — plus discovery/event tuning (stability polls, dedup window, caps, MAC-table retention). Poll cadence is not global: how often each switch is polled is set per SNMP Walk task in the Scheduler (schedule-only — the collector never polls on its own timer).
Port status & speed
For each interface the collector reads three standard SNMP dimensions and derives one effective status shown in the Port Map: admin status (ifAdminStatus — is the port enabled?), operational status (ifOperStatus — is the link up?), and spanning-tree state (dot1dStpPortState — is it forwarding, or held blocked by STP?). Speed comes from ifHighSpeed. The effective status is one of: up, down (enabled but no link — e.g. an empty or unplugged port), disabled (admin-shut), blocked (up but STP is holding it), lower-layer-down, absent (no module/SFP), or dormant/testing/unknown. Status is a state, not a fault: an enabled port with nothing plugged in is simply down — it is never flagged as an error just for being down. Some switches don't expose spanning-tree over SNMP — there the status falls back to admin+operational only and never shows blocked.
Port errors are a separate dimension. Whether a port is actually faulting comes from the switch's own error counters (ifInErrors / ifOutErrors), not from up/down state. The Port Map shows a red error count badge on any port that has recorded errors, and the collector flags a port as actively erroring when that counter rises between polls. The switch carries a Ports With Errors attribute (count of ports whose errors rose this poll) — put a threshold Alert rule on it (> 0) to be notified when links start erroring; the alert detail names the offending ports. A change to any port's status or speed, and any port that starts erroring, is written to the event log (Investigate → category snmp_sync). The switch also carries a Ports Down attribute (count of down / lower-layer-down ports) for a "lost ports" threshold alert.
Power over Ethernet. On PoE-capable switches the Port Map shows a per-port PoE badge from the standard POWER-ETHERNET-MIB — delivering (with the negotiated power class), searching, off, or fault. Non-PoE switches simply show no PoE badge.
Vendor differences (why some fields read "unknown")
The collector speaks only standard SNMP MIBs, which keeps it working across vendors without per-model configuration. Two things help it stay accurate on gear from different makers:
- Vendor identification. Each switch reports a standard
sysObjectID; the collector reads it to record the switch's vendor (shown as Vendor (SNMP) in the Attributes ▸ Network group). This is only a hint — every reading is still confirmed from the actual data, never assumed from the label. - VLAN learning mode. Most switches learn MAC addresses per VLAN (IVL), so the forwarding table tells us each device's VLAN. Some (e.g. Alcatel OmniSwitch) use Shared VLAN Learning (SVL), where the forwarding table carries no per-device VLAN at all. The collector detects this and shows VLAN Learning (SNMP) =
IVLorSVL. On an SVL switch the per-device VLAN is left blank rather than shown as a wrong value — a blank VLAN there means "the switch doesn't expose it by standard means", not a fault.
Wherever a vendor exposes a value only through its own private MIB (for example the per-device VLAN on an SVL switch, or wireless clients on an access point), Octotor reports it as unknown rather than guessing. A blank field is deliberate — it means the standard tables didn't carry it.
Uplink / trunk ports
A switch's forwarding table tells you which port a device is reachable through, not where it's physically plugged in. An uplink/trunk port that connects to another switch therefore lists every downstream device's MAC — so without special handling all of them would be wrongly mapped to that one port. Octotor treats uplink ports as transit: their devices are still shown in the Port Map (labelled "via uplink (transit)") but are not assigned a switch-port or a "connected to" relation, and never raise a new-device discovery on that switch.
Uplinks are detected two ways: (1) mark them per switch — enter the port numbers in Uplink ports on the switch's SNMP Monitoring card (e.g. 24,53); and (2) auto — any port with more learned MACs than Settings ▸ SNMP Collector ▸ Uplink auto-threshold (default 3, 0 = off). Marking is authoritative; the threshold catches the obvious ones you didn't mark. (Automatic neighbour detection via LLDP is planned.)
To go the other way, use Access ports on the same card: any port number you list there is forced to access and its devices are mapped normally — even if the auto-threshold would otherwise flag it as an uplink. Admin marking wins: Access ports overrides both the threshold and the Uplink ports list, so a port listed as access is never treated as transit.
Speed alerts (sub-gigabit / speed changes)
To alert on slow links, set Min port speed (Mbps) under Settings ▸ SNMP Collector (default 1000 = 1 Gbps). Every poll the collector counts up-ports below that floor into the switch's Ports Below Speed Floor attribute — create a threshold Alert rule on it (> 0) to be notified when any port negotiates below 1 Gbps (e.g. a bad cable dropping a gigabit link to 100 Mbps). To alert on any speed change, the switch also carries a Ports Speed-Changed last poll attribute (count of ports whose speed differed from the previous poll; it resets to 0 on the next clean poll) — a threshold rule > 0 fires on a change and auto-resolves. To create either: Alerts ▸ + New Rule ▸ type = threshold ▸ pick the attribute ▸ operator > ▸ value 0 ▸ choose a notification channel.
New-device alerts
When the collector sees a stable, IP-resolved MAC that isn't a known asset, it queues it for discovery and writes a device_discovered event (Investigate → snmp_sync). The switch also carries a Pending Devices attribute (count of not-yet-approved devices found via that switch) — put a threshold Alert rule on it (e.g. > 0) to be notified when unknown gear appears on the network.
Switch & device network details
Each SNMP poll now also records the switch's own Switch MAC, Subnet Mask and Default Gateway (Overview → Attributes). For every device the collector maps to a switch port it records the Connected Switch IP (the mgmt IP of the switch it's plugged into) and the Switch Port Speed (the port's negotiated speed) alongside the existing Switch Port / VLAN. Windows and Linux collectors also fill each computer's Default Gateway, Subnet Mask and DNS Servers ("ipconfig /all"-style). Collector-written attributes carry the AUTO provenance badge (not MANUAL).
Switch-to-switch topology
When two managed switches are linked, the collector records a Connected to relation between them (Overview → Relations), so you can see which switch uplinks to which. It's detected from LLDP neighbours when the switches expose it, and falls back to matching a switch's own MAC in another switch's forwarding table. (This complements uplink/access marking — it identifies the neighbour, not just that a port is a trunk.)
Finding a port on the Port Map
Use the search box on a switch's Port Map tab to filter rows by port number, port name, connected asset name, MAC or IP — handy on a busy 48-port switch. Speed/uplink labels and the transit markers are preserved while filtering.
Scheduled SNMP-Walk history
A scheduled SNMP Walk task now shows its runs in the task History panel (triggered / nothing-to-poll / skipped / rejected), even though an SNMP poll doesn't create a job the way a script task does.
Roles — why two kinds
A plain L2 switch knows MAC → port but not IP addresses. To resolve MAC → IP (needed to auto-assign an unknown device to a customer by subnet), the collector reads the ARP table of the VLAN's L3 gateway (a router, L3 switch, or firewall). This is standard, routed SNMP — the collector works across VLANs and remote sites; it never needs to sit on the same network segment as the device.
Ask the AI assistant
The Goose AI assistant can query SNMP data directly through two read-only tools: get_snmp_devices (list the monitored switches and their poll state) and get_switch_ports (read a switch's full port map — MAC/IP per port, link speed, effective status). Ask e.g. "which ports are down on SW-CORE-01?" or "what's plugged into the core switch?"
Security
- Read-only: the collector issues SNMP GET/WALK only — it has no code path that can write to (reconfigure) a switch. Use read-only community strings; prefer SNMPv3 with authPriv where the gear supports it (v2c sends the community in clear text on the LAN).
- Key separation: the collector holds only its own SNMP key, never the master encryption key — a compromised collector cannot decrypt other Octotor credentials.
- Master switch on by default (idles until devices are configured; one click in Settings > SNMP turns it off) and egress restricted to SNMP (UDP 161) + the database.
Licence
The SNMP collector is a Pro-tier feature.
Backup Collector — Veeam backup state on your assets
The backup collector reads the job history of a Veeam Backup & Replication server and writes the result onto the computers that server protects. On each protected computer you see when its last successful backup ran and how the last run ended. On the backup server you see how many jobs succeeded, ended with warnings, failed, or are overdue, and how many failed recently. Six alert rules fire when a backup fails (now, or at any time in the last 24 hours), ends with a warning, or is late. The collector script windows/veeam-vbr-collect.ps1 only reads from Veeam: it never starts, stops, edits, or deletes a backup job. This feature needs a Pro or Enterprise license.
What the collector writes
On every computer it matched to a backed-up item (the BACKUP group in the Attributes tab):
| Attribute | Meaning |
|---|---|
| Backup — Last Successful Run | The newest restore point Veeam holds for this computer, or the end time of the newest job run that ended with Success. This value is never cleared. |
| Backup — Last Result | How the newest job run ended: Success, Warning, Failed, or Not protected (the computer is no longer in any backup job on that server). |
| Backup Job Name | The Veeam job or jobs that include this computer. |
| Backup Server | The Veeam server that reported it. |
| Backup Overdue | Yes when the last successful run is older than the job's own schedule allows (schedule interval times 1.25, or 30 hours when the schedule cannot be read). |
| Backup Copy — Last Successful Run | The newest successful backup copy run, when a copy job exists. |
| Backup — Last Warning or Error Message | The last warning or error lines of the newest run that ended with Warning or Failed. Empty after a Success. |
On the backup server itself: Backup Product, Backup Data — Last Collected, the job counts (Backup Jobs — Total / Successful / With Warnings / Failed / No Last Result / Disabled / Overdue) with a matching list of job names for each count, Backup Jobs — Failed Recently (with its list of names) for every job that had a failed run in the last 24 hours, or since the previous collection when that is longer ago, even if that job is idle or green again by now, and Backed-Up Items With No Asset for items Veeam protects that Octotor could not match to an asset.
Set it up step by step
- Mark the backup server. Open Assets, open the Veeam server, go to the Attributes tab, and set Veeam Backup Server to Yes. The collector task targets this attribute, so only servers you mark are ever queried.
- Give Octotor a Windows credential for that server. On the same asset, open the Credentials tab and link a Windows account. The account must be allowed to load the Veeam PowerShell module; the Veeam role Backup Viewer is enough, because the script only reads. Veeam 13 or newer: the backup server must also have PowerShell 7 installed (Microsoft's free download,
https://aka.ms/powershell), because Veeam 13 provides its PowerShell module for PowerShell 7 only. The collector checks the installed Veeam version, runs its Veeam part in PowerShell 7 when the version is 13 or newer, and tells you in plain words when PowerShell 7 is missing. Veeam 12 and older need nothing extra. - Schedule the collector. Open Scheduler and click + New task. Script:
windows/veeam-vbr-collect.ps1. Target: an attribute filter Veeam Backup Server equals true. Schedule: once a day after the backup window ends, for example30 6 * * *(06:30 every day). In the Execution section set Timeout (sec) to 240: the collector reads the whole job history and a server with many jobs needs more than the 30-second SSH default (a cut-off run showsSSH connection timed out after 30 sand names the field to raise). The same applies to a server reached over WinRM: a run started from the Run page uses the Timeout field of that page (or the WinRM default of 180 seconds when the field is empty), so give a manual run at least 240 seconds too. A server with a long job history needs more: on a Veeam 13 server with 8 jobs and about 1,500 recorded runs the collector took 9½ minutes, so set Timeout (sec) to 900 when the task covers such servers (a cut-off run showstimed out after N sand names the field to raise). Save the task. - Check the first run. After the task has run, open the backup server asset. The Backup jobs tab lists every job run and every backed-up item with its result. The Attributes tab shows the BACKUP group with the counts. Open one of the protected computers: its BACKUP group now carries its own values.
- Alerts. Six rules are seeded and enabled under Alerts: Backup job failed on server (critical), Backup job failed recently on server (critical — fires for a job that failed in the last 24 hours, or since the previous collection when that is longer ago, even when that job is idle or green again by the time the collector runs), Last backup of this computer failed (critical), Backup overdue for this computer (warning), Backup job warning on server (warning), Last backup of this computer ended with a warning (warning). Threshold rules only fire for assets whose Threshold alert switch (asset Overview ▸ Alerts card) is on; by default the collector switches it on for every computer it matches and for the backup server (see the setting below).
Settings
- Settings ▸ Backup Collector ▸ Switch on threshold alerts for the computers the collector finds — Yes (default) means every collector run turns the Threshold alert switch on for the matched computers and the backup server, and writes each switch-on to the audit trail. No means the collector leaves the per-asset switches alone.
- Settings ▸ Maintenance ▸ Backup job history (days) — how long job sessions stay in the Backup jobs tab (default 90 days).
Worked example
The backup server BK-01 at customer Tripleor runs three Veeam jobs. The file server FS-02 is in the job 02 File servers, which runs every night at 01:00. You marked BK-01 as a Veeam Backup Server, linked its Windows credential, and scheduled the collector for 06:30 daily.
- On 8 September the 01:00 run of 02 File servers ends with Failed because the file server was unreachable.
- At 06:30 the collector runs on BK-01. On FS-02 it writes Backup — Last Result = Failed, Backup — Last Warning or Error Message = "Failed to connect to FS-02: The network path was not found", and leaves Backup — Last Successful Run at 7 September 01:12 (the last good restore point). On BK-01 it writes Backup Jobs — Failed = 1 and Backup Jobs — Failed (names) = "02 File servers".
- The rule Last backup of this computer failed raises a critical alert on FS-02, and Backup job failed on server raises one on BK-01 naming the failed job. The error text itself sits in FS-02's Backup — Last Warning or Error Message attribute. Your notification channels deliver both.
- You open BK-01 ▸ Backup jobs, click Failed, and open the Log of the FS-02 row to read the Veeam log lines. View job output opens the Jobs tab with the full collector output.
- You fix the network issue and re-run the job in Veeam. After the next collector run at 06:30 the next day, FS-02 shows Backup — Last Result = Success and a new Backup — Last Successful Run; the message attribute is emptied; both alerts resolve.
When a run fails, or finishes but lands no backup data
A collector run that cannot read Veeam still ends as a green job (exit code 0) — the reason is inside its output, not in the job status. Open the backup server asset, go to the Jobs tab, and open the collector run; the errors list at the end of its output says what happened. The same message is recorded in Investigate (category backup, "nothing landed"). The messages you can see:
Veeam Backup & Replication 13.x needs PowerShell 7 on the backup server, and PowerShell 7 (pwsh.exe) is not installed there— install PowerShell 7 on that server (Microsoft's installer,https://aka.ms/powershell, default folderC:\Program Files\PowerShell\7), then run the task again. Nothing else changes: the collector finds PowerShell 7 by itself.Veeam PowerShell not available under PowerShell 5.1 ...followed by the error of each attempt (Import-Module Veeam.Backup.PowerShell: ...andAdd-PSSnapin VeeamPSSnapIn: ...) — the Veeam console (which carries the PowerShell module) is not installed on that machine, or the account is not allowed to use it. Check that the credential's account can open the Veeam console on the server.PowerShell 7 (...pwsh.exe) did not return the collector result (exit code N): ...— PowerShell 7 is installed but the Veeam part did not complete; the text after the colon is what PowerShell 7 wrote (its error, or whatever it printed instead of the result). Runpwshon the server as the same account and typeImport-Module Veeam.Backup.PowerShellto see the full message.... needs PowerShell 7, which is installed, but this run could not hand the work to it: ...— the account could not write its temporary script file, or was not allowed to startpwsh.exe(application control or antivirus). The text after the colon names which. Allow it for the collector's account, then run the task again.SSH connection timed out after N s/WinRM connection timed out after N s— the run did not finish inside the time limit named in the message. Raise the task's Timeout (sec) (or the Run page's Timeout for a manual run); a server with a long job history can need several minutes.- Status identity mismatch before any output — the pre-run identity check did not get an answer over the protocol the task forces. Set the task's Protocol to Auto so each server is reached the way its asset is configured (SSH or WinRM).
Ask the AI assistant
The Goose AI assistant reads the same data through two read-only tools: get_backup_state (which computers are protected, their last result, and how many days since a successful backup) and get_backup_sessions (the job run history of a backup server or of one computer, with the log lines of failed items). Ask for example "Which computers at Tripleor have no successful backup in the last 2 days?" or "Why did the backup of FS-02 fail last night?"
How computers are matched
Each backed-up item is matched by name to a computer asset of the same customer as the backup server: the item name, the DNS name Veeam recorded for the guest on its newest restore point, and the short form of either. The DNS name is what makes a virtual machine match when its name in the hypervisor differs from its host name (for example a machine named FS-02_replica in Hyper-V whose Windows host name is FS-02: it lands on the asset FS-02). When two Veeam items map to the same asset, the newest backup wins and the job names are combined. If two assets could match the same item, nothing is written to either of them and the item is listed under Backed-Up Items With No Asset with the note "(ambiguous)". Items with no matching asset are listed there too, so you can create or rename the asset and the next run will match it.
Reading the Backup jobs tab
Each row is one job run, or one backed-up item inside a run: the job name on the first line and Backed-up item: name under it. On a computer's own Backup jobs tab the item line is left out, because the item is that computer; a backup job and its backup copy job appear as two rows per day, told apart by the Type column. The result chip shows the item's own result when it has one, otherwise the job's. Log expands the last log lines Veeam recorded for a failed or warning item. The filter chips re-read the rows from the server. The tab is hidden on installs without a Pro or Enterprise license and on switches, persons, and account assets.
M365 Connectors
M365 Connectors sync Microsoft 365 / Entra objects into Octotor straight from the platform — no Windows box or on-prem agent. Phase 1 collects users, license assignment, MFA registration status, and Entra-joined devices; they land through the same discovery pipeline as AD collection (auto-approve or pending queue per the discovery_auto_approve setting). One connector per customer.
Master switch
Settings > M365 Connectors > Collector master switch (default Disabled). While disabled the collector container makes no outbound connections at all — connectors stay stored but inert, scheduled syncs skip, and Test connection refuses to run. Certificate generation still works while disabled (it is local-only crypto). Enable the switch only when you are ready for Octotor to talk to Microsoft's endpoints (login.microsoftonline.com and graph.microsoft.com — nothing else).
How authentication works
Octotor uses certificate-based app-only Graph access (Microsoft's recommended pattern for unattended services). Octotor generates an RSA-3072 keypair per connector; the private key never leaves Octotor and is stored encrypted under a dedicated key that only the collector container holds. You upload the public certificate to your Entra app registration. At sync time the collector signs a short-lived JWT with the private key and exchanges it for a Graph token — no client secrets, nothing to rotate in two places.
Setting up a connector — step by step
One-time per tenant, ~10 minutes. Steps 1–2 and 5 happen in the Microsoft Entra portal and require a Global Administrator of the customer tenant; steps 3–4 and 6 happen in Octotor. (This walkthrough was validated live against a real tenant on 2026-07-03.)
Part 1 — register the application (Entra portal)
- Sign in to
entra.microsoft.comwith a Global Administrator account of the tenant you are connecting. - Go to Identity > Applications > App registrations > + New registration.
- Name: e.g.
Octotor Collector(any name works). Supported account types: "Accounts in this organizational directory only" (single tenant). Redirect URI: leave empty. Click Register. - On the app's Overview page, copy two values for step 4: Directory (tenant) ID and Application (client) ID. Neither is a secret — they are identifiers.
Part 2 — grant read-only Graph permissions
- In the app: API permissions > + Add a permission > Microsoft Graph > Application permissions (NOT Delegated).
- Tick the base set:
User.Read.All,Organization.Read.All,Device.Read.All. Then the optional set — each unlocks extra data and degrades gracefully (sync still works, the sync summary notes what's missing):AuditLog.Read.All— MFA Status/Methods, per-user last sign-in, and the sign-in events feed (Part 7; sign-ins additionally require an Entra ID P1/P2 tenant)Reports.Read.All— mailbox size (usage reports)GroupMember.Read.All— group membership (all group types, Teams tagged)RoleManagement.Read.Directory— activated directory roles per user (Global Administrator, …)MailboxSettings.Read— mail-forwarding visibility: user-created inbox rules that forward/redirect mail (classic BEC indicator). Detects rule-based forwarding only — the admin-set "Email forwarding" mailbox property is a separate Exchange API and is not covered.
- Click "Grant admin consent for <tenant>" and confirm — the Status column must show green checks on every row. This is the step that requires the Global Admin role; without consent, Test fails with a consent error.
Part 3 — create the connector and its certificate (Octotor)
- Open Settings > M365 Connectors > Add connector: pick the customer this tenant belongs to, paste the Tenant ID and Application (client) ID from Part 1, click Create + generate certificate.
- The CERT pill turns ready within a few seconds (Octotor generates an RSA-3072 keypair; the private key is stored encrypted and never leaves the collector). If the pill stays pending (typically: the connector was created before the collector container was started) or shows error, click the row's Regenerate button to re-request key generation — the collector also retries all stuck-pending connectors automatically on startup. Example: on a fresh install where
COMPOSE_PROFILES=m365was set after the connector was created, the pill stays pending; start the collector container and it turns ready on boot without any clicks. - Click Cert on the row — it downloads
octotor-m365-connector-<id>.cer(the public half only; there is no private-key download).
Part 4 — upload the certificate to Entra
- In the Entra app: Certificates & secrets > Certificates tab > Upload certificate, pick the downloaded
.cerfile, add. - Sanity check: the thumbprint Entra now shows must equal the THUMBPRINT on the connector row in Octotor. If they differ you uploaded the wrong file.
Part 5 — test and sync
- In Octotor: set the Collector master switch to Enabled and Save (until now the collector has made no outbound connection at all).
- Click Test on the connector row. Expected: the TEST pill goes pending → ok within a few seconds; hovering the row shows your organization name (Octotor acquired a token AND read
/v1.0/organization— proving both the cert upload and the admin consent). - Sync runs land discovered users and Entra devices in the Assets > Discovery panel (or create them directly when Auto-approve discovered identities is on). Scheduled/recurring sync is configured in the Scheduler ("M365 Sync" task type).
- On a synced device, the Entra values (OS, compliance, join type, account state, last seen, MDM enrollment, owner) live on a Microsoft 365 device account linked to the computer — exactly like an AD machine account, and like user accounts. The computer's Attributes tab shows the account as a "Microsoft 365 · read-only · collected" card; deleting the account asset removes the collected Entra data. A hybrid-joined machine carries both its AD machine account and its M365 device account on the same computer. The registered owner also links the device to its person (like AD's assigned-to).
- Collected per user account: state, licenses, MFA status + methods, last sign-in, account created, last password change, usage location, office, employee ID, company, manager, mailbox size, group membership (all group types; Teams-backed groups tagged (team)), directory roles (activated assignments — Global Administrator etc.), and mail forwarding (enabled inbox rules that forward/redirect, shown as rule → address; None when the mailbox has no such rule — so a rule appearing or disappearing is a change an alert rule can fire on). Mailbox size needs
Reports.Read.All; groups needGroupMember.Read.All; last sign-in needsAuditLog.Read.All+ Entra P1/P2; roles needRoleManagement.Read.Directory; mail forwarding needsMailboxSettings.Read— each degrades gracefully with a note in the sync summary when missing.
Part 6 — schedule recurring syncs
- Open Scheduler and click + New task.
- Set Task type to M365 Sync — the asset/script sections disappear and an M365 connector picker appears (connectors themselves are managed by admins in Settings > M365 Connectors).
- Pick the connector, name the task (e.g.
m365-nightly), choose a schedule (nightly is typical — a sync only writes attribute changes), Save. - Run Now on the task row triggers an immediate sync. Dispatch is fire-and-forget: the task history shows the dispatch (ok / skipped / error), and the sync's own result (
sweep_completed/sweep_failedwith counts) appears in Investigate under the m365_sync category. - When the collector master switch is OFF, scheduled syncs are skipped (visible in the task history) — nothing runs and no outbound connection is made.
Part 7 — sign-in events + alerts
Each sync also collects sign-in events (successes and failures) from Entra's auditLogs/signIns — requires AuditLog.Read.All (application) and an Entra ID P1/P2 tenant; without them this phase is skipped with a note in the sync summary, and the user/device phases still run.
- Where to see them: open an M365 account asset (Assets > Users > Type = Microsoft 365) — its drawer shows a Sign-ins panel with the latest events (time, status, location, IP, app).
- Alerting: two rule shapes ship under the signin rule type in Alert Center > Rules (both seeded enabled, global):
- M365 sign-in outside allowed countries — a successful sign-in from a country outside the allowlist (default
IL) fires a security alert; one open alert per account (re-occurrences bump the count). Edit the rule to change the country list. - M365 sign-in failure burst — ≥5 failed sign-ins for one account within 15 minutes (both numbers editable).
- M365 sign-in outside allowed countries — a successful sign-in from a country outside the allowlist (default
- Change alerts (license / groups / roles / any attribute): threshold rules support the changed (any transition) operator — pick the attribute (e.g.
license,groups,roles,mail_forwarding), operator changed, no value needed. Fires whenever a sync lands a different value, with old → new in the alert detail; the first-ever collection of an attribute does not fire. Scope globally (Customer = Global) or to one user via the rule's target attribute filter (e.g.upn equals jsmith@…). When the same attribute key exists on several providers, the Attribute-key picker offers an all types entry plus per-provider entries (e.g. Groups (m365)) — a provider-scoped rule fires only for assets of that type. - Per-asset opt-in: threshold/changed rules only evaluate assets whose Threshold alert flag is on. Toggle it on any asset — device, user, or provider account — via the asset drawer > Edit > Alert Settings card, or in bulk from either table's selection bar (Bulk Alert Settings…). Accounts created by the collectors opt in automatically.
- Limits to know: events with no location data are skipped by location rules; sign-ins for accounts not (yet) approved into Octotor are stored but not evaluated; each sync reads at most 5000 new events (the sync summary says so loudly when the cap is hit).
- Detection latency = your sync cadence. A 30-minute recurring M365 Sync task gives ~30-minute alerting latency; nightly sync means next-morning alerts.
- Retention: sign-in events are pruned after Settings > Maintenance > M365 Sign-ins (days) — default 90.
Troubleshooting
- Error mentioning consent / "required Microsoft Graph permission" — Part 2 step 3 (admin consent) is missing, or a permission wasn't added. Grant consent, then see the next point.
AADSTScredential / certificate error — the cert upload (Part 4) didn't happen, or a wrong Tenant/Client ID was entered (Part 3).AADSTS90002 Tenant not found= wrong Tenant ID.- Changed Entra permissions but Octotor still reports the old error — the collector caches its Graph token for ~1 hour, and the cached token predates your change. Click Test on the connector (it forces a fresh token) or wait out the hour.
- MFA Status shows Unknown for everyone —
AuditLog.Read.Allisn't granted/consented (it is optional); the sync summary in Investigate says exactly this when it happens. - Microsoft renamed its endpoints (rare) — the two hostnames the collector talks to (
login.microsoftonline.com,graph.microsoft.com) are configurable under Settings > M365 Connectors > Microsoft endpoints. They double as the collector's outbound allow-list, so only change them for a real Microsoft endpoint change; empty = built-in default; applies on the next sync/test.
Statuses
| Column | Values |
|---|---|
| CERT | pending (generating) → ready · error (hover the row for the reason) |
| TEST | not run · pending (dispatched to the collector) · ok · error (hover for the redacted reason) |
| STATE | Enabled / Disabled — per-connector switch, independent of the master switch |
Security notes
- The private key is encrypted with a key (
M365_CONNECTOR_KEY) that exists only in the collector container — the API server cannot decrypt connector keys, and there is no private-key download. - Deleting a connector destroys the encrypted private key. The Entra app registration is untouched — remove it tenant-side if the customer is offboarded.
- Graph permissions above are read-only. Octotor never writes to the tenant.
- Test/keygen errors shown in the UI are redacted — tokens, assertions, and key material never appear in logs or the audit trail.
Sync scheduling (recurring collection) arrives with the Scheduler task type M365 Sync — see the Scheduler section once available.
How Permissions Work
Octotor uses a layered permission system. Each layer narrows what a user can see and do.
Layer 1: Customer (Asset Visibility)
Each user is assigned to specific customers or "All Customers". This is the outermost filter — a user can never see assets belonging to a customer they're not assigned to.
| Setting | Effect |
|---|---|
| All Customers | User sees all assets from every customer (default) |
| Specific customers | User sees only assets belonging to their assigned customers |
Layer 2: Role (Ceiling)
Every user has one role. The role defines the maximum actions possible.
| Role | Can do | Cannot do |
|---|---|---|
| Admin | Everything | Nothing restricted |
| Operator | View assets, execute scripts, view logs, run protocols | Manage settings, manage users, delete assets, manage credentials, manage scheduler |
| Viewer | View dashboard, view assets, view own logs, investigate (logs only) | Everything else — job events hidden in Investigation |
Layer 3: Groups (Scope)
Custom groups narrow an operator's access. Without any custom group, an operator sees everything their role allows. With a custom group, they only see what the group grants.
Multiple Groups
A user can be in multiple custom groups. Their effective permissions are the union of all groups.
Built-in Groups
| Group | Auto-assigned to | Editable? |
|---|---|---|
| Admins | Admin users | No — admins bypass all checks |
| Operators | Operator users | No — use custom groups to narrow |
| Viewers | Viewer users | No — viewer permissions are fixed |
Permission Change Effect
Permission changes take effect within 30 seconds — no logout/login required. The system checks permissions on every API request using a short-lived cache.
Network Address Translation (NetMap)
When managing assets across multiple customer sites, IP address ranges can overlap. For example, two customers may both use 192.168.0.0/24 on their LANs. To avoid conflicts when routing through Tailscale, subnet routers use SNAT to remap one customer's range to a unique range.
NetMap tells Octotor which IP translations to apply per customer, so ping and SSH reach the correct Tailscale-routed address. Asset IPs in the database always remain the real LAN addresses — translation happens at runtime only.
Example
| Customer | TRIPLEOR |
| Original Network | 192.168.0.0/16 (their real LAN) |
| Mapped Network | 10.99.0.0/16 (Tailscale SNAT'd) |
| Asset stored IP | 192.168.0.10 |
| Octotor pings | 10.99.0.10 (translated) |
Key Rules
- Translation is per-customer — the same IP range can be real for one customer and translated for another.
- Original and mapped CIDR prefix lengths must match (e.g., both /16 or both /24).
- A customer can have multiple mappings (different subnets mapped independently).
- If no mapping matches, the stored IP is used as-is.
Adding a mapping
- Go to Settings > NetMap (admin only).
- Click + Add mapping and pick the Customer.
- Enter the Original network — the customer's real LAN CIDR, e.g.
192.168.0.0/16. - Enter the Mapped network — the Tailscale-SNAT'd CIDR, e.g.
10.99.0.0/16. It must have the same prefix length as the original. - Click Save. Within ~60s (the rule-cache TTL) every ping / SSH / WinRM / SNMP to that customer's assets connects to the translated address, while the stored/displayed IP stays the real LAN one.
192.168.0.10 but the job connects to 10.99.0.10. If a probe still hits the real IP, the mapping's prefix length probably doesn't match the original.CLI Appliances (Check Point, Cisco, …)
Some devices — firewalls, switches, routers — aren't managed by installing an agent or running an ordinary shell script. You drive them through their own command-line interface: you type a command, the device shows a menu or asks a question, you answer, and so on. Octotor supports these devices as CLI appliances, and automates those back-and-forth sessions with recipes.
1. Add the device as a CLI appliance
On the Assets page add the device (e.g. a Check Point firewall) and set its
OS family to CLI appliance (Check Point / Cisco). This tells Octotor to connect over SSH,
skip the operating-system probes it runs on servers, and never try sudo. Add a
Vendor attribute (Check Point Quantum Spark, Cisco IOS, …) so the right recipes are offered for
that device. Attach an SSH credential just like any other asset.
2. Pick an action and fill in the plain-language form
On the Run page, choose the device and then an action (a recipe). Each action shows a short description and, if it needs any input, a form with clearly-labelled fields — for example “VPN peer gateway (IP address)” with a hint and an example value. There is no code or command syntax to learn; you fill in what the field asks for and press Run. Octotor validates the input (an IP field must be a real IP, etc.) before anything is sent to the device.
3. What happens under the hood
Interactive actions run in a dedicated, isolated worker container (oct-recipe-worker) so a session that
stalls on one device can never affect ordinary SSH/WinRM jobs. The worker opens an SSH session, walks the device's
menus step by step (waiting for each prompt before it types the next answer), captures the full transcript into the
job output, and enforces safety limits: per-step and overall timeouts, and a guard that refuses to send
dangerous inputs (for example, a Check Point reset-all-tunnels menu option is blocked; only the
specific peer you chose is reset).
Seeded example: Check Point site-to-site VPN
- Show VPN tunnel status — read-only; lists the current site-to-site tunnels. Safe to run any time.
- Reset VPN tunnel — clears the encrypted connection to the one peer gateway you enter; the tunnel renegotiates automatically within seconds. Because it changes device state it is a destructive action and prompts for the action password (see Security).
Scheduling & automatic reset (end-to-end)
The same action can run on a schedule or be fired automatically by an alert:
- Scheduled: Scheduler → New task → Task type = Script → pick the recipe as the Script. The same plain-language form appears right there in the task editor — fill in the values (e.g. the peer gateway) and they're saved with the task. It runs on your cron schedule.
- Automatic (alert-triggered): create the task with Trigger = On alert and its recipe values, then in Alerts Admin point an alert rule's Run task on fire at it. Now, for example, when a firewall's monitored tunnel/endpoint goes down, Octotor automatically runs the Reset VPN tunnel recipe against the peer you configured — no operator action needed. Per-task cooldown and max-per-hour guardrails prevent reset storms.
Because the recipe's parameters are stored on the task, the automation always knows exactly which peer to act on.
Collecting firewall inventory (Check Point)
Beyond running recipes, Octotor can pull a full inventory snapshot from a Check Point Quantum Spark firewall. Run the System info action (or schedule a Check Point sync) and the device's Overview fills in with its model, software version, serial number, license expiry, uptime, and — rendered as sortable tables on the device panel:
- Network interfaces — each port and VLAN with its IP, subnet mask, and DHCP pool.
- Site-to-site VPN tunnels — peer gateway, encryption domain, authentication, and enabled state.
- DHCP leases — active client leases with client name, IP, MAC and the lease window (the real lease database, filterable per interface/VLAN).
- Remote-access security — whether gateway-wide two-factor authentication is required, and which users have VPN access.
Syncing firewall users & hosts into Assets
A Check Point sync reads the firewall's local user objects and host objects and files them into Assets exactly the way the Active Directory and Microsoft 365 connectors do: each object is matched to an existing person or computer (or proposed for approval in the discovery queue), then linked as an account under that owner. Host objects become device-side accounts and fold into Devices; user objects become user-side accounts and fold into Users — see User Assets & Accounts. The sync honours the same auto-approve setting as AD and M365, so on a strict tenant unmatched objects wait for you in the discovery queue.
To run it on a schedule, create a Scheduler task with Task type = Check Point
Sync. The Target section picks the firewalls: choose a specific firewall for one device, or set
Asset type = firewall to sync every firewall in scope — optionally narrowed by the Customer dropdown.
Worked example: task ALL-FW-NIGHTLY, Task type Check Point Sync, Customer Any customer, Asset type
firewall, no specific asset, cron 0 3 * * * — every enabled firewall (or CLI appliance) across all
customers syncs its users and hosts at 03:00, one sync per firewall, and each run appears separately in Investigate under the
checkpoint_sync category.
Jump Hosts — reaching a device through a bastion
Some devices are not reachable directly from the Octotor server — you first SSH into a jump host (bastion) on the customer's network and from there to the device. Configure this once under Settings ▸ Jump Hosts: give the jump host its address and an SSH credential. Then, on the device's Assets ▸ Overview ▸ Edit, pick that Jump Host from the dropdown. From then on every SSH connection to that asset goes through the bastion: appliance recipes, the Check Point account sync, and ordinary SSH jobs of any kind — scripts, commands, collectors and scheduled tasks — on any device type, Windows hosts with OpenSSH included. The device's own credential is used on the second hop. The job output shows the line Routing via jump host user@host:port (SSH).
Worked example: a Veeam backup server BK-1040 at a customer site is only reachable through that site's Linux bastion site-jump (192.0.2.10). Create a credential for the bastion login, add a jump host named site-jump with that address and credential under the customer, then open BK-1040 ▸ Overview ▸ Edit and set Jump Host = site-jump. The scheduled backup collector task for BK-1040 now runs over SSH through site-jump; its job output starts with the routing line, then Checking SSH port 22 on 192.168.10.5 via the jump host…, then the script output.
- The reachability check before a job (normally ping + port check) and the identity check (hostname probe) also run through the jump host when one is attached, so a target that only the bastion can see does not fail the pre-flight.
- If the attached jump host is disabled, or its credential was deleted, the job fails with a clear message — while a jump host is attached, Octotor never silently falls back to a direct connection. Before a jump host or a credential is deleted, the Settings page tells you which jump hosts or assets depend on it.
- Deleting a jump host detaches it from every asset that used it (the asset's Jump Host field goes back to Direct) and the next job on those assets connects directly. If they are only reachable through a bastion, create the jump host again and re-attach it.
- If the jump host itself cannot be reached, the job output says Could not reach the jump host user@host:port and the target is not blamed; if the bastion answered but could not open a connection to the target, the output says the target did not respond via the jump host.
- WinRM jobs on an asset with a jump host attached fail with a message that says so — WinRM is not routed through a jump host. Run the job over SSH (OpenSSH on the Windows host) or set the asset's Jump Host to Direct.
- No offline alerts for assets behind a jump host. Availability monitoring (ping and port checks) runs from the Octotor server directly, which cannot see a device that is only reachable through a bastion, so such an asset would look permanently offline. An asset with a jump host attached is therefore excluded from availability (offline) alerts; any availability alert that was open when the jump host was attached is resolved automatically. Threshold alerts on collected values (disk space, backup results, and so on) keep working, because the collector job runs through the jump host.
- The jump credential is stored encrypted in the database like every other credential — nothing is kept in plain text or in environment variables.
- Jump hosts and credentials are scoped to their customer: an operator only sees the jump hosts and credentials that belong to the customers they manage, and a credential from one customer cannot be attached to another customer's jump host.
Credentials for CLI appliances
When you create the SSH credential for an appliance (or its jump host), set Applies to = CLI appliance. Credentials carry a name of their own — the Assets ▸ Credentials panel lists them by that name, with the login shown on a separate Login: line, so two credentials that share a username (say two admin accounts on different firewalls) stay easy to tell apart.
License Agreement
Download .mdOctotor is distributed under a Source-Available license. The Licensee may inspect the source installed on a Licensed Instance for the Licensee's internal purposes — including security review, understanding how the Software operates, compliance verification, and reporting bugs — while reuse, redistribution, and competing products are not permitted. Octotor and the Octotor logo are trade names and unregistered trademarks of Caprior. Governing law: State of Israel.
Loading license text…
About Octotor
| Version | — |
| Build Date | — |
| Instance Name | — |
| Instance ID | — |
| Your Username | — |
| Your Role | — |
WinRM Remote Management
Octotor supports Windows Remote Management (WinRM) as an alternative to SSH for executing commands on Windows machines. WinRM uses PowerShell remoting over HTTP (port 5985) with NTLM authentication.
Windows Target Requirements
Run the following on each Windows target (as Administrator):
Enable-PSRemoting -Force Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
WinRM must be enabled and the firewall must allow port 5985 (HTTP). HTTPS (port 5986) and Kerberos authentication are planned for a future release.
Protocol Resolution
Octotor determines which protocol (SSH or WinRM) to use for each asset using this hierarchy:
| # | Priority | Source |
|---|---|---|
| 1 | Run Command override | One-time selection in the Run Command modal (not saved) |
| 2 | Task force protocol | Scheduled task configuration: Auto / Force SSH / Force WinRM |
| 3 | Asset override | Per-asset Connection Protocol field in the asset edit modal |
| 4 | Global default | Settings > Management Protocols > Execution Defaults (per OS family) |
| 5 | Fallback | SSH (always available) |
If WinRM is resolved but globally disabled (Settings > Management Protocols > WinRM = Disabled), the worker automatically falls back to SSH and logs a warning.
Execution Flow
Identity Verification
WinRM supports hostname identity verification, similar to the SSH gate. When enabled, Octotor connects via WinRM and runs [System.Net.Dns]::GetHostName() to verify the remote machine's identity before executing the actual command. Configure the default gate per OS family in Settings > Monitoring > Identity Verification.
Management Protocols Settings
| # | Setting | Description |
|---|---|---|
| 1 | Protocol Status (SSH/WinRM) | Global enable/disable. Disabled protocols are hidden from all UI and the worker falls back to SSH. |
| 2 | Execution Defaults | Default protocol per OS family (Windows: WinRM or SSH, Linux: SSH) |
| 3 | WinRM Default Port | Default: 5985. Override per-asset via the WinRM Port attribute. |
| 4 | WinRM Timeout | Connection timeout in seconds. Default: 30. |
| 5 | WinRM Auth Method | Currently NTLM (Negotiate). Kerberos and Certificate planned for future. |
Services Status
Overview
The Services page provides a live dashboard of system health. It is available to administrators only and auto-refreshes every 10 seconds.
Sections
| # | Section | Description |
|---|---|---|
| 1 | Host | CPU load averages, memory usage, database size, and backup freshness indicator. |
| 2 | Containers | All running oct-* containers with status, uptime, CPU %, memory, and restart count. Requires Docker socket mount (configured automatically by the installer). |
| 3 | Service Heartbeats | Background services (autoping, tcpmonitor, scheduler, maintenance) report their last heartbeat. A "stale" indicator appears if no heartbeat is received for over 2 minutes. |
| 4 | Active Work | Count of currently running and queued jobs. |
| 5 | Recent Errors | Last 10 error entries from the action log. |
| 6 | Service Controls | Placeholder for stop/start/restart controls — planned for a future release. |
Architecture
Background services run in a dedicated oct-worker container, separate from the API. This isolation means a stuck background task cannot affect API responsiveness. Services communicate via the database (LISTEN/NOTIFY) and write heartbeats to the service_heartbeats table so the API can report their health.
- An operator reports a
whoamijob sitting in queued for 20 minutes. You open Services. - Service Heartbeats shows
ssh-workerwith a stale flag — last heartbeat 18 minutes ago (healthy services update every ≤30s). - Containers confirms
oct-ssh-worker's restart count jumped and it isn't consuming the queue. - You restart the worker on the host (
docker compose restart oct-ssh-worker); its heartbeat goes green within 30s and the queued job runs to done.
Software Updates
Overview
Octotor checks once a day whether a newer release has been published, and shows the result in Settings ▸ Updates. When an update exists, users with Settings access also see a dismissible banner under the navigation bar. The check is anonymous: Octotor fetches one static file (the published version list) and sends nothing about this installation — no identifiers, no counts, no parameters. Installing an update stays a deliberate command-line step; nothing installs itself.
The Updates panel
Open Settings ▸ Updates. The Status panel shows:
| # | Field | Meaning |
|---|---|---|
| 1 | Current version | The version this installation is running |
| 2 | Latest known | The newest published version for your major release line, as of the last check |
| 3 | Last check | When the last check ran and whether it succeeded — a failed check (for example, a site firewall blocking the deployment host) is recorded here and is harmless |
Check now runs a check immediately. Daily update check is the opt-out: set it to Disabled and save to stop the background check — the Check now button keeps working either way.
Worked example: checking for and installing an update
- Open Settings ▸ Updates and click Check now.
- Suppose the panel now shows Current version
v3.2.0and Latest knownv3.2.1, with the note "An update is available". - On the host machine (SSH, not this web UI), run the upgrade one-liner:
curl -fsSL https://get.octotor.com/upgrade | sudo bash
It downloads the current release bundle, verifies the image signatures, backs up the database, and upgrades in place. To install a specific version instead of the latest:curl -fsSL https://get.octotor.com/upgrade | sudo bash -s -- --version=v3.2.1 - After the upgrade completes, reload this UI — the version in the corner and in Settings ▸ Updates now reads
v3.2.1, and the update banner disappears on the next check.
If the panel shows "You are on the latest published version for this major", there is nothing to install. A separate note about a newer major version means a bigger upgrade exists — contact licensing to discuss it; the daily check never installs or changes anything by itself.
Support Bundle
Overview
When you contact support about a problem, they usually need to see the system's state: versions, service health, recent failures. The support bundle collects that into one downloadable file. Nothing is ever sent anywhere automatically — there is no upload feature by design. The file downloads to your computer, and you send it to support yourself by email or your own file share.
What is and is not in the bundle
| # | Included | Never included |
|---|---|---|
| 1 | Version, migration level, service heartbeats | Credentials or credential data |
| 2 | License state summary (tier, expiry) | Encryption keys, JWT secrets, API tokens |
| 3 | Recent failed jobs (metadata only) + alert counts | .env contents |
| 4 | Error entries from the action log | Job outputs and commands (can embed secrets) |
| 5 | Settings, with secret-looking values masked | License key material |
Worked example: sending a bundle to support
- Support asks: "please send a diagnostic bundle."
- Open Settings ▸ Support and click Generate bundle.
- Your browser downloads a file such as
octotor-support-octotor-2026-07-28.tgz, and the panel confirms "Bundle download started". - Attach that file to your reply to support (email or your file share). That's the whole flow — Octotor itself has sent nothing.
Host-side diagnostics (when the web UI can't help)
Container-level problems (a service that won't start, docker issues) aren't visible from inside the app. For those, run the host script on the server over SSH:
sudo bash /opt/octopus/scripts/octotor-diag.sh
It writes /tmp/octotor-diag-<date>.tgz with container status, redacted log tails, the compose configuration with all environment values stripped, disk/memory info, and network reachability checks. Send that file the same way — by your own hand.
Database Maintenance
Overview
The Maintenance section in Settings provides database lifecycle management: retention policies, optimization, and visibility into database health. All maintenance actions are logged and visible in the Investigate page.
Data Retention
Configure how long each type of data is kept before automatic cleanup:
| Setting | Default | What It Deletes |
|---|---|---|
| Event Log Retention | 90 days | Action log entries (login, config changes, identity alerts, all system operations) |
| Job History Retention | 90 days | Completed/failed jobs and their output text. Running and queued jobs are never deleted. |
| Identity History Retention | 30 days | DNS/SSH/collector verification records from the Identity tab |
| AI Conversations Retention | 90 days | Goose chat history and recipe execution logs |
| Attribute History Retention | 180 days | Attribute change log ("RAM changed from 8GB to 16GB") |
Scheduled Maintenance
When enabled, maintenance runs automatically on a cron schedule. Each run:
- Prunes data older than the retention limits
- Runs VACUUM ANALYZE (reclaims dead tuples, updates query planner)
- Deletes old backup files beyond the backup retention period
Cron examples:
| Expression | Meaning |
|---|---|
0 2 * * * | Daily at 2:00 AM |
0 3 * * 0 | Every Sunday at 3:00 AM |
0 */6 * * * | Every 6 hours |
30 1 1 * * | 1st of every month at 1:30 AM |
Manual Actions
| Action | What It Does | Risk |
|---|---|---|
| Backup Status | Shows the most recent backup file, how long ago it was created, and a health indicator: green (✓ < 24h), yellow (⚠ 24–48h overdue), red (✗ > 48h — check host cron). Backups run via host cron (daily at 2 AM) using backup.sh. | None (read-only) |
| Optimize (VACUUM ANALYZE) | Reclaims space from deleted rows and updates query planner statistics. No locks, no downtime. | None |
| Deep Optimize (VACUUM FULL) | Rewrites all tables to reclaim maximum disk space. Locks all tables during operation — users may see errors. | Brief downtime |
| Manual Prune | Delete rows older than N days from a selected table. Shows a preview count before deleting. | Permanent — deleted data cannot be recovered |
Backup Architecture
Backups run via a host cron job (installed by setup-prod.sh). The cron entry runs backup.sh daily at 2 AM, which calls docker compose exec oct-postgres pg_dump — the postgres container's native pg_dump is always version-matched to the database. The last 7 backups are kept; older files are automatically removed.
Backup files are stored in data/backups/, which is mounted into the oct-api container as /data/backups. This allows the Settings > Maintenance page to list, download, and delete backup files. The Backup Status card shows freshness (how long since the last backup) with a color-coded health indicator.
To run a backup manually: cd /opt/octopus && ./backup.sh
To change the backup schedule: crontab -e on the host and edit the backup.sh cron entry.
Backup Security
Backup files contain the full database including:
- Encrypted credentials — AES-256 encrypted with MASTER_KEY (ciphertext, not plaintext)
- Password hashes — bcrypt hashes of user passwords
- Customer data — asset names, IPs, hostnames, attributes
The MASTER_KEY itself is not in the backup (it's in the .env file). Backup files should be stored securely and not shared.
Restore from Backup
A backup is a full logical pg_dump of the database — restoring it brings back every record: assets, attributes, users and permissions, settings, scheduler tasks, job history, alerts, and credentials. Two things live outside the dump and must be handled, or the restore is incomplete:
- Credentials need the original
MASTER_KEY. Every stored secret is AES-GCM encrypted with theMASTER_KEYfrom.env(SNMP credentials withSNMP_CONNECTOR_KEY). Restore the database onto a stack whose.envhas a different key and every credential is unreadable — you would re-enter them all. Keep the original.envwith the backup. - The license is machine-bound.
license.oct+install-key.pemlive on the host under/opt/octopus/license/, not in the dump. On a fresh install the install key is new, so the old license fails its machine check — reissue the license for the new install (or restore the originallicense/folder if it's the same host).
./restore.sh data/backups/<file>.sql.gz. It restores into a throwaway *_verify database, compares every table's row count against the live DB, then drops it — the live data is never touched. A clean run ends with ✓ backup restores cleanly.Actual restore (onto a fresh install or after data loss):
- Stand the stack up, but put the original
MASTER_KEY/SNMP_CONNECTOR_KEY/JWT_SECRET/POSTGRES_PASSWORDin.envbefore first boot. - Load the dump into the database:
Or use the guarded helper:cd /opt/octopus ./backup.sh pre-restore # safety snapshot of current state gunzip -c data/backups/<file>.sql.gz \ | docker compose exec -T oct-postgres psql -U octopus -d octopus docker compose restart oct-api./restore.sh data/backups/<file>.sql.gz --into-live(asks you to typeRESTOREto confirm). - Reissue the license for the new install (unless you restored the original
/opt/octopus/license/).
.env, a full recovery re-configures nothing beyond the license (and only on new hardware). With the dump alone (no .env), you additionally re-enter credentials. The full runbook is docs/restore-procedure.md.Database State Table
Shows per-table statistics: row count, disk size, dead tuples (indicates fragmentation), and when PostgreSQL last auto-vacuumed. Use "Get Info" to refresh individual tables or "Refresh All" for the complete view.
Octotor — IT Asset Management & Remote Operations Platform