- Go 99.6%
- Makefile 0.4%
Record types, event names, sources, violation types, HTTP headers, and compliance actions are now exported constants consumable by both the agent and applications importing the server package. |
||
|---|---|---|
| .forgejo/workflows | ||
| cmd | ||
| docs | ||
| internal | ||
| pkg/siemserver | ||
| .gitignore | ||
| .goreleaser.yaml | ||
| CLAUDE.md | ||
| doc.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| managed-settings.json | ||
| README.md | ||
| renovate.json | ||
ai-agent
A Go daemon that watches Claude Code JSONL session files and ships raw records to a SIEM endpoint over HTTP. Designed for enterprise-wide deployment via MDM with at-least-once delivery and zero transformation of records.
Features
- Session log collection — watches
~/.claude/projects/for JSONL session files via fsnotify + polling backstop - Durable delivery — outbox pattern with bbolt ensures zero data loss on crash
- Organization compliance — scans Claude Code and Claude Desktop configs, checks email domains and org IDs against server-managed policy, ships violations as SIEM events
- Claude Code hooks — integrates with
SessionStartandUserPromptSubmithooks to display compliance banners and block/warn on policy violations - Cross-platform — single static binary for macOS (amd64/arm64), Linux (amd64), and Windows (amd64)
- Unprivileged — runs without root/admin privileges
Quick Start
# Build all platform binaries
make build
# Set required environment variables
export CLAUDE_SIEM_ENDPOINT=http://your-siem-server:8080
export CLAUDE_SIEM_TOKEN=your-bearer-token
export CLAUDE_SIEM_HMAC_SECRET=your-hmac-secret
# Run in foreground
./dist/ai-agent-darwin-arm64 run
# Or install as a system service
./dist/ai-agent-darwin-arm64 install
CLI Commands
| Command | Description |
|---|---|
run |
Run daemon in foreground (used by service managers) |
run --test |
Dry-run: discover and display events that would be shipped |
check |
Exit 0 if daemon is running, exit 1 if not |
check --hook <event> |
Compliance check for Claude Code hooks (SessionStart or UserPromptSubmit) |
install |
Copy binary to stable path and register as system service |
uninstall |
Stop and remove service |
start |
Start installed service |
stop |
Stop installed service |
status |
Print service status and PID |
Use --debug on any command for debug-level logging.
Configuration
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
CLAUDE_SIEM_ENDPOINT |
Yes | — | SIEM base URL; agent derives /ingest, /config, and /update paths |
CLAUDE_SIEM_TOKEN |
Yes | — | Bearer token for SIEM authentication |
CLAUDE_SIEM_HMAC_SECRET |
Yes | — | HMAC-SHA256 shared secret for request signing |
CLAUDE_SIEM_POLL_INTERVAL |
No | 300s |
Polling backstop interval (minimum 60s) |
Managed Config
The agent fetches server-managed configuration from GET {endpoint}/config on startup and at each poll interval. The config controls filtering, shipping, and compliance policy:
{
"version": 1,
"filters": {
"ignore_types": ["file-history-snapshot", "progress"],
"drop_sidechain": false,
"drop_meta": false,
"drop_tool_calls": false
},
"shipping": {
"batch_size": 100,
"flush_interval_seconds": 300
},
"compliance": {
"permitted_email_domains": ["company.com"],
"permitted_org_ids": ["org-uuid"],
"banner": "This session is logged for compliance.",
"action": "block",
"violation_message": "Personal accounts are not permitted on company devices."
}
}
Compliance Actions
block— violations prevent Claude Code sessions from starting and block every prompt (exit 2)warn— violations are injected into Claude's prompt context as a reminder; usage is allowed but logged
Claude Code Hooks
Deploy via managed settings or user settings (~/.claude/settings.json):
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{ "type": "command", "command": "ai-agent check --hook SessionStart" }
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{ "type": "command", "command": "ai-agent check --hook UserPromptSubmit" }
]
}
]
}
}
Architecture
~/.claude/projects/**/*.jsonl
|
v
+-----------+ fsnotify / poll +----------+
| Watcher |---------------------->| Reader |
+-----------+ +----+-----+
| atomic tx:
| events + offset
v
+----------+
| Store | bbolt (siem.db)
| outbox | <- events waiting to ship
| state | <- file byte offsets
| deadltr | <- failed batches
+----+-----+
|
v
+----------+ HTTP POST +------+
| Shipper |------------------->| SIEM |
| | Bearer + HMAC | |
+----------+ +------+
Package Map
cmd/collector/ Main binary — Cobra CLI (install/uninstall/start/stop/status/run/check)
cmd/server/ Demo SIEM receiver — file-based storage, serves config + updates
pkg/siemserver/ Importable server library — Huma handlers for ingest, config, stats
internal/compliance/ Org compliance scanner — reads Claude Code/Desktop configs, checks policy
internal/config/ Managed config fetch (with client identity), bbolt cache, hot-reload
internal/logging/ Custom slog.Handler + RotatingWriter (10MB, 3 files)
internal/reader/ JSONL reading, offset tracking, filtering rules
internal/shipper/ Batching, HTTP POST, HMAC signing, outbox drain
internal/store/ bbolt wrapper — state + outbox + deadletter + config buckets
internal/platform/ Machine ID, paths, PID file, OS service install
Filtering Rules
- Skip compact summaries — records with
isCompactSummary: true(synthetic context, no audit value) - Deduplicate by UUID — in-memory seen set per file, reset on restart
- Skip ignored types — server-managed
filters.ignore_typeslist - Drop sidechain — optionally skip agent/subagent conversations
- Drop meta — optionally skip system-injected meta messages
- Drop tool calls — optionally strip tool_use content blocks
Rules 1-2 are hardcoded. Rules 3-6 are server-managed. Everything else ships as-is.
Development
make build # Cross-compile all 4 platform binaries to dist/
make darwin-arm64 # Build single target
make test # go test -race -cover ./internal/... ./pkg/...
make clean # rm -rf dist/
make snapshot # GoReleaser snapshot build
make release # GoReleaser release build
Demo Server
A standalone SIEM receiver for local testing:
make build
./dist/demo-server --token mytoken --hmac-secret mysecret
# In another terminal
export CLAUDE_SIEM_ENDPOINT=http://localhost:8080
export CLAUDE_SIEM_TOKEN=mytoken
export CLAUDE_SIEM_HMAC_SECRET=mysecret
./dist/ai-agent-darwin-arm64 run --debug
The demo server auto-detects dist/ for serving update artifacts and config.json for managed config.
Testing
go test ./... # Run all tests
go test -race ./... # With race detector
go test -cover ./internal/... ./pkg/... # With coverage
All tests use t.TempDir() for I/O and httptest.Server for HTTP. Table-driven tests throughout.
Security
| Mechanism | Purpose |
|---|---|
| HMAC-SHA256 | Sign batch payloads to SIEM (X-Siem-Signature header) |
| TLS | Authenticate HTTPS servers (system trust store) |
| PID file locking | Prevent concurrent daemon instances |
Platform Notes
- macOS: IOPlatformUUID for machine ID,
~/Library/Application Support/Claude/config.jsonfor Desktop config - Linux:
/etc/machine-id, requires kernel >= 5.10.94 (ext4 fast commit fix for bbolt) - Windows: Registry MachineGuid
License
MIT License. See LICENSE for details.