Machine Fingerprints and Bindings
Forge licenses are not floating. Each activation binds the license to a specific machine using a hardware fingerprint. This page explains why, what gets hashed, how the limits work per tier, and how stale bindings get cleaned up over time.
Why machine bindings exist
Section titled “Why machine bindings exist”License keys are strings. A string can be copied and shared. Machine bindings make a license key useful on a limited number of machines, matching the seat count you purchased.
The binding model is server-authoritative: the license server tracks which fingerprints are active for each license. The signed key you store locally is a credential; the server decides whether that credential is accepted on the current machine.
What gets hashed
Section titled “What gets hashed”When you run forge activate, the binary collects three values from the current machine:
| Input | Source |
|---|---|
| Machine ID | /etc/machine-id (Linux), IOPlatformUUID (macOS), Registry MachineGuid (Windows) |
| Hostname | gethostname() |
| Primary network interface MAC address | First non-loopback adapter |
All three are combined and passed through SHA-256. The resulting 64-character hex string is the fingerprint. We never store the raw inputs — only the hash reaches our servers.
The hash is deterministic for a given machine. If you reinstall the OS without wiping the machine ID, the fingerprint is unchanged and your activation survives. If the machine ID is regenerated (some cloud images do this on first boot), a new fingerprint is produced and the old binding becomes stale.
Seat limits per tier
Section titled “Seat limits per tier”| Tier | Seats | Notes |
|---|---|---|
| Community | 0 | No activation required. No MCP tools. CLI-only in limited mode. |
| Solo | 1 | One machine at a time. |
| Pro | 3 | Three machines simultaneously (laptop, desktop, home server, etc.). |
| Team | Per-member | Each team member gets one seat. Admin manages the roster. |
“Seats” are concurrent bindings, not total activations. You can deactivate a machine and activate a new one as many times as you need — the seat limit is how many machines can be active at once.
Ephemeral environments
Section titled “Ephemeral environments”CI runners, GitHub Codespaces, GitLab CI, Docker containers, and Devcontainers produce a fresh machine ID on every boot. Activating normally in these environments would consume a seat on each run and exhaust your binding slots within hours.
Forge handles this automatically: when it detects an ephemeral environment, it skips fingerprint registration entirely. The license is validated and the session is authorized, but no binding is recorded and no seat is consumed.
Ephemeral detection checks, in priority order:
FORGE_EPHEMERAL=1environment variable (explicit override — always wins)CODESPACES=true(GitHub Codespaces)GITPOD_WORKSPACE_IDset (Gitpod)CI=truewith a known CI vendor variable (GITHUB_ACTIONS,GITLAB_CI,CIRCLECI,BUILDKITE,JENKINS_URL)/proc/1/cgroupcontainsdocker,containerd,libpod, orkubepods/.dockerenvexistsDEVCONTAINER=trueorREMOTE_CONTAINERS=true
If you are running on a bare-metal machine that accidentally matches one of the file-based signals (some VMs leave docker artifacts in cgroups), set FORGE_EPHEMERAL=0 to force persistent mode.
Ephemeral sessions cache the validation result in /tmp/forge-session-cache.json for one hour, so a multi-step CI job does not hit the license server on every invocation.
See Use Forge in CI, Use Forge in Codespaces, and Use Forge in Docker for setup guides.
Stale binding auto-eviction
Section titled “Stale binding auto-eviction”A machine that has not sent a heartbeat in 90 days is considered stale. When you run forge activate on a new machine and your seat limit is full, Forge checks whether any current binding is stale. If one is found, it offers to evict the inactive binding and take the seat in its place:
License seat limit reached for solo tier.
One of your bindings has been inactive: Platform: macos-aarch64 Last heartbeat: 2025-11-18 (152 days ago)
Evict this inactive binding and activate on this machine? [y/N]:Confirm with y and activation completes. The old binding is removed, the new machine is registered, and a re-issued license key is written to ~/.forge/license.json.
A few constraints on eviction:
- Maximum 2 evictions per license per rolling 30-day window. This prevents a compromised key from cycling through machines. If you hit this limit, contact support@forge.ironpinelabs.com.
- Eviction requires the old binding to be genuinely 90 days inactive. A machine that comes back online resets its staleness timer.
- If the evicted machine comes back online, its next heartbeat returns an
unknown_bindingresponse. Forge degrades to community mode and prompts the user to re-activate. The re-activation will trigger another seat-limit check.
You receive an email notification when a binding is evicted, with a 7-day window to contact support and reverse it if you did not expect it.
Portal self-service
Section titled “Portal self-service”If a machine dies before 90 days have passed, you can revoke its binding manually from the portal at https://forge.ironpinelabs.com/portal/login. Sign in with the email on your license, find the dead machine in the table, and revoke it. See Recover from a dead machine.
Data retention
Section titled “Data retention”| Data | Retention |
|---|---|
| Fingerprint hash | Retained while the binding is active. Removed when the binding is revoked or evicted. |
| Heartbeat timestamps | Retained per binding for eviction eligibility. Removed with the binding. |
| Ephemeral usage records | Aggregated weekly; rows older than 13 months are purged. |
| Binding event audit log | 12 months. |
Raw hardware identifiers (machine ID, hostname, MAC address) are never stored. Only the SHA-256 hash is transmitted and retained.
Privacy
Section titled “Privacy”For the full data handling policy, see the Forge Privacy Policy.
The short version: fingerprint hashes are used only for seat enforcement. They are not correlated with your code, your repo contents, or any other license holder’s data. Ephemeral usage records track only counts, source tags (e.g., ci:github_actions), platform, and client version — never file paths or code.