-
Notifications
You must be signed in to change notification settings - Fork 17
Add AGENTS.md and copilot-instructions.md for AI agent onboarding
#133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+172
−0
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
8178580
Add AGENTS.md and copilot-instructions.md for AI agent onboarding
francisfuzz 96b0b6f
fix: update cmd to generate an executable binary
francisfuzz 31ee458
fix: update cmd to get the build output as an exec binary
francisfuzz 0803d01
Fix build command and errors.As usage per review feedback
francisfuzz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # gh-stack: Copilot Instructions | ||
|
|
||
| A Go CLI extension (`gh stack`) for managing stacked branches and pull requests. Uses Cobra for commands, bubbletea/lipgloss for TUI, and `stretchr/testify` for tests. | ||
|
|
||
| ## Build and validate | ||
|
|
||
| ```sh | ||
| go mod download # install deps | ||
| go build -o gh-stack . # build | ||
| go vet ./... # static analysis. Always run before tests. | ||
| go test -race -count=1 ./... # tests with race detection | ||
| ``` | ||
|
|
||
| No Makefile, no code generation, no external linter config. Standard Go toolchain only. | ||
|
|
||
| ## Project layout | ||
|
|
||
| - `cmd/`: One Cobra command per file. Each exports `<Name>Cmd(cfg *config.Config)` with logic in `run<Name>()`. | ||
| - `internal/git/`: `Ops` interface (52 methods) wrapping git CLI. `MockOps` for tests. Package-level functions delegate to swappable `ops` variable. | ||
| - `internal/github/`: `ClientOps` interface (11 methods) for GitHub API. `MockClient` for tests. | ||
| - `internal/config/`: `Config` struct passed to all commands. Holds I/O, colors, and test hooks (`SelectFn`, `ConfirmFn`, `InputFn`, `GitHubClientOverride`). | ||
| - `internal/stack/`: Stack file (`.git/gh-stack`, JSON) management with file locking. | ||
| - `internal/tui/`: bubbletea views (`stackview`, `modifyview`). | ||
|
|
||
| ## Coding conventions | ||
|
|
||
| - Return typed `ExitError` sentinels (codes 1-10 in `cmd/utils.go`) from `RunE`. Never call `os.Exit()` directly. | ||
| - Check errors with `errors.As(err, &ExitError{})`. | ||
| - Table-driven tests with `t.Run()` subtests. | ||
| - Use `config.NewTestConfig()` for test configs with captured I/O. | ||
| - Mock git: `restore := git.SetOps(&git.MockOps{...}); defer restore()`. Always defer restore. | ||
| - Mock GitHub: `cfg.GitHubClientOverride = &github.MockClient{...}`. | ||
| - Mock prompts: set `cfg.SelectFn`, `cfg.ConfirmFn`, or `cfg.InputFn`. | ||
| - Load stack files with `stack.Load(dir)` after writing to get correct checksums. | ||
|
|
||
| For full architecture details, see [AGENTS.md](../AGENTS.md) in the repository root. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # gh-stack: Agent Instructions | ||
|
|
||
| A GitHub CLI (`gh`) extension for managing stacked branches and pull requests. Written in Go, it automates creating branches, keeping them rebased, setting PR base branches, and navigating between stack layers. | ||
|
|
||
| ## Build, test, and validate | ||
|
|
||
| ```sh | ||
| go mod download # install dependencies | ||
| go build -o gh-stack . # build (produces ./gh-stack binary) | ||
| go vet ./... # static analysis. Run before tests. | ||
| go test -race -count=1 ./... # all tests with race detection | ||
| ``` | ||
|
|
||
| Always run `go vet` before `go test`. CI runs both on every push/PR across ubuntu, windows, and macOS (`test.yml`). | ||
|
|
||
| There is no Makefile, linter config, or code generation step. The standard Go toolchain is all that's needed. | ||
|
|
||
| ### Install locally as a `gh` extension | ||
|
|
||
| ```sh | ||
| go build -o gh-stack . | ||
| gh extension remove stack 2>/dev/null | ||
| gh extension install . | ||
| ``` | ||
|
|
||
| ## Project structure | ||
|
|
||
| ``` | ||
| main.go # entrypoint. Calls cmd.Execute(). | ||
| cmd/ # Cobra commands (one file per command + tests) | ||
| root.go # registers all subcommands in four groups | ||
| utils.go # shared helpers, ExitError types, exit codes | ||
| internal/ | ||
| git/ # git.Ops interface + defaultOps (exec-based) | ||
| gitops.go # Ops interface (52 methods) | ||
| mock_ops.go # MockOps. Each method has a corresponding *Fn field. | ||
| github/ # github.ClientOps interface + real Client | ||
| client_interface.go # ClientOps interface (11 methods) | ||
| mock_client.go # MockClient. Uses function-pointer fields for testing. | ||
| stack/ # stack file (.git/gh-stack) management, JSON schema, locking | ||
| schema.json # JSON Schema for the stack file format | ||
| config/ # Config struct (I/O, colors, test overrides) | ||
| testing.go # NewTestConfig(). Returns *Config + stdout/stderr pipes. | ||
| branch/ # branch naming (Slugify, DateSlug, NextNumberedName) | ||
| modify/ # interactive stack modification state machine | ||
| pr/ # PR template discovery | ||
| tui/ # bubbletea/bubbles/lipgloss terminal UI | ||
| stackview/ # interactive stack visualization | ||
| modifyview/ # interactive modify session UI | ||
| shared/ # shared TUI types | ||
| docs/ # Astro + Starlight documentation site | ||
| skills/ # AI agent skill definition (SKILL.md) | ||
| ``` | ||
|
|
||
| ### Command groups (registered in `cmd/root.go`) | ||
|
|
||
| | Group | Commands | | ||
| |-------|----------| | ||
| | Stack management | `init`, `add`, `view`, `checkout`, `modify`, `unstack` | | ||
| | Remote operations | `submit`, `sync`, `rebase`, `push`, `link` | | ||
| | Navigation | `switch`, `up`, `down`, `top`, `bottom`, `trunk` | | ||
| | Utilities | `alias`, `feedback` | | ||
|
|
||
| ## Coding patterns | ||
|
|
||
| ### Command structure | ||
|
|
||
| Each command lives in its own file (`cmd/<name>.go`) and follows this pattern: | ||
|
|
||
| 1. Define an `<name>Options` struct for flags/args. | ||
| 2. Export a `<Name>Cmd(cfg *config.Config) *cobra.Command` constructor. | ||
| 3. Implement logic in a private `run<Name>(cfg, opts, args)` function. | ||
| 4. The `RunE` field on the command calls `run<Name>`. | ||
|
|
||
| ### Error handling | ||
|
|
||
| Use typed exit codes defined in `cmd/utils.go`: | ||
|
|
||
| | Code | Sentinel | Meaning | | ||
| |------|----------|---------| | ||
| | 1 | `ErrSilent` | Error already printed | | ||
| | 2 | `ErrNotInStack` | Branch/stack not found | | ||
| | 3 | `ErrConflict` | Rebase conflict | | ||
| | 4 | `ErrAPIFailure` | GitHub API error | | ||
| | 5 | `ErrInvalidArgs` | Invalid arguments or flags | | ||
| | 6 | `ErrDisambiguate` | Multiple stacks/remotes, can't auto-select | | ||
| | 7 | `ErrRebaseActive` | Rebase already in progress | | ||
| | 8 | `ErrLockFailed` | Stack file lock contention | | ||
| | 9 | `ErrStacksUnavailable` | Stacked PRs not enabled for repository | | ||
| | 10 | `ErrModifyRecovery` | Modify session interrupted | | ||
|
|
||
| Return these from `RunE`. Never call `os.Exit()` directly from commands. Check with `errors.As(err, &ExitError{})`. | ||
|
francisfuzz marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Testing patterns | ||
|
|
||
| - **Framework:** `stretchr/testify` (`assert`, `require`) for assertions. | ||
| - **Table-driven tests** are the norm. See `cmd/utils_test.go` for examples. | ||
| - **Config:** Use `config.NewTestConfig()` which returns `(*Config, stdoutReader, stderrReader)` with captured I/O and no-op color functions. | ||
| - **Git mocking:** Call `git.SetOps(&git.MockOps{...})`. It returns a restore function. Always `defer restore()` to prevent test pollution. | ||
| - **GitHub mocking:** Set `cfg.GitHubClientOverride = &github.MockClient{...}`. | ||
| - **Prompt mocking:** Set `cfg.SelectFn`, `cfg.ConfirmFn`, or `cfg.InputFn` on the config to simulate interactive input. | ||
| - **Stack file setup:** Use `stack.Load(dir)` after writing a stack file to get correct checksums for `Save`. | ||
|
|
||
| ### Key interfaces | ||
|
|
||
| - **`git.Ops`** (`internal/git/gitops.go`): 52 methods wrapping git CLI calls. The production implementation uses `cli/go-gh`'s `client.Command()` via `run()` and `runSilent()` helpers. Package-level functions (e.g., `git.CurrentBranch()`) delegate to a swappable package-level `ops` variable. | ||
| - **`github.ClientOps`** (`internal/github/client_interface.go`): 11 methods for GitHub API (PRs, stacks). Injected via `cfg.GitHubClientOverride` in tests. | ||
| - **`config.Config`** (`internal/config/config.go`): Central configuration passed to all commands. Holds I/O streams, color functions, and test hook fields (`SelectFn`, `ConfirmFn`, `InputFn`, `TokenForHostFn`, `RepoOverride`). | ||
|
|
||
| ### Stack file | ||
|
|
||
| - **Location:** `.git/gh-stack` (JSON format, schema version 1). | ||
| - **Schema:** `internal/stack/schema.json`. | ||
| - **Locking:** Exclusive file lock at `.git/gh-stack.lock` with 5-second timeout. Errors surface as `LockError`. | ||
| - **Staleness:** Concurrent modifications detected via `StaleError`. | ||
|
|
||
| ## CI workflows (`.github/workflows/`) | ||
|
|
||
| | Workflow | Trigger | What it does | | ||
| |----------|---------|-------------| | ||
| | `test.yml` | push to main, PRs | `go vet` + `go test -race -count=1 ./...` on 3 OS matrix | | ||
| | `release.yml` | `v*` tags | Cross-platform precompiled binaries via `cli/gh-extension-precompile` | | ||
| | `docs.yml` | push to main (docs/**) | Builds Astro/Starlight docs, deploys to GitHub Pages | | ||
|
|
||
| ## Non-obvious things | ||
|
|
||
| - The `Queued` field on `BranchRef` is transient (populated from GitHub API, never persisted to the stack JSON file). | ||
| - `git.SetOps()` replaces the **package-level** ops variable. Forgetting `defer restore()` in a test will break every subsequent test in the package. | ||
| - Interrupt detection: Ctrl+C is caught as `terminal.InterruptErr`, wrapped into an `errInterrupt` sentinel, and printed with a friendly message before a silent exit. | ||
| - Rerere: on first rebase conflict, the user is prompted to enable `git rerere`. If declined, a flag file prevents future prompts. `tryAutoResolveRebase()` loops up to 1000 times auto-continuing when rerere resolves conflicts. | ||
| - The `.gitignore` ignores `/gh-stack` and `/gh-stack.exe` (the built binary). | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.