Skip to content

Deploy the collector

The ARIS collector is a host-resident agent. Install it on each workstation or server where you want to observe supported AI tools, then connect it to the core ingest gRPC listener.

This page documents the current evaluation and small-pilot setup, where collector mTLS certificates are provisioned manually. For larger fleets, see Enterprise collector deployment for the target model before rolling out broadly.

The collector does four things:

  • watches same-user supported AI processes;
  • optionally tails local transcript JSONL files;
  • optionally captures supported IDE SQLite stores;
  • optionally accepts local OTLP/gRPC telemetry on 127.0.0.1:4317;
  • buffers envelopes in an encrypted local queue and forwards them to core.

Install core first

Finish Run with Docker Compose and confirm the web UI works before adding collectors. The collector forwards to core, so debugging is much easier once the identity foundation is already healthy.

1. Enable core ingest

Core only starts the collector ingest listener when ARIS_INGEST_GRPC_ADDR is set. In production, put the ingest listener behind a private network address or load balancer reachable only from the network segments where collector hosts run. mTLS still performs the collector authorization at the ingest layer.

The three certificate files are the server side of mutual TLS:

Setting Plain-English meaning
ARIS_INGEST_SERVER_CERT_FILE Core's public certificate. Collectors use it to prove they are talking to your ARIS core, not an impostor.
ARIS_INGEST_SERVER_KEY_FILE Core's private key for that certificate. Keep it secret.
ARIS_INGEST_CLIENT_CA_FILE The CA certificate core trusts for collector client certificates. Any collector certificate must chain to this CA.

The paths below are inside the core container. You still need to create the files on the Docker host and mount them into those paths.

Add these settings to the core environment:

ARIS_INGEST_GRPC_ADDR=0.0.0.0:8443
ARIS_INGEST_SERVER_CERT_FILE=/run/secrets/ingest-server.crt
ARIS_INGEST_SERVER_KEY_FILE=/run/secrets/ingest-server.key
ARIS_INGEST_CLIENT_CA_FILE=/run/secrets/collector-client-ca.crt

Generate evaluation certificates

For a first install, you can generate a small private CA with OpenSSL. Replace core.aris.example.com with the DNS name collectors will use to reach core, and replace eng-laptop-42.acme.internal with the first collector host identity.

mkdir -p dev-pki/core dev-pki/collectors

# 1. Create a CA that signs collector client certificates.
openssl genrsa -out dev-pki/collector-ca.key 4096
openssl req -x509 -new -nodes \
  -key dev-pki/collector-ca.key \
  -sha256 -days 3650 \
  -subj "/CN=ARIS Collector CA" \
  -out dev-pki/collector-ca.crt

# 2. Create core's ingest server certificate.
openssl genrsa -out dev-pki/core/ingest-server.key 4096
openssl req -new \
  -key dev-pki/core/ingest-server.key \
  -subj "/CN=core.aris.example.com" \
  -out dev-pki/core/ingest-server.csr
cat > dev-pki/core/ingest-server.ext <<'EOF'
subjectAltName=DNS:core.aris.example.com
extendedKeyUsage=serverAuth
EOF
openssl x509 -req \
  -in dev-pki/core/ingest-server.csr \
  -CA dev-pki/collector-ca.crt \
  -CAkey dev-pki/collector-ca.key \
  -CAcreateserial \
  -out dev-pki/core/ingest-server.crt \
  -days 825 -sha256 \
  -extfile dev-pki/core/ingest-server.ext

# 3. Create one collector client certificate.
openssl genrsa -out dev-pki/collectors/eng-laptop-42.key 4096
openssl req -new \
  -key dev-pki/collectors/eng-laptop-42.key \
  -subj "/CN=eng-laptop-42.acme.internal" \
  -out dev-pki/collectors/eng-laptop-42.csr
cat > dev-pki/collectors/eng-laptop-42.ext <<'EOF'
subjectAltName=DNS:eng-laptop-42.acme.internal
extendedKeyUsage=clientAuth
EOF
openssl x509 -req \
  -in dev-pki/collectors/eng-laptop-42.csr \
  -CA dev-pki/collector-ca.crt \
  -CAkey dev-pki/collector-ca.key \
  -CAcreateserial \
  -out dev-pki/collectors/eng-laptop-42.crt \
  -days 825 -sha256 \
  -extfile dev-pki/collectors/eng-laptop-42.ext

chmod 600 dev-pki/core/ingest-server.key dev-pki/collectors/eng-laptop-42.key

After this, the important files are:

Host file Mount or copy to Used by
dev-pki/core/ingest-server.crt /run/secrets/ingest-server.crt in the core container Core server certificate.
dev-pki/core/ingest-server.key /run/secrets/ingest-server.key in the core container Core server private key.
dev-pki/collector-ca.crt /run/secrets/collector-client-ca.crt in the core container Core's trust bundle for collector client certs.
dev-pki/collector-ca.crt /etc/aris/collector/core-ingest-ca.crt on each collector host Collector's trust bundle for core's server cert.
dev-pki/collectors/eng-laptop-42.crt /etc/aris/collector/collector.crt on that collector host Collector client certificate.
dev-pki/collectors/eng-laptop-42.key /etc/aris/collector/collector.key on that collector host Collector client private key.

Evaluation CA

The commands above are enough for a lab or pilot. For production, refer to Enterprise collector deployment for the enrollment path, or issue per-device certificates from your normal internal PKI with exactly one DNS or URI SAN identity per collector and track certificate expiry, rotation, and revocation.

Mount the files into core

For Docker Compose evaluation, add the ingest environment, mounts, and port to the core service:

services:
  core:
    environment:
      ARIS_INGEST_GRPC_ADDR: "0.0.0.0:8443"
      ARIS_INGEST_SERVER_CERT_FILE: /run/secrets/ingest-server.crt
      ARIS_INGEST_SERVER_KEY_FILE: /run/secrets/ingest-server.key
      ARIS_INGEST_CLIENT_CA_FILE: /run/secrets/collector-client-ca.crt
    volumes:
      - ./dev-pki/core/ingest-server.crt:/run/secrets/ingest-server.crt:ro
      - ./dev-pki/core/ingest-server.key:/run/secrets/ingest-server.key:ro
      - ./dev-pki/collector-ca.crt:/run/secrets/collector-client-ca.crt:ro
    ports:
      - "8443:8443"

Core runs as a non-root container user. The key file must be readable by that user and must not have group/world permission bits. On Linux Docker hosts, if core logs permission denied for ingest-server.key, use Docker secrets or change the host file owner to the container user while keeping mode 0600.

Restart core after changing these settings:

docker compose up -d --build core
docker compose logs core | grep 'ingest listening'

2. Issue collector certificates

Each collector needs its own client certificate and key. If you used the evaluation commands above, the first pair is already generated:

dev-pki/collectors/eng-laptop-42.crt
dev-pki/collectors/eng-laptop-42.key

The client certificate must have exactly one DNS or URI SAN identity. ARIS uses that SAN as the collector host_id, and core rejects envelopes whose host_id does not match the authenticated certificate identity.

Example identity:

DNS SAN: eng-laptop-42.acme.internal
URI SAN: spiffe://acme.internal/device/eng-laptop-42

Use a stable identity value that your PKI or enrollment flow can issue. In secure mode the collector derives host_id from the certificate SAN; if you set host_id explicitly in collector.yaml, it must match that single DNS or URI SAN exactly. Common Name (CN)-only certificates are not accepted for collector identity.

Keep the private key private. You will copy it into the collector directory after creating the service user and directories below.

chmod 600 dev-pki/collectors/eng-laptop-42.key

Do not reuse one client certificate across many hosts

Reusing a certificate makes every host report the same host_id. Issue one certificate per host or per managed device identity.

3. Build or install the binary

From the repository root, build the collector for the current host:

cd core
cd collector
go build -trimpath -o ../bin/aris-collector ./cmd/aris-collector

Install it where your service manager expects it, for example:

sudo install -m 0755 ./bin/aris-collector /usr/local/bin/aris-collector

For Ubuntu 22.04/24.04 pilots, ARIS also has an internal Debian package builder. For RHEL 9-family pilots, ARIS has a matching RPM builder:

make package-collector-deb VERSION=0.1.0
make package-collector-rpm VERSION=0.1.0

Both package formats install the same runtime contract under /usr/local/bin, /etc/aris/collector, and /var/lib/aris/collector. They do not ship a placeholder collector.yaml, because aris-collector enroll writes that file with exclusive-create semantics. The systemd unit uses ExecCondition=aris-collector validate-config ..., so installing the package before enrollment does not start a crash loop. Fleet tooling should place the enrollment token and CA bundles, run aris-collector enroll with --config-out /etc/aris/collector/collector.yaml, --cert-out /etc/aris/collector/collector.crt, --key-out /etc/aris/collector/collector.key, and --state-dir /var/lib/aris/collector, remove the token, fix package runtime ownership, then enable and start aris-collector.service.

After enrollment, match package runtime ownership and modes before starting systemd:

sudo chown root:aris-collector /etc/aris/collector/collector.yaml
sudo chmod 0640 /etc/aris/collector/collector.yaml
sudo chown aris-collector:aris-collector /etc/aris/collector/collector.key
sudo chmod 0600 /etc/aris/collector/collector.key
sudo chown root:aris-collector /etc/aris/collector/collector.crt
sudo chmod 0644 /etc/aris/collector/collector.crt

For managed macOS pilots, ARIS has an internal LaunchDaemon package builder:

make package-collector-macos-pkg VERSION=0.1.0

The macOS package installs /usr/local/bin/aris-collector and /Library/LaunchDaemons/ai.ryora.aris.collector.plist, creates the _aris-collector service account, and prepares /Library/Application Support/ARIS/collector. It does not ship collector.yaml; Jamf or equivalent tooling should pre-stage the Core CA bundles, enroll with --allow-root-acknowledged I-UNDERSTAND-ROOT-MODE, --config-out, --cert-out, --key-out, and --state-dir under /Library/Application Support/ARIS/collector, repair ownership and modes, then enable and start the LaunchDaemon. The initial package uses file-backed certificate material; Keychain-backed storage remains future work.

For managed Windows pilots, ARIS has an internal WiX MSI builder:

make package-collector-windows-msi VERSION=0.1.0

The Windows MSI installs C:\Program Files\ARIS\Collector\aris-collector.exe, creates the demand-start aris-collector Windows Service running under NT AUTHORITY\LocalService, and prepares C:\ProgramData\ARIS\Collector. It does not ship collector.yaml; Intune, SCCM, or equivalent tooling should pre-stage the Core CA bundles, stage a one-time token file through a protected channel, enroll with package-compatible --config-out, --cert-out, --key-out, and --state-dir paths under C:\ProgramData\ARIS\Collector, remove the token, repair ACLs for the NT SERVICE\aris-collector service SID, validate the config, then start the service. The initial Windows package uses file-backed certificate material; Windows certificate store and TPM-backed key storage remain future work.

4. Create collector.yaml

On Linux systemd hosts, create a dedicated service user and private directories:

sudo useradd --system \
  --home-dir /var/lib/aris/collector \
  --create-home \
  --shell /usr/sbin/nologin \
  aris-collector

sudo install -d -m 0700 -o aris-collector -g aris-collector /etc/aris/collector
sudo install -d -m 0700 -o aris-collector -g aris-collector /var/lib/aris/collector

Copy the CA, collector certificate, and collector key into place:

sudo install -m 0644 -o aris-collector -g aris-collector \
  dev-pki/collector-ca.crt /etc/aris/collector/core-ingest-ca.crt
sudo install -m 0644 -o aris-collector -g aris-collector \
  dev-pki/collectors/eng-laptop-42.crt /etc/aris/collector/collector.crt
sudo install -m 0600 -o aris-collector -g aris-collector \
  dev-pki/collectors/eng-laptop-42.key /etc/aris/collector/collector.key

Minimal production config:

paths:
  state_dir: /var/lib/aris/collector

forwarder:
  core_endpoint: core.aris.example.com:8443
  mtls:
    cert_path: /etc/aris/collector/collector.crt
    key_path: /etc/aris/collector/collector.key
    server_ca_path: /etc/aris/collector/core-ingest-ca.crt
    server_name: core.aris.example.com

sources:
  process:
    enabled: true
  otel:
    enabled: true
  transcript:
    enabled: true
  vscdb:
    enabled: true

For a per-user collector, put state_dir under that user's home directory. transcript.enabled: true auto-watches supported transcript directories under the running user's home. vscdb.enabled: true captures supported IDE stores, including VS Code AI extensions and Cursor IDE. No per-host enumeration is required. The collector intentionally refuses to run as root unless you explicitly opt in, because a root collector can observe every user's AI activity on the host.

5. Validate the config

Run validation as the same user that will run the collector:

aris-collector validate-config --config /etc/aris/collector/collector.yaml

Expected output:

ok

Validation is intentionally strict. It checks YAML keys, secure directory modes, mTLS file readability, private-key permissions, and the client certificate SAN/host_id relationship.

6. Run the collector

Foreground test:

aris-collector run --config /etc/aris/collector/collector.yaml

In another shell:

aris-collector status --config /etc/aris/collector/collector.yaml

You should see queue, source, and forwarder state. A healthy forwarder has last_err=none and increasing sent / acked counts once AI-tool activity is observed.

For long-lived use, wrap the same command in your service manager. The collector handles SIGINT and SIGTERM with a graceful shutdown that stops sources, drains accepted envelopes into the queue, and then closes the forwarder and queue.

Example systemd unit:

[Unit]
Description=ARIS collector
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=aris-collector
Group=aris-collector
ExecCondition=/usr/local/bin/aris-collector validate-config --config /etc/aris/collector/collector.yaml
ExecStart=/usr/local/bin/aris-collector run --config /etc/aris/collector/collector.yaml
Restart=on-failure
RestartSec=10s

[Install]
WantedBy=multi-user.target

ExecCondition makes a missing or invalid config skip service start instead of crash-looping. Alerting should treat repeated condition skips as unhealthy during rollout, because systemd does not mark them the same way as a failed ExecStart.

7. Configure AI clients

The collector's OTLP receiver listens on loopback by default:

otel:
  grpc_addr: 127.0.0.1:4317

Once the collector is healthy, configure Claude Code on the same host to export to it. The exact environment variables, MDM-distributable settings, and privacy gates are covered in Configure → Claude Code. Leave the receiver on loopback unless you have a specific LAN collection design; LAN binding requires mTLS on the collector's OTLP listener.

VS Code AI extensions such as GitHub Copilot, Codex, Claude Code, Gemini, and Kimi do not need client-side configuration. See Configure → VS Code AI extensions.

Development loopback

For local development only, the collector can forward without mTLS to a loopback core endpoint:

host_id: dev-laptop

forwarder:
  core_endpoint: 127.0.0.1:8443
  insecure: true

This mode only accepts loopback IP literals. It is not for production and cannot be pointed at a hostname or remote address.

See also