fremforge CLI
The fremforge CLI is a single-binary wrapper around the public REST API. Same verbs, same authorization model, same scopes. Distributed from EU PoPs only; no npm registry, no Docker Hub, no Sigstore Fulcio dependency.
Install
One-liner (recommended)
curl -sSfL https://cli.frem.sh/cli/install.sh | shThe installer auto-detects your OS (Linux or macOS) and architecture (arm64 or x86_64), downloads the matching binary from https://cli.frem.sh/cli/, downloads the canonical SHA256SUMS from https://trust.frem.sh/ (a separate host with a separate writer credential, so a compromise of the binary host alone cannot forge a match), verifies the SHA-256, and installs to ~/.local/bin/fremforge or /usr/local/bin/fremforge.
Override the install location with FREMFORGE_INSTALL_DIR:
curl -sSfL https://cli.frem.sh/cli/install.sh | FREMFORGE_INSTALL_DIR=/opt/fremforge/bin shPin a specific version:
curl -sSfL https://cli.frem.sh/cli/install.sh | FREMFORGE_VERSION=0.1.0 shManual download
If you’d rather not pipe a remote script to sh, the binaries are reachable directly. Pick the matching pair:
| OS | Arch | URL |
|---|---|---|
| macOS | arm64 | https://cli.frem.sh/cli/fremforge-darwin-arm64 |
| macOS | x86_64 | https://cli.frem.sh/cli/fremforge-darwin-x64 |
| Linux | arm64 | https://cli.frem.sh/cli/fremforge-linux-arm64 |
| Linux | x86_64 | https://cli.frem.sh/cli/fremforge-linux-x64 |
| Windows | x86_64 | https://cli.frem.sh/cli/fremforge-windows-x64.exe |
The architecture suffix is x64 (not x86_64) and arm64 — these match Bun’s --target tokens. uname -m reports x86_64 on Intel/AMD, so map it to x64 when building the URL by hand (the one-liner installer does this for you).
Verify against the canonical hash on trust.frem.sh before running the binary:
# 0. Map uname -m's x86_64 to the published x64 token
arch=$(uname -m); [ "$arch" = x86_64 ] && arch=x64
# 1. Download the binary
curl -fsSL https://cli.frem.sh/cli/fremforge-$(uname -s | tr A-Z a-z)-$arch \
-o fremforge
# 2. Download the canonical SHA256SUMS (separate host, separate credential)
curl -fsSL https://trust.frem.sh/SHA256SUMS -o SHA256SUMS
# 3. Verify
sha256sum --check --ignore-missing SHA256SUMS
# 4. Install
chmod +x fremforge
sudo install -m 0755 fremforge /usr/local/bin/fremforgeVerify the Ed25519 signature (optional, recommended)
Beyond the SHA-256 match, each release is signed as a DSSE-wrapped in-toto Statement under the same trust root as fremforge SLSA build provenance. The verifier downloads the public trust root from www.frem.sh/.well-known/slsa-trust-root.json and checks the Ed25519 signature on the SHA256SUMS bytes.
# Pull the trust root and the signed envelope
curl -fsSL https://www.frem.sh/.well-known/slsa-trust-root.json -o slsa-trust-root.json
curl -fsSL https://trust.frem.sh/SHA256SUMS.intoto.jsonl -o SHA256SUMS.intoto.jsonl
# Verify using slsa-verifier
slsa-verifier verify-artifact fremforge \
--provenance-path SHA256SUMS.intoto.jsonl \
--source-uri https://frem.sh/internal-fremforge/monolith \
--builder-id https://frem.sh/runner-controller/v1 \
--trusted-root slsa-trust-root.jsonThe trust root is the same one used for SLSA-L2 build provenance on artifacts your runner produces, same Ed25519 key, same builderId, same verification recipe.
Authentication
The CLI supports three credential modes, resolved in this order: --token=… flag, FREMFORGE_TOKEN env var, then the stored login at ~/.config/fremforge/auth.json.
Recommended — browser-based login (no paste)
fremforge auth loginOpens your browser to frem.sh, you approve the device, the token lands at ~/.config/fremforge/auth.json (mode 600) and every subsequent invocation auto-loads it. Same OAuth2 + PKCE flow your git push already uses, so revoking the token at frem.sh/-/user/settings/applications revokes git access and CLI access in one step.
fremforge auth status # show current login + expiry
fremforge auth logout # revoke + delete the local fileThe token works on both the fremforge REST API (/api/v1/orgs/…) AND Forgejo’s native API (/api/v1/repos/…) — Forgejo accepts its own OAuth bearers natively, and the fremforge api validates them via introspection against Forgejo’s /api/v1/user. Same identity, both surfaces.
CI / scripted use — PAT
For non-interactive contexts (CI jobs, scripts, agents), mint a scoped PAT. Easiest is the CLI itself once you’ve logged in interactively once (fremforge auth tokens create --name=… --scopes=… — see Mint a scoped PAT for CI); or mint one at https://frem.sh/-/user/settings/applications. Then:
export FREMFORGE_TOKEN='<your PAT>'
fremforge whoamiOverride the base URL with FREMFORGE_URL= (must be HTTPS); default is https://frem.sh.
Commands
fremforge auth login Browser-based OAuth2+PKCE login.
fremforge auth logout Revoke + delete the stored token.
fremforge auth status Show current login + expiry.
fremforge whoami Print the user the token authenticates as.
fremforge data-export start <slug> Queue a full data export for the org.
fremforge data-export list <slug> List recent export jobs.
fremforge dependency-updates enable <slug> Enable hosted Renovate for the org.
fremforge dependency-updates disable <slug> Disable hosted Renovate for the org.
fremforge dependency-updates run-now <slug> Trigger an out-of-cycle Renovate run (1/h cap).
fremforge audit-log <slug> Fetch the org audit-log slice.
[--since=DATE] [--actor=…] [--action=…] [--limit=N]
fremforge audit-verify <slug> [--human] Walk the per-tenant audit hash chain + WORM
anchor; report integrity.
Exit 0=ok, 2=partial, 3=broken, 4=anchor_mismatch.
fremforge sbom <owner>/<repo> <tag> Download a release SBOM.
[--format=spdx|cyclonedx]
fremforge runs <owner>/<repo> List recent CI runs (JSON; --human for a table).
[--limit=N] [--status=…] [--event=…]
fremforge runs logs <owner>/<repo> <run-id> Fetch a run's logs (text/plain, all jobs).
fremforge auth tokens create Mint a scoped PAT (printed once).
--name=N --scopes=a,b [--ttl-days=N]
fremforge auth tokens list List your PATs (--human for a table).
fremforge auth tokens revoke <token-id> Revoke a PAT.
fremforge findings <type> <slug> Security findings. type ∈ secrets |
[--status=…] [--repo=…] dependencies | signed-commits | attestations.
fremforge secrets list <slug> List org Actions/CI secret names.
fremforge secrets set <slug> <NAME> Set a secret (value via FREMFORGE_SECRET_VALUE).
fremforge secrets delete <slug> <NAME> Delete a secret.
fremforge seats list <slug> List org members + seat usage.
fremforge seats add <slug> --email=E Add a member (--username=, --full-name= optional).
fremforge seats remove <slug> <username> Remove a member.
fremforge version Print the CLI version.Run fremforge --help for the canonical reference, or pipe to --human on any command that supports it for table-formatted output.
Worked examples
Audit-chain integrity (use in CI)
export FREMFORGE_TOKEN='<your PAT, audit:read scope>'
# Human-readable, for terminals
fremforge audit-verify acme --human
# Script-friendly: exit code reflects integrity_status
# 0 = ok, 2 = partial, 3 = broken, 4 = anchor_mismatch
fremforge audit-verify acme || {
echo "integrity check failed with exit code $?"
exit 1
}See audit chain integrity for the full guarantee.
Self-service data export
# Kick off
fremforge data-export start acme | jq .
# Poll
fremforge data-export list acme | jq '.[] | {id, status, created_at}'See data export for the artifact format, retention, and signed-URL download flow.
Dependency updates (hosted Renovate)
fremforge dependency-updates enable acme
fremforge dependency-updates run-now acme # 1/h rate-limit appliesSee dependency updates for what gets enrolled and how to scope it per-repo.
SBOM download
fremforge sbom acme/api v1.4.0 --format=spdx > sbom.spdx.json
fremforge sbom acme/api v1.4.0 --format=cyclonedx > sbom.cyclonedx.jsonAudit log slice
fremforge audit-log acme --since=2026-05-01 --action=push-protection-override | jq .CI runs + logs
List recent runs, then pull a run’s full logs (every job concatenated) by its global run id:
# List the 20 most recent runs as a table
fremforge runs acme/api --human
# Script-friendly: grab the newest run id, then fetch its logs
run_id=$(fremforge runs acme/api --limit=1 | jq -r '.workflow_runs[0].id')
fremforge runs logs acme/api "$run_id"
# Tail just the failing step
fremforge runs logs acme/api "$run_id" | grep -iE "error|failed|exit code" | tail<run-id> is the global run id shown by fremforge runs (the .workflow_runs[].id field) — not the per-workflow run number in the web UI URL. The logs endpoint returns text/plain with all jobs in one response; no per-job artifact download needed.
Mint a scoped PAT for CI
After your first fremforge auth login, mint narrow-scoped child tokens for CI without leaving the terminal. The token is printed once — capture it immediately:
fremforge auth tokens create --name=ci-readonly --scopes=findings:read,orgs:read --ttl-days=30 \
| jq -r .token
fremforge auth tokens list --human
fremforge auth tokens revoke <token-id>You can only grant scopes your own token already holds, and wildcard (*) cannot be minted here.
Manage CI secrets
fremforge secrets list acme
# Pass the value via env (preferred — not in shell history or `ps`)
FREMFORGE_SECRET_VALUE="$(cat ./deploy-key)" fremforge secrets set acme DEPLOY_KEY
fremforge secrets delete acme OLD_TOKENSeats / members
fremforge seats list acme --human # cap + usage + roster
fremforge seats add acme --email=jane@acme.io --full-name="Jane Doe"
fremforge seats remove acme janeAdding a member over the contracted seat cap returns a 409 with a billing link — buy more seats first.
Output format
By default every command emits JSON to stdout, script-friendly and pipe-friendly. Pass --human on the commands that support it (currently audit-verify) for a formatted summary.
Updating the CLI
The one-liner installer is idempotent, running it again pulls the latest binary, re-verifies the checksum, and overwrites the old binary in place:
curl -sSfL https://cli.frem.sh/cli/install.sh | shSovereignty notes
The CLI distribution path is fully EU-sovereign:
- Binaries: T Cloud Public OBS (eu-de, Magdeburg / Biere, Germany), behind a Bunny pull-zone restricted to EU PoPs only.
- SHA256SUMS + DSSE envelope: A separate T Cloud Public OBS bucket (
trust.frem.sh) with a separate writer credential, splitting the binary host from the integrity host means compromising one cannot forge a match against the other. - Trust root: Static JSON file served from
www.frem.sh(same Bunny EU-only routing). - No npm registry dependency: registry.npmjs.com runs in US AWS; the CLI never touches it on install or on use.
- No Docker Hub dependency: same reason.
- No Sigstore Fulcio / Rekor: Sigstore’s transparency log is US-hosted. fremforge runs its own Ed25519 signer + a static trust root rather than depending on Fulcio.
Sub-processors involved on the install path are listed in the public sub-processor register and are the same ones already covering customer Personal Data per the DPA Annex B.