Skip to article
← Back to knowledge base

Installing the collectors

Getting data in

macOS, Windows and Linux, and what each one reports.

A collector is a single script that runs as root on a machine, on whatever
schedule you already use for scripts, reads the configuration files AI tools
leave in a person's home directory, and posts what it found to the receiver.
There is no agent, no service and nothing listening. It runs, it reports, it
exits.

Most of what Nyxus knows comes from these. The cloud sources say who signed in
to what; the collector is the only thing that can tell you a CLI tool on a
laptop is signed into a personal account, or that something on that laptop
starts an AI tool on a schedule with nobody watching.

What it reports

The same five surfaces on every operating system, with the same finding
schema, to the same receiver.

Surface

Example

Does it see an account?

cli

Claude Code, Codex CLI, Gemini CLI

Yes, from the tool's own config file

ide

AI extensions in VS Code, Cursor, JetBrains

No, presence only

browser

AI extensions in Chrome, Brave, Edge

No, presence only

desktop

AI apps in Applications, local runtimes like Ollama

No, presence only

mcp

MCP servers wired into an AI tool's config

No, the server names only

On macOS and Linux it also reads the scheduler - launchd, cron, systemd
timers - for jobs that start an AI tool without being asked. Those carry
mode: autonomous and the cadence the scheduler itself reports, which is
what What runs without a person is built from.

An account finding says which of three things it found, rather than leaving
two of them blank: a config file with an account in it is a person, a
config file with no account is a machine credential - a key that
authenticates with nobody behind it, the one that survives somebody being
offboarded - and a config directory with no account file at all is none.

Which tools to look for is fetched from the receiver at runtime, not compiled
into the script. Covering a new AI tool is a registry entry, made in the
portal, not a re-push through your MDM.

Where the script comes from

Take it from the portal, under Operations > Enrolled devices. The download is
the same script for everyone, with your receiver URL and a fresh enrollment
token already substituted as its own defaults. That is the whole of the
setup: download, push it through whatever you use, done.

The settings below are documented so you can read what was substituted and
override it deliberately, rather than discover later that something was
assumed.

Corporate domains are never baked into the download. The receiver serves
those at runtime, so changing them is a change in one place.

macOS, through Jamf

  1. Add nyxus-collector.sh as a script object in Jamf, under Settings,
    Computer Management, Scripts. The file needs no edits.

  2. Create a policy that runs it. Jamf reserves parameters 1 to 3, so the
    script reads from parameter 4:

Parameter

Value

4

Receiver base URL, e.g. https://nyxus.example.com

5

The bearer token: either the shared token, or an enrollment token (nyxe_...)

6

Corporate domains, comma-separated, e.g. example.com,example.co.uk

  1. Trigger on Recurring Check-in, and add a custom trigger such as nyxus so
    you can run it on demand with sudo jamf policy -event nyxus. Frequency
    Ongoing; the throttling below keeps the volume sane.

An optional Jamf Extension Attribute that reads last_scan.txt gives you
per-device scan status in inventory.

Windows, through Intune

Deploy it as a platform script, under Devices, Scripts and remediations -
not a Proactive Remediation. Remediations offer scheduling and console status
but need Windows E3/E5 or the Intune Suite add-on; platform scripts need no
extra licensing, and the receiver is the reporting layer anyway.

Settings:

  • Run this script using the logged on credentials: No. It runs as SYSTEM.

  • Enforce script signature check: No, unless you sign it yourself.

  • Run script in 64 bit PowerShell Host: Yes.

Intune platform scripts take no parameters, so three variables at the top of
the file carry the configuration:

$ReceiverBase     = 'https://nyxus.example.com'
$Token            = 'nyxe_...'
$CorporateDomains = @('example.com')

Keep the token in single quotes. PowerShell treats those literally, so a $
inside a token cannot expand into something else.

Two consequences of the platform-script model are worth knowing before you
roll out. Scripts run at assignment and at device check-in, then re-run when
the script content changes, so there is no tight recurring schedule and
Windows reports less often than a Jamf-scheduled Mac. And there is no native
per-device status in the Intune console; the breadcrumb at
C:\ProgramData\nyxus\last_scan.txt and the portal fill that role.

Linux, through anything

The only requirement is something that can run a script as root on a
schedule. There is no MDM dependency and nothing Linux-specific to buy. An
RMM with a script feature, an Ansible cron or systemd-timer role, a Salt
state, a Puppet resource, or plain cron all work.

Three environment variables:

NYXUS_RECEIVER_BASE   receiver base URL, e.g. https://nyxus.example.com
NYXUS_TOKEN           bearer or enrollment token
NYXUS_CORP_DOMAINS    corporate domains, comma-separated

Environment variables do not survive sudo on their own, so pass them
through it when you run it by hand:

sudo NYXUS_RECEIVER_BASE=https://nyxus.example.com \
     NYXUS_TOKEN="$TOKEN" \
     NYXUS_CORP_DOMAINS=example.com \
     ./nyxus-collector.sh

Enrollment, and why the token matters

An enrollment token (nyxe_...) is the one to use. On its first run the
machine enrolls itself, stores a device credential of its own, and can be
revoked individually from then on. The shared bearer token works, but every
machine holding it is the same machine as far as the receiver is concerned,
and revoking one revokes all of them.

The credential lives in /Library/Application Support/nyxus on macOS,
C:\ProgramData\nyxus on Windows (restricted to SYSTEM and Administrators),
and /var/lib/nyxus on Linux. Mint a token in the portal, under Operations >
Enrollment tokens; each download mints its own.

Corporate domains, the setting to get right

An empty corporate-domain list means no domain counts as corporate, so
every account a collector finds reports as a personal account. You will know
within an hour of the first rollout, because the estate will look like
everybody is using a personal account for everything.

Set it on the receiver rather than in the script. A receiver-side list
overrides what the script carries, so the fleet follows a change without an
MDM re-edit.

How often it reports

  • Personal-account findings report at most once an hour. A personal
    account is a state, not an event, and repeating it every check-in adds
    volume without adding information.

  • Everything else reports at most once a day.

  • A new tool, or an account that changed, reports immediately at either
    severity. The throttle is per finding, not per machine.

State for the throttle sits beside the credential, so you can schedule the
policy as often as you like without flooding your log store.

Checking one has reported

Pilot on a single machine. Every deployment of a collector has found
something on first contact with a real machine, and it is better to see that
on one than on fifty.

After a run, check three things:

  1. The policy or script log has no error lines.

  2. last_scan.txt, beside the credential, lists the tools you expect and
    ends with [posted=N suppressed=N] and no parse failure.

  3. The device appears under Operations > Enrolled devices, and its findings
    under Discovery.

On Windows, check the user field is populated on those findings. If it is
empty, identity resolution needs attention on your image - and that is the
failure worth catching on one machine.

When it reports nothing

If the collector cannot fetch or parse the registry, it exits with an error
and reports nothing at all. That is deliberate: an empty scan and a clean
machine look identical in a log store, and a collector that quietly reports
nothing is worse than one that fails loudly. The failure shows in the policy
log and as a failed run.

What to tell your EDR team

The collector runs as root or SYSTEM, reads files in user home directories,
and posts to an external URL. That is a reasonable description of something
malicious, and EDR products sometimes treat it as one. An allowlist entry for
the script path and the receiver URL avoids an awkward afternoon.

Evidence strings use a literal ~ in place of the home directory, so
usernames never appear in an evidence path.

© 2026 Aman Karir