diff --git a/README.md b/README.md index 57d4c82..ada2e7a 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,11 @@ fixbuddy reads open GitHub issues, asks one agent to verify and fix each issue, The goal is controlled automation: one issue per branch, one issue per PR, explicit labels for every outcome, and full logs for every agent call. - +

+ fixbuddy turning a GitHub issue into a reviewed, merged pull request +

+ +The branch, commit, diff, and push above are real; the AI agents and GitHub calls are stubbed for a deterministic, offline recording — see docs/demo. ## Why fixbuddy diff --git a/docs/demo.gif b/docs/demo.gif new file mode 100644 index 0000000..c6876d0 Binary files /dev/null and b/docs/demo.gif differ diff --git a/docs/demo/README.md b/docs/demo/README.md new file mode 100644 index 0000000..459e140 --- /dev/null +++ b/docs/demo/README.md @@ -0,0 +1,25 @@ +# Demo GIF + +`docs/demo.gif` (shown at the top of the main README) is recorded with +[VHS](https://github.com/charmbracelet/vhs). + +To keep it reproducible and offline, the recording uses **deterministic demo +doubles**, not real services: + +- `bin/agent` — stands in for the AI coding CLIs (`claude` / `codex`). It emits the + `DONE-*` markers fixbuddy expects and, in the FIX stage, makes a **real** small + code change, so the diff fixbuddy reviews and the PR it opens are genuine. +- `bin/gh` — stands in for the GitHub CLI with canned responses. + +Everything else is the **real** fixbuddy pipeline: branch creation, the local +commit, the `git diff`, `git push` (to a local bare repo), and the +label / state-machine flow. + +## Regenerate + +```bash +bash docs/demo/gen.sh +``` + +Requires `vhs` on `PATH`. Writes `docs/demo.gif`. Edit `demo.tape` to change the +timing/size/theme. diff --git a/docs/demo/bin/agent b/docs/demo/bin/agent new file mode 100755 index 0000000..7942844 --- /dev/null +++ b/docs/demo/bin/agent @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Deterministic demo double for an AI coding CLI (used as claude/codex when recording +# docs/demo.gif). This is NOT a real agent. It emits the DONE-* markers fixbuddy expects +# and, in the FIX stage, makes a REAL small code fix so the diff fixbuddy reviews and the +# PR it opens are genuine. Stage is detected from the prompt fixbuddy pipes on stdin. +# See docs/demo/README.md. +prompt="$(cat)" + +case "$prompt" in + *"implementing a fix"*) + sleep 1 + ( cd "$DEMO_PROJECT" \ + && sed -i.bak 's/a - b/a + b/' src/calc.py && rm -f src/calc.py.bak \ + && git add -A \ + && git commit -q -m "Fix add(): return a + b, not a - b" ) + echo "Found the operator bug in add() and corrected it (a - b -> a + b)." + echo "DONE-FIX-APPLIED" + ;; + *"independent senior code reviewer"*) + sleep 1 + echo "The diff changes 'a - b' to 'a + b' in add(). Correct, minimal, in scope." + echo "DONE-APPROVED" + ;; + *) + sleep 1 + echo "Reproduced: add(2, 3) returns -1 instead of 5. The bug is real." + echo "DONE-PROCEED" + ;; +esac diff --git a/docs/demo/bin/gh b/docs/demo/bin/gh new file mode 100755 index 0000000..390d179 --- /dev/null +++ b/docs/demo/bin/gh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Deterministic demo double for the GitHub CLI, used only when recording docs/demo.gif. +# Returns canned responses so fixbuddy's pipeline runs end-to-end offline. NOT real. +# Everything else (git branch/commit/diff/push to a local bare repo) is genuine. +case "$1 $2" in + "repo view") echo "main" ;; + "issue list") + case "$*" in + *fix:pr-open*) echo "[]" ;; # the "unstick" scan finds nothing + *) echo '[{"number":7,"title":"add() returns the wrong result","labels":[{"name":"bug"},{"name":"severity:medium"}],"url":"https://github.com/acme/calc/issues/7","body":"add(2, 3) should return 5 but returns -1. The operator looks wrong."}]' ;; + esac ;; + "pr create") echo "https://github.com/acme/calc/pull/12" ;; + "pr view") echo "true" ;; # PR reported as merged -> clean "merged" ending + "pr list") echo "" ;; + *) : ;; # label create/list, issue edit/comment, pr merge, auth setup-git -> no-op OK +esac +exit 0 diff --git a/docs/demo/demo.tape b/docs/demo/demo.tape new file mode 100644 index 0000000..a865bdc --- /dev/null +++ b/docs/demo/demo.tape @@ -0,0 +1,19 @@ +# fixbuddy demo — recorded with VHS (https://github.com/charmbracelet/vhs). +# Run via: bash docs/demo/gen.sh (sets up PATH/env, then runs `vhs` on this file) +Output docs/demo.gif + +Require fixbuddy + +Set Shell "bash" +Set FontSize 16 +Set Width 1320 +Set Height 600 +Set Padding 24 +Set Theme "Dracula" +Set TypingSpeed 35ms + +Sleep 600ms +Type "fixbuddy --repo acme/calc --project /tmp/fixbuddy-demo/playground --yes" +Sleep 500ms +Enter +Sleep 9s diff --git a/docs/demo/gen.sh b/docs/demo/gen.sh new file mode 100755 index 0000000..2b60353 --- /dev/null +++ b/docs/demo/gen.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Regenerate docs/demo.gif with VHS, using deterministic demo doubles (no real services). +# Usage: bash docs/demo/gen.sh (requires `vhs` on PATH) +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +DEMO_DIR="$REPO_ROOT/docs/demo" +WORK=/tmp/fixbuddy-demo + +command -v vhs >/dev/null || { echo "vhs not found — install https://github.com/charmbracelet/vhs"; exit 1; } + +rm -rf "$WORK" +mkdir -p "$WORK/bin" "$WORK/home" + +# Runtime bin: stub agents + stub gh + fixbuddy, all on PATH. +chmod +x "$DEMO_DIR/bin/agent" "$DEMO_DIR/bin/gh" +ln -sf "$DEMO_DIR/bin/agent" "$WORK/bin/claude" +ln -sf "$DEMO_DIR/bin/agent" "$WORK/bin/codex" +ln -sf "$DEMO_DIR/bin/gh" "$WORK/bin/gh" +ln -sf "$REPO_ROOT/fixbuddy.sh" "$WORK/bin/fixbuddy" + +# Playground repo with a real bug and a real origin (so `git push` genuinely works). +git init -q --bare "$WORK/origin.git" +git clone -q "$WORK/origin.git" "$WORK/playground" 2>/dev/null +( + cd "$WORK/playground" + git config user.email demo@example.com + git config user.name "demo" + git checkout -q -b main + mkdir -p src + printf 'def add(a, b):\n return a - b # BUG: should be a + b\n' > src/calc.py + git add -A + git commit -q -m "calc: initial" + git push -q -u origin main +) + +export PATH="$WORK/bin:$PATH" +export DEMO_PROJECT="$WORK/playground" +export HOME="$WORK/home" # isolate fixbuddy run logs + +cd "$REPO_ROOT" +vhs "$DEMO_DIR/demo.tape" +echo "Wrote $REPO_ROOT/docs/demo.gif"