From 28233fd920a2909dc06c1ede43f2aecfe96505b7 Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Sat, 21 Feb 2026 13:53:17 +0900 Subject: [PATCH 01/12] feat: add CLAUDE.md --- CLAUDE.md | 391 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..481bf214a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,391 @@ +# CLAUDE.md — GitProxy + +## Project Overview + +GitProxy is a Git HTTP proxy that intercepts Git operations (primarily `git push`) and enforces organizational policies before allowing changes to reach the actual Git host. + +It acts as: + +- A **policy enforcement engine** (via processors and plugins) +- A **review/approval gate** (manual or automated) +- A **proxy server** for Git operations +- A **UI + API layer** for reviewing, approving, and auditing pushes + +The core design principle is a **chain-of-processors architecture** where each Git action flows through ordered processing steps. + +--- + +## Build & Run + +``` +# Build +npm run build + +# Run unit tests +npm run test + +# Run e2e tests +npm run test:e2e + +# Lint check/fix +npm run lint +npm run lint:fix + +# Format check/fix +npm run format:check +npm run format +``` + +**Stack: ** + +--- + +## High-Level Architecture + +GitProxy consists of four main components: + +``` +Contributor (git push) + ↓ +HTTP Proxy (/src/proxy) + ↓ +Action Chain (Processors + Plugins) + ↓ +Service API (/src/service) + ↓ +Database (audit, users, repos, approvals) + ↓ +Web UI (/src/ui) +``` + +### 1. Proxy Server (`/src/proxy`) + +Express-based HTTP proxy that: + +- Intercepts Git operations +- Parses requests into an `Action` +- Executes the appropriate **Action Chain** +- Blocks, rejects, or queues for approval + +Core concepts: + +- **Action** — Represents a Git operation (push/pull/default) +- **Chain** — Ordered list of processors +- **Processor (Step)** — A single policy enforcement unit +- **Plugin** — Custom processor injected externally + +--- + +### 2. Service API (`/src/service`) + +Express application responsible for: + +- UI communication +- Authentication (Passport strategies) +- Database access +- Approval/rejection workflows + +Default port: `8080` + +Authentication strategies supported: + +- Local +- ActiveDirectory +- OpenID Connect + +--- + +### 3. Configuration (`/src/config`) + +Loads and validates `proxy.config.json`. + +Controls: + +- Authentication methods +- Repository allowlist +- Commit message policies +- Database configuration +- Feature flags + +Schema reference: +[https://git-proxy.finos.org/docs/configuration/reference/](https://git-proxy.finos.org/docs/configuration/reference/) + +--- + +### 4. Web UI (`/src/ui`) + +React-based UI used to: + +- View pending pushes +- Review diffs +- Approve/reject pushes +- Manage repositories/users (depending on role) + +--- + +## Core Architectural Model + +### Action Lifecycle (Push) + +1. `parseAction` classifies request +2. `pushActionChain` executes processors in strict order +3. If blocked → rejected +4. If valid → queued for approval +5. Approver reviews in UI +6. If approved → user re-pushes to actual remote + +--- + +### Action Chains + +#### Push Action Chain + +``` +parsePush +checkEmptyBranch +checkRepoInAuthorisedList +checkCommitMessages +checkAuthorEmails +checkUserPushPermission +pullRemote +writePack +checkHiddenCommits +checkIfWaitingAuth +preReceive +getDiff +gitleaks +scanDiff +blockForAuth +``` + +**Order matters.** Some processors depend on artifacts created by previous ones (e.g., cloned repo, computed diff). + +--- + +#### Pull Action Chain + +``` +checkRepoInAuthorisedList +``` + +--- + +#### Default Action Chain + +``` +checkRepoInAuthorisedList +``` + +--- + +### Processor Rules + +When modifying or adding processors: + +- They must be **idempotent** +- They must clearly define: + - Required inputs + - Side effects + - Failure mode (reject vs throw vs auto-approve) + +- They must not mutate shared state outside the `Action` +- They must preserve audit traceability + +If a processor requires data not available at the end of the chain, it must be inserted earlier. + +--- + +### Plugin System + +Plugins: + +- Extend push/pull chains +- Are externally defined processors +- Should not modify core system invariants +- Must respect chain ordering semantics + +If logic needs access to internal chain data before plugins execute, implement a **custom processor**, not a plugin. + +--- + +## Authentication Model + +Authentication applies to: + +- UI access +- Approval workflow +- User management + +It does NOT authenticate Git pushes via the proxy itself — Git identity is derived from commit metadata (`user.email`). + +Supported methods: + +- Local (default) +- ActiveDirectory +- OpenID Connect + +New strategies must: + +1. Extend `/src/service/passport` +2. Provide a `configure()` function +3. Match config `type` +4. Be added to `authStrategies` in `index.ts` + +--- + +## Audit Model + +After chain execution: + +- `audit` stores: + - Action metadata + - Processor results + - Approval state + +If repository clone occurred: + +- `clearBareClone` must clean up disk artifacts + +Never introduce processor changes that bypass audit logging. + +Audit integrity is critical. + +--- + +## Development Guidelines for Agents + +### 1. Respect the Chain Architecture + +The action chain is the core abstraction. + +When implementing new functionality: + +- Decide whether it belongs in: + - Existing processor + - New processor + - Plugin + - Service layer + - UI + +- Do NOT insert logic randomly in the proxy request handler. + +--- + +### 2. Separation of Concerns + +- Proxy handles Git interception + chain execution +- Service handles authentication + state +- Config handles validation and schema +- UI handles display + approval user flow + +Do not mix responsibilities across modules. + +--- + +### 3. Approval Semantics + +Important rule: + +> A push must never reach the real Git remote unless explicitly approved or auto-approved by policy. + +Changes must not bypass: + +- `blockForAuth` +- Approval state checks +- Waiting authorization checks + +--- + +### 4. Configuration Safety + +When introducing new config options: + +- Add schema validation +- Provide sensible defaults +- Ensure backward compatibility +- Document in schema reference + +Never silently change default security behavior. + +--- + +### 5. Adding New Policies + +#### If simple and configurable: + +Add to existing processor (if cohesive). + +#### If complex and reusable: + +Create a new processor. + +#### If organization-specific: + +Implement as plugin. + +Ask: + +- Does this require diff access? +- Does this require cloned repo? +- Does this require user database? +- Does this need to run before approval gating? + +--- + +### Testing Expectations + +When modifying: + +#### Proxy / Processors + +- Must test: + - Success path + - Rejection path + - Audit logging (`step.error`, `step.log`) + +#### Config + +- Must test: + - Invalid values + - Default values + +--- + +## Common Pitfalls + +- Breaking processor order dependencies +- Mixing UI and service logic +- Introducing security regressions in approval flow +- Mutating global/shared state outside `Action` + +--- + +## License Header + +All source files must include the Apache 2.0 license header (see any existing file). + +--- + +## Agent Workflow + +**The main agent must act as an orchestrator.** Never do work inline that can be delegated to a subagent. + +- **Delegate everything:** Use the Task tool with specialized subagents for all research, code exploration, code writing, testing, and analysis. The main agent should plan, coordinate, and summarize — not do the work itself. +- **Maximize parallelism:** Launch multiple subagents concurrently whenever their tasks are independent. For example, when exploring code patterns AND analyzing tests AND checking dependencies, spawn all three agents in a single message rather than sequentially. Always send independent Task calls in a **single message** with multiple tool-use blocks. + + +--- + +## Summary + +GitProxy is: + +- A deterministic policy pipeline +- Wrapped in a Git HTTP proxy +- With an approval gate +- Backed by a service API +- Audited end-to-end + +All changes must respect that flow. From 2befb38c224f407b7ed8b9e112a60100afce63fb Mon Sep 17 00:00:00 2001 From: Juan Escalada Date: Sat, 21 Feb 2026 14:52:27 +0900 Subject: [PATCH 02/12] feat: add claude commands --- .claude/commands/commit.md | 58 +++++++++++++++++++ .claude/commands/docs.md | 38 ++++++++++++ .claude/commands/implement.md | 106 ++++++++++++++++++++++++++++++++++ .claude/commands/issue.md | 31 ++++++++++ .claude/commands/lint.md | 14 +++++ .claude/commands/summary.md | 44 ++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 .claude/commands/commit.md create mode 100644 .claude/commands/docs.md create mode 100644 .claude/commands/implement.md create mode 100644 .claude/commands/issue.md create mode 100644 .claude/commands/lint.md create mode 100644 .claude/commands/summary.md diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md new file mode 100644 index 000000000..73c9b56ea --- /dev/null +++ b/.claude/commands/commit.md @@ -0,0 +1,58 @@ +Create a git commit for the current staged/unstaged changes using Conventional Commits. + +Rules: + +1. Run `git status` and `git diff` to understand what changed +2. Stage relevant files (prefer specific files over `git add -A`) +3. Write a commit message following Conventional Commits format +4. Use `--signoff` to sign off using the committer's git config (do NOT hardcode any name/email) +5. Do NOT add Co-Authored-By or any other trailers beyond Signed-off-by +6. If there are no changes, say so and stop + +Commit format: + +``` +[optional scope]: +``` + +Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore + +Scope (optional): a noun describing the affected area in parentheses. +Common scopes: config, api, proxy, db, e2e, docker, ci. + +Subject line rules: + +- Imperative mood ("add", not "added" or "adds") +- Do NOT capitalize the first letter after the type prefix +- Do NOT end with a period +- Keep under 72 characters total + +For breaking changes, add `!` after the type/scope: + +``` +feat(config)!: rename queue config key +``` + +Examples of good messages: + +- "feat(api): add support for rejection reason" +- "fix(config): handle invalid regex on commitConfig" +- "refactor(ts): remove any/as usages in push-actions" +- "test(proxy): add tests for Git hosts other than GitHub" +- "docs: update architecture diagram in Architecture.md" +- "build: bump express to 5.2.1" +- "chore: remove unused import in services/push.ts" + +Commit command: + +``` +git commit --signoff -m "[scope]: " +``` + +Do NOT: + +- Use long multi-line messages for simple changes +- Add Co-Authored-By trailers +- Use past tense ("added", "fixed") +- Hardcode any author name or email +- Omit the type prefix diff --git a/.claude/commands/docs.md b/.claude/commands/docs.md new file mode 100644 index 000000000..6d46d0375 --- /dev/null +++ b/.claude/commands/docs.md @@ -0,0 +1,38 @@ +Update existing project documentation to reflect the current state of the branch. + +Steps: + +1. Run `git diff master...HEAD --stat` and `git log master..HEAD --oneline` to understand what changed on this branch +2. Read the changed files to understand what was added, removed, or modified +3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `CLAUDE.md` +4. Identify documentation that is now outdated or missing based on the branch changes +5. Apply minimal, targeted edits to bring docs in line with the code + +What to update: + +- **Architecture.md** — new push actions, configuration parameters, plugins, build steps, authentiction methods +- **README.md** — project description, features list, usage examples +- **CLAUDE.md** — project structure, architecture, key modules, common pitfalls, build commands + +Principles: + +- **Minimal changes only.** Do not rewrite sections that are already accurate. Edit the smallest possible region. +- **Capture important information.** New commands, config keys, classes, architecture changes, and breaking changes must be documented. +- **Keep it concise.** Prefer inline descriptions over new subsections. Use tables and bullet points. Avoid verbose prose. +- **Match existing style.** Follow the formatting, tone, and structure already in each file. Do not add headings, sections, or patterns that don't already exist. +- **One edit per concern.** If a section needs updating, make one focused edit rather than rewriting the whole section. +- **Skip trivial changes.** Internal refactors, renames, or implementation details that don't affect the public interface do not need doc updates. + +After editing, report what was updated: + +- List each file edited and a one-line description of the change +- If no docs needed updating, say "Documentation is up to date" and stop + +Do NOT: + +- Create new documentation files +- Add sections or headings that don't already exist +- Rewrite large blocks of text when a small edit suffices +- Document internal implementation details +- Add emojis, badges, or decorative elements +- Update docs for changes that don't affect user-facing behavior diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md new file mode 100644 index 000000000..1d6a9dd14 --- /dev/null +++ b/.claude/commands/implement.md @@ -0,0 +1,106 @@ +Implement a GitHub issue end-to-end: fetch the issue, plan, code with approval, commit incrementally, and generate a PR summary. + +The argument is an issue number (e.g. `/implement 42`) or a full GitHub URL (e.g. `/implement https://github.com/finos/git-proxy/issues/42`). If no argument is given, ask the user. + +## Phase 1: Fetch issue + +1. Parse the argument: + - If it is a full URL like `https://github.com/{owner}/{repo}/issues/{number}`, extract `{owner}/{repo}` and `{number}`. + - If it is just a number, use the current repo (run `gh repo view --json nameWithOwner -q .nameWithOwner` to get it). +2. Fetch issue details: + ``` + gh issue view --repo --json title,body,labels,assignees,comments + ``` +3. Display a summary to the programmer: + - Issue number and title + - Labels (if any) + - Body (truncated to ~40 lines if longer) + - Number of comments and any noteworthy discussion points +4. Ask the programmer to confirm this is the right issue before proceeding. Use AskUserQuestion with options: "Proceed", "Show full issue body", "Cancel". + +## Phase 2: Branch setup + +1. List all configured remotes: `git remote -v` +2. If there is more than one remote, ask the programmer which remote to use as upstream using AskUserQuestion (list the remote names as options). + If there is only one remote, use it automatically. +3. Fetch and update master from the chosen remote: + ``` + git fetch + git checkout master + git pull master + ``` +4. Create a new branch from master. The branch name must follow this convention: + - Format: `/` where `` is a Conventional Commits type (`feat`, `fix`, `refactor`, `docs`, `chore`, etc.) and `` is a kebab-case summary derived from the issue title (3-5 words max). + - Examples: `feat/dynamic-allocation-support`, `fix/event-watcher-reconnect`, `refactor/pod-spec-converter` + - Pick the type based on the issue labels and description (e.g. a bug report maps to `fix/`, a feature request to `feat/`). + ``` + git checkout -b / + ``` +5. Confirm to the programmer: "Created branch `` from `/master`." + +## Phase 3: Plan + +1. Based on the issue description, explore the codebase to understand the relevant code paths. Use subagents to search for files, classes, and patterns referenced in or implied by the issue. +2. Create an implementation plan with numbered steps. Each step should be a logical, committable unit of work. The plan must include: + - A 1-2 sentence summary of the issue + - Numbered steps, where each step has a title, a description of what to change, and the affected file paths +3. Save the plan to `plans/implement-.md` using this format: + + ``` + ## Issue #: + + <1-2 sentence summary of what the issue asks for> + + ## Steps + + 1. <step title> + - <what to change and where> + - Files: <path/to/file.ts> + + 2. <step title> + - <what to change and where> + - Files: <path/to/file.ts, path/to/other.ts> + ``` + +4. Show the full plan to the programmer for approval. +5. Ask the programmer using AskUserQuestion with options: "Approve plan", "Modify plan", "Cancel". +6. If the programmer wants modifications, iterate on the plan until approved. + +## Phase 4: Execute step by step + +For each step in the approved plan: + +1. Announce the step: "Step <n>/<total>: <step title>" +2. Make the code changes for that step +3. If the step involves logic changes, run tests (`npm run test`) and show the result +4. Show the programmer a brief summary of what changed (key files and the nature of the change) +5. Ask the programmer using AskUserQuestion with options: "Commit this step", "Revise changes", "Skip this step", "Stop here". +6. If the programmer picks "Commit this step", run the /commit skill to commit the changes +7. If the programmer picks "Revise changes", iterate until they are satisfied +8. If the programmer picks "Skip this step", move to the next step without committing +9. If the programmer picks "Stop here", skip all remaining steps and jump to Phase 5 + +After each commit, briefly confirm the commit was made and move to the next step. + +## Phase 5: Summary + +1. After all steps are complete (or the programmer stops early): + - Run the /summary skill to generate a PR description based on all commits made during this session + - Show the summary to the programmer +2. Do NOT create a PR or push. Just present the summary for the programmer to use when they are ready. +3. If no commits were made (e.g. the programmer cancelled early), skip the summary and say so. + +## Rules + +- Never make code changes without programmer approval +- Always show what changed after each step before committing +- The programmer can modify, skip, reorder, or stop steps at any point +- Save the plan file before starting execution so the programmer has a reference +- Each commit should be a logical unit (one step = one commit, unless the step is trivial) +- If the issue is from a different repo (not the current one), fetch it via the full URL but make changes in the current repo +- No emojis in any output +- Do not create a PR or push to remote — only local commits and a summary +- If a step requires running tests, run them and show results before committing +- Use subagents for codebase exploration and code changes; keep the main flow focused on coordination and programmer interaction + +$ARGUMENTS diff --git a/.claude/commands/issue.md b/.claude/commands/issue.md new file mode 100644 index 000000000..3d7a239b8 --- /dev/null +++ b/.claude/commands/issue.md @@ -0,0 +1,31 @@ +Create a GitHub issue markdown file from the details provided by the user. + +The user will describe a bug, feature request, or discussion context (e.g. Slack conversations, error logs, reproduction steps). Your job is to turn that into a well-structured issue and save it to `plans/`. + +Steps: + +1. Read the user's input to understand the problem, who reported it, and any logs or reproduction steps provided +2. Investigate the codebase to identify relevant code paths, pinpoint where the issue likely originates, and gather context that would help a contributor understand the problem +3. Write a concise GitHub issue markdown file and save it to `plans/issue-<short-slug>.md` + +Issue format: + +- Start with `## <title>` as the first line (this becomes the GitHub issue title) +- `### Problem` — 2-3 sentences explaining the issue and its impact +- `### Steps to Reproduce` — numbered list (if applicable) +- `### Expected Behavior` — 1-2 sentences +- `### Actual Behavior` — include relevant log snippets in code blocks, keep them short (trim stack traces to the key lines) +- `### Potential Root Cause` — based on your codebase investigation, explain where the issue likely lives. Link to source code using upstream GitHub URLs: `https://github.com/finos/git-proxy/blob/master/...#L<start>-L<end>`. +- `### Affected Files` — table with file links and one-line role descriptions +- `### Additional Context` — bullet points for version info, related code paths, or anything else useful + +Style rules: + +- Keep it concise — the whole issue should be under 80 lines +- Use code blocks sparingly — only for key log lines and small code snippets +- Do not propose fixes or implementation approaches +- Do not add Labels, Description, or Title as separate sections — the `##` heading is the title +- Write for a contributor who knows the project but hasn't seen this specific bug +- No emojis + +$ARGUMENTS diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md new file mode 100644 index 000000000..467b49a99 --- /dev/null +++ b/.claude/commands/lint.md @@ -0,0 +1,14 @@ +Check and fix code formatting using ESLint and Prettier. + +Steps: + +1. Run `npm run format:check` to see if there are formatting violations +2. If violations are found, run `npm run format` to auto-fix them +3. Run `npm run lint` to see if there are linting errors +4. If errors are found, run `npm run lint:fix` to auto-fix them +5. After applying, run `git diff --stat` to show what files were reformatted +6. Summarize the changes (which files, what kind of formatting was fixed) + +If no violations are found, say so and stop. + +Do NOT commit the formatting changes — just apply and report. diff --git a/.claude/commands/summary.md b/.claude/commands/summary.md new file mode 100644 index 000000000..01db775b6 --- /dev/null +++ b/.claude/commands/summary.md @@ -0,0 +1,44 @@ +Generate a concise implementation summary for a PR description. + +Steps: + +1. First, run the `/docs` command to ensure documentation is up to date with the branch changes +2. Run `git diff master...HEAD --stat` and `git log master..HEAD --oneline` to understand all changes on this branch +3. Read the changed files to understand what was implemented and why +4. Get the current branch name: `git rev-parse --abbrev-ref HEAD` +5. Write a summary suitable for a GitHub PR description +6. Save the raw markdown summary (without the wrapping code fence) to `plans/<branch-name>-summary.md`, replacing any `/` in the branch name with `-` + +Summary format rules: + +- The summary must be GitHub-flavored markdown that renders nicely in a PR description +- Do NOT use any headings (`#`, `##`, `###`, etc.) — structure the summary with bold labels and line breaks instead +- Use `**bold**` for section labels (e.g., `**What:**`, `**Why:**`, `**Changes:**`) +- Use backtick-wrapped inline code for file names, config keys, commands, and identifiers +- Use markdown bullet points (`-`) for listing changes +- Use numbered lists for verification steps +- Use `[text](url)` for hyperlinks when referencing issues or external resources +- Start with `**What:**` — a one-line statement explaining the change +- Follow with `**Why:**` — 2-3 sentences max explaining the motivation +- Include `**Changes:**` — key changes as bullet points (no nested bullets) +- If there are new tests, add `**Tests:**` with one line describing coverage +- End with `**How to verify:**` — concrete steps as a numbered list +- Keep the total summary under 30 lines +- Do not repeat file paths or class names unnecessarily +- Focus on behavior changes, not implementation details +- Write in present tense, active voice + +Output rules: + +- Do NOT print the summary to the conversation +- Only save it to the file and tell the user where it was saved: "Summary saved to `plans/<branch-name>-summary.md`" + +Do NOT: + +- Use headings (`#`, `##`, `###`) anywhere in the summary +- Use tables or badges +- List every single file changed +- Include generic boilerplate like "This PR adds..." +- Add emojis +- Over-explain things that are obvious from the diff +- Print the summary content in the conversation output From d4c944c854bb554943aa29767524d826130b70a5 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Sat, 21 Feb 2026 15:16:09 +0900 Subject: [PATCH 03/12] fix: add /plans to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c6076f1af..5bf58af5b 100644 --- a/.gitignore +++ b/.gitignore @@ -275,3 +275,6 @@ website/.docusaurus # Generated from testing /test/fixtures/test-package/package-lock.json + +# Agentic AI generated files +/plans \ No newline at end of file From 79e88ca0342666c31da573bb9358242a31503b65 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Sat, 21 Feb 2026 15:17:22 +0900 Subject: [PATCH 04/12] fix: update agent commands to use main instead of master --- .claude/commands/docs.md | 2 +- .claude/commands/implement.md | 10 +++++----- .claude/commands/issue.md | 2 +- .claude/commands/summary.md | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.claude/commands/docs.md b/.claude/commands/docs.md index 6d46d0375..b17da29b6 100644 --- a/.claude/commands/docs.md +++ b/.claude/commands/docs.md @@ -2,7 +2,7 @@ Update existing project documentation to reflect the current state of the branch Steps: -1. Run `git diff master...HEAD --stat` and `git log master..HEAD --oneline` to understand what changed on this branch +1. Run `git diff main...HEAD --stat` and `git log main..HEAD --oneline` to understand what changed on this branch 2. Read the changed files to understand what was added, removed, or modified 3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `CLAUDE.md` 4. Identify documentation that is now outdated or missing based on the branch changes diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md index 1d6a9dd14..cb7d54980 100644 --- a/.claude/commands/implement.md +++ b/.claude/commands/implement.md @@ -23,20 +23,20 @@ The argument is an issue number (e.g. `/implement 42`) or a full GitHub URL (e.g 1. List all configured remotes: `git remote -v` 2. If there is more than one remote, ask the programmer which remote to use as upstream using AskUserQuestion (list the remote names as options). If there is only one remote, use it automatically. -3. Fetch and update master from the chosen remote: +3. Fetch and update main from the chosen remote: ``` git fetch <remote> - git checkout master - git pull <remote> master + git checkout main + git pull <remote> main ``` -4. Create a new branch from master. The branch name must follow this convention: +4. Create a new branch from main. The branch name must follow this convention: - Format: `<type>/<short-slug>` where `<type>` is a Conventional Commits type (`feat`, `fix`, `refactor`, `docs`, `chore`, etc.) and `<short-slug>` is a kebab-case summary derived from the issue title (3-5 words max). - Examples: `feat/dynamic-allocation-support`, `fix/event-watcher-reconnect`, `refactor/pod-spec-converter` - Pick the type based on the issue labels and description (e.g. a bug report maps to `fix/`, a feature request to `feat/`). ``` git checkout -b <type>/<short-slug> ``` -5. Confirm to the programmer: "Created branch `<branch-name>` from `<remote>/master`." +5. Confirm to the programmer: "Created branch `<branch-name>` from `<remote>/main`." ## Phase 3: Plan diff --git a/.claude/commands/issue.md b/.claude/commands/issue.md index 3d7a239b8..245c868f3 100644 --- a/.claude/commands/issue.md +++ b/.claude/commands/issue.md @@ -15,7 +15,7 @@ Issue format: - `### Steps to Reproduce` — numbered list (if applicable) - `### Expected Behavior` — 1-2 sentences - `### Actual Behavior` — include relevant log snippets in code blocks, keep them short (trim stack traces to the key lines) -- `### Potential Root Cause` — based on your codebase investigation, explain where the issue likely lives. Link to source code using upstream GitHub URLs: `https://github.com/finos/git-proxy/blob/master/...#L<start>-L<end>`. +- `### Potential Root Cause` — based on your codebase investigation, explain where the issue likely lives. Link to source code using upstream GitHub URLs: `https://github.com/finos/git-proxy/blob/main/...#L<start>-L<end>`. - `### Affected Files` — table with file links and one-line role descriptions - `### Additional Context` — bullet points for version info, related code paths, or anything else useful diff --git a/.claude/commands/summary.md b/.claude/commands/summary.md index 01db775b6..383dad452 100644 --- a/.claude/commands/summary.md +++ b/.claude/commands/summary.md @@ -3,7 +3,7 @@ Generate a concise implementation summary for a PR description. Steps: 1. First, run the `/docs` command to ensure documentation is up to date with the branch changes -2. Run `git diff master...HEAD --stat` and `git log master..HEAD --oneline` to understand all changes on this branch +2. Run `git diff main...HEAD --stat` and `git log main..HEAD --oneline` to understand all changes on this branch 3. Read the changed files to understand what was implemented and why 4. Get the current branch name: `git rev-parse --abbrev-ref HEAD` 5. Write a summary suitable for a GitHub PR description From 64435eb909186f717b6ac9992fbcd0c21ea29465 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Sat, 21 Feb 2026 15:49:28 +0900 Subject: [PATCH 05/12] feat: add address-review.md command for agents --- .claude/commands/address-review.md | 111 +++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .claude/commands/address-review.md diff --git a/.claude/commands/address-review.md b/.claude/commands/address-review.md new file mode 100644 index 000000000..1ed9d286a --- /dev/null +++ b/.claude/commands/address-review.md @@ -0,0 +1,111 @@ +Address review comments on a GitHub pull request. + +The argument is a PR number (e.g. `/address-review 98`). If no number is given, ask the user. + +## Phase 1: Fetch and display comments + +1. Save the current branch name: `git rev-parse --abbrev-ref HEAD` +2. Checkout the PR branch: `gh pr checkout <number> --detach` +3. Fetch all review comments: + +``` +gh api repos/{owner}/{repo}/pulls/<number>/comments --paginate +``` + +4. Group comments by file. For each comment, extract: `id`, `path`, `line` (or `original_line`), `body`, `user.login`, `in_reply_to_id` (to detect threads). +5. Filter out threads that are already resolved or where the last message is from the PR author (likely already addressed). +6. Present a numbered summary to the programmer: + +``` +PR #<number> — <n> unaddressed review comments + + 1. <file>:<line> — @<author>: <first 80 chars of comment> + 2. <file>:<line> — @<author>: <first 80 chars of comment> + ... +``` + +If there are no unaddressed comments, say so and return to the original branch. + +## Phase 2: Walk through each comment + +For each comment in order, show: + +- The full comment body +- The file path and line number +- The relevant code context (read ~10 lines around the commented line from the actual file) +- The author who left the comment + +Then ask the programmer what to do using AskUserQuestion with these options: + +- **Fix** — Make a code change to address the comment. After the programmer picks this, analyze the comment and the surrounding code, propose a fix, and apply it with Edit. Show the programmer what changed and confirm before moving to the next comment. +- **Reply** — Draft a reply to the comment. Write a concise, human-sounding response (see tone rules below). Show the exact text to the programmer. They can modify it. Queue the reply for posting in Phase 3. +- **Skip** — Move to the next comment without action. + +If the programmer chooses Fix, apply the change and move on. If they choose Reply, queue it. Track all code changes and queued replies separately. + +## Phase 3: Commit, push, and post replies + +After walking through all comments: + +**Code changes:** +If any code fixes were made, run the /commit skill to create a commit with the changes, then push: + +``` +git push +``` + +**Replies:** +If there are queued replies, show all of them in a final summary: + +``` +Queued replies: + +1. <file>:<line> — reply to @<author>: + "<reply text>" + +2. <file>:<line> — reply to @<author>: + "<reply text>" +``` + +Ask the programmer for final confirmation before posting. They can modify any reply text at this point. + +Post each reply as a separate API call: + +``` +gh api repos/{owner}/{repo}/pulls/<number>/comments/<comment_id>/replies \ + --method POST \ + -f body="<reply text>" +``` + +After all replies are posted, return to the original branch: + +``` +git checkout <original-branch> +``` + +## Reply tone and style + +Follow these rules strictly when drafting replies: + +- Write as a human developer, not an AI. Never mention AI, automation, or tools. +- No markdown headings (#, ##, ###) in replies. Plain text and inline formatting only. +- Keep replies concise — 1-3 sentences. Get to the point. +- Conversational, collaborative tone: "good catch, fixed in the latest push", "I think this is fine because...", "yeah, updated this to use X instead" +- Be direct but not dismissive. If you disagree with a comment, explain briefly why. +- No bullet lists. Keep it flowing as natural text. +- No emojis. +- The programmer gets final say on every reply before it is posted. + +## Rules + +- Never post anything to GitHub without explicit programmer confirmation +- Never modify code without programmer approval +- Show exact reply text before queuing it +- The programmer can modify any reply at any point +- Always checkout with `--detach` to avoid creating local branches +- After everything is done, return to the original branch +- No emojis in any output +- No markdown headings in any output or posted content +- If an API call fails, show the error and ask the programmer how to proceed + +$ARGUMENTS From 2f29862538ffe0cd4bb59593b147791488157a18 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Sat, 21 Feb 2026 15:55:40 +0900 Subject: [PATCH 06/12] docs: update Contributing section with links to Claude files --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93dd7fbbc..5663f2990 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ customize for your environment, see the [project's documentation](https://git-pr ## Contributing -Your contributions are at the core of making this a truly open source project. Any contributions you make are **greatly appreciated**. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for more information. +Your contributions are at the core of making this a truly open source project. Any contributions you make are **greatly appreciated**. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for more information. For AI-assisted development (Cursor/Claude), see [`CLAUDE.md`](CLAUDE.md) and the [`.claude/commands`](.claude/commands) directory. ## Security From 9bf34bed6d7a8771b746a88bad6262ded5c1bd76 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Mon, 30 Mar 2026 22:21:10 +0900 Subject: [PATCH 07/12] chore: rename claude files/directories to agents --- {.claude => .agents}/commands/address-review.md | 0 {.claude => .agents}/commands/commit.md | 0 {.claude => .agents}/commands/docs.md | 0 {.claude => .agents}/commands/implement.md | 0 {.claude => .agents}/commands/issue.md | 0 {.claude => .agents}/commands/lint.md | 0 {.claude => .agents}/commands/summary.md | 0 CLAUDE.md => AGENTS.md | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename {.claude => .agents}/commands/address-review.md (100%) rename {.claude => .agents}/commands/commit.md (100%) rename {.claude => .agents}/commands/docs.md (100%) rename {.claude => .agents}/commands/implement.md (100%) rename {.claude => .agents}/commands/issue.md (100%) rename {.claude => .agents}/commands/lint.md (100%) rename {.claude => .agents}/commands/summary.md (100%) rename CLAUDE.md => AGENTS.md (99%) diff --git a/.claude/commands/address-review.md b/.agents/commands/address-review.md similarity index 100% rename from .claude/commands/address-review.md rename to .agents/commands/address-review.md diff --git a/.claude/commands/commit.md b/.agents/commands/commit.md similarity index 100% rename from .claude/commands/commit.md rename to .agents/commands/commit.md diff --git a/.claude/commands/docs.md b/.agents/commands/docs.md similarity index 100% rename from .claude/commands/docs.md rename to .agents/commands/docs.md diff --git a/.claude/commands/implement.md b/.agents/commands/implement.md similarity index 100% rename from .claude/commands/implement.md rename to .agents/commands/implement.md diff --git a/.claude/commands/issue.md b/.agents/commands/issue.md similarity index 100% rename from .claude/commands/issue.md rename to .agents/commands/issue.md diff --git a/.claude/commands/lint.md b/.agents/commands/lint.md similarity index 100% rename from .claude/commands/lint.md rename to .agents/commands/lint.md diff --git a/.claude/commands/summary.md b/.agents/commands/summary.md similarity index 100% rename from .claude/commands/summary.md rename to .agents/commands/summary.md diff --git a/CLAUDE.md b/AGENTS.md similarity index 99% rename from CLAUDE.md rename to AGENTS.md index 481bf214a..d86970c2a 100644 --- a/CLAUDE.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# CLAUDE.md — GitProxy +# AGENTS.md — GitProxy ## Project Overview From e832b24c83455523f657ec71b5ff48ab13e94a54 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Mon, 30 Mar 2026 22:29:12 +0900 Subject: [PATCH 08/12] fix: add extra rule to checkout target branch during agentic review --- .agents/commands/address-review.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.agents/commands/address-review.md b/.agents/commands/address-review.md index 1ed9d286a..f86304b1a 100644 --- a/.agents/commands/address-review.md +++ b/.agents/commands/address-review.md @@ -103,6 +103,7 @@ Follow these rules strictly when drafting replies: - Show exact reply text before queuing it - The programmer can modify any reply at any point - Always checkout with `--detach` to avoid creating local branches +- Never push while in detached state. Before any push, explicitly checkout the target branch after programmer confirmation - After everything is done, return to the original branch - No emojis in any output - No markdown headings in any output or posted content From 869d62b77712581a9d5d6e5a96758a4ea6d3e705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C4=86ori=C4=87?= <denis85@gmail.com> Date: Wed, 1 Apr 2026 12:27:34 +0200 Subject: [PATCH 09/12] docs: add AGENTS-based AI tool instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Denis Ćorić <denis85@gmail.com> --- .agents/commands/address-review.md | 2 ++ .agents/commands/commit.md | 2 ++ .agents/commands/docs.md | 9 +++++++-- .agents/commands/implement.md | 2 ++ .agents/commands/issue.md | 2 ++ .agents/commands/lint.md | 2 ++ .agents/commands/summary.md | 2 ++ .claude/commands/address-review.md | 3 +++ .claude/commands/commit.md | 3 +++ .claude/commands/docs.md | 3 +++ .claude/commands/implement.md | 3 +++ .claude/commands/issue.md | 3 +++ .claude/commands/lint.md | 3 +++ .claude/commands/summary.md | 3 +++ .cursor/commands/address-review.md | 3 +++ .cursor/commands/commit.md | 3 +++ .cursor/commands/docs.md | 3 +++ .cursor/commands/implement.md | 3 +++ .cursor/commands/issue.md | 3 +++ .cursor/commands/lint.md | 3 +++ .cursor/commands/summary.md | 3 +++ .cursor/rules/00-core.mdc | 14 ++++++++++++++ .github/copilot-instructions.md | 15 +++++++++++++++ .gitignore | 3 ++- CLAUDE.md | 11 +++++++++++ README.md | 2 +- 26 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 .claude/commands/address-review.md create mode 100644 .claude/commands/commit.md create mode 100644 .claude/commands/docs.md create mode 100644 .claude/commands/implement.md create mode 100644 .claude/commands/issue.md create mode 100644 .claude/commands/lint.md create mode 100644 .claude/commands/summary.md create mode 100644 .cursor/commands/address-review.md create mode 100644 .cursor/commands/commit.md create mode 100644 .cursor/commands/docs.md create mode 100644 .cursor/commands/implement.md create mode 100644 .cursor/commands/issue.md create mode 100644 .cursor/commands/lint.md create mode 100644 .cursor/commands/summary.md create mode 100644 .cursor/rules/00-core.mdc create mode 100644 .github/copilot-instructions.md create mode 100644 CLAUDE.md diff --git a/.agents/commands/address-review.md b/.agents/commands/address-review.md index f86304b1a..1db7cd3b1 100644 --- a/.agents/commands/address-review.md +++ b/.agents/commands/address-review.md @@ -1,5 +1,7 @@ Address review comments on a GitHub pull request. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + The argument is a PR number (e.g. `/address-review 98`). If no number is given, ask the user. ## Phase 1: Fetch and display comments diff --git a/.agents/commands/commit.md b/.agents/commands/commit.md index 73c9b56ea..03bd5f0b9 100644 --- a/.agents/commands/commit.md +++ b/.agents/commands/commit.md @@ -1,5 +1,7 @@ Create a git commit for the current staged/unstaged changes using Conventional Commits. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + Rules: 1. Run `git status` and `git diff` to understand what changed diff --git a/.agents/commands/docs.md b/.agents/commands/docs.md index b17da29b6..753f0e83f 100644 --- a/.agents/commands/docs.md +++ b/.agents/commands/docs.md @@ -1,10 +1,12 @@ Update existing project documentation to reflect the current state of the branch. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + Steps: 1. Run `git diff main...HEAD --stat` and `git log main..HEAD --oneline` to understand what changed on this branch 2. Read the changed files to understand what was added, removed, or modified -3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `CLAUDE.md` +3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `AGENTS.md`, `CLAUDE.md`, `.github/copilot-instructions.md`, `.cursor/rules/00-core.mdc` 4. Identify documentation that is now outdated or missing based on the branch changes 5. Apply minimal, targeted edits to bring docs in line with the code @@ -12,7 +14,10 @@ What to update: - **Architecture.md** — new push actions, configuration parameters, plugins, build steps, authentiction methods - **README.md** — project description, features list, usage examples -- **CLAUDE.md** — project structure, architecture, key modules, common pitfalls, build commands +- **AGENTS.md** — canonical project architecture, invariants, testing commands, and AI-agent workflow guidance +- **CLAUDE.md** — Claude-specific entry point that should remain aligned with `AGENTS.md` +- **.github/copilot-instructions.md** — short Copilot-compatible summary of the highest-priority repo rules +- **.cursor/rules/00-core.mdc** — Cursor-compatible summary that should stay aligned with `AGENTS.md` Principles: diff --git a/.agents/commands/implement.md b/.agents/commands/implement.md index cb7d54980..24f3a48fc 100644 --- a/.agents/commands/implement.md +++ b/.agents/commands/implement.md @@ -1,5 +1,7 @@ Implement a GitHub issue end-to-end: fetch the issue, plan, code with approval, commit incrementally, and generate a PR summary. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + The argument is an issue number (e.g. `/implement 42`) or a full GitHub URL (e.g. `/implement https://github.com/finos/git-proxy/issues/42`). If no argument is given, ask the user. ## Phase 1: Fetch issue diff --git a/.agents/commands/issue.md b/.agents/commands/issue.md index 245c868f3..492a5c627 100644 --- a/.agents/commands/issue.md +++ b/.agents/commands/issue.md @@ -1,5 +1,7 @@ Create a GitHub issue markdown file from the details provided by the user. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + The user will describe a bug, feature request, or discussion context (e.g. Slack conversations, error logs, reproduction steps). Your job is to turn that into a well-structured issue and save it to `plans/`. Steps: diff --git a/.agents/commands/lint.md b/.agents/commands/lint.md index 467b49a99..3355769a8 100644 --- a/.agents/commands/lint.md +++ b/.agents/commands/lint.md @@ -1,5 +1,7 @@ Check and fix code formatting using ESLint and Prettier. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + Steps: 1. Run `npm run format:check` to see if there are formatting violations diff --git a/.agents/commands/summary.md b/.agents/commands/summary.md index 383dad452..28ad72097 100644 --- a/.agents/commands/summary.md +++ b/.agents/commands/summary.md @@ -1,5 +1,7 @@ Generate a concise implementation summary for a PR description. +Read `AGENTS.md` first. It is the canonical project guide for this repository. + Steps: 1. First, run the `/docs` command to ensure documentation is up to date with the branch changes diff --git a/.claude/commands/address-review.md b/.claude/commands/address-review.md new file mode 100644 index 000000000..3326ad03e --- /dev/null +++ b/.claude/commands/address-review.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/address-review.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md new file mode 100644 index 000000000..845f233c2 --- /dev/null +++ b/.claude/commands/commit.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/commit.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/docs.md b/.claude/commands/docs.md new file mode 100644 index 000000000..bca8db967 --- /dev/null +++ b/.claude/commands/docs.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/docs.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md new file mode 100644 index 000000000..f515db2a5 --- /dev/null +++ b/.claude/commands/implement.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/implement.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/issue.md b/.claude/commands/issue.md new file mode 100644 index 000000000..aa5be1af6 --- /dev/null +++ b/.claude/commands/issue.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/issue.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md new file mode 100644 index 000000000..256caf84d --- /dev/null +++ b/.claude/commands/lint.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/lint.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/summary.md b/.claude/commands/summary.md new file mode 100644 index 000000000..09de812e4 --- /dev/null +++ b/.claude/commands/summary.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/summary.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/address-review.md b/.cursor/commands/address-review.md new file mode 100644 index 000000000..3326ad03e --- /dev/null +++ b/.cursor/commands/address-review.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/address-review.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/commit.md b/.cursor/commands/commit.md new file mode 100644 index 000000000..845f233c2 --- /dev/null +++ b/.cursor/commands/commit.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/commit.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/docs.md b/.cursor/commands/docs.md new file mode 100644 index 000000000..bca8db967 --- /dev/null +++ b/.cursor/commands/docs.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/docs.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/implement.md b/.cursor/commands/implement.md new file mode 100644 index 000000000..f515db2a5 --- /dev/null +++ b/.cursor/commands/implement.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/implement.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/issue.md b/.cursor/commands/issue.md new file mode 100644 index 000000000..aa5be1af6 --- /dev/null +++ b/.cursor/commands/issue.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/issue.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/lint.md b/.cursor/commands/lint.md new file mode 100644 index 000000000..256caf84d --- /dev/null +++ b/.cursor/commands/lint.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/lint.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/summary.md b/.cursor/commands/summary.md new file mode 100644 index 000000000..09de812e4 --- /dev/null +++ b/.cursor/commands/summary.md @@ -0,0 +1,3 @@ +Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/summary.md`. + +If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/rules/00-core.mdc b/.cursor/rules/00-core.mdc new file mode 100644 index 000000000..90725d3f5 --- /dev/null +++ b/.cursor/rules/00-core.mdc @@ -0,0 +1,14 @@ +--- +description: Core GitProxy repository rules +alwaysApply: true +--- + +# GitProxy Core Rules + +`AGENTS.md` is the canonical project guide for this repository. Read it and apply it as the source of truth. + +- Preserve the chain-of-processors architecture and separation between proxy, service, config, and UI. +- Never bypass approval gating, `blockForAuth`, waiting-authorization checks, or audit logging. +- Keep processors idempotent, operate through the `Action` object, and respect chain ordering dependencies. +- For config changes, update schema validation, preserve backward-compatible defaults, and avoid silent security regressions. +- Validate changes with the repo commands from `AGENTS.md` and prefer targeted tests when possible. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..185046c22 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,15 @@ +# GitProxy Copilot Instructions + +Read `AGENTS.md` for the full project guide. Use the rules below as the highest-priority summary for Copilot surfaces that truncate long instruction files. + +- Preserve the GitProxy flow: Git HTTP proxy -> ordered action chain -> service API -> audit trail -> approval gate. +- A push must never reach the real remote unless it is explicitly approved or auto-approved by policy. +- Do not bypass `blockForAuth`, waiting-authorization checks, or audit logging. +- Keep proxy, service, config, and UI responsibilities separate. Do not place policy logic ad hoc in request handlers. +- The action chain is the core abstraction. Put reusable enforcement logic in processors, organization-specific logic in plugins, and UI/auth state changes in the service layer. +- Processor order matters. If logic depends on cloned repositories, diffs, or earlier artifacts, place it accordingly. +- Processors must be idempotent, use the `Action` object instead of shared mutable state, and preserve audit traceability. +- Configuration changes must update schema validation, keep backward-compatible defaults, and avoid weakening security by default. +- Authentication strategies apply to UI and approval workflows. Git push identity is derived from commit metadata, not interactive auth. +- When changing proxy/processors, test success paths, rejection paths, and audit logging. When changing config, test invalid values and defaults. +- Use the standard repo commands: `npm run build`, `npm run test`, `npm run test:e2e`, `npm run lint`, `npm run format:check`. diff --git a/.gitignore b/.gitignore index 5bf58af5b..f38f3b36a 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ web_modules/ # dotenv environment variables file .env .env.test +.claude/worktrees/ # parcel-bundler cache (https://parceljs.org/) .cache @@ -277,4 +278,4 @@ website/.docusaurus /test/fixtures/test-package/package-lock.json # Agentic AI generated files -/plans \ No newline at end of file +/plans diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..eb3cde903 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,11 @@ +# Claude Instructions + +Read and follow `AGENTS.md` first. It is the canonical project guide for this repository. + +Additional Claude-specific notes: + +- Apply `AGENTS.md` as the source of truth. If this file and `AGENTS.md` ever differ, `AGENTS.md` wins. +- Keep changes aligned with the chain-of-processors architecture. Do not bypass approval gating, `blockForAuth`, waiting-authorization checks, or audit logging. +- Prefer the existing build, test, lint, and format commands listed in `AGENTS.md`. +- Project slash-command entry points live in `.claude/commands/` and delegate to the shared definitions in `.agents/commands/`. +- Treat `.claude/worktrees/` as local machine state. Do not rely on it or commit changes from it. diff --git a/README.md b/README.md index 5663f2990..57f91af3f 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ customize for your environment, see the [project's documentation](https://git-pr ## Contributing -Your contributions are at the core of making this a truly open source project. Any contributions you make are **greatly appreciated**. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for more information. For AI-assisted development (Cursor/Claude), see [`CLAUDE.md`](CLAUDE.md) and the [`.claude/commands`](.claude/commands) directory. +Your contributions are at the core of making this a truly open source project. Any contributions you make are **greatly appreciated**. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for more information. For AI-assisted development, start with [`AGENTS.md`](AGENTS.md). Tool-specific entry points are provided in [`CLAUDE.md`](CLAUDE.md), [`.cursor/rules/00-core.mdc`](.cursor/rules/00-core.mdc), and [`.github/copilot-instructions.md`](.github/copilot-instructions.md). Shared slash-command prompts live in [`.agents/commands`](.agents/commands), with tool-native entry points in [`.claude/commands`](.claude/commands) and [`.cursor/commands`](.cursor/commands). ## Security From de9d1bbf027ac49b6e3e4b596c14c42ba9f6082d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C4=86ori=C4=87?= <denis85@gmail.com> Date: Wed, 1 Apr 2026 13:10:27 +0200 Subject: [PATCH 10/12] chore: migrate commands to skills, add .claude/skills symlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Denis Ćorić <denis85@gmail.com> --- .../address-review/SKILL.md} | 5 +++++ .../{commands/commit.md => skills/commit/SKILL.md} | 5 +++++ .agents/{commands/docs.md => skills/docs/SKILL.md} | 8 ++++++-- .../implement.md => skills/implement/SKILL.md} | 5 +++++ .../{commands/issue.md => skills/issue/SKILL.md} | 5 +++++ .agents/{commands/lint.md => skills/lint/SKILL.md} | 5 +++++ .../summary.md => skills/summary/SKILL.md} | 7 ++++++- .claude/commands/address-review.md | 3 --- .claude/commands/commit.md | 3 --- .claude/commands/docs.md | 3 --- .claude/commands/implement.md | 3 --- .claude/commands/issue.md | 3 --- .claude/commands/lint.md | 3 --- .claude/commands/summary.md | 3 --- .claude/skills | 1 + .cursor/commands/address-review.md | 3 --- .cursor/commands/commit.md | 3 --- .cursor/commands/docs.md | 3 --- .cursor/commands/implement.md | 3 --- .cursor/commands/issue.md | 3 --- .cursor/commands/lint.md | 3 --- .cursor/commands/summary.md | 3 --- .cursor/rules/00-core.mdc | 14 -------------- CLAUDE.md | 2 +- 24 files changed, 39 insertions(+), 60 deletions(-) rename .agents/{commands/address-review.md => skills/address-review/SKILL.md} (97%) rename .agents/{commands/commit.md => skills/commit/SKILL.md} (94%) rename .agents/{commands/docs.md => skills/docs/SKILL.md} (94%) rename .agents/{commands/implement.md => skills/implement/SKILL.md} (97%) rename .agents/{commands/issue.md => skills/issue/SKILL.md} (93%) rename .agents/{commands/lint.md => skills/lint/SKILL.md} (88%) rename .agents/{commands/summary.md => skills/summary/SKILL.md} (92%) delete mode 100644 .claude/commands/address-review.md delete mode 100644 .claude/commands/commit.md delete mode 100644 .claude/commands/docs.md delete mode 100644 .claude/commands/implement.md delete mode 100644 .claude/commands/issue.md delete mode 100644 .claude/commands/lint.md delete mode 100644 .claude/commands/summary.md create mode 120000 .claude/skills delete mode 100644 .cursor/commands/address-review.md delete mode 100644 .cursor/commands/commit.md delete mode 100644 .cursor/commands/docs.md delete mode 100644 .cursor/commands/implement.md delete mode 100644 .cursor/commands/issue.md delete mode 100644 .cursor/commands/lint.md delete mode 100644 .cursor/commands/summary.md delete mode 100644 .cursor/rules/00-core.mdc diff --git a/.agents/commands/address-review.md b/.agents/skills/address-review/SKILL.md similarity index 97% rename from .agents/commands/address-review.md rename to .agents/skills/address-review/SKILL.md index 1db7cd3b1..feb71336a 100644 --- a/.agents/commands/address-review.md +++ b/.agents/skills/address-review/SKILL.md @@ -1,3 +1,8 @@ +--- +name: address-review +description: Address review comments on a GitHub pull request +--- + Address review comments on a GitHub pull request. Read `AGENTS.md` first. It is the canonical project guide for this repository. diff --git a/.agents/commands/commit.md b/.agents/skills/commit/SKILL.md similarity index 94% rename from .agents/commands/commit.md rename to .agents/skills/commit/SKILL.md index 03bd5f0b9..bf46ff384 100644 --- a/.agents/commands/commit.md +++ b/.agents/skills/commit/SKILL.md @@ -1,3 +1,8 @@ +--- +name: commit +description: Create a conventional commit for the current staged/unstaged changes +--- + Create a git commit for the current staged/unstaged changes using Conventional Commits. Read `AGENTS.md` first. It is the canonical project guide for this repository. diff --git a/.agents/commands/docs.md b/.agents/skills/docs/SKILL.md similarity index 94% rename from .agents/commands/docs.md rename to .agents/skills/docs/SKILL.md index 753f0e83f..ccbb3473c 100644 --- a/.agents/commands/docs.md +++ b/.agents/skills/docs/SKILL.md @@ -1,3 +1,8 @@ +--- +name: docs +description: Update existing project documentation to reflect the current state of the branch +--- + Update existing project documentation to reflect the current state of the branch. Read `AGENTS.md` first. It is the canonical project guide for this repository. @@ -6,7 +11,7 @@ Steps: 1. Run `git diff main...HEAD --stat` and `git log main..HEAD --oneline` to understand what changed on this branch 2. Read the changed files to understand what was added, removed, or modified -3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `AGENTS.md`, `CLAUDE.md`, `.github/copilot-instructions.md`, `.cursor/rules/00-core.mdc` +3. Read the current documentation files: `README.md`, `docs/Architecture.md`, `AGENTS.md`, `CLAUDE.md`, `.github/copilot-instructions.md` 4. Identify documentation that is now outdated or missing based on the branch changes 5. Apply minimal, targeted edits to bring docs in line with the code @@ -17,7 +22,6 @@ What to update: - **AGENTS.md** — canonical project architecture, invariants, testing commands, and AI-agent workflow guidance - **CLAUDE.md** — Claude-specific entry point that should remain aligned with `AGENTS.md` - **.github/copilot-instructions.md** — short Copilot-compatible summary of the highest-priority repo rules -- **.cursor/rules/00-core.mdc** — Cursor-compatible summary that should stay aligned with `AGENTS.md` Principles: diff --git a/.agents/commands/implement.md b/.agents/skills/implement/SKILL.md similarity index 97% rename from .agents/commands/implement.md rename to .agents/skills/implement/SKILL.md index 24f3a48fc..5cf96e0f9 100644 --- a/.agents/commands/implement.md +++ b/.agents/skills/implement/SKILL.md @@ -1,3 +1,8 @@ +--- +name: implement +description: Implement a GitHub issue end-to-end: fetch, plan, code with approval, commit incrementally, and generate a PR summary +--- + Implement a GitHub issue end-to-end: fetch the issue, plan, code with approval, commit incrementally, and generate a PR summary. Read `AGENTS.md` first. It is the canonical project guide for this repository. diff --git a/.agents/commands/issue.md b/.agents/skills/issue/SKILL.md similarity index 93% rename from .agents/commands/issue.md rename to .agents/skills/issue/SKILL.md index 492a5c627..5d8814674 100644 --- a/.agents/commands/issue.md +++ b/.agents/skills/issue/SKILL.md @@ -1,3 +1,8 @@ +--- +name: issue +description: Create a GitHub issue markdown file from a bug report, feature request, or discussion context +--- + Create a GitHub issue markdown file from the details provided by the user. Read `AGENTS.md` first. It is the canonical project guide for this repository. diff --git a/.agents/commands/lint.md b/.agents/skills/lint/SKILL.md similarity index 88% rename from .agents/commands/lint.md rename to .agents/skills/lint/SKILL.md index 3355769a8..25f042f66 100644 --- a/.agents/commands/lint.md +++ b/.agents/skills/lint/SKILL.md @@ -1,3 +1,8 @@ +--- +name: lint +description: Check and fix code formatting using ESLint and Prettier +--- + Check and fix code formatting using ESLint and Prettier. Read `AGENTS.md` first. It is the canonical project guide for this repository. diff --git a/.agents/commands/summary.md b/.agents/skills/summary/SKILL.md similarity index 92% rename from .agents/commands/summary.md rename to .agents/skills/summary/SKILL.md index 28ad72097..979c4b778 100644 --- a/.agents/commands/summary.md +++ b/.agents/skills/summary/SKILL.md @@ -1,10 +1,15 @@ +--- +name: summary +description: Generate a concise implementation summary for a PR description +--- + Generate a concise implementation summary for a PR description. Read `AGENTS.md` first. It is the canonical project guide for this repository. Steps: -1. First, run the `/docs` command to ensure documentation is up to date with the branch changes +1. First, run the `/docs` skill to ensure documentation is up to date with the branch changes 2. Run `git diff main...HEAD --stat` and `git log main..HEAD --oneline` to understand all changes on this branch 3. Read the changed files to understand what was implemented and why 4. Get the current branch name: `git rev-parse --abbrev-ref HEAD` diff --git a/.claude/commands/address-review.md b/.claude/commands/address-review.md deleted file mode 100644 index 3326ad03e..000000000 --- a/.claude/commands/address-review.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/address-review.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md deleted file mode 100644 index 845f233c2..000000000 --- a/.claude/commands/commit.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/commit.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/docs.md b/.claude/commands/docs.md deleted file mode 100644 index bca8db967..000000000 --- a/.claude/commands/docs.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/docs.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md deleted file mode 100644 index f515db2a5..000000000 --- a/.claude/commands/implement.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/implement.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/issue.md b/.claude/commands/issue.md deleted file mode 100644 index aa5be1af6..000000000 --- a/.claude/commands/issue.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/issue.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md deleted file mode 100644 index 256caf84d..000000000 --- a/.claude/commands/lint.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/lint.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/commands/summary.md b/.claude/commands/summary.md deleted file mode 100644 index 09de812e4..000000000 --- a/.claude/commands/summary.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/summary.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 000000000..2b7a412b8 --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/.cursor/commands/address-review.md b/.cursor/commands/address-review.md deleted file mode 100644 index 3326ad03e..000000000 --- a/.cursor/commands/address-review.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/address-review.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/commit.md b/.cursor/commands/commit.md deleted file mode 100644 index 845f233c2..000000000 --- a/.cursor/commands/commit.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/commit.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/docs.md b/.cursor/commands/docs.md deleted file mode 100644 index bca8db967..000000000 --- a/.cursor/commands/docs.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/docs.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/implement.md b/.cursor/commands/implement.md deleted file mode 100644 index f515db2a5..000000000 --- a/.cursor/commands/implement.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/implement.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/issue.md b/.cursor/commands/issue.md deleted file mode 100644 index aa5be1af6..000000000 --- a/.cursor/commands/issue.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/issue.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/lint.md b/.cursor/commands/lint.md deleted file mode 100644 index 256caf84d..000000000 --- a/.cursor/commands/lint.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/lint.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/commands/summary.md b/.cursor/commands/summary.md deleted file mode 100644 index 09de812e4..000000000 --- a/.cursor/commands/summary.md +++ /dev/null @@ -1,3 +0,0 @@ -Read `AGENTS.md` first, then follow the shared command definition in `.agents/commands/summary.md`. - -If there is any conflict, `AGENTS.md` wins. diff --git a/.cursor/rules/00-core.mdc b/.cursor/rules/00-core.mdc deleted file mode 100644 index 90725d3f5..000000000 --- a/.cursor/rules/00-core.mdc +++ /dev/null @@ -1,14 +0,0 @@ ---- -description: Core GitProxy repository rules -alwaysApply: true ---- - -# GitProxy Core Rules - -`AGENTS.md` is the canonical project guide for this repository. Read it and apply it as the source of truth. - -- Preserve the chain-of-processors architecture and separation between proxy, service, config, and UI. -- Never bypass approval gating, `blockForAuth`, waiting-authorization checks, or audit logging. -- Keep processors idempotent, operate through the `Action` object, and respect chain ordering dependencies. -- For config changes, update schema validation, preserve backward-compatible defaults, and avoid silent security regressions. -- Validate changes with the repo commands from `AGENTS.md` and prefer targeted tests when possible. diff --git a/CLAUDE.md b/CLAUDE.md index eb3cde903..78926b3c6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,5 +7,5 @@ Additional Claude-specific notes: - Apply `AGENTS.md` as the source of truth. If this file and `AGENTS.md` ever differ, `AGENTS.md` wins. - Keep changes aligned with the chain-of-processors architecture. Do not bypass approval gating, `blockForAuth`, waiting-authorization checks, or audit logging. - Prefer the existing build, test, lint, and format commands listed in `AGENTS.md`. -- Project slash-command entry points live in `.claude/commands/` and delegate to the shared definitions in `.agents/commands/`. +- Project slash commands are defined as skills in `.agents/skills/`. - Treat `.claude/worktrees/` as local machine state. Do not rely on it or commit changes from it. From cf23a9f9ff134b1b41f54544d01b251ff635fbe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C4=86ori=C4=87?= <denis85@gmail.com> Date: Wed, 1 Apr 2026 13:24:31 +0200 Subject: [PATCH 11/12] chore: add opencode command stubs delegating to agent skills MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Denis Ćorić <denis85@gmail.com> --- .opencode/commands/address-review.md | 5 +++++ .opencode/commands/commit.md | 5 +++++ .opencode/commands/docs.md | 5 +++++ .opencode/commands/implement.md | 5 +++++ .opencode/commands/issue.md | 5 +++++ .opencode/commands/lint.md | 5 +++++ .opencode/commands/summary.md | 5 +++++ 7 files changed, 35 insertions(+) create mode 100644 .opencode/commands/address-review.md create mode 100644 .opencode/commands/commit.md create mode 100644 .opencode/commands/docs.md create mode 100644 .opencode/commands/implement.md create mode 100644 .opencode/commands/issue.md create mode 100644 .opencode/commands/lint.md create mode 100644 .opencode/commands/summary.md diff --git a/.opencode/commands/address-review.md b/.opencode/commands/address-review.md new file mode 100644 index 000000000..272b42b93 --- /dev/null +++ b/.opencode/commands/address-review.md @@ -0,0 +1,5 @@ +--- +description: Address review comments on a GitHub PR +--- + +Follow @.agents/skills/address-review/SKILL.md. diff --git a/.opencode/commands/commit.md b/.opencode/commands/commit.md new file mode 100644 index 000000000..3b6431c2c --- /dev/null +++ b/.opencode/commands/commit.md @@ -0,0 +1,5 @@ +--- +description: Create a Conventional Commit with signoff +--- + +Follow @.agents/skills/commit/SKILL.md. diff --git a/.opencode/commands/docs.md b/.opencode/commands/docs.md new file mode 100644 index 000000000..09bdec8fa --- /dev/null +++ b/.opencode/commands/docs.md @@ -0,0 +1,5 @@ +--- +description: Update project docs per repo guidelines +--- + +Follow @.agents/skills/docs/SKILL.md. diff --git a/.opencode/commands/implement.md b/.opencode/commands/implement.md new file mode 100644 index 000000000..347b1cbdb --- /dev/null +++ b/.opencode/commands/implement.md @@ -0,0 +1,5 @@ +--- +description: Implement a change following repo workflow +--- + +Follow @.agents/skills/implement/SKILL.md. diff --git a/.opencode/commands/issue.md b/.opencode/commands/issue.md new file mode 100644 index 000000000..d341c58bb --- /dev/null +++ b/.opencode/commands/issue.md @@ -0,0 +1,5 @@ +--- +description: Create a GitHub issue markdown file +--- + +Follow @.agents/skills/issue/SKILL.md. diff --git a/.opencode/commands/lint.md b/.opencode/commands/lint.md new file mode 100644 index 000000000..0652b71d2 --- /dev/null +++ b/.opencode/commands/lint.md @@ -0,0 +1,5 @@ +--- +description: Run repo format + lint workflow +--- + +Follow @.agents/skills/lint/SKILL.md. diff --git a/.opencode/commands/summary.md b/.opencode/commands/summary.md new file mode 100644 index 000000000..9f4eedfa1 --- /dev/null +++ b/.opencode/commands/summary.md @@ -0,0 +1,5 @@ +--- +description: Generate a concise PR implementation summary +--- + +Follow @.agents/skills/summary/SKILL.md. From dfc14193001af585231fbd1974e89e87deb36eb8 Mon Sep 17 00:00:00 2001 From: Juan Escalada <juanescalada175@gmail.com> Date: Fri, 3 Apr 2026 15:22:01 +0900 Subject: [PATCH 12/12] fix: add graphql query to detect PR comments' resolved status --- .agents/skills/address-review/SKILL.md | 41 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/.agents/skills/address-review/SKILL.md b/.agents/skills/address-review/SKILL.md index feb71336a..4779985ae 100644 --- a/.agents/skills/address-review/SKILL.md +++ b/.agents/skills/address-review/SKILL.md @@ -13,14 +13,49 @@ The argument is a PR number (e.g. `/address-review 98`). If no number is given, 1. Save the current branch name: `git rev-parse --abbrev-ref HEAD` 2. Checkout the PR branch: `gh pr checkout <number> --detach` -3. Fetch all review comments: +3. Fetch review data (pick one): + + **REST (simple):** Lists inline review comments; it does **not** include per-thread `resolved` status, so you cannot rely on it alone to skip resolved threads. ``` gh api repos/{owner}/{repo}/pulls/<number>/comments --paginate ``` -4. Group comments by file. For each comment, extract: `id`, `path`, `line` (or `original_line`), `body`, `user.login`, `in_reply_to_id` (to detect threads). -5. Filter out threads that are already resolved or where the last message is from the PR author (likely already addressed). +**GraphQL (for filtering resolved threads):** Returns `reviewThreads` with `isResolved`, `isOutdated`, paths/lines, and nested comments—use this when step 5 must honor “already resolved.” Paginate with `cursor` (use `null` or omit for the first page; then pass `reviewThreads.pageInfo.endCursor` while `hasNextPage` is true). + +``` +gh api graphql -f query=' +query($owner:String!, $repo:String!, $number:Int!, $cursor:String) { + repository(owner:$owner, name:$repo) { + pullRequest(number:$number) { + reviewThreads(first:100, after:$cursor) { + pageInfo { hasNextPage endCursor } + nodes { + isResolved + isOutdated + path + line + originalLine + comments(first:100) { + nodes { + databaseId + body + author { login } + createdAt + url + } + } + } + } + } + } +}' -F owner={owner} -F repo={repo} -F number=<number> -F cursor=<cursor> +``` + +First page: pass JSON `null` for `cursor` (see `gh help api` / your shell for how `gh` expects null). Later pages: set `cursor` to the previous response’s `reviewThreads.pageInfo.endCursor` until `hasNextPage` is false. + +4. Group comments by file. For each comment, extract: `id`, `path`, `line` (or `original_line`), `body`, `user.login`, `in_reply_to_id` (to detect threads). If you used GraphQL, map `databaseId` to `id` and thread fields as needed. +5. Filter out threads that are already resolved (when using GraphQL method). 6. Present a numbered summary to the programmer: ```