Offline Behavior and Network Calls
This page documents what the ssg CLI and daemon do when there is no network,
what degrades, and how you can confirm that a rule evaluation makes no network call on your own
machine. Air-gapped use is not supported and is not verified: every governed path needs a verified paid license JWT (see the license boundary below). The background-call list below is derived from the shipped Go runtime
(sigmashake-gov/go). The Go source files that support each call are listed at the end of this page.
Note 2026-10-11: an earlier version of this page described a usage heartbeat every 2 minutes, an automatic audit sync every 5 minutes and a telemetry POST. Those calls exist only in the legacy TypeScript daemon. The shipped Go daemon does not make them. The page is re-derived from the Go source.
What needs no network call per tool call
Rule evaluation is local: it makes no network call for each tool call. The ssg
eval engine (pure-Go in-process, go/internal/goengine) loads rules from
the local SQLite database at ~/.sigmashake/rules.db and evaluates every tool
call in-process. No external binary or shared library is required — the Go engine
runs entirely within the ssg process with no subprocesses on the eval hot path.
Nothing in this chain requires a network call by default. A DENY, ALLOW, or ASK
decision is computed locally and returned to the calling agent before any network
I/O could occur. The one exception is the opt-in Jev assist (bring-your-own
TypeSafe key): when it is on and a key resolves, ssg eval sends the tool name
and input to api.typesafe.ai, and an Ask result can override a local Allow.
What you can verify yourself. With the daemon running, run a dry-run probe with all network interfaces disabled (or while capturing traffic — see the self-test section below):
ssg probe hook --tool=Bash --input='{"command":"ls -la"}'
The command returns a governance decision. If it returns a decision, local eval is working. If the binary itself is unavailable, see the degraded-mode section.
The daemon (ssg daemon) makes no network call to load rules, evaluate tool calls
over a Unix socket, or write audit rows to local SQLite. Its background tickers
(license heartbeat, fleet heartbeat) do use the network, as listed below.
The dashboard (ssg serve) serves the governance UI at 127.0.0.1:5599.
The dashboard SPA and all its assets are embedded in the binary. Loading the
dashboard does not make external network calls. The dashboard itself reads state
from the local daemon over loopback, so it loads without a network as long as the daemon
is running.
The license boundary
Every value surface needs a verified paid license JWT that accounts.sigmashake.com issues. This applies to ssg eval, the PreToolUse hook, the daemon and the offline hook fallback. Without a verified license, the check is fail-closed: every call is blocked with Pro license required. See Plans and limits.
- The license JWT lasts 30 days for Pro and 90 days for Enterprise.
- The daemon refreshes it about every 6 hours, when it can reach accounts.sigmashake.com.
- The CLI keeps accepting the JWT for 7 days after it expires. After that, the machine has no valid license and blocks every call.
A machine with no route to accounts.sigmashake.com therefore works only until the last JWT it holds is 7 days past expiry. Revoking a token or unpairing a device stops new license mints only. An already-issued JWT keeps working until it expires.
What makes background network calls and when
The daemon runs several background tickers. All are fire-and-forget and non-fatal — a network failure never blocks or fails an evaluation.
License heartbeat (licensed tier only)
- Endpoint:
https://accounts.sigmashake.com/api/v1/license/heartbeat - Cadence: every 6 hours (with about 10 % jitter)
- Payload fields:
jwt(your license JWT),fingerprint(the one-way SHA-256 machine fingerprint),version,daily_eval_count - Trigger condition: only fires when a license JWT exists at
~/.sigmashake/license.jwt(i.e., you have a Pro or Enterprise license) - What happens offline: the POST fails silently and the next tick retries. The daemon continues with the last successfully verified tier.
The account service pairs the fingerprint with your account on a valid heartbeat. No tool-call content, file paths, source code, credentials or rule bodies are in the payload.
Tier behavior when heartbeat cannot reach the server. The license JWT
already contains your tier claim. The daemon re-reads the JWT from disk. As long as the JWT has not expired, your tier is
preserved locally without a successful heartbeat.
Revocation requires a successful heartbeat response with status: "revoked" to
take effect. It is never applied speculatively offline.
No usage heartbeat
The shipped Go daemon sends no separate usage heartbeat. Unlicensed installs send no heartbeat to accounts.sigmashake.com. Only the license heartbeat above carries the daily evaluation count, and only when a license JWT exists.
Fleet heartbeat (fleet-enrolled devices only)
- Endpoint:
https://fleet.sigmashake.com/api/v1/agents/heartbeat(theSSG_FLEET_API_URLenvironment variable overrides the host; the daemon accepts onlyhttps, orhttpfor loopback addresses) - Cadence: every 5 minutes. After a failure the retry delay doubles from 30 seconds up to the 5-minute interval.
- Payload fields:
agent_id,policy_version,ssg_version. The agent JWT goes in theAuthorizationheader. - Trigger condition: only fires when an agent JWT exists at
~/.sigmashake/agent.jwt, whichssg fleet enrollwrites. - What happens offline: the POST fails and the daemon retries with the back-off above. The server returns a rotated agent JWT (1 hour TTL) that the daemon writes to
agent.jwt. Without a successful heartbeat, the JWT expires.
Telemetry
The shipped Go runtime has no telemetry send path. ssg telemetry only shows or changes the local opt-in flag in ~/.sigmashake/telemetry.json. The Go hot path for evaluation never reads that file. The default state is opted out.
ssg telemetry # show the current state
cat ~/.sigmashake/telemetry.json
# opted_in: false means the opt-in flag is off.
Audit sync (Enterprise only, on demand)
- Command:
ssg audit-sync(no background timer runs it in the Go daemon) - Endpoint (default):
https://hub.sigmashake.com/api/v1/audit/sync - Endpoint (override): the
--urlflag or theSSG_AUDIT_SYNC_URLenvironment variable - Trigger condition: only runs when you run it, when a license JWT or fleet enrollment file exists, and when a hub auth token exists.
- Payload fields: batches of audit rows, each containing
timestamp,tool,capability,decision,rule_id,input_summary(truncated to 200 characters, never the full tool input),client,ssg_version. - What happens offline: the command fails. Unsynced rows stay in the local SQLite audit log and the next run sends them.
- Retention: SigmaShake does not enforce one cloud audit-retention period across all stores. Cloud audit logs are available on the Enterprise plan only. Pro and free plans do not sync audit rows to SigmaShake servers; their audit log stays on the local device. Fleet deletes its own audit events daily after the per-organization
audit_retention_days(default 90). No cold tier exists. See the DPA (section 10) for the full table. Dated note 2026-10-13: this replaces earlier text that said no enforced limit existed.
Update check
- Endpoint:
https://download.sigmashake.com/cli/latest.json - Cadence: the CLI refreshes a local cache at startup when the cache is more than 24 hours old; skipped entirely when
SSG_NO_UPDATE_CHECKis set - Timeout: 3 seconds (fire-and-forget; does not block evaluation)
- What happens offline: fails silently. No upgrade prompt is shown.
Hub pull
- Endpoint:
https://hub.sigmashake.com/api(ruleset bodies come only from the license-gated hub API). The signed manifest onraw.githubusercontent.com/sigmashakeinc/rulesis read only whenSSG_HUB_GITHUB_FASTPATH=1is set. - Trigger:
ssg hub pulland hub-related dashboard operations - What happens offline: hub pulls fail with an error. Rules already installed on disk continue to work.
What degrades when offline
| Feature | Offline behavior |
|---|---|
| Rule evaluation (eval/probe) | Makes no network call per tool call. Needs a verified paid license JWT; without one, every call is blocked (fail-closed) |
| Daemon and dashboard | Run locally. Governed paths need the license JWT |
| License tier (licensed) | Preserved from cached JWT until the JWT is 7 days past expiry. After that, checks hard-block |
| License heartbeat | Silent failure; does not affect eval |
| Fleet heartbeat | Retries with back-off; the agent JWT expires without a successful beat |
Audit cloud sync (ssg audit-sync) | Command fails; rows stay local and the next run sends them |
| Hub rule pulls | Fail with an error; installed rules are unaffected |
| Update checks | Silent failure; no upgrade prompt shown |
ssg auth login | Requires network (browser OAuth / device flow) |
| Fleet policy pull | Cannot pull new policy bundle; last cached bundle applies |
Self-test: prove zero egress during evaluation
Example procedure — adapt to your environment. The commands below were not
executed in producing this page; they are provided as a reproducible template
for independent verification on your own machine. The ssg probe hook command
itself (the subject of the test) was verified by the author.
Step 1 — capture baseline traffic
Open a terminal and start a packet capture or proxy. On Linux with tcpdump:
# Capture all non-loopback TCP traffic to a file, run in background
sudo tcpdump -i any -w /tmp/ssg-offline-check.pcap 'not (host 127.0.0.1 or host ::1)' &
TCPDUMP_PID=$!
On macOS, replace -i any with -i en0 (or whichever interface has your
default route). Alternatively, use mitmproxy or any HTTPS proxy you trust —
set HTTPS_PROXY to its address before the probe command.
Step 2 — run the eval probe
ssg probe hook --tool=Bash --input='{"command":"echo hello"}'
Expected output: a governance decision (allow, deny, or ask) with no
network activity visible in the capture.
Step 3 — stop the capture and inspect
# Stop tcpdump
kill $TCPDUMP_PID
# Inspect captured packets (should show zero rows to external hosts)
tcpdump -r /tmp/ssg-offline-check.pcap -n 2>/dev/null | grep -v '^$' | head -20
If no packets appear (or only loopback packets appear), the eval made no external network calls.
Why no network calls happen during eval (default configuration). If the opt-in Jev assist is on, ssg eval sends the tool name and input to api.typesafe.ai. Otherwise the eval path reads rules from the
local SQLite database, runs them through the pure-Go in-process engine, and
writes the result to the local audit log. There is no IPC to a remote service or
subprocess on the critical path. The background heartbeat tickers run on their
own intervals and are not triggered by an eval call. If the capture shows a license or fleet heartbeat, it came from the ticker and not from the eval.
Verifying the telemetry flag
ssg telemetry
The Go runtime has no telemetry send path. The command shows the local opt-in flag only.
Air-gapped use (not supported)
SigmaShake does not support air-gapped deployments and has not verified them. Do not plan an air-gapped installation on this page.
A machine with no internet access has these limits:
ssg auth logincannot complete (it needs accounts.sigmashake.com).- The license JWT cannot be issued or refreshed. When the last JWT is 7 days past its expiry, the machine blocks every governed call.
- Hub rule pulls are unavailable (they need hub.sigmashake.com, the license-gated hub API; GitHub raw content is only the opt-in fast path).
- Fleet heartbeats never reach the server, and the agent JWT expires.
- Update checks never complete.
Rules that are already installed on disk keep working while the license JWT is valid. The daemon and the dashboard stay on loopback.
Honest boundary
This document describes the network behavior of the ssg CLI and daemon as
implemented in the Go runtime (sigmashake-gov/go). The legacy TypeScript source
(sigmashake-gov/src) made extra calls that the Go runtime does not make. The
desktop applications (SigmaShake Desktop for Linux, macOS, and Windows) embed
ssg serve and the ssg binary but add their own update-check calls and
desktop-platform integrations. Those behaviors are documented in the respective
desktop app guides and are not covered here.
You can check each call against the Go source files listed below. Calls that this page does not list are not documented here.
Source references for the calls on this page:
| Claim | Source file |
|---|---|
| Eval makes no network call per tool call | sigmashake-gov/go/internal/goengine/engine.go — Engine / Engine.Evaluate (pure-Go in-process; no subprocess on eval hot path) |
License heartbeat endpoint, payload (with fingerprint) and 6-hour cadence | sigmashake-gov/go/internal/daemon/license_heartbeat.go |
| Fleet heartbeat endpoint, payload and 5-minute cadence | sigmashake-gov/go/internal/daemon/fleet_heartbeat.go |
| No telemetry send path; opt-in flag only | sigmashake-gov/go/internal/config/telemetry_state.go, sigmashake-gov/go/internal/cli/telemetry.go |
| Audit sync endpoint, payload, on-demand command | sigmashake-gov/go/internal/cli/audit.go — auditRunSync() |
| Update check endpoint, 24-hour cache, 3-second timeout, silent failure | sigmashake-gov/go/internal/cli/update_notice.go; sigmashake-gov/go/internal/cli/update.go |
| Hub pull endpoint and opt-in GitHub fast path | sigmashake-gov/go/internal/cli/hub.go |