Bootstrap command and gfj alias
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
- Created
src/gh_forgejo_shim/bootstrap.pywith repository detection, host allowlisting, shim installation, PATH checks, auth checks, and Git remote checks. - Added the
bootstrapsubcommand to the existing argparse CLI. - Added the
gfjentry point inpyproject.tomlas a shorter alias for the same CLI. - Added tests covering successful bootstrap, missing PATH/auth/origin metadata repair output, and origin repair suggestions from a non-origin Forgejo remote.
- Updated the README install and quickstart sections to lead with
gfj bootstrap.
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
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.
Failures include commands such as export PATH=..., git fetch origin, git remote set-head origin -a, and branch upstream setup.
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.
1 unmodified line23456783 unmodified lines1213141516171818 unmodified lines37383940414243444546474849505152535448 unmodified lines103104105106107108101 unmodified lines2102112122132142152162172182192202212221 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 linespipx install gh-forgejo-shim```Then add at least one Forgejo host:```shgh-forgejo-shim config add-host git.example.com18 unmodified lines## Quickstart For GitHub-Style Tools1. 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:```shgh-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 CoversGitHub-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 linesgh 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 Commands101 unmodified linesRemove the generated wrapper:```shgh-forgejo-shim uninstall-shim```Remove the macOS GUI PATH LaunchAgent:```shgh-forgejo-shim uninstall-gui-path```See [docs/rollback.md](docs/rollback.md) for PATH troubleshooting and recovery steps.1 unmodified line23456783 unmodified lines12131415161718192021222324252627282930313218 unmodified lines515253545556575859606162636465666768697048 unmodified lines119120121122123124125126101 unmodified lines2282292302312322332342352362372382392401 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 linespipx install gh-forgejo-shim```From inside a Forgejo checkout, run the bootstrap command:```shgfj 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:```shgh-forgejo-shim bootstrap```If you prefer to do the setup manually, add at least one Forgejo host:```shgh-forgejo-shim config add-host git.example.com18 unmodified lines## Quickstart For GitHub-Style Tools1. 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:```shgfj 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 CoversGitHub-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 linesgh 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 Commands101 unmodified linesRemove the generated wrapper:```shgfj uninstall-shim```Remove the macOS GUI PATH LaunchAgent:```shgfj uninstall-gui-path```See [docs/rollback.md](docs/rollback.md) for PATH troubleshooting and recovery steps.
31 unmodified lines32333435363731 unmodified lines[project.scripts]gh-forgejo-shim = "gh_forgejo_shim.cli:main"[tool.setuptools]package-dir = { "" = "src" }31 unmodified lines3233343536373831 unmodified lines[project.scripts]gh-forgejo-shim = "gh_forgejo_shim.cli:main"gfj = "gh_forgejo_shim.cli:main"[tool.setuptools]package-dir = { "" = "src" }
4 unmodified lines567891038 unmodified lines49505152535455 unmodified lines1101111121131141154 unmodified linesfrom pathlib import Pathfrom . import __version__from .config import add_host, load_config, remove_hostfrom .doctor import format_checks, run_checksfrom .gui_path import install_gui_path, uninstall_gui_path38 unmodified linesprint(format_checks(checks))return 0 if all(check.ok for check in checks) else 1if 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 linessubparsers.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 lines56789101138 unmodified lines50515253545556575859606162636465666755 unmodified lines1231241251261271281291301311321331341351364 unmodified linesfrom pathlib import Pathfrom . import __version__from .bootstrap import format_bootstrap, run_bootstrapfrom .config import add_host, load_config, remove_hostfrom .doctor import format_checks, run_checksfrom .gui_path import install_gui_path, uninstall_gui_path38 unmodified linesprint(format_checks(checks))return 0 if all(check.ok for check in checks) else 1if 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 1print(format_bootstrap(result))return 0 if result.ok else 1if 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 linessubparsers.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
bootstrapchecks for discoverable auth tokens but does not make a network call to Forgejo. This avoids surprising remote API behavior during setup.- Git remote repair is printed rather than applied. That keeps repository history and remotes under the user's control.
- If
~/.local/bin/ghexists and is not managed by this project, bootstrap refuses to overwrite unless the user passes--force. - The Beads Dolt pull step failed because this local Beads database has no configured remote. The code and exported Beads files were still committed locally.
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.