Close out the plan with the remaining polish items and a full README.
Shell completions (cmd/gitflow):
- New `completion [bash|zsh|fish|powershell]` command backed by cobra's
generators, wired into the root command
Desktop notifications (internal/notify):
- Send() dispatches to notify-send (Linux) with an osascript fallback
(macOS); Windows is a documented no-op for now; missing notifiers are
silent, never errors
- watch --notify sends a notification listing repositories whose state
changed since the previous frame
Color themes (internal/presenter):
- ThemeMode (dark/light) with ParseTheme; light uses bright ANSI variants
(90-97) that stay legible on light backgrounds; threaded through the
table, compact, and suggestions renderers; new --theme flag validated
and dumped by config
Custom rules (internal/rules):
- Rule{name, field (ahead|behind|stash|changes), op (==,!=,<,<=,>,>=),
value, label} with upfront validation in both Validate and Eval
- Config gains a `rules:` section (yaml/env only, no flag), validated at
load; matches render as a "FLAGS (custom rules)" section via a new
presenter.Flags renderer, shown in scan and watch frames
Docs:
- readme.md fully rewritten: features, install, usage, examples, flag
table, status classes, configuration reference, AI agent behavior and
--ai-execute guardrails, development layout, CI, and future work
- implementation.md gains an Implementation Progress section recording
every phase branch and the deviations from the original plan
Multi-platform:
- Verified cross-compilation for windows/amd64 and darwin/arm64; the
notify package is split behind build tags
Testing:
- rules: validation, operator semantics, Eval ordering, invalid-rule
errors
- presenter: ParseTheme, light-theme bright codes (and absence of
dark-theme codes), Flags rendering (empty = silent, matches render)
- config: rules loading from file, invalid-rule rejection, bad theme and
bad provider rejection
- notify: no-op behaviour when no notifier is installed (skipped when one
is, to avoid firing real notifications)
Verified: go build, go vet, go test -race (10 packages), gofmt clean,
windows/darwin cross-compile, completion generation, rules + light theme
smoke test, watch --notify graceful shutdown (exit 0, no orphans).
328 lines
11 KiB
Markdown
328 lines
11 KiB
Markdown
# Git Flow — Detailed Development Plan
|
||
|
||
## Overview
|
||
|
||
**Git Flow** is a Go CLI tool that discovers Git repositories under a user-specified parent directory, periodically scans their status, and presents findings with AI-driven suggestions for next actions (e.g., "commit pending changes", "push branch X", "pull latest from main").
|
||
|
||
---
|
||
|
||
## Phase 0: Project Scaffolding & Tooling
|
||
|
||
| Task | Details | Deliverable |
|
||
|---|---|---|
|
||
| **Module init** | `go mod init github.com/<user>/gitflow` | `go.mod` |
|
||
| **Directory layout** | Flat-to-modular structure appropriate for a CLI (see layout below) | Dir tree |
|
||
| **Tooling** | Add `golangci-lint` config, `Makefile`, `.gitignore` | Dev tooling |
|
||
| **CI skeleton** | GitHub Actions: lint + test on push | `.github/workflows/ci.yml` |
|
||
|
||
### Recommended Directory Layout
|
||
|
||
```
|
||
gitflow/
|
||
├── cmd/gitflow/ # main entry point
|
||
├── internal/
|
||
│ ├── scanner/ # repo discovery + git status scanning
|
||
│ ├── presenter/ # output formatting (table, JSON, TUI)
|
||
│ ├── scheduler/ # periodic scan loop
|
||
│ ├── ai/ # AI agent integration
|
||
│ ├── config/ # CLI flags, env vars, config file parsing
|
||
│ └── git/ # thin wrappers around git commands
|
||
├── pkg/ # shared types (RepoInfo, Status, etc.)
|
||
├── go.mod / go.sum
|
||
├── Makefile
|
||
├── .golangci.yml
|
||
└── readme.md
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 1: Core — Repo Discovery & Status Scanning
|
||
|
||
This is the foundational layer. Everything else depends on it.
|
||
|
||
### 1.1 Define the Domain Types (`pkg/types.go` or `internal/scanner/types.go`)
|
||
|
||
```go
|
||
type RepoStatus int
|
||
const (
|
||
StatusUnknown RepoStatus = iota
|
||
StatusClean
|
||
StatusModified
|
||
StatusAhead
|
||
StatusBehind
|
||
StatusDiverged
|
||
StatusDetached
|
||
StatusBare
|
||
StatusError
|
||
)
|
||
|
||
type RepoInfo struct {
|
||
Path string
|
||
RemoteURL string
|
||
Branch string
|
||
Status RepoStatus
|
||
ModifiedFiles []string
|
||
StagedFiles []string
|
||
UntrackedFiles []string
|
||
AheadBy int
|
||
BehindBy int
|
||
StashCount int
|
||
LastFetch time.Time
|
||
Error string
|
||
}
|
||
|
||
type ScanResult struct {
|
||
ScannedAt time.Time
|
||
ParentDir string
|
||
Repos []RepoInfo
|
||
TotalCount int
|
||
ErrorCount int
|
||
}
|
||
```
|
||
|
||
### 1.2 Repo Discovery (`internal/scanner/discover.go`)
|
||
|
||
- Walk the directory tree starting from the parent directory
|
||
- Detect `.git` directories (including bare repos, submodules, worktrees)
|
||
- Respect `.gitignore`-style exclusion patterns via a `--exclude` flag
|
||
- Respect depth limits via a `--depth` / `--max-depth` flag
|
||
- Use `filepath.WalkDir` for efficient traversal (no `os.FileInfo` allocations)
|
||
|
||
**Pattern**: Single-responsibility — the discoverer only finds repos; status scanning is a separate step.
|
||
|
||
### 1.3 Status Scanner (`internal/scanner/status.go`)
|
||
|
||
- For each discovered repo, run `git` porcelain commands:
|
||
- `git status --porcelain -b` for branch, ahead/behind, modified/staged/untracked
|
||
- `git remote -v` for remote URL
|
||
- `git stash list` for stash count
|
||
- Parse output into `RepoInfo`
|
||
- **Resilience patterns** from Go skill:
|
||
- Timeout each `git` command (e.g., 10s via `context.WithTimeout`)
|
||
- Handle repos with errors gracefully — mark as `StatusError`, don't crash
|
||
- Run scans concurrently with a bounded worker pool (`errgroup` + semaphore)
|
||
|
||
### 1.4 Git Command Wrapper (`internal/git/`)
|
||
|
||
- Thin wrapper: `func Status(ctx context.Context, repoPath string) (RepoInfo, error)`
|
||
- Uses `os/exec` with context for cancellation/timeout
|
||
- No external git library dependency — `os/exec` is sufficient for porcelain commands
|
||
|
||
---
|
||
|
||
## Phase 2: CLI & Configuration
|
||
|
||
### 2.1 CLI Framework
|
||
|
||
Use **Cobra** + **Viper** (standard Go CLI stack):
|
||
|
||
| Flag | Type | Default | Description |
|
||
|---|---|---|---|
|
||
| `--dir` / `-d` | string | `.` (cwd) | Parent directory to scan |
|
||
| `--interval` / `-i` | duration | `0` (run once) | Rescan interval (e.g., `5m`, `30s`) |
|
||
| `--format` / `-f` | string | `table` | Output format: `table`, `json`, `compact` |
|
||
| `--exclude` | []string | `[]` | Glob patterns to exclude |
|
||
| `--max-depth` | int | `0` (unlimited) | Max traversal depth |
|
||
| `--ai` | bool | `false` | Enable AI suggestions |
|
||
| `--ai-provider` | string | `openai` | AI backend |
|
||
| `--ai-model` | string | `gpt-4o` | AI model |
|
||
| `--watch` / `-w` | bool | `false` | Watch mode (alias for interval) |
|
||
|
||
### 2.2 Configuration File
|
||
|
||
Support `~/.gitflow.yaml` for defaults:
|
||
|
||
```yaml
|
||
ai:
|
||
provider: openai
|
||
api_key_env: OPENAI_API_KEY
|
||
model: gpt-4o
|
||
defaults:
|
||
interval: 5m
|
||
format: table
|
||
exclude:
|
||
- "node_modules"
|
||
- "vendor"
|
||
```
|
||
|
||
### 2.3 Commands
|
||
|
||
```
|
||
gitflow scan # one-shot scan
|
||
gitflow watch # periodic scan (uses --interval)
|
||
gitflow config # show/edit config
|
||
gitflow version # version info
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 3: Presentation Layer
|
||
|
||
### 3.1 Table Output (default)
|
||
|
||
Rich terminal table using `bubbletea` / `lipgloss` (or simpler: `tablewriter`):
|
||
|
||
```
|
||
REPOSITORY BRANCH STATUS AHEAD/BEHIND CHANGES
|
||
~/projects/api main ✓ clean 0 / 0 -
|
||
~/projects/web feat/login ✗ modified 3 / 0 2M, 1U
|
||
~/projects/lib main ⚠ behind 0 / 5 -
|
||
~/projects/legacy (detached) ⚠ detached - -
|
||
|
||
4 repos scanned | 1 clean | 2 need attention | 2 errors
|
||
```
|
||
|
||
### 3.2 JSON Output
|
||
|
||
For scripting / piping:
|
||
|
||
```json
|
||
{
|
||
"scanned_at": "2026-01-01T12:00:00Z",
|
||
"parent_dir": "/home/user/projects",
|
||
"repos": [...],
|
||
"summary": {"total": 4, "clean": 1, "attention": 2, "errors": 1}
|
||
}
|
||
```
|
||
|
||
### 3.3 Compact Output
|
||
|
||
One line per repo with color-coded status symbols.
|
||
|
||
---
|
||
|
||
## Phase 4: Periodic Scanner (Scheduler)
|
||
|
||
### 4.1 Watch Mode (`internal/scheduler/scheduler.go`)
|
||
|
||
- Runs scan on a `time.Ticker` at the configured interval
|
||
- Clears terminal and re-renders (or uses TUI refresh)
|
||
- Handles SIGINT/SIGTERM for graceful shutdown
|
||
- Shows time until next scan in footer
|
||
|
||
**Pattern**: Use `signal.NotifyContext` for graceful shutdown. Defer cleanup immediately after resource acquisition.
|
||
|
||
### 4.2 Change Detection
|
||
|
||
- Between scans, compare current vs previous `ScanResult`
|
||
- Highlight repos that changed state
|
||
- Optionally trigger desktop notifications (via `beeep` or `notify-send`)
|
||
|
||
---
|
||
|
||
## Phase 5: AI Agent Integration
|
||
|
||
### 5.1 AI Module (`internal/ai/`)
|
||
|
||
**Interface-first design** (for testability and provider flexibility):
|
||
|
||
```go
|
||
type Provider interface {
|
||
Suggest(ctx context.Context, repos []RepoInfo) ([]Suggestion, error)
|
||
}
|
||
|
||
type Suggestion struct {
|
||
RepoPath string
|
||
Action string // "commit", "push", "pull", "stash", "pr", "cleanup"
|
||
Message string // Human-readable suggestion
|
||
Command string // Suggested git command to run
|
||
Priority int // 0=low, 1=medium, 2=high
|
||
}
|
||
```
|
||
|
||
### 5.2 Providers
|
||
|
||
1. **OpenAI** (default): GPT-4o with structured output (JSON Schema) for reliable parsing
|
||
2. **Ollama** (local/offline): Support for local models
|
||
3. **Anthropic Claude**: Alternative cloud provider
|
||
|
||
### 5.3 Prompt Design
|
||
|
||
Construct a prompt that includes:
|
||
- A summary table of all repos and their statuses
|
||
- The top 3-5 repos needing attention
|
||
- Instructions to output structured JSON with specific action types
|
||
|
||
### 5.4 AI Output Display
|
||
|
||
- Show suggestions in a separate section below the status table
|
||
- Color-coded by priority
|
||
- Optional: `--ai-execute` flag to auto-run suggested commands (with confirmation)
|
||
|
||
---
|
||
|
||
## Phase 6: Polish & Advanced Features
|
||
|
||
| Feature | Description |
|
||
|---|---|
|
||
| **Color themes** | Light/dark terminal themes via `lipgloss` |
|
||
| **TUI mode** | Full interactive TUI with `bubbletea` — navigate repos, expand details, trigger AI suggestions |
|
||
| **Custom actions** | User-defined rules: "if behind > 10 commits, mark as critical" |
|
||
| **Webhook/notifications** | Send alerts to Slack/Discord when repos need attention |
|
||
| **Multi-platform** | Test on Linux, macOS, Windows (WSL) |
|
||
| **Completion** | Shell completions for bash, zsh, fish via Cobra |
|
||
|
||
---
|
||
|
||
## Technology Choices Summary
|
||
|
||
| Concern | Choice | Rationale |
|
||
|---|---|---|
|
||
| CLI framework | Cobra + Viper | Industry standard, completions, env binding |
|
||
| Git interaction | `os/exec` (porcelain) | No dependency needed; porcelain output is stable |
|
||
| TUI (optional) | Bubble Tea + Lip Gloss | Best Go TUI ecosystem |
|
||
| AI integration | HTTP client + JSON Schema | Provider-agnostic, no heavy SDK required |
|
||
| Concurrency | `errgroup` + semaphore | Bounded parallelism, error propagation |
|
||
| Testing | `testing` + `testify` | Standard + assertions |
|
||
| Linting | `golangci-lint` | Comprehensive Go linting |
|
||
|
||
---
|
||
|
||
## Milestone Schedule
|
||
|
||
| Milestone | Scope | Estimated Effort |
|
||
|---|---|---|
|
||
| **M1 — Skeleton** | Phase 0: module, layout, Makefile, CI | 0.5 day |
|
||
| **M2 — Discovery** | Phase 1: repo walker + git status parser | 1–2 days |
|
||
| **M3 — CLI** | Phase 2: Cobra commands, flags, config | 1 day |
|
||
| **M4 — Display** | Phase 3: table + JSON + compact output | 1 day |
|
||
| **M5 — Watch** | Phase 4: scheduler, auto-refresh, signals | 1 day |
|
||
| **M6 — AI** | Phase 5: provider interface, OpenAI, suggestions | 1–2 days |
|
||
| **M7 — Polish** | Phase 6: TUI, themes, completions, docs | 2–3 days |
|
||
|
||
**Total estimated effort**: ~7–10 days for a solid v1.0
|
||
|
||
---
|
||
|
||
## Implementation Progress
|
||
|
||
All phases from this plan are implemented and merged into `main` (branch
|
||
per phase, merged with `--no-ff`, no remote pushes).
|
||
|
||
| Phase | Branch | Status |
|
||
|---|---|---|
|
||
| 0 — Scaffolding | `feat/phase-0-scaffolding` | ✅ done |
|
||
| 1 — Discovery & scanning | `feat/phase-1-discovery-scanning` | ✅ done |
|
||
| 2 — CLI & configuration | `feat/phase-2-cli-config` | ✅ done |
|
||
| 3 — Presentation | `feat/phase-3-presentation` | ✅ done |
|
||
| 4 — Scheduler / watch | `feat/phase-4-scheduler` | ✅ done |
|
||
| 5 — AI agent | `feat/phase-5-ai` | ✅ done |
|
||
| 6 — Polish | `feat/phase-6-polish` | ✅ done |
|
||
|
||
### Deviations from the plan
|
||
|
||
- **`LastFetch` field dropped** (phase 1): the only reliable source is a
|
||
reflog of the remote-tracking ref, which does not exist on fresh clones;
|
||
noted as future work instead.
|
||
- **Full bubbletea TUI deferred** (phase 6): the plan listed it as
|
||
optional; watch mode + completions + themes + notifications were
|
||
implemented instead.
|
||
- **Webhooks deferred** (phase 6): desktop notifications cover the
|
||
alerting case; Slack/Discord noted as future work.
|
||
- **AI defaults**: `ai-model` defaults to `gpt-4o` (plan) with
|
||
provider-specific fallbacks (ollama → `llama3.2`, anthropic →
|
||
`claude-3-5-haiku-latest`); `--ai-execute` implemented with an
|
||
allowlist + per-command confirmation instead of a bare auto-run.
|
||
- **testify** was not added: stdlib `testing` covers all suites, keeping
|
||
the dependency tree minimal.
|