Bootstrap command and gfj alias

2026-05-31 Beads: gh-forgejo-shim-crk Repository implementation task

Added a first-run bootstrap command that detects the current Forgejo repository, allowlists its host, installs the shim, checks PATH and auth, validates common Git remote shape, and prints exact repair commands. Added gfj as a shorter console alias and updated the README quickstart around it.

Summary

The setup path is now centered on one command: gfj bootstrap. It performs safe setup steps automatically and leaves users with concrete shell commands for anything that needs manual repair.

Changes Made

Context

Non-expert users can get stuck because GitHub-style tools need several things to line up at once: a detectable repository, a configured Forgejo host allowlist, an installed gh wrapper, a PATH where that wrapper wins, auth that the shim can discover, and conventional origin/origin/HEAD metadata. The bootstrap command gathers those checks into one guided pass.

Important Implementation Details

Safe mutations.

The command writes the host allowlist and installs the managed shim. It does not rewrite Git remotes automatically, because that can affect user workflow. Instead, it prints exact commands.

Repair output.

Failures include commands such as export PATH=..., git fetch origin, git remote set-head origin -a, and branch upstream setup.

Alias strategy.

gh-forgejo-shim remains the explicit durable command. gfj maps to the same entry point for day-to-day use.

Relevant Diff Snippets

Rendered with Diffs server-side rendering through @pierre/diffs/ssr, so the saved document includes static diff markup and remains readable offline.

README.md
-9+27
1 unmodified line
2
3
4
5
6
7
8
3 unmodified lines
12
13
14
15
16
17
18
18 unmodified lines
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
48 unmodified lines
103
104
105
106
107
108
101 unmodified lines
210
211
212
213
214
215
216
217
218
219
220
221
222
1 unmodified line
`gh-forgejo-shim` is a small, stdlib-only Python CLI for Codex.app, T3 Code, and other GitHub-oriented tools used with Forgejo repositories.
It installs a durable management command named `gh-forgejo-shim`. When you opt in, it can also place a user-local `gh` wrapper in front of the real GitHub CLI. Real GitHub repositories still go to the real `gh`; allowlisted Forgejo repositories route a narrow set of repository and pull request commands through Forgejo-friendly behavior.
V1 is not full `gh` emulation. It exists to keep GitHub-style development tools from treating Forgejo repositories like broken GitHub repositories.
3 unmodified lines
pipx install gh-forgejo-shim
```
Then add at least one Forgejo host:
```sh
gh-forgejo-shim config add-host git.example.com
18 unmodified lines
## Quickstart For GitHub-Style Tools
1. Install the package with `pipx`.
2. Add each Forgejo host explicitly.
3. Install the shim.
4. On macOS, run `gh-forgejo-shim install-gui-path` if the tool was launched from Finder, Dock, Spotlight, or another GUI launcher.
5. Make sure the Forgejo repository has an `origin` remote, fetched `origin/*` refs, an `origin/HEAD` default branch pointer, and branch upstream tracking. Codex.app, T3 Code, and other GitHub-style tools often probe conventional Git metadata before they ask `gh` for repository or pull request details.
6. Confirm the setup:
```sh
gh-forgejo-shim doctor
```
7. Restart the GUI tool, open the Forgejo repository, and use the normal repository, branch, commit, push, and pull request workflows.
## What This Setup Covers
GitHub-style tools do not rely only on `gh pr ...`. They commonly combine plain Git commands with GitHub CLI commands. The shim helps with the GitHub CLI side, while the repository remote shape below helps the tool recognize the repository before it invokes `gh`.
48 unmodified lines
gh pr status --json number,title,url,headRefName,state
```
If your tool is connected to a remote SSH workspace, apply the same remote setup inside that remote checkout too. Fixing the local Mac checkout does not change a separate remote clone.
## Supported Wrapper Commands
101 unmodified lines
Remove the generated wrapper:
```sh
gh-forgejo-shim uninstall-shim
```
Remove the macOS GUI PATH LaunchAgent:
```sh
gh-forgejo-shim uninstall-gui-path
```
See [docs/rollback.md](docs/rollback.md) for PATH troubleshooting and recovery steps.
1 unmodified line
2
3
4
5
6
7
8
3 unmodified lines
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
18 unmodified lines
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
48 unmodified lines
119
120
121
122
123
124
125
126
101 unmodified lines
228
229
230
231
232
233
234
235
236
237
238
239
240
1 unmodified line
`gh-forgejo-shim` is a small, stdlib-only Python CLI for Codex.app, T3 Code, and other GitHub-oriented tools used with Forgejo repositories.
It installs a durable management command named `gh-forgejo-shim`, plus a shorter daily-use alias named `gfj`. When you opt in, it can also place a user-local `gh` wrapper in front of the real GitHub CLI. Real GitHub repositories still go to the real `gh`; allowlisted Forgejo repositories route a narrow set of repository and pull request commands through Forgejo-friendly behavior.
V1 is not full `gh` emulation. It exists to keep GitHub-style development tools from treating Forgejo repositories like broken GitHub repositories.
3 unmodified lines
pipx install gh-forgejo-shim
```
From inside a Forgejo checkout, run the bootstrap command:
```sh
gfj bootstrap
```
`bootstrap` detects the current repository, adds its host to the allowlist, installs the user-local `gh` shim, checks whether PATH resolves to the shim, verifies that Forgejo auth can be discovered, checks `origin` and `origin/HEAD`, and prints exact repair commands for anything it cannot fix automatically.
The long command name works the same way:
```sh
gh-forgejo-shim bootstrap
```
If you prefer to do the setup manually, add at least one Forgejo host:
```sh
gh-forgejo-shim config add-host git.example.com
18 unmodified lines
## Quickstart For GitHub-Style Tools
1. Install the package with `pipx`.
2. Open a terminal inside your Forgejo repository.
3. Run `gfj bootstrap`.
4. Copy and run any repair commands it prints.
5. On macOS, run `gfj install-gui-path` if the tool was launched from Finder, Dock, Spotlight, or another GUI launcher.
6. Confirm the setup:
```sh
gfj doctor
```
7. Restart the GUI tool, open the Forgejo repository, and use the normal repository, branch, commit, push, and pull request workflows.
For scripted setup or documentation, use `gh-forgejo-shim`. For day-to-day typing, `gfj` is the same command with a shorter name.
## What This Setup Covers
GitHub-style tools do not rely only on `gh pr ...`. They commonly combine plain Git commands with GitHub CLI commands. The shim helps with the GitHub CLI side, while the repository remote shape below helps the tool recognize the repository before it invokes `gh`.
48 unmodified lines
gh pr status --json number,title,url,headRefName,state
```
`gfj bootstrap` checks these same basics and prints the matching commands when something is missing.
If your tool is connected to a remote SSH workspace, apply the same remote setup inside that remote checkout too. Fixing the local Mac checkout does not change a separate remote clone.
## Supported Wrapper Commands
101 unmodified lines
Remove the generated wrapper:
```sh
gfj uninstall-shim
```
Remove the macOS GUI PATH LaunchAgent:
```sh
gfj uninstall-gui-path
```
See [docs/rollback.md](docs/rollback.md) for PATH troubleshooting and recovery steps.
pyproject.toml
+1
31 unmodified lines
32
33
34
35
36
37
31 unmodified lines
[project.scripts]
gh-forgejo-shim = "gh_forgejo_shim.cli:main"
[tool.setuptools]
package-dir = { "" = "src" }
31 unmodified lines
32
33
34
35
36
37
38
31 unmodified lines
[project.scripts]
gh-forgejo-shim = "gh_forgejo_shim.cli:main"
gfj = "gh_forgejo_shim.cli:main"
[tool.setuptools]
package-dir = { "" = "src" }
src/gh_forgejo_shim/cli.py
+21
4 unmodified lines
5
6
7
8
9
10
38 unmodified lines
49
50
51
52
53
54
55 unmodified lines
110
111
112
113
114
115
4 unmodified lines
from pathlib import Path
from . import __version__
from .config import add_host, load_config, remove_host
from .doctor import format_checks, run_checks
from .gui_path import install_gui_path, uninstall_gui_path
38 unmodified lines
print(format_checks(checks))
return 0 if all(check.ok for check in checks) else 1
if command == "install-gui-path":
if sys.platform != "darwin":
print("gh-forgejo-shim: install-gui-path is only supported on macOS", file=sys.stderr)
55 unmodified lines
subparsers.add_parser("uninstall-gui-path", help="remove the macOS GUI PATH LaunchAgent")
subparsers.add_parser("doctor", help="check shim configuration")
subparsers.add_parser("version", help="print version")
config = subparsers.add_parser("config", help="manage persistent configuration")
4 unmodified lines
5
6
7
8
9
10
11
38 unmodified lines
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
55 unmodified lines
123
124
125
126
127
128
129
130
131
132
133
134
135
136
4 unmodified lines
from pathlib import Path
from . import __version__
from .bootstrap import format_bootstrap, run_bootstrap
from .config import add_host, load_config, remove_host
from .doctor import format_checks, run_checks
from .gui_path import install_gui_path, uninstall_gui_path
38 unmodified lines
print(format_checks(checks))
return 0 if all(check.ok for check in checks) else 1
if command == "bootstrap":
try:
result = run_bootstrap(
bin_dir=Path(namespace.bin_dir).expanduser() if namespace.bin_dir else None,
force=namespace.force,
)
except OSError as exc:
print(f"gh-forgejo-shim: {exc}", file=sys.stderr)
return 1
print(format_bootstrap(result))
return 0 if result.ok else 1
if command == "install-gui-path":
if sys.platform != "darwin":
print("gh-forgejo-shim: install-gui-path is only supported on macOS", file=sys.stderr)
55 unmodified lines
subparsers.add_parser("uninstall-gui-path", help="remove the macOS GUI PATH LaunchAgent")
subparsers.add_parser("doctor", help="check shim configuration")
bootstrap = subparsers.add_parser(
"bootstrap",
help="detect the current repo, install the shim, and print exact setup repair commands",
)
bootstrap.add_argument("--bin-dir")
bootstrap.add_argument("--force", action="store_true", help="overwrite an unrelated gh at the shim path")
subparsers.add_parser("version", help="print version")
config = subparsers.add_parser("config", help="manage persistent configuration")

Expected Impact for End-Users

New users can now run one obvious command from a Forgejo checkout, fix the listed gaps, and then return to their normal GitHub-style tool workflow. Daily commands are shorter without removing the explicit long command name from scripts or docs.

Validation

python3 -m unittest

Ran 60 tests in 3.548s
OK
bd dolt pull

Error: fetch from origin/main: Error 1105: no remote

Issues, Limitations, and Mitigations

Follow-up Work

No follow-up Beads issues were needed for this pass. A later improvement could add a --check dry-run mode if users want diagnostics without any config or shim writes.