gohai is an SDK-first Go library for collecting comprehensive system
facts, inspired by Chef Ohai. Import it into your Go application for
typed access to system facts — or use the standalone gohai CLI, a thin
wrapper over the same SDK.
🐧 Linux-first. macOS is supported with a narrower field surface (see per-collector docs for platform coverage); Windows is not supported.
Each collector wraps a well-maintained backing source (gopsutil,
ghw, procfs, cloud SDKs) and reshapes its output into typed Go
structs. gohai's value is the unified API, typed structs, and pluggable
collector model — not reimplementing /proc parsing from scratch.
gohai produces a validated OCSF inventory_info event
(class_uid 5001) via --format ocsf. Standard OCSF attributes map
directly; a gohai vendor extension
(uid 1337) carries fields OCSF doesn't yet cover — validated against
OCSF's own schema validator (12/12 tests passing).
Field names follow a three-tier naming ladder:
- OCSF (Open Cybersecurity Schema Framework) — primary
authority. ~108 fields map to standard OCSF objects (
device,device_hw_info,os,network_interface,cloud,package,process). Browse schema.ocsf.io. - OpenTelemetry Resource Semantic Conventions — when OCSF is silent. ~74 fields cover CPU microarchitecture, memory states, filesystem attributes, hardware detail.
- gohai convention — for the ~768 remaining fields where no
standard has an opinion. Starts from the backing library's field
name in
snake_case.
The complete per-field mapping lives in
schemas/field-mapping.md. Gap candidates
for upstream OCSF PRs are tracked in
schemas/ocsf-gaps.md.
What we collect draws on Chef Ohai's plugin methodology. What we call each field draws on OCSF + OpenTelemetry.
gohai is built to be embedded in OSAPI and other Go services that need typed system facts for routing, guards, discovery, inventory, and compliance. The CLI is a convenience — the SDK is the product.
curl -fsSL https://github.com/osapi-io/gohai/raw/main/install.sh | bashInstalls to ~/.local/bin (or /usr/local/bin as root) — SHA-256 checksums
verified. Override with GOHAI_INSTALL_DIR=/some/path or pin a version with
GOHAI_VERSION=1.0.0.
Other install methods
go install github.com/osapi-io/gohai@latestgo get github.com/osapi-io/gohaigit clone https://github.com/osapi-io/gohai.git
cd gohai
go build -o gohai .| Feature | Description |
|---|---|
| 🔌 Pluggable Collectors | Enable/disable individual fact collectors |
| 🏗️ Typed Structs | Strongly-typed Go structs for all facts |
| 📄 JSON Output | Nested JSON output for CLI and programmatic use |
| 🗺️ Flat Map Access | Dot-separated key-value access |
| 🐧 Cross-Platform | Linux primary, macOS best-effort |
| 🔗 Collector Dependencies | Automatic dependency resolution between facts |
| ⚡ Concurrent Collection | Collectors run concurrently; dependency graph resolves order when any collector declares deps. |
| ⏱️ Per-Collector Timings | Opt-in --with-timings / WithTimings() embeds per-collector durations, status, and error messages under _timings in the JSON output |
| 📊 OCSF + OpenTelemetry + Ohai | Field names follow OCSF then OpenTelemetry; data sources mirror Chef Ohai's plugins |
| 🔄 Native OCSF Output | --format ocsf produces a standards-compliant OCSF inventory_info event (class_uid 5001) — feed directly into SIEMs and data lakes |
| 🔌 SDK Integration | Import as a Go package for OSAPI and others |
65 collectors across 9 categories. See the Collectors reference for the full catalog — implementation status, default membership, schema mappings, and per-collector docs.
Collectors are individually toggled using node_exporter-style flags —
--collector.<name> to opt in, --no-collector.<name> to opt out. SDK
consumers use gohai.WithEnabled(...) / gohai.WithDisabled(...) /
gohai.WithCollectors(...).
Defaults are opt-in. gohai.New() returns an empty registry. Pass
gohai.WithDefaults() for the recommended set (cheap + near-universal —
identity, base hardware, network, load, virt detect). The CLI wires
WithDefaults() automatically; pass --no-defaults to skip it and use only
explicit --collector.X flags.
gohai collect --pretty # default collectors, pretty JSON
gohai collect --format ocsf --pretty # OCSF inventory_info event
gohai collect --flat # flat key=value pairs
gohai collect --no-defaults --collector.cpu # specific collectors only
gohai collect --pretty | gohai validate # validate against schema
gohai version # build infoImporters should read the full API reference on pkg.go.dev for every Option, Facts field, and Info struct —
that's the authoritative API surface. The examples below show the two
usage shapes.
Collecting facts (producer side):
package main
import (
"context"
"fmt"
"log"
"github.com/osapi-io/gohai/pkg/gohai"
)
func main() {
g, err := gohai.New(
gohai.WithDefaults(), // the recommended set
gohai.WithEnabled("process", "packages"), // plus these two
)
if err != nil {
log.Fatal(err)
}
facts, err := g.Collect(context.Background())
if err != nil {
log.Fatal(err)
}
// Typed access — pkg.go.dev documents every Info struct's fields.
fmt.Printf("OS: %s %s\n", facts.Platform.Name, facts.Platform.Version)
fmt.Printf("Cores: %d\n", facts.CPU.Cores)
fmt.Printf("Memory: %d bytes\n", facts.Memory.Total)
// Serialize for transport / storage.
b, _ := facts.PrettyJSON()
fmt.Println(string(b))
}Consuming stored facts (decoder side — e.g. a server that received a fact blob from an agent):
var facts gohai.Facts
if err := json.Unmarshal(payload, &facts); err != nil {
log.Fatal(err)
}
// Typed access on the decoded value — no map[string]any guessing.
fmt.Println(facts.Platform.Name, facts.CPU.Cores)
fmt.Println(facts.Network.DefaultInterface)Per-collector timings + error messages can be embedded in Facts by adding
gohai.WithTimings() to gohai.New(...) — useful for debugging slow
collectors or seeing why a collector failed without blocking the run.
See the Timings field on pkg.go.dev.
Detecting which cloud you're on. Enable the cloud collectors
(WithCategory("cloud")) and switch on Facts.Cloud() — returns a
*Cloud with Name set to a provider identifier, or nil when no
cloud was detected. Use the exported gohai.CloudAWS / CloudGCE /
CloudAzure / etc. constants instead of raw strings:
g, _ := gohai.New(gohai.WithCategory("cloud"))
facts, _ := g.Collect(ctx)
cloud := facts.Cloud()
if cloud == nil { return } // not on a supported cloud
switch cloud.Name {
case gohai.CloudAWS:
fmt.Println(facts.Ec2.Region, facts.Ec2.IAMInfo.InstanceProfileArn)
case gohai.CloudGCE:
fmt.Println(facts.Gce.ProjectID, facts.Gce.Zone)
}Rich per-provider data lives on the typed Facts.Ec2 / Facts.Gce /
etc. field. See docs/collectors/cloud.md
for the full pattern.
- Package documentation on pkg.go.dev — generated API reference. Every
Option,Factsfield, andInfostruct is documented there. This is the authoritative SDK reference. - Collectors reference — one doc per collector with fields, schema mappings (OCSF + OpenTelemetry), and Ohai source alignment.
- Schemas — JSON Schema, field-naming strategy (OCSF > OTel > convention), OCSF gap analysis, and cloud canonical overlay.
- Development — prerequisites, setup, testing, commit conventions.
- Contributing — PR workflow.
See the Development guide for prerequisites, setup, and conventions. See the Contributing guide before submitting a PR.
gohai stands on the shoulders of the following projects — as methodology references, as backing libraries we wrap, or as peers solving adjacent problems:
Fact collectors (direct peers):
- Chef Ohai — the canonical reference. Ruby-based plugin-driven fact collector; every gohai collector cross-references the corresponding Ohai plugin for data sources and per-distro edge cases.
- Puppet Facter — Puppet's equivalent. Different JSON shape, overlapping fact surface.
- osquery — Meta's SQL-based endpoint visibility. Different abstraction (SQL), same data space; common reference point when evaluating an inventory tool.
- Ansible setup —
Ansible's built-in fact gathering, exposed as
ansible_factsin playbooks. - Salt Grains — SaltStack's static facts.
Backing libraries (we import these):
- gopsutil — primary source for dynamic runtime state (memory, network I/O, process enumeration, virtualization detection).
- ghw — canonical for physical hardware topology (CPU NUMA, DIMMs, block devices, DMI, GPU, PCI).
- procfs — Linux
/procand/sysparsing when a library doesn't cover a field. - go-sysinfo — Elastic's alternative for host/platform/kernel facts.
- avfs — virtual filesystem abstraction used in every collector that reads files, so tests can run against in-memory fixtures.
Other Go libraries in the space:
- gosigar — Cloud Foundry's Go port of Hyperic Sigar. Historical reference for Go-based host metrics.
- go-ps — narrow process-listing library. gopsutil supersedes it for our use.
- goprocinfo — lightweight
/procparser. gopsutil + procfs cover the same ground for us.
Methodology references (we read, don't import):
- node_exporter — gold
standard for tricky Linux
/procand/sysparsing. Apache-2, but we rewrite in our style rather than import. - psutil — the Python library gopsutil is a port of; the original design reference for the dynamic-state facts.
The MIT License.