Skip to content

Getting started with thfg

thfg is a gh-style command-line interface for Forgejo, designed to work with the Forgejo API Proxy. This guide walks you through installation, configuration, and your first commands.

Already installed? Jump to Common first commands or read the thfg vs thfg api vs curl decision guide to understand when to reach for each tool.


Terminal window
git clone https://pastoral-oyster.pikapod.net/forgejo-proxy/forgejo-proxy-cli.git
cd forgejo-proxy-cli

The CLI depends on @forgejo-proxy/sdk, published to a private registry protected by Authelia. Obtain a read token from the team Bitwarden vault (entry: npm.registry.hochguertel.work), then:

Terminal window
cp .npmrc.example .npmrc
# Edit .npmrc — replace YOUR_TOKEN_HERE with your token

Your .npmrc should look like:

@forgejo-proxy:registry=https://npm.registry.hochguertel.work/
//npm.registry.hochguertel.work/:_authToken=<your-token>

Option A — global install (recommended):

Terminal window
task cli:global:install

This builds the CLI and installs it globally so that thfg is available anywhere in your terminal. This is the easiest approach for daily use.

Option B — manual link:

Terminal window
bun install
cd packages/cli && bun link

Verify the install:

Terminal window
thfg --help

Terminal window
# Log in with a Forgejo API token
thfg auth login --token <YOUR_FORGEJO_TOKEN>
# Also store WebUI credentials (needed for project and log commands)
thfg auth login --username <your-username> --password <your-password>
# Check your auth state
thfg auth status

The config is stored at ~/.config/thfg/config.json. The top-level key is hosts, an array of HostEntry objects — one per Forgejo instance.

{
"hosts": [
{
"name": "my-forgejo",
"host": "https://forgejo.example.com",
"proxyUrl": "https://forgejo-proxy.example.com",
"token": "your-api-token",
"username": "your-forgejo-username",
"password": "your-forgejo-password",
"remotes": [
"git@forgejo.example.com",
"https://forgejo.example.com"
]
}
],
"defaultOrg": "my-org",
"defaultRepo": "my-org/my-repo"
}
FieldRequiredDescription
nameyesUnique identifier for this host entry
hostyesForgejo instance base URL
proxyUrlnoForgejo API Proxy URL — routes API calls through the proxy
tokennoForgejo API token (set via thfg auth login)
usernamenoWebUI username — required for project and log commands
passwordnoWebUI password — required for project and log commands
remotesnoGit remote URL prefixes used to auto-detect this host

Add multiple entries to hosts to work with more than one Forgejo instance. thfg selects the active host by matching your git remote URL against the remotes prefixes in each entry. When working outside a git repo, the first host in the array is used as the default.

{
"hosts": [
{
"name": "personal",
"host": "https://forgejo.personal.example.com",
"remotes": ["git@forgejo.personal.example.com"]
},
{
"name": "work",
"host": "https://forgejo.work.example.com",
"proxyUrl": "https://proxy.work.example.com",
"remotes": ["git@forgejo.work.example.com", "https://forgejo.work.example.com"]
}
]
}
VariableDescription
FORGEJO_HOSTOverride Forgejo host URL (creates a transient entry, never written to disk)
FORGEJO_TOKEN / FORGEJO_API_TOKENOverride the API token
FORGEJO_PROXY_URLOverride the proxy URL
FORGEJO_WEBUI_USERNAMEWebUI username — used when FORGEJO_HOST is active (CI/CD)
FORGEJO_WEBUI_PASSWORDWebUI password — used when FORGEJO_HOST is active (CI/CD)

Terminal window
# List repositories in your default org
thfg repo list
# List issues detected from the current git repo
thfg issue list
# Dispatch a workflow
thfg workflow run deploy.yml --repo myorg/myrepo
# List workflow runs (newest first)
thfg run list --repo myorg/myrepo
# List projects for an org (requires WebUI credentials)
thfg project list --org myorg
# Show config
thfg config list
# Output in JSON or YAML
thfg repo list --output-format json
thfg run list --output-format yaml

Terminal window
thfg repo list
thfg repo view myorg/myrepo
thfg repo create my-new-repo --description "..." --private
thfg repo clone myorg/myrepo
Terminal window
thfg issue list --repo myorg/myrepo --state open
thfg issue list --me # issues assigned to you across all repos
thfg issue view 42 --repo myorg/myrepo
thfg pr list --repo myorg/myrepo
thfg pr merge 7 --repo myorg/myrepo
Terminal window
# List files in a repository directory
thfg repo file list myorg/myrepo
thfg repo file list myorg/myrepo --path src/
# Read a file's contents from a repository
thfg repo file get myorg/myrepo --path README.md
thfg repo file get myorg/myrepo --path src/main.py --ref v1.2.0 # specific branch/tag/commit
Terminal window
thfg workflow list --repo myorg/myrepo
thfg workflow run deploy.yml --repo myorg/myrepo
thfg run list --repo myorg/myrepo
thfg run logs --repo myorg/myrepo --job failed
thfg run watch 123 --repo myorg/myrepo
Terminal window
thfg secret list --repo myorg/myrepo
thfg secret set MY_SECRET=value --repo myorg/myrepo
thfg variable list --repo myorg/myrepo
thfg variable set MY_VAR=value --repo myorg/myrepo

When thfg doesn’t have the command you need

Section titled “When thfg doesn’t have the command you need”

Use the built-in escape hatch for endpoints under the normalized /api/v1 surface:

Terminal window
# Send an authenticated request to an /api/v1 endpoint
thfg api /repos/myorg/myrepo/topics
# PATCH with JSON fields
thfg api /repos/myorg/myrepo --method PATCH --field description="New desc"
# Inspect the merged proxy contract
thfg api spec

Root-path exceptions stay separate:

Terminal window
# Health stays at the root
curl "$FORGEJO_PROXY_URL/health"
# ActivityPub uses dedicated commands
thfg activitypub repo actor myorg/myrepo

Read the full decision guide: thfg vs thfg api vs curl

If you are updating older scripts, follow Migrate to the normalized /api/v1 API surface.


SymptomFix
thfg: command not foundRun task cli:global:install from the repo root, or cd packages/cli && bun link
401 UnauthorizedCheck token with thfg auth status
401 on project listAdd WebUI credentials: thfg auth login --username u --password p
invalid repo formatRun from a git repo or set a default: thfg repo set-default owner/repo
Connection errorsCheck proxyUrl in thfg config list