diff --git a/cookbook/copilot-sdk/dotnet/ralph-loop.md b/cookbook/copilot-sdk/dotnet/ralph-loop.md index 0b2bb570..e8807c6d 100644 --- a/cookbook/copilot-sdk/dotnet/ralph-loop.md +++ b/cookbook/copilot-sdk/dotnet/ralph-loop.md @@ -119,13 +119,24 @@ try // Fresh session — each task gets full context budget var session = await client.CreateSessionAsync( - new SessionConfig { Model = "claude-sonnet-4.5" }); + new SessionConfig + { + Model = "claude-sonnet-4.5", + // Pin the agent to the project directory + WorkingDirectory = Environment.CurrentDirectory, + // Auto-approve tool calls for unattended operation + OnPermissionRequest = (_, _) => Task.FromResult( + new PermissionRequestResult { Kind = "approved" }), + }); try { var done = new TaskCompletionSource(); session.On(evt => { - if (evt is AssistantMessageEvent msg) + // Log tool usage for visibility + if (evt is ToolExecutionStartEvent toolStart) + Console.WriteLine($" ⚙ {toolStart.Data.ToolName}"); + else if (evt is AssistantMessageEvent msg) done.TrySetResult(msg.Data.Content); }); @@ -224,6 +235,8 @@ dotnet build 6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan 7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes 8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it +9. **Set `WorkingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly +10. **Auto-approve permissions**: Use `OnPermissionRequest` to allow tool calls without interrupting the loop ## When to Use a Ralph Loop @@ -238,3 +251,8 @@ dotnet build - One-shot operations that don't benefit from iteration - Vague requirements without testable acceptance criteria - Exploratory prototyping where direction isn't clear + +## See Also + +- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions +- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts diff --git a/cookbook/copilot-sdk/dotnet/recipe/ralph-loop.cs b/cookbook/copilot-sdk/dotnet/recipe/ralph-loop.cs index 920a78f2..ba6b2d51 100644 --- a/cookbook/copilot-sdk/dotnet/recipe/ralph-loop.cs +++ b/cookbook/copilot-sdk/dotnet/recipe/ralph-loop.cs @@ -43,14 +43,25 @@ try // Fresh session — each task gets full context budget var session = await client.CreateSessionAsync( - new SessionConfig { Model = "claude-sonnet-4.5" }); + new SessionConfig + { + Model = "claude-sonnet-4.5", + // Pin the agent to the project directory + WorkingDirectory = Environment.CurrentDirectory, + // Auto-approve tool calls for unattended operation + OnPermissionRequest = (_, _) => Task.FromResult( + new PermissionRequestResult { Kind = "approved" }), + }); try { var done = new TaskCompletionSource(); session.On(evt => { - if (evt is AssistantMessageEvent msg) + // Log tool usage for visibility + if (evt is ToolExecutionStartEvent toolStart) + Console.WriteLine($" ⚙ {toolStart.Data.ToolName}"); + else if (evt is AssistantMessageEvent msg) done.TrySetResult(msg.Data.Content); }); diff --git a/cookbook/copilot-sdk/go/ralph-loop.md b/cookbook/copilot-sdk/go/ralph-loop.md index cc7807c4..f7a8c27c 100644 --- a/cookbook/copilot-sdk/go/ralph-loop.md +++ b/cookbook/copilot-sdk/go/ralph-loop.md @@ -111,6 +111,7 @@ import ( "log" "os" "strconv" + "strings" copilot "github.com/github/copilot-sdk/go" ) @@ -127,6 +128,8 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error { } defer client.Stop() + cwd, _ := os.Getwd() + fmt.Println(strings.Repeat("━", 40)) fmt.Printf("Mode: %s\n", mode) fmt.Printf("Prompt: %s\n", promptFile) @@ -141,14 +144,24 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error { for i := 1; i <= maxIterations; i++ { fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations) - // Fresh session — each task gets full context budget session, err := client.CreateSession(ctx, &copilot.SessionConfig{ - Model: "claude-sonnet-4.5", + Model: "claude-sonnet-4.5", + WorkingDirectory: cwd, + OnPermissionRequest: func(_ copilot.PermissionRequest, _ map[string]string) copilot.PermissionRequestResult { + return copilot.PermissionRequestResult{Kind: "approved"} + }, }) if err != nil { return err } + // Log tool usage for visibility + session.On(func(event copilot.Event) { + if te, ok := event.(copilot.ToolExecutionStartEvent); ok { + fmt.Printf(" ⚙ %s\n", te.Data.ToolName) + } + }) + _, err = session.SendAndWait(ctx, copilot.MessageOptions{ Prompt: string(prompt), }) @@ -258,6 +271,8 @@ go build ./... 6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan 7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes 8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it +9. **Set `WorkingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly +10. **Auto-approve permissions**: Use `OnPermissionRequest` to allow tool calls without interrupting the loop ## When to Use a Ralph Loop @@ -272,3 +287,8 @@ go build ./... - One-shot operations that don't benefit from iteration - Vague requirements without testable acceptance criteria - Exploratory prototyping where direction isn't clear + +## See Also + +- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions +- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts diff --git a/cookbook/copilot-sdk/go/recipe/ralph-loop.go b/cookbook/copilot-sdk/go/recipe/ralph-loop.go index 18de5976..30513927 100644 --- a/cookbook/copilot-sdk/go/recipe/ralph-loop.go +++ b/cookbook/copilot-sdk/go/recipe/ralph-loop.go @@ -39,6 +39,8 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error { } defer client.Stop() + cwd, _ := os.Getwd() + fmt.Println(strings.Repeat("━", 40)) fmt.Printf("Mode: %s\n", mode) fmt.Printf("Prompt: %s\n", promptFile) @@ -53,14 +55,24 @@ func ralphLoop(ctx context.Context, mode string, maxIterations int) error { for i := 1; i <= maxIterations; i++ { fmt.Printf("\n=== Iteration %d/%d ===\n", i, maxIterations) - // Fresh session — each task gets full context budget session, err := client.CreateSession(ctx, &copilot.SessionConfig{ - Model: "claude-sonnet-4.5", + Model: "claude-sonnet-4.5", + WorkingDirectory: cwd, + OnPermissionRequest: func(_ copilot.PermissionRequest, _ map[string]string) copilot.PermissionRequestResult { + return copilot.PermissionRequestResult{Kind: "approved"} + }, }) if err != nil { return fmt.Errorf("failed to create session: %w", err) } + // Log tool usage for visibility + session.On(func(event copilot.Event) { + if te, ok := event.(copilot.ToolExecutionStartEvent); ok { + fmt.Printf(" ⚙ %s\n", te.Data.ToolName) + } + }) + _, err = session.SendAndWait(ctx, copilot.MessageOptions{ Prompt: string(prompt), }) diff --git a/cookbook/copilot-sdk/nodejs/ralph-loop.md b/cookbook/copilot-sdk/nodejs/ralph-loop.md index 13e74fc8..5153790a 100644 --- a/cookbook/copilot-sdk/nodejs/ralph-loop.md +++ b/cookbook/copilot-sdk/nodejs/ralph-loop.md @@ -99,8 +99,21 @@ async function ralphLoop(mode: Mode, maxIterations: number = 50) { for (let i = 1; i <= maxIterations; i++) { console.log(`\n=== Iteration ${i}/${maxIterations} ===`); - // Fresh session — each task gets full context budget - const session = await client.createSession({ model: "claude-sonnet-4.5" }); + const session = await client.createSession({ + model: "claude-sonnet-4.5", + // Pin the agent to the project directory + workingDirectory: process.cwd(), + // Auto-approve tool calls for unattended operation + onPermissionRequest: async () => ({ allow: true }), + }); + + // Log tool usage for visibility + session.on((event) => { + if (event.type === "tool.execution_start") { + console.log(` ⚙ ${event.data.toolName}`); + } + }); + try { await session.sendAndWait({ prompt }, 600_000); } finally { @@ -200,6 +213,8 @@ npm run build 6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan 7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes 8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it +9. **Set `workingDirectory`**: Pin the session to your project root so tool operations resolve paths correctly +10. **Auto-approve permissions**: Use `onPermissionRequest` to allow tool calls without interrupting the loop ## When to Use a Ralph Loop @@ -214,3 +229,8 @@ npm run build - One-shot operations that don't benefit from iteration - Vague requirements without testable acceptance criteria - Exploratory prototyping where direction isn't clear + +## See Also + +- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions +- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts diff --git a/cookbook/copilot-sdk/nodejs/recipe/package-lock.json b/cookbook/copilot-sdk/nodejs/recipe/package-lock.json index a5a8fea5..47e85e5a 100644 --- a/cookbook/copilot-sdk/nodejs/recipe/package-lock.json +++ b/cookbook/copilot-sdk/nodejs/recipe/package-lock.json @@ -8,7 +8,7 @@ "name": "copilot-sdk-cookbook-recipes", "version": "1.0.0", "dependencies": { - "@github/copilot-sdk": "file:../../src" + "@github/copilot-sdk": "*" }, "devDependencies": { "@types/node": "^22.19.7", diff --git a/cookbook/copilot-sdk/nodejs/recipe/ralph-loop.ts b/cookbook/copilot-sdk/nodejs/recipe/ralph-loop.ts index 3bd5e4cf..f22e2bee 100644 --- a/cookbook/copilot-sdk/nodejs/recipe/ralph-loop.ts +++ b/cookbook/copilot-sdk/nodejs/recipe/ralph-loop.ts @@ -39,9 +39,19 @@ async function ralphLoop(mode: Mode, maxIterations: number) { for (let i = 1; i <= maxIterations; i++) { console.log(`\n=== Iteration ${i}/${maxIterations} ===`); - // Fresh session — each task gets full context budget const session = await client.createSession({ model: "claude-sonnet-4.5", + // Pin the agent to the project directory + workingDirectory: process.cwd(), + // Auto-approve tool calls for unattended operation + onPermissionRequest: async () => ({ allow: true }), + }); + + // Log tool usage for visibility + session.on((event) => { + if (event.type === "tool.execution_start") { + console.log(` ⚙ ${event.data.toolName}`); + } }); try { diff --git a/cookbook/copilot-sdk/python/ralph-loop.md b/cookbook/copilot-sdk/python/ralph-loop.md index ae666eb2..55790c27 100644 --- a/cookbook/copilot-sdk/python/ralph-loop.md +++ b/cookbook/copilot-sdk/python/ralph-loop.md @@ -108,10 +108,20 @@ async def ralph_loop(mode: str = "build", max_iterations: int = 50): for i in range(1, max_iterations + 1): print(f"\n=== Iteration {i}/{max_iterations} ===") - # Fresh session — each task gets full context budget - session = await client.create_session( - SessionConfig(model="claude-sonnet-4.5") + session = await client.create_session(SessionConfig( + model="claude-sonnet-4.5", + # Pin the agent to the project directory + working_directory=str(Path.cwd()), + # Auto-approve tool calls for unattended operation + on_permission_request=lambda _req, _ctx: {"kind": "approved", "rules": []}, + )) + + # Log tool usage for visibility + session.on(lambda event: + print(f" ⚙ {event.data.tool_name}") + if event.type.value == "tool.execution_start" else None ) + try: await session.send_and_wait( MessageOptions(prompt=prompt), timeout=600 @@ -210,6 +220,8 @@ python -m pytest 6. **The plan is disposable**: If the agent goes off track, delete `IMPLEMENTATION_PLAN.md` and re-plan 7. **Keep `AGENTS.md` brief**: It's loaded every iteration — operational info only, no progress notes 8. **Use a sandbox**: The agent runs autonomously with full tool access — isolate it +9. **Set `working_directory`**: Pin the session to your project root so tool operations resolve paths correctly +10. **Auto-approve permissions**: Use `on_permission_request` to allow tool calls without interrupting the loop ## When to Use a Ralph Loop @@ -224,3 +236,8 @@ python -m pytest - One-shot operations that don't benefit from iteration - Vague requirements without testable acceptance criteria - Exploratory prototyping where direction isn't clear + +## See Also + +- [Error Handling](error-handling.md) — timeout patterns and graceful shutdown for long-running sessions +- [Persisting Sessions](persisting-sessions.md) — save and resume sessions across restarts diff --git a/cookbook/copilot-sdk/python/recipe/ralph_loop.py b/cookbook/copilot-sdk/python/recipe/ralph_loop.py index f6ef1f62..823981bf 100644 --- a/cookbook/copilot-sdk/python/recipe/ralph_loop.py +++ b/cookbook/copilot-sdk/python/recipe/ralph_loop.py @@ -43,10 +43,23 @@ async def ralph_loop(mode: str = "build", max_iterations: int = 50): for i in range(1, max_iterations + 1): print(f"\n=== Iteration {i}/{max_iterations} ===") - # Fresh session — each task gets full context budget - session = await client.create_session( - SessionConfig(model="claude-sonnet-4.5") + session = await client.create_session(SessionConfig( + model="claude-sonnet-4.5", + # Pin the agent to the project directory + working_directory=str(Path.cwd()), + # Auto-approve tool calls for unattended operation + on_permission_request=lambda _req, _ctx: { + "kind": "approved", + "rules": [], + }, + )) + + # Log tool usage for visibility + session.on(lambda event: + print(f" ⚙ {event.data.tool_name}") + if event.type.value == "tool.execution_start" else None ) + try: await session.send_and_wait( MessageOptions(prompt=prompt), timeout=600