167 lines
7.2 KiB
Markdown
167 lines
7.2 KiB
Markdown
|
|
# fj — guide for Claude Code sessions
|
||
|
|
|
||
|
|
`fj` is a personal Forgejo/Gitea CLI tool, modeled on GitHub's `gh`. It targets `forgejo.zerova.net` (and Codeberg). The user (sid) owns it; the canonical repo is `public/fj` on forgejo.zerova.net (mirrored from there to nowhere else).
|
||
|
|
|
||
|
|
This file is read first by Claude Code when working in `~/repos/fj`. Goal: get a session productive quickly without re-deriving the dev workflow each time.
|
||
|
|
|
||
|
|
## Layout
|
||
|
|
|
||
|
|
```
|
||
|
|
~/repos/fj/
|
||
|
|
├── cmd/ cobra command definitions, one file per subject area
|
||
|
|
│ ├── root.go rootCmd, --config plumbing, OnInitialize
|
||
|
|
│ ├── auth.go login/status/logout/token (uses persistent --hostname)
|
||
|
|
│ ├── api.go raw API access; --json/--json-fields/--jq/--paginate
|
||
|
|
│ ├── json.go shared JSON output helpers (addJSONFlags/wantJSON/outputJSON)
|
||
|
|
│ ├── paginate.go generic paginateGitea[T] helper for list commands
|
||
|
|
│ ├── errors.go CLIError with structured Hint field
|
||
|
|
│ ├── actions.go Forgejo Actions; runs/workflows via factory functions
|
||
|
|
│ ├── aliases.go top-level `fj run` / `fj workflow` aliases — calls actions.go factories
|
||
|
|
│ ├── repo.go pr.go issue.go release.go wiki.go label.go milestone.go
|
||
|
|
│ └── ...
|
||
|
|
├── internal/
|
||
|
|
│ ├── api/client.go SharedHTTPClient (30s timeout); GetJSON/DoJSON/DownloadFile
|
||
|
|
│ ├── config/config.go YAML config; honors --config via SetExplicitConfigPath
|
||
|
|
│ ├── git/ repo + host detection from `git remote`
|
||
|
|
│ ├── iostreams/ wrapped stdin/stdout/stderr + spinner + pager + colors
|
||
|
|
│ └── text/ formatting helpers
|
||
|
|
├── main.go thin entrypoint; ContextualError + JSON-error rendering
|
||
|
|
├── Makefile build / lint / test (no release automation)
|
||
|
|
├── CHANGELOG.md Keep-a-Changelog format
|
||
|
|
└── README.md
|
||
|
|
```
|
||
|
|
|
||
|
|
## Build, install, test
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go build ./... # quick build check
|
||
|
|
go test ./... # unit tests
|
||
|
|
go install . # build + install to ~/go/bin/fj (the binary that's on PATH)
|
||
|
|
make lint # golangci-lint, if you have it
|
||
|
|
```
|
||
|
|
|
||
|
|
After any change in cmd/ or internal/, run `go install .` and the global `fj` reflects it immediately. There's no daemon/restart.
|
||
|
|
|
||
|
|
## Auth
|
||
|
|
|
||
|
|
The user is authenticated as `sid` on `forgejo.zerova.net`. Token lives in `~/.config/fj/config.yaml` (mode 0600). For HTTPS git pushes from this host, the token can be injected via `git -c "http.extraHeader=Authorization: token <T>" push` — the local SSH key (`sid@debian` on forgejo) is also registered, so `git@forgejo.zerova.net:public/fj.git` works directly.
|
||
|
|
|
||
|
|
## Code review pattern (use this for non-trivial changes)
|
||
|
|
|
||
|
|
For audits or significant refactors, run **three reviewers in parallel** with non-overlapping focuses (we did this in the v0.4.0 cycle and it found bugs none would have caught alone):
|
||
|
|
|
||
|
|
- **Codex** — read-only sandbox, peer-AI cross-check
|
||
|
|
```bash
|
||
|
|
codex exec --skip-git-repo-check --sandbox read-only \
|
||
|
|
-m gpt-5.4-mini --config model_reasoning_effort="medium" "<prompt>" 2>/dev/null
|
||
|
|
```
|
||
|
|
For follow-up rounds resume the same session: `echo "<prompt>" | codex exec --skip-git-repo-check resume --last 2>/dev/null`. Codex remembers prior critique.
|
||
|
|
|
||
|
|
- **Claude general-purpose agent A** — architecture / UX / code-quality
|
||
|
|
- **Claude general-purpose agent B** — security / correctness / error handling
|
||
|
|
|
||
|
|
Tell each reviewer what the **siblings** are covering so they don't duplicate. Cap reports at ~600 words. Consolidate findings by severity (HIGH / MEDIUM / LOW) before presenting to the user.
|
||
|
|
|
||
|
|
## Release process
|
||
|
|
|
||
|
|
We use semver. **Pre-1.0**: breaking change → minor bump (e.g. v0.3.x → v0.4.0).
|
||
|
|
|
||
|
|
1. **Bump version**
|
||
|
|
```go
|
||
|
|
// cmd/root.go
|
||
|
|
Version: "0.4.0",
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Update CHANGELOG.md** — prepend a new section. Format:
|
||
|
|
```markdown
|
||
|
|
## [0.4.0] - YYYY-MM-DD
|
||
|
|
|
||
|
|
### BREAKING
|
||
|
|
- <thing that broke>
|
||
|
|
|
||
|
|
### Added
|
||
|
|
- ...
|
||
|
|
### Changed
|
||
|
|
- ...
|
||
|
|
### Fixed
|
||
|
|
- ...
|
||
|
|
### Security
|
||
|
|
- ...
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Commit** the version+changelog bump as a single commit:
|
||
|
|
```bash
|
||
|
|
git commit -m "chore: bump version to 0.4.0"
|
||
|
|
```
|
||
|
|
|
||
|
|
4. **Tag** the commit:
|
||
|
|
```bash
|
||
|
|
git tag -a v0.4.0 -m "Release v0.4.0: <one-line summary>"
|
||
|
|
```
|
||
|
|
|
||
|
|
5. **Push** commits and tag:
|
||
|
|
```bash
|
||
|
|
git push origin main
|
||
|
|
git push origin v0.4.0
|
||
|
|
```
|
||
|
|
|
||
|
|
6. **Create the Forgejo release page** via fj itself:
|
||
|
|
```bash
|
||
|
|
fj release create v0.4.0 \
|
||
|
|
--title "v0.4.0: <summary>" \
|
||
|
|
--notes "$(awk '/^## \[0.4.0\]/{flag=1;next} /^## /{flag=0} flag' CHANGELOG.md)"
|
||
|
|
```
|
||
|
|
(The awk one-liner extracts the just-added CHANGELOG section as release notes.)
|
||
|
|
|
||
|
|
7. **Update the homebrew tap** — see the next section.
|
||
|
|
|
||
|
|
## Updating the homebrew tap (`public/homebrew-sid`)
|
||
|
|
|
||
|
|
The tap lives at `~/repos/homebrew-sid` (or `git@forgejo.zerova.net:public/homebrew-sid.git`). The `Formula/fj.rb` formula references the source by `tag:` + `revision:` (SHA), so a release bump touches three lines:
|
||
|
|
|
||
|
|
```ruby
|
||
|
|
url "ssh://git@forgejo.zerova.net/public/fj.git",
|
||
|
|
tag: "v0.4.0", # was v0.3.2
|
||
|
|
revision: "<SHA of v0.4.0 tag>" # update
|
||
|
|
|
||
|
|
test do
|
||
|
|
assert_match "0.4.0", shell_output("#{bin}/fj --version") # update
|
||
|
|
end
|
||
|
|
```
|
||
|
|
|
||
|
|
To get the SHA:
|
||
|
|
```bash
|
||
|
|
git -C ~/repos/fj rev-parse v0.4.0
|
||
|
|
```
|
||
|
|
|
||
|
|
Then in `~/repos/homebrew-sid`:
|
||
|
|
```bash
|
||
|
|
# edit Formula/fj.rb (the three lines above)
|
||
|
|
git commit -am "fj: bump to v0.4.0"
|
||
|
|
git push origin main
|
||
|
|
```
|
||
|
|
|
||
|
|
After push, users can `brew update && brew upgrade fj` to pick up the new version.
|
||
|
|
|
||
|
|
## Common footguns
|
||
|
|
|
||
|
|
- **`fj` reads the current dir's `git origin`** to detect the host. In a directory whose origin points at github.com (e.g. /opt/stacks/claude-code-proxy/build), bare `fj api ...` errors with "no configuration found for host github.com". Pass `--hostname forgejo.zerova.net` explicitly, or `cd` somewhere else.
|
||
|
|
- **`--json=fields` was removed in v0.4.0** in favor of `--json-fields fields` (or `--json-fields=fields`). The old `=fields` form was a `NoOptDefVal=" "` sentinel hack. `--json` is now a plain Bool meaning "as JSON".
|
||
|
|
- **`--config` was silently ignored before v0.4.0.** Old fj versions read --config into Viper but `internal/config.Load()` always read the default path. Fixed; `fj --config other.yaml auth login` now writes to other.yaml.
|
||
|
|
- **The `actions` and `run`/`workflow` command trees share factory functions** in `cmd/actions.go` (`newRunCmd`, `newWorkflowCmd`). Don't add flags directly to `runListCmd` style globals — they don't exist anymore. Edit the factory and both `fj actions run list` and `fj run list` get the change.
|
||
|
|
|
||
|
|
## Useful commands
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Live test against forgejo (using the new flags)
|
||
|
|
fj --hostname forgejo.zerova.net api repos/public/fj --json-fields full_name,description
|
||
|
|
|
||
|
|
# Walk paginated endpoints
|
||
|
|
fj --hostname forgejo.zerova.net api 'repos/public/fj/commits?limit=10' --paginate --jq '.[].sha[0:8]'
|
||
|
|
|
||
|
|
# Confirm both command trees stay in sync after edits
|
||
|
|
diff <(fj run list --help | grep -E "^ -|^ --" | sort) \
|
||
|
|
<(fj actions run list --help | grep -E "^ -|^ --" | sort)
|
||
|
|
# Empty diff = trees agree. Any output = factory drift.
|
||
|
|
```
|