--- name: gather-plan-apply description: "MANDATORY before starting any task. Enforces the GPA execution loop that prevents tool call sprawl. G: GATHER phase combines discover queries + memory reads + file reads into one phase. P: Plan in text with zero tool calls. A: APPLY all writes/edits/verification in one phase. One call per tool type per phase — batch all same-type operations together. Covers dependency analysis, batch opportunities, scope estimation, and loop-back triggers." metadata: version: 2.0.0 category: protocol tags: [gpa, gather, plan, apply, workflow, token-efficiency, strict-workflow] --- ## Resources ``` scripts/ validate-gpa-compliance.sh references/ examples-and-checklists.md ``` # Gather-Plan-Apply Protocol (GPA Workflow) The GPA loop enforces a **one-call-per-tool-type-per-phase** workflow that eliminates token waste from excessive tool calls. This is NOT a suggestion — it is a MANDATORY execution pattern for all GoodVibes agents. ## THE EXACT WORKFLOW ``` 0. LOAD SKILLS (once, before any GPA cycle) - Call get_skill_content for role-relevant skills - This is NOT part of the GPA cycle itself 1. G — GATHER (1-2 tool calls) - Check .goodvibes/memory/ files FIRST (failures, patterns, decisions) - Single `discover` call with ALL queries batched inside - Multiple query types (glob, grep, symbols, structural) in one call - Can search file content via grep/symbols queries - Batch any file reads that need full content alongside discover - Output: files_only or locations (minimal verbosity) 2. P — PLAN (0 tool calls, cognitive only) - Agent thinks about what it learned from GATHER - Plans which files to create/write/edit - Plans which commands to run for validation - Identifies ALL batch opportunities — same-type ops go in one call - Plans the EXACT apply call structure 3. A — APPLY (1-2 tool calls) - Writes and edits batched into one precision_write or precision_edit call - Validation commands batched into one precision_exec call - Key: one call per tool type, everything batched inside it 4. LOOP — Back to G if: - Results didn't match expectations - Scope changed - Validation failed ``` ## CALL BUDGET PER CYCLE | Phase | Tool Calls | Type | Purpose | |-------|-----------|------|----------| | **G** (Gather) | 1-2 | `discover` + optional `precision_read` | All discovery + memory reads | | **P** (Plan) | 0 | Cognitive | Plan apply operations | | **A** (Apply) | 1-2 | `precision_write`/`precision_edit` + `precision_exec` | All writes/edits + validation | | **TOTAL** | **2-4** | | | **Core rule**: One call per tool type per phase. Never make two `precision_read` calls in the same phase — batch both files into the one call. **Note on sequential calls:** Sequential calls are acceptable when operations depend on each other (e.g., write then verify). Always prefer true batching via internal precision tool arrays (files array, edits array, commands array). ## KEY RULES (NON-NEGOTIABLE) 1. **`discover` batches ALL discovery queries into 1 call** — NEVER use separate `precision_glob`, `precision_grep` for discovery 2. **Plan steps produce ZERO tool calls** — they are cognitive (agent thinks in text) 3. **One call per tool type per phase** — if you need 3 files read, batch them in 1 `precision_read` call 4. **APPLY output = 1-2 calls** — precision_write/edit for files, precision_exec for commands 5. **ToolSearch is NOT part of GPA** — load tools once at start, don't search mid-cycle 6. **Check memory FIRST** — always read .goodvibes/memory/ before implementing ## Phase 1: GATHER (1-2 calls) ### Initial Setup: Check Memory Before discovering files, check what's already known. Batch memory reads with your discover call or as a separate read: ```yaml # GOOD: Memory reads batched with file content reads precision_read: files: - path: ".goodvibes/memory/failures.json" - path: ".goodvibes/memory/patterns.json" - path: ".goodvibes/memory/decisions.json" verbosity: minimal ``` ### The `discover` Tool The `discover` tool runs multiple grep/glob/symbols/structural queries **in parallel**, returning results keyed by query ID. This is your primary discovery mechanism. **Pattern: Batch ALL discovery queries** ```yaml # GOOD: 1 discover call with everything discover: queries: - id: existing_files type: glob patterns: ["src/features/auth/**/*.ts"] - id: existing_patterns type: grep pattern: "export (function|const|class)" glob: "src/features/**/*.ts" - id: exported_hooks type: symbols query: "use" kinds: ["function"] - id: console_logs type: structural structural_pattern: "console.log($$$ARGS)" verbosity: files_only ``` **Query types:** - **glob** - Find files by path patterns - **grep** - Find files containing patterns - **symbols** - Find exported functions/types/classes - **structural** - Find AST patterns (e.g., function calls) **Output modes:** - `count_only` - Just counts (scope estimation) - `files_only` - File paths only (building target lists) ← **USE THIS** - `locations` - File paths + line numbers (when you need exact locations) ### Reading Full File Contents For reading full file contents, use `precision_read` in the GATHER phase, batched with memory reads or as a second call if discover results are needed first. ### [BAD] vs [GOOD] Gather Patterns **[BAD] — Sequential discovery queries (multiple tool calls)** ```yaml # BAD: 4 separate tool calls for discovery precision_glob: patterns: ["src/**/*.ts"] precision_grep: queries: - id: exports pattern: "export function" precision_read: files: - path: ".goodvibes/memory/failures.json" precision_grep: queries: - id: imports pattern: "import.*from" ``` **[GOOD] — Single discover call + batched memory reads (2 tool calls)** ```yaml # GOOD: 1 discover call with all queries discover: queries: - id: files type: glob patterns: ["src/**/*.ts"] - id: exports type: grep pattern: "export function" glob: "src/**/*.ts" - id: imports type: grep pattern: "import.*from" glob: "src/**/*.ts" verbosity: files_only # GOOD: Memory reads in one batched call precision_read: files: - path: ".goodvibes/memory/failures.json" - path: ".goodvibes/memory/patterns.json" - path: ".goodvibes/memory/decisions.json" verbosity: minimal ``` ## Phase 2: PLAN (0 calls, cognitive only) ### Purpose Planning is **cognitive work**, not tool calls. You think in text about: - Which files to create/write - Which files to edit (with exact find/replace) - Which commands to run for validation - ALL batch opportunities — same-type ops must be batched **Output: A written plan with NO tool calls** ### Plan Structure ``` Plan: 1. Create the following files: - src/features/auth/types.ts — User interface - src/features/auth/hooks.ts — useAuth hook - src/features/auth/index.ts — barrel export 2. Edit the following files: - src/app/layout.tsx — wrap App with AuthProvider 3. Validate: - npm run typecheck (expect exit 0) - npm run lint (expect exit 0) 4. Batch plan: - Call 1 (Apply): precision_write with 3 files + precision_edit with 1 edit - Call 2 (Apply): precision_exec with 2 commands ``` ### [BAD] vs [GOOD] Planning **[BAD] — Vague plan that leads to sequential calls** ``` Plan: - Create some files - Maybe edit layout - Run typecheck ``` This leads to: ```yaml precision_write: ... # 1st call precision_write: ... # 2nd call! (should be batched) precision_edit: ... # 3rd call! (could combine with above pattern) ``` **[GOOD] — Specific plan with exact batch structure** ``` Plan: 1. Write 3 files in 1 precision_write call: - src/features/auth/types.ts (symbols) - src/features/auth/hooks.ts (content) - src/features/auth/index.ts (content) 2. Edit 1 file in 1 precision_edit call: - src/app/layout.tsx — wrap with AuthProvider 3. Validate in 1 precision_exec call: - npm run typecheck - npm run lint ``` ## Phase 3: APPLY (1-2 calls) ### Pattern: Batch All Writes/Edits **Single precision_write with multiple files:** ```yaml precision_write: files: - path: "src/features/auth/types.ts" content: | export interface User { id: string; email: string; } - path: "src/features/auth/hooks.ts" content: | import type { User } from './types'; export function useAuth(): User | null { /*...*/ } - path: "src/features/auth/index.ts" content: | export * from './types'; export * from './hooks'; verbosity: count_only ``` **OR single precision_edit with multiple edits:** ```yaml precision_edit: edits: - path: "src/app/layout.tsx" find: "" replace: "" - path: "src/middleware.ts" find: "export const config = {}" replace: "export const config = { matcher: ['/dashboard/:path*'] }" - path: "src/lib/api.ts" find: "headers: {}" replace: "headers: { Authorization: `Bearer ${token}` }" verbosity: minimal ``` **Validation via precision_exec (second Apply call):** ```yaml precision_exec: commands: - cmd: "npm run typecheck" expect: exit_code: 0 - cmd: "npm run lint" expect: exit_code: 0 verbosity: minimal ``` ### [BAD] vs [GOOD] Apply Batching **[BAD] — 3 separate precision_write calls** ```yaml precision_write: files: - path: "file1.ts" content: "..." precision_write: # Second call! files: - path: "file2.ts" content: "..." precision_write: # Third call! files: - path: "file3.ts" content: "..." ``` **[GOOD] — 1 precision_write call with 3 files** ```yaml precision_write: files: - path: "file1.ts" content: "..." - path: "file2.ts" content: "..." - path: "file3.ts" content: "..." verbosity: count_only ``` ## Phase 4: LOOP (When to Return to Gather) ### Loop Triggers 1. **Results don't match expectations** — Typecheck fails, tests fail, unexpected behavior 2. **Scope changed** — Discovery revealed different situation than expected 3. **New information** — Task requirements clarified during execution ### Loop Pattern ```yaml # Initial GPA cycle discover: ... # Gather call 1 precision_read: ... # Gather call 2 (memory + key files) precision_write: ... # Apply call 1 precision_exec: ... # Apply call 2 — FAILS typecheck # LOOP: Start new GPA cycle with refined discovery discover: # Gather call 1 (new cycle) queries: - id: find_missing_import type: grep pattern: "export.*User" glob: "src/**/*.ts" verbosity: locations # Need exact location precision_edit: ... # Apply call 1 (new cycle) - fix the issue precision_exec: ... # Apply call 2 (new cycle) - re-validate ``` ## Complete Example: Implementing Auth Feature ### Cycle 1: Initial Implementation **Step 1 — GATHER (2 calls)** ```yaml # Call 1: Check memory precision_read: files: - path: ".goodvibes/memory/failures.json" - path: ".goodvibes/memory/decisions.json" verbosity: minimal # Call 2: Discover landscape discover: queries: - id: existing_auth type: glob patterns: ["src/features/auth/**/*.ts", "src/**/auth*.ts"] - id: auth_patterns type: grep pattern: "(useAuth|getSession|AuthProvider)" glob: "src/**/*.{ts,tsx}" - id: user_types type: symbols query: "User" kinds: ["interface", "type"] verbosity: files_only ``` **Step 2 — PLAN (0 calls, cognitive)** ``` Gather results: - No memory failures for auth - No existing auth files - No auth patterns in use - User type exists in src/types/user.ts Plan: Apply Call 1 (precision_write): Create 3 auth files Apply Call 2 (precision_exec): typecheck + lint ``` **Step 3 — APPLY (2 calls)** ```yaml # Call 1: Create files precision_write: files: - path: "src/features/auth/provider.tsx" content: | import { ClerkProvider } from '@clerk/nextjs'; export function AuthProvider({ children }: { children: React.ReactNode }) { return {children}; } - path: "src/features/auth/hooks.ts" content: | import { useUser } from '@clerk/nextjs'; import type { User } from '@/types/user'; export function useAuth(): User | null { const { user } = useUser(); if (!user) return null; return { id: user.id, email: user.emailAddresses[0].emailAddress, name: user.fullName }; } - path: "src/features/auth/index.ts" content: | export { AuthProvider } from './provider'; export { useAuth } from './hooks'; verbosity: count_only # Call 2: Validate precision_exec: commands: - cmd: "npm run typecheck" expect: exit_code: 0 - cmd: "npm run lint" expect: exit_code: 0 verbosity: minimal # Result: typecheck FAILS — missing @clerk/nextjs ``` **Total calls in Cycle 1: 4** (precision_read + discover + precision_write + precision_exec) ### Cycle 2: Fix Missing Dependency **Step 1 — GATHER (1 call)** ```yaml discover: queries: - id: package_json type: glob patterns: ["package.json"] - id: clerk_usage type: grep pattern: "@clerk/nextjs" glob: "src/**/*.{ts,tsx}" verbosity: files_only ``` **Step 2 — PLAN (0 calls, cognitive)** ``` Discovery: @clerk/nextjs not in package.json Plan: Apply Call 1 (precision_exec): npm install @clerk/nextjs, then typecheck ``` **Step 3 — APPLY (1 call)** ```yaml precision_exec: commands: - cmd: "npm install @clerk/nextjs" - cmd: "npm run typecheck" expect: exit_code: 0 verbosity: minimal # Result: PASSES ``` **Total calls in Cycle 2: 2** (discover + precision_exec) ## Common Violations and Fixes | Violation | Tool Calls | Fix | |-----------|-----------|-----| | Sequential precision_read calls | 5+ | Batch all files into 1 precision_read call | | Sequential precision_write calls | 5+ | Batch all files into 1 precision_write call | | Using precision_glob + precision_grep separately | 2+ | Use 1 discover call with both query types | | Reading outline, then content | 2 | Read content once if you'll need it | | Planning via tool calls | 1+ | Plan in text (cognitive work = 0 calls) | | Memory reads skipped | - | Always check .goodvibes/memory/ in Gather phase | ## Enforcement If you find yourself making the same tool type twice in a phase, you are violating the protocol. Stop and restructure: 1. Identify which calls are discovery → batch into 1 `discover` call 2. Identify which calls are memory/file reads → batch into 1 `precision_read` call 3. Identify which calls are writes/edits → batch into same-type calls (writes together, edits together) 4. Ensure planning happens in text, not via tools Target: **one call per tool type per phase**. ## Summary - **G** (Gather): check memory + `discover` + optional `precision_read` for key files - **P** (Plan): 0 calls (cognitive) - **A** (Apply): `precision_write`/`precision_edit` + `precision_exec` for validation - **LOOP**: Start new cycle if needed **Rule: One call per tool type per phase. Maximize batching within each call.** Make this your default mode of operation.