- Rust 96.4%
- Shell 3%
- Makefile 0.6%
| .forgejo | ||
| assets | ||
| claude | ||
| dist/homebrew | ||
| docs | ||
| hooks | ||
| scripts | ||
| src | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| SECURITY.md | ||
fj
A native CLI for Forgejo and Gitea-compatible forges.
Open PRs, triage issues, ship releases, and tail Actions logs from the terminal,
all from a single binary. Tokens prefer your OS keychain, with a 0600 file fallback for headless hosts. Multi-host from day one.
Why fj
If you self-host Forgejo or Gitea, scripting it has meant pasting curl
commands, juggling a ~/.netrc, or wrapping your own scripts around git and
the web UI. tea exists but lags Forgejo features and ships no signed release.
fj is the piece in the middle: a single binary that tracks the Forgejo
/api/v1 surface, ships signed and notarized macOS builds (no Gatekeeper
warnings), a Linux binary, and a Homebrew tap. Tokens prefer the
macOS Keychain, the Linux Secret Service, or the Windows Credential Manager.
On headless systems without a usable keychain, fj falls back to a 0600
tokens.toml in its XDG config directory. FJ_TOKEN is always checked first
and overrides persistent storage for that process.
What you get over hand-rolled scripts:
- Repo auto-detection. Inside any clone,
fj pr listalready knows the repo and the host. No-Rplumbing. - Retry, pagination, and a jq-ish projector built into every call.
- JSON-native output (
--json,--json-fields) so scripts and AI agents can drive it without screen-scraping.
Compatibility: built and tested against Forgejo (7.x and newer); most commands work on Gitea too. See docs/compatibility.md.
Install
Homebrew (macOS and Linux x86_64), signed and notarized:
brew tap rasterandstate/tap
brew install fj
Linux tarball:
curl -fsSL https://rasterhub.com/rasterstate/fj/releases/download/v0.2.0/fj-v0.2.0-linux-x86_64.tar.gz | tar -xz
sudo mv fj-v0.2.0-linux-x86_64/fj /usr/local/bin/fj
From source (any platform with a current Rust toolchain):
cargo install --git https://rasterhub.com/rasterstate/fj --tag v0.2.0
Windows compiles but is untested. File an issue if you try it.
Quickstart
fj auth login # pick Fjord Account or a Forgejo token; stored in keychain or 0600 file fallback
fj repo view # auto-detects the repo from your git remote
fj pr list --state all -L 10 # latest 10 PRs
fj pr list --base main --no-draft # branch/draft filters
fj issue list --milestone v1 --mentioned alice
fj issue create --template bug # seed body from repo templates
fj pr create --template # choose a PR template interactively
fj api /version # raw API escape hatch
-R/--repo is always optional inside a clone (fj reads origin then
upstream to find the slug). Outside a clone, pass it explicitly. create --template uses Forgejo's issue-template API when present and falls back to
reading template files from the repository's default branch.
Everyday workflows
Review a PR:
fj pr checkout 42 # fetch and check out the PR branch
fj pr diff 42 | less # or `fj pr files 42` for a file summary
fj pr review 42 --event approve --body "LGTM"
fj pr request-review 42 alice bob # tag specific reviewers
Triage your inbox:
fj pr status # cross-repo dashboard of PRs you care about
fj status # notifications inbox
fj status --mark-read # clear it
Cut a release:
fj release create v1.2.3 \
--title "1.2.3" \
--body "$(cat RELEASE_NOTES.md)" \
--asset dist/foo-x86_64.tar.gz
Inspect an Actions run:
fj run view 42 --log-failed # failed steps across every job
fj run view 42 --log --job 1 # one job's full log
fj run download 42 --list --json # artifacts as JSON
Built for automation and agents
fj is JSON-native, so it scripts cleanly and AI agents can drive it without
parsing tables:
fj pr list --json --json-fields number,title,user.login # selective JSON projection
fj api /repos/foo/bar/pulls --paginate -q '.[].number' # raw API + jq-ish path
It also ships a Claude Code plugin so agents (and people) can drive fj from natural language:
/plugin marketplace add rasterandstate/fj-claude-plugin
/plugin install fj@rasterandstate
And fj agent review / fix / explain bring AI code ops to the terminal,
with local secret redaction before anything leaves your machine.
See docs/agent.md. (preview)
Stacked PRs
fj stack manages a chain of dependent branches and their PRs: each PR targets
the one below it, and the chain merges bottom-up. State is local and
git-native in .git/fj/stack.json, with no server state.
fj stack new "Login Flow" # author a stack and its first branch
fj stack review # PR number, review, CI, and mergeability per item
fj stack sync # push branches and create/update the PRs
fj stack ship # merge bottom-up behind a green-and-approved gate
Full guide, including split and absorb: docs/stacks.md. (preview)
Command reference
Run fj --help for the live list; every group has its own --help.
| Area | Commands |
|---|---|
| Repos and code | repo, issue, pr, release, search, browse |
| Actions | run, workflow, secret, variable |
| Account and host | auth, instances, org, ssh-key, gpg-key |
| Power and config | api, alias, config, protect, hook, extension, completion, man |
| Preview | work, stack, agent |
Global flags (work on every command): --host / FJ_HOST, --debug,
--color, --no-pager, and --json-fields.
--color=auto|always|never controls ANSI color output. Precedence is
--color, then NO_COLOR / FORCE_COLOR, then fj config set no_color true,
then terminal detection.
--json applies to data-returning commands such as list, view, and other
commands that document JSON output. --web applies to list/view commands that
can open results in the browser.
Configuration
| Location | What |
|---|---|
$XDG_CONFIG_HOME/fj/hosts.toml (~/Library/Application Support/fj/hosts.toml on macOS) |
host registry + current default |
$XDG_CONFIG_HOME/fj/aliases.toml |
user-defined command shortcuts |
$XDG_CONFIG_HOME/fj/config.toml |
editor / pager / browser / color preferences |
OS keychain, service fj, key = hostname |
Preferred persistent API token store |
$XDG_CONFIG_HOME/fj/tokens.toml |
0600 fallback token store when the OS keychain is unavailable |
FJ_TOKEN |
Process-scoped token override for headless/CI jobs; checked before persistent stores |
Contributing
git clone https://rasterhub.com/rasterstate/fj
cd fj
cargo build --release # ~4 MB stripped binary at target/release/fj
./scripts/install-hooks.sh # local gates: fmt, clippy -D warnings, tests, audit, release build
make install puts a signed copy on your PATH and installs the man pages.
See CONTRIBUTING.md for the full workflow and
docs/architecture.md for the module graph and design.
Documentation
docs/architecture.md: module graph, HTTP funnel, repo resolution, test strategydocs/stacks.md: stacked branches and PRsdocs/agent.md: AI-assisted code opsdocs/jq.md:fj api --jqprojection syntaxdocs/compatibility.md: Forgejo version matrix and known caveatsdocs/faq.md: tokens, hosts, debug, scripting, pluginsdocs/troubleshooting.md: keychain prompts, 401s, hook bypass, pager opt-outCONTRIBUTING.md: build / test / release workflowCHANGELOG.md: release notesSECURITY.md: security policy + threat model
License
MIT.