From 4761c8d4c1dd61c0505bc06229dd20af03ba93f6 Mon Sep 17 00:00:00 2001 From: Jon Gallant <2163001+jongio@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:52:45 -0700 Subject: [PATCH 1/3] docs: add a stability policy and refresh stale version examples grut is at v0.8.0 with real usage and no written statement of what is stable, so every config key, JSON field and exit code is currently a contract by accident. docs/stability.md names the surface deliberately: command and flag names, --json output shapes, --check exit codes, config keys, the extension manifest and host functions, and default keybindings. It also names what stays free to change, notably everything under internal/ (which Go already prevents outside code from importing) and TUI rendering. The more useful half is the list of what has to happen before 1.0 is worth tagging. Only two of the ten commands that emit --json have their shape documented, the --check exit codes are undocumented, and the extension manifest has no schema version. Freezing a surface nobody has written down does not achieve much. Also updates the pinned-install examples in README and CONTRIBUTING, which still used v0.1.0 and implied the project was seven minor versions younger than it is. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98ae0c9c-bdbe-418e-8488-15082edca7dc --- CONTRIBUTING.md | 4 +-- README.md | 10 ++++-- docs/stability.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 docs/stability.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3bb6c57..7ce5c02e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,13 +48,13 @@ To install the latest release (or test against a specific version): curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh # Specific version — Linux / macOS -curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh -s -- v0.1.0 +curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh -s -- v0.8.0 # Latest — Windows (PowerShell) irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex # Specific version — Windows (PowerShell) -$v="v0.1.0"; irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex +$v="v0.8.0"; irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex ``` ## Development Workflow diff --git a/README.md b/README.md index 0de70d6b..e870b8f9 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh To install a specific version: ```bash -curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh -s -- v0.1.0 +curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh -s -- v0.8.0 ``` ### PowerShell script (Windows) @@ -130,7 +130,7 @@ irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex To install a specific version: ```powershell -$v="v0.1.0"; irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex +$v="v0.8.0"; irm https://raw.githubusercontent.com/jongio/grut/main/install.ps1 | iex ``` ### Go Install @@ -243,6 +243,12 @@ Config file: `~/.config/grut/config.toml` (Linux/macOS) or `%APPDATA%\grut\confi See [docs/configuration.md](docs/configuration.md) for all options. +## Stability + +grut is pre-1.0, so pin a version if you depend on it in automation. See +[docs/stability.md](docs/stability.md) for what 1.0 will guarantee and what +still has to be documented before it is tagged. + ## Building from Source ```bash diff --git a/docs/stability.md b/docs/stability.md new file mode 100644 index 00000000..f1a868e5 --- /dev/null +++ b/docs/stability.md @@ -0,0 +1,86 @@ +# Stability and Versioning + +grut is pre-1.0. This document says what that means today, what will be +guaranteed at 1.0, and what has to be true before 1.0 is worth tagging. + +## Today (0.x) + +Anything can change in a minor release. In practice the CLI surface has been +additive for several releases, but nothing here is promised yet, so pin a +version if you depend on grut in automation: + +```bash +curl -fsSL https://raw.githubusercontent.com/jongio/grut/main/install.sh | sh -s -- v0.8.0 +``` + +## What 1.0 will cover + +At 1.0 the following become part of the compatibility surface. Breaking any of +them requires a major version bump. + +### Command and flag names +The subcommands (`clean`, `completion`, `config`, `doctor`, `ext`, `keys`, +`mcp`, `report`, `run`, `status`, `theme`, `update`, `version`) and their +flags. Flags may be added; existing ones keep their meaning. + +### Machine-readable output +Ten commands emit structured output behind `--json`, fourteen flags in total +once subcommands are counted. Once 1.0 lands, the shape of that output is a +contract: fields may be added, but existing fields will not be removed, +renamed, or change type. + +### Exit codes +`--check` on `clean`, `doctor`, and `status` is an exit-code gate intended for +CI. Zero means the checked condition holds, non-zero means it does not. Scripts +depending on that distinction will keep working. + +### Configuration keys +The TOML keys documented in [configuration.md](configuration.md). Keys may be +added. Removing or repurposing one is breaking. + +Unknown keys are ignored rather than rejected, so a config written for a newer +grut still loads on an older one, minus the unrecognized settings. + +### Extension API +The `extension.toml` manifest schema, the permission model, and the Lua and +WASM host functions in [extensions.md](extensions.md). Third-party extensions +are the surface most expensive to break, since the author is not us. + +### Default keybindings +Default bindings will not be reassigned to different actions in a minor +release. Adding a binding to a previously unbound key is not breaking. + +## What 1.0 will not cover + +- **Go packages under `internal/`.** Go forbids importing these from outside + the module, so they are not an API. They can be restructured at any time. +- **TUI rendering.** Panel layout, colours, spacing, and glyphs are + presentation, not contract. Themes exist for callers who care. +- **Log and audit line formats**, unless a specific format is documented as + machine-readable. +- **Prerelease and dev builds.** + +## Before tagging 1.0 + +Freezing a surface is only meaningful if the surface is written down. Current +gaps: + +- [ ] **Document every `--json` shape.** Two of the ten commands are documented + today ([report-json.md](report-json.md), + [version-json.md](version-json.md)). The rest are contracts by accident + rather than by description. +- [ ] **Document the `--check` exit codes**, including what non-zero means for + each command. +- [ ] **Audit config keys for dead settings.** A key that is declared but + unread becomes a permanent obligation at 1.0. `socket_auth` was one of + these and has been removed; the rest of the schema deserves the same + pass. +- [ ] **Version the extension manifest.** Third-party extensions need a way to + declare which schema they target. +- [ ] **State the supported platform and Go version floor.** + +## Deprecation + +After 1.0, anything on the covered surface that is going away gets deprecated +before removal: it keeps working for at least one minor release, warns when +used, and the release notes name the replacement. \ No newline at end of file From 9df8cb44bab146a446397c3649dbbb3fd7c73c5d Mon Sep 17 00:00:00 2001 From: Jon Gallant <2163001+jongio@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:58:50 -0700 Subject: [PATCH 2/3] docs(git): explain why the package is not split into sub-packages doc.go carried a TODO(arch) saying internal/git should be split into sub-packages per issue #167. Acting on it is not possible as written, and the TODO invited someone to try. Every domain file holds methods on *Client, and Go does not allow declaring methods on a type owned by another package. A split would mean fragmenting Client into per-domain clients, which destroys the single GitClient interface the AI middleware implements and every panel consumes, or demoting the methods to free functions, which rewrites every call site while the sub-packages still import git for the Client type. The shared state also argues against it. One OpQueue and one Cache serialise and cache across domains, because a branch operation and a stash operation must not race. Per-domain packages would each need that shared state back, so the coupling relocates rather than dissolves. And the cost is not being felt: roughly 4,000 lines over 30 files, under 140 lines each, already separated and named by domain. The file layout is the split the review asked for. Replaces the TODO with that reasoning plus the signal actually worth watching, which is per-file size rather than file count. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98ae0c9c-bdbe-418e-8488-15082edca7dc --- internal/git/doc.go | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/internal/git/doc.go b/internal/git/doc.go index 9b0be435..828e9e91 100644 --- a/internal/git/doc.go +++ b/internal/git/doc.go @@ -3,10 +3,33 @@ // OpQueue to prevent concurrent writes from corrupting repository state. // Read operations run concurrently against the same queue. // -// TODO(arch): This package has grown to 27+ files spanning 15+ distinct -// domains (blame, bisect, branch, diff, difftree, log, merge, queue, reflog, -// remote, reset, revert, stage_patch, stash, tag, undo, url, worktree). -// A future refactor should split it into sub-packages (e.g. git/branch, -// git/stash, git/log) to restore single-responsibility at the package level. -// See https://github.com/jongio/grut/issues/167 for context. +// On the file count: this package spans many domains (blame, bisect, branch, +// diff, difftree, log, merge, queue, reflog, remote, reset, revert, +// stage_patch, stash, tag, undo, url, worktree), and an automated review +// (issue #167) flagged that as a god package to be split into sub-packages. +// It is deliberately not split, for three reasons. +// +// First, Go does not permit it directly. Every domain file holds methods on +// *Client, and methods cannot be declared on a type owned by another package. +// Splitting would mean either fragmenting Client into per-domain clients, +// which destroys the single GitClient interface that the AI middleware +// implements and every panel consumes, or demoting the methods to free +// functions, which changes every call site and leaves the sub-packages +// importing git for the Client type anyway. +// +// Second, the shared state is the point. Client carries one OpQueue and one +// Cache. Serialisation and caching are correctness properties that hold +// across domains: a branch operation and a stash operation must not race. +// Per-domain packages would each need a reference back to that shared state, +// so the coupling would move rather than disappear. +// +// Third, the cost is not being paid. The package is roughly 4,000 lines +// across 30 files, averaging under 140 lines each, already separated by +// domain and named for it. Navigation happens by file, and the file layout is +// exactly the split the review asked for. +// +// The signal worth watching is file size rather than file count. If a single +// domain file outgrows ~500 lines, split that file. If a domain grows genuine +// state of its own, independent of the queue and cache, that is the point to +// reconsider a sub-package for it. package git From 4a6d1b5c8e515e47e819a289a4e69322d363d905 Mon Sep 17 00:00:00 2001 From: Jon Gallant <2163001+jongio@users.noreply.github.com> Date: Thu, 27 Aug 2026 15:02:32 -0700 Subject: [PATCH 3/3] docs(ai-git-ops): record the blocker on task 20 Task 20 reads as panel wiring, but AnalyzeBranches is not reachable from any panel. Point at #418 so the next person does not rediscover that from scratch. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98ae0c9c-bdbe-418e-8488-15082edca7dc --- docs/specs/ai-git-ops/tasks.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/specs/ai-git-ops/tasks.md b/docs/specs/ai-git-ops/tasks.md index ab3f4e8e..94474a7e 100644 --- a/docs/specs/ai-git-ops/tasks.md +++ b/docs/specs/ai-git-ops/tasks.md @@ -15,6 +15,8 @@ Enhance `internal/panels/branches/`: when AI enabled, stale/merged/abandoned bra The analysis engine already exists in `internal/ai/ops/branch.go` (task 12); only the panel wiring is outstanding. `ops.Branch` is currently referenced from no non-test panel code. +**Blocked on #418.** The wiring is not panel-local. `AnalyzeBranches` lives on the concrete `*middleware.AIGitClient` rather than the `git.GitClient` interface, panels are registered with the plain client before the AI client is built (`cmd/root.go:232` vs `:283`), and the layer that converts op results into panel messages does not exist yet. The same gap blocks six other shipped ops, so the access pattern should be decided once in #418 rather than invented here. + ## IN PROGRESS (none)