Skip to content

Add agentic coding loop with tools and orchestrator#22

Open
cpetersen wants to merge 8 commits intomainfrom
agent-loop
Open

Add agentic coding loop with tools and orchestrator#22
cpetersen wants to merge 8 commits intomainfrom
agent-loop

Conversation

@cpetersen
Copy link
Copy Markdown
Member

Summary

Adds a Claude Code-style agentic coding assistant to ragnar. The agent can read files, write code, run commands, and self-correct — all orchestrated by a two-level loop architecture designed to be readable and hackable by Ruby developers.

Architecture: Two Levels of Looping

Level 1 — Tool execution (RubyLLM handles this)
The LLM makes tool calls within a single turn. RubyLLM automatically executes tools, feeds results back, and loops until the LLM produces a final response.

Level 2 — Task orchestration (Orchestrator)
The "brain outside the brain" manages multiple LLM turns:

  • Auto-detects project type (Ruby/Rust/Node/Python) and runs validation between turns
  • Feeds test failures back to the LLM for self-correction
  • Uses tool-based signaling for completion detection (not string heuristics)

Tools (8 RubyLLM::Tool subclasses)

Tool Purpose
ReadFile Read files with line numbers, offset/limit
WriteFile Create/overwrite files
EditFile Search-and-replace with uniqueness validation
BashExec Shell execution with safety blocklist
ListFiles Glob-based file search
Grep ripgrep/grep content search
TaskComplete Agent signals task completion (uses halt)
AskUser Agent requests user clarification (uses halt)

Key Design Decisions

  • TaskComplete tool instead of string matching — The agent explicitly signals completion by calling a tool, not by saying "I'm done" in prose. RubyLLM's halt mechanism stops the loop immediately. This eliminated a bug where the orchestrator looped 6 times after the agent was already done.
  • AskUser tool for user interaction — Same pattern: the agent calls a tool to pause and ask the user, rather than the orchestrator parsing the response for questions.
  • Validation is orchestrator-driven — The LLM doesn't decide to run tests; the orchestrator runs them automatically after detecting file changes.

CLI

# Agentic coding mode
ragnar --profile opus code "Write FizzBuzz in Ruby and run it"

# In TUI
ragnar> /code Add error handling to the login form

Files

  • lib/ragnar/tools/ — 8 tool classes (~310 lines)
  • lib/ragnar/agent.rb — Agent with persistent chat + tools (114 lines)
  • lib/ragnar/orchestrator.rb — Level 2 loop (163 lines)
  • exe/ragnar — Fixed arg ordering for --profile before command

Test plan

  • 387 specs, 0 failures (49 new)
  • ragnar --profile opus code "Create fizzbuzz.rb in /tmp and run it" — completes in 1 iteration
  • Tool calls display in real time
  • Existing RAG, TUI, profile features unaffected
  • BashExec blocks dangerous commands (rm -rf /, shutdown)
  • EditFile rejects ambiguous matches
  • TaskComplete/AskUser use RubyLLM halt correctly

🤖 Generated with Claude Code

cpetersen and others added 4 commits March 28, 2026 15:44
Core Tools (RubyLLM::Tool subclasses):
- ReadFile: read files with line numbers, offset/limit support
- WriteFile: create/overwrite files, auto-create directories
- EditFile: search-and-replace edits with uniqueness validation
- BashExec: shell execution with safety blocklist and output truncation
- ListFiles: glob-based file search
- Grep: ripgrep/grep wrapper for content search

Agent (Level 1 — single LLM turn with tool calls):
- Wraps persistent RubyLLM chat with all tools registered
- System prompt for coding assistant behavior
- Tool call/result callbacks for real-time visibility
- Tracks modified files across tool calls
- step/ask/add_context/next_step interface for Orchestrator

Orchestrator (Level 2 — multi-turn task completion):
- Manages multiple Agent turns toward a goal
- Auto-detects project type (Ruby/Rust/Node/Python)
- Runs validation (tests/lint) between LLM turns
- Feeds failures back to Agent for self-correction
- Iteration limits with user confirmation to continue
- Event-based callback for TUI integration

CLI Integration:
- /code TASK command runs the full agentic loop
- Real-time tool call display during execution
- --max-iterations and --profile flags
- Works in both CLI and TUI modes

Specs: 377 total (39 new), 0 failures
- Tool specs: ReadFile, WriteFile, EditFile, BashExec, ListFiles
- Agent: initialization, step, context, reset
- Orchestrator: completion detection, iteration limits, project detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add section 3 covering /code command, agent loop architecture (Level 1
tool calls + Level 2 orchestrator), available tools, and auto-validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite exe/ragnar to detect command position and reorder args so
  global options (--profile) work before or after the command name
- Remove default_command :interactive (handled by executable instead)
- Add exit_on_failure? to suppress Thor deprecation warning
- Both work now: ragnar --profile opus code "task"
                  ragnar code --profile opus "task"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of string-matching "I've completed" in LLM responses (fragile,
caused 6 unnecessary iterations), the agent now signals completion by
calling the TaskComplete tool. RubyLLM's halt mechanism stops the tool
loop immediately and returns the summary.

New tools:
- TaskComplete: agent calls when task is done, with summary
- AskUser: agent calls when it needs user clarification

Orchestrator changes:
- detect_signal reads last tool call instead of parsing prose
- Loop structure: check signal first, then decide next action
- Validation still runs on task_complete if files were modified

System prompt updated to instruct the LLM to use these tools.

387 specs, 0 failures (6 new tool/orchestrator specs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Base automatically changed from migrate-to-ruby-llm to main March 29, 2026 00:28
cpetersen and others added 4 commits March 28, 2026 17:37
- Enable bundler-cache in ruby/setup-ruby (caches compiled native
  extensions for red-candle, clusterkit, lancelot)
- Add restore-keys for cargo cache (partial hits still save time)
- Remove manual bundle install (handled by bundler-cache)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ragnar is no longer just a RAG pipeline — it's a hackable, Claude Code-style
coding agent. The README now leads with that identity:

- New tagline: "An agentic coding assistant for Ruby"
- Architecture section: two-level loop diagram (Orchestrator + Agent)
- Tools table with all 8 tools
- "How It Works" section for developers: key files, line counts, design decisions
- Quick Start leads with /code (agentic mode), not indexing
- RAG is presented as one capability, not the whole product
- Built With table replaces scattered acknowledgments
- Removed outdated sections (performance benchmarks, optimization tips,
  detailed topic modeling examples)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Orchestrator: expanded class comment explaining Level 1 vs Level 2 and
  why the orchestrator exists ("chatbot with tools" vs "coding assistant")
- Agent: explains what happens inside chat.ask(), why history persists,
  and how the tool call log connects to the Orchestrator
- TaskComplete: documents the journey from string matching to tool-based
  signaling, and why this pattern is used in production agents
- BashExec: explains the three-part tool pattern (description, params, execute)
  and how RubyLLM converts it to JSON Schema automatically
- tools.rb: explains how to add new tools
- README: "designed to be read, understood, and extended" (not "to learn from")

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant