Koban

Quick start configs

Production-ready Koban agent configurations for enrolling Macs and syncing observations to Fleet.

This page gives you copy-paste configurations for running the Koban agent against Fleet with sync turned on. Each example is production-shaped: it enrolls a Mac, authenticates steady-state sync, and routes inventory and findings to Fleet.

Koban reads config from two places, and they have different jobs:

  • Local config on each Mac (~/.config/koban/koban.yaml): bootstraps enrollment and enables sync. This is where the Fleet endpoint and enrollment token live, plus any machine-specific paths.
  • Fleet org bundle: shared policy (timing, enabled surfaces, sync limits, rules) authored as YAML, validated and canonicalized to JSON by Fleet, then pulled by every enrolled Mac over the sensor protocol.

Anything you omit falls back to built-in defaults (section-level merge), so a partial file is valid.

Enrollment tokens are short-lived bootstrap credentials, not steady-state secrets. Fleet defaults to one use and a 24 hour lifetime. Issue them narrowly, template them through your MDM, and never commit them. After enrollment, sync authenticates with the device client certificate, not the token. See Authentication.

Before you start

  • The agent is installed on the Mac. See Installation.
  • You have your Fleet endpoint origin, e.g. https://fleet.example.com.
  • An admin has created an enrollment token in Fleet.

1. Bootstrap a Mac (local config)

This is the smallest config that enrolls a Mac and turns on sync. Write it to ~/.config/koban/koban.yaml, then restart the agent. Everything else inherits the shipped defaults.

# ~/.config/koban/koban.yaml  (per-Mac)
sync:
  enabled: true
  protocol: kobanSensorV1
  endpoint: https://fleet.example.com
  enrollmentToken: kbn_enroll_REPLACE_ME   # short-lived, one-time bootstrap

On first sync the agent generates a P-256 device key, exchanges the enrollment token for a client certificate, and stores its identity in the macOS Keychain. From then on it populates tenantID, deviceID, and the certificate itself, so you do not set those by hand.

Rolling out across a fleet? Ship this file through your MDM and substitute the enrollmentToken per device (or per batch) from a templated variable. Once a Mac is enrolled, the token is spent and can be left blank on subsequent pushes.

2. Publish org policy (Fleet bundle)

Once Macs are enrolled, drive everything else from a Fleet bundle so policy stays consistent across the org. Author it as YAML in Fleet; Fleet validates it, stores canonical JSON, and serves it to enrolled agents.

Keep machine-specific paths (Homebrew prefixes, configPath, projectRoots) out of the bundle. Those belong in local config. The bundle owns shared policy: generation, timing, which surfaces are inventoried, sync limits, and rules.

Baseline production

All surfaces on, built-in rules, default batch limits. A solid starting point that captures everything Koban watches and ships the full default ruleset.

# Fleet org bundle
generation: "2026-06-04"

watch:
  debounceMilliseconds: 800
  pollIntervalSeconds: 300

sync:
  maxBatchBytes: 524288   # 512 KB per upload
  maxBatchEvents: 500

homebrew:
  enabled: true
claude:
  enabled: true
codex:
  enabled: true
pi:
  enabled: true
cursor:
  enabled: true
opencode:
  enabled: true
javascript:
  enabled: true
python:
  enabled: true

# rules omitted = built-in default ruleset.
# See /docs/fleet-rules#built-in-rules

Bump generation every time you change policy. That is the signal that tells enrolled Macs to download the new bundle.

High-signal (low noise)

Tuned for teams that want alerts only on behavior-affecting changes. This keeps the agent-config and Homebrew-tap surfaces loud while dropping the high-volume info findings (new packages, dependency installs). It replaces the rules list with a focused set, so only these rules fire.

# Fleet org bundle
generation: "2026-06-04"

watch:
  debounceMilliseconds: 800
  pollIntervalSeconds: 300

sync:
  maxBatchBytes: 524288
  maxBatchEvents: 500

rules:
  # New MCP servers on any agent surface.
  - id: agent.mcp.new-server
    surface: claudeConfig
    triggers: [added]
    match: fieldContainsAny
    field: kind
    values: [mcpServer]
    severity: notable
    title: New MCP server
    rationale: A new MCP server was added to agent configuration.

  # Commands that download and run remote code.
  - id: agent.config.suspicious-command
    surface: claudeConfig
    triggers: [added, modified]
    match: fieldContainsAny
    field: detail
    values: [curl, wget, "| sh", "| bash", "bash -c", "sh -c", eval, base64]
    severity: suspicious
    title: Suspicious command
    rationale: Command contains shell patterns used to download and run remote code.

  # Config pointing at a remote endpoint.
  - id: agent.config.remote-transport
    surface: claudeConfig
    triggers: [added, modified]
    match: fieldHasURLScheme
    field: detail
    schemes: [http, https, ws, wss]
    severity: notable
    title: Remote configuration endpoint
    rationale: Configuration points at a remote host instead of running locally.

  # Packages from unofficial Homebrew taps.
  - id: homebrew.untrusted-tap
    surface: homebrew
    triggers: [added, modified]
    match: fieldNotInList
    field: origin
    allowed: [homebrew/core, homebrew/cask]
    severity: notable
    title: Third-party tap
    rationale: Package came from a Homebrew tap outside the official core and cask repos.

Repeat the agent rules per surface (codexConfig, piConfig, cursorConfig, opencodeConfig) if you run more than one AI tool. The built-in defaults already do this for you, which is why most teams start from Baseline production and only trim from there.

Maximum visibility

For high-assurance environments. Tighter polling, and Koban also reads managed-settings files (org-pushed Claude and OpenCode policy) so you can see when those change. Keeps the full default ruleset.

# Fleet org bundle
generation: "2026-06-04"

watch:
  debounceMilliseconds: 500
  pollIntervalSeconds: 120   # rescan every 2 minutes

sync:
  maxBatchBytes: 524288
  maxBatchEvents: 500

claude:
  enabled: true
  includeManagedSettings: true     # reads org-managed Claude settings

opencode:
  enabled: true
  includeManagedPreferences: true  # reads org-managed OpenCode preferences

# rules omitted = full built-in default ruleset.

includeManagedSettings and includeManagedPreferences read org-pushed policy files only when those files exist and are readable. They are off by default because not every fleet uses managed configuration.

Tuning sync throughput

The defaults are sized for typical developer Macs. Adjust in the Fleet bundle if you are syncing large fleets or bursty inventories.

FieldDefaultWhen to change
maxBatchBytes524288 (512 KB)Lower on constrained networks; raise to flush large initial snapshots faster.
maxBatchEvents500Raise to reduce request count on big first-sync bursts.

The agent also honors retryAfterSeconds, maxBatchBytes, and maxBatchEvents returned by Fleet in each sync response, so Fleet can throttle a noisy device without a config push.

Verify it worked

After deploying config to a Mac:

  1. Restart the Koban agent.
  2. Open the menubar item and confirm it shows as enrolled and syncing (not the development token fallback).
  3. In Fleet, confirm the device appears and its last check-in is recent.
  4. Make a change that should trigger a rule (add an MCP server, install from a third-party tap) and confirm the finding lands in Fleet with the expected severity.

Where to go next