Ssherlock — read-only SSH fleet collector that produces JSON made for an LLM to reason over

Second one from me this week: ssherlock, a fleet inventory and posture collector in Crystal.

Point it at your fleet. It logs in read-only over SSH, gathers the evidence, and hands you one JSON file per host — shaped for an LLM to reason over.

The premise is a split of labour. ssherlock plays the detective and does the fieldwork: it visits every host over SSH, runs a catalogue of read-only commands (lscpu, ss -tlnp, pveversion, esxcli … — never a mutation), and writes <label>.json per host plus an aggregated all.json. The writeup — hardware obsolescence, capacity headroom, security posture, config drift across the fleet — is an analyst’s job, and that analyst is an LLM. ssherlock never calls a model itself; it just makes its output deterministic enough that the reasoning on top stands on solid ground.

ssherlock run                      # collect the whole fleet from ./ssherlock.yml
ssherlock run web01 db01           # only these machines (by label or host)
ssherlock run --redact             # mask secrets before anything hits disk
ssherlock presets linux            # dump a resolved preset as YAML

Checks, RuboCop-style

The part I’m happiest with. Presets shipped in the binary are the default rule packs; your fleet file’s overrides: block is your .rubocop.yml. It layers on top of a preset, keyed by preset name — set a check to null to disable it, redeclare it to retune (keys deep-merge over the preset’s), or declare one the preset never had, sections created on the fly. The presets themselves are never edited.

overrides:
  linux:
    services:
      packages: ~                    # disable
    storage:
      df:
        command: df -hT -x tmpfs     # retune
    custom:                          # brand-new section
      reboot_pending:
        command: '[ -f /var/run/reboot-required ] && echo yes || echo no'

Presets can also inherit from one another (linux-full extends linux), and you can define your own inline in the fleet file or in a presets_dir, resolved inline > directory > baked, without rebuilding.

Each check carries declarative metadata — category (inventory/capacity/security/…), severity, and expected, a free-text description of a good result — which rides into the JSON to steer the analysis. ssherlock deliberately never evaluates expected or computes a pass/fail; that judgement belongs to the analyst.

Other bits

  • One static binary, presets baked in via baked_file_system — drop it on a jump host, nothing to install on the targets, no agent to deploy.
  • Fleet-parallel with bounded concurrency, per-host and per-command timeouts.
  • Bastion relay, ssh -G config resolution, optional known_hosts verification.
  • --redact masks PEM keys, password=… pairs and bearer tokens before writing — while keeping policy keys like PasswordAuthentication no readable, so the report doesn’t lose its meaning.
  • ssherlock skill install materialises the companion analysis skill (also baked into the binary) into ./.claude/skills/, but the binary never runs it. all.json is plain structured data — pipe it into whatever assistant you like.

Crystal-specific notes

Built on ssh2.cr (thanks @spider-gazelle), admiral, baked_file_system and spectator.

One limitation worth writing down, because it’s a genuine language-level constraint rather than a bug I can fix: Crystal cannot cancel a fiber blocked on a frozen SSH read. Every check has a caller-side timeout (cmd_timeout + 5s), but if a remote command wedges, the reading fiber parks until the host’s session closes at the end of that host’s collection. Mitigation is server-side timeout wrapping (wrap: true in a preset’s options), with the caller-side guard as the fallback for presets that can’t use it — ESXi’s busybox shell, mainly. Happy to hear if anyone has a better pattern for this; it’s the one place where I wanted a cancellable read and didn’t have one.

Source, releases and full docs: GitHub - jbox-web/ssherlock: Read-only SSH fleet audit collector in Crystal — one static binary, preset-based command catalogues (Linux, Proxmox, VMware ESXi), and one structured JSON envelope per host, shaped for an LLM to reason over. · GitHub (MIT).

1 Like