Skip to content

License File Format

When you run forge activate <key>, Forge validates the Ed25519-signed license key entirely offline, then writes the parsed license data to ~/.forge/license.json. The raw key string is never stored — only its SHA-256 hash and the decoded payload fields.

The file is written with 0600 permissions on Unix (owner-read/write only).


{
"license": {
"v": 1,
"email": "[email protected]",
"tier": "solo",
"seats": 1,
"features": [
"dashboard",
"plugins",
"semantic_search",
"workflow_tools"
],
"issued": "2026-04-15T10:00:00Z",
"expires": "2027-04-15T00:00:00Z",
"trial": false,
"machine_bindings": [],
"team_id": null,
"is_team_admin": false
},
"key_hash": "a3f1b2c4d5e6...",
"activated_at": "2026-04-15T10:30:00Z"
}

FieldTypeDescription
licenseobjectThe decoded license payload from the signed key. See License Payload below.
key_hashstringSHA-256 hash of the raw license key string (hex-encoded, 64 characters). Used by the heartbeat client to identify the license server-side without transmitting the key itself. Value is "<unknown>" for licenses activated before v1.3.0.
activated_atstringISO-8601 UTC timestamp of when forge activate last ran on this machine. Value is "unknown" for licenses migrated from the v1.2.0 bare format.

FieldTypeDescription
vintegerLicense schema version. Currently always 1.
emailstringEmail address associated with the purchase. Displayed masked in forge license output (e.g., p***[email protected]).
tierstringLicense tier: "community", "solo", "pro", or "team".
seatsintegerNumber of seats. Always 1 for Solo and Pro. Team licenses have the seat count at purchase. Team requires a minimum of 3 seats.
featuresarray of stringsFeature flags granted by this license. See Feature Flags below.
issuedstringISO-8601 UTC timestamp when the key was signed by the Forge backend.
expiresstringISO-8601 UTC timestamp when the license expires. After this date, Forge falls back to Community Mode and displays a renewal prompt.
trialbooleantrue for 14-day trial licenses. Trial licenses have full feature access for the selected tier. Defaults to false for licenses signed before v1.3.0.
machine_bindingsarray of stringsSHA-256 hashes of machine fingerprints this license is bound to. Empty means unbound (backward-compatible default). Populated by forge activate on each machine.
team_idstring or nullTeam subscription ID for Team tier licenses, in the format "team_<stripe_subscription_id>". null for Solo and Pro licenses.
is_team_adminbooleantrue only for the first seat on a Team subscription (the admin who purchased). Grants access to the admin portal for seat management and team invite generation.

The features array contains string identifiers for capabilities granted by the license. Each tier is a strict superset of the tier below it.

Feature FlagMinimum TierDescription
dashboardSoloLocal web dashboard (forge serve --dashboard).
pluginsSoloCustom health check plugins (.forge/plugins/*.yaml).
semantic_searchSoloVector similarity search in forge_search.
workflow_toolsSoloforge_prepare, forge_validate, forge_understand.
multi_repoProIndex and query multiple repositories.
ci_modeProforge ci command with CI annotation output.
scipProSCIP index ingestion (forge ingest-scip, forge_ingest_scip).
cross_repo_searchProSearch across multiple indexed repositories simultaneously.
priority_updatesProPriority update channel.
shared_configsTeam.forge/team.yml shared team configuration.
volume_keysTeamVolume license key management.
admin_portalTeam (admin only)Web admin portal for seat management and invite tokens.
ci_cacheTeamR2-backed CI index caching (forge index --cache-to, forge ci --team).

The raw license key — the string you paste into forge activate — has this structure:

<base64(json_payload)>.<base64(ed25519_signature)>

Both components use standard base64 (not URL-safe). The signature is an Ed25519 signature over the raw JSON payload bytes (not their base64 representation). The Forge binary has the matching public key compiled in and validates the signature entirely offline — no network call is made during activation.


Forge handles three on-disk formats transparently:

  1. Current format (v1.3.0+): The { "license": {...}, "key_hash": "...", "activated_at": "..." } wrapper shown above.
  2. Pre-v1.3.0 format: A bare License JSON object. Loaded and automatically treated as if key_hash is "<unknown>" and activated_at is "unknown". The file is upgraded to the current format on the next forge activate.
  3. Licenses signed by v1.2.0: Keys that lack trial, machine_bindings, team_id, and is_team_admin fields. These fields default to false, [], null, and false respectively via serde defaults — no re-activation is required.

Do not edit ~/.forge/license.json by hand. The file contains a copy of the decoded license payload; it does not contain the signature. Altering the payload does not bypass validation because the signature is checked only at forge activate time, not at runtime. Feature gates throughout Forge check the features array from the loaded file, which is re-read from disk on each forge serve startup.

If your license file becomes corrupted, run forge activate <key> again with your original key.