Fleet Pipeline stage 3: code generation and PR creation. Receives a planned work item, materializes the target repository, generates code via LLM, commits the changes, opens a draft PR, and handles the feedback loop when a validator rejects. Also ships finalized work — marking PRs ready, adding labels, posting summaries, and cleaning up.
assessor → planner → developer → validator → developer (feedback) → ship
↑ ↓
└─────── incorporate_feedback ────────────┘
Add to your Gemfile or gemspec:
gem 'lex-developer'Materializes the target repo into a worktree, generates code via LLM, applies file changes, commits, pushes, and opens a draft PR.
result = Legion::Extensions::Developer::Runners::Developer.implement(
work_item: {
work_item_id: 'uuid-001',
source_ref: 'LegionIO/lex-exec#42',
title: 'Fix sandbox timeout on macOS',
repo: { owner: 'LegionIO', name: 'lex-exec', default_branch: 'main', language: 'ruby' },
config: {
estimated_difficulty: 0.5,
implementation: { max_iterations: 5 },
feedback: { summarize_after: 2 }
},
pipeline: {
stage: 'planned',
attempt: 0,
trace: [],
feedback_history: [],
plan: {
approach: 'Increase default timeout to 120s',
files_to_modify: [{ path: 'lib/sandbox.rb', action: 'modify', reason: 'Fix timeout' }],
test_strategy: 'Add unit test for default timeout'
}
}
}
)
result[:success] # => true
result[:work_item][:pipeline][:stage] # => 'implemented'
result[:work_item][:pipeline][:branch_name] # => 'fleet/fix-lex-exec-42'
result[:work_item][:pipeline][:pr_number] # => 99
result[:work_item][:pipeline][:changes] # => ['lib/sandbox.rb', 'spec/sandbox_spec.rb']The thinking budget scales with attempt number: 16K tokens on attempt 0, doubling each round up to 64K.
Called by the feedback actor when the validator rejects. Summarizes accumulated feedback (AALP pattern), increments the attempt counter, and re-enters implement on the existing worktree branch.
result = Legion::Extensions::Developer::Runners::Developer.incorporate_feedback(
work_item: {
# ... same shape as implement ...
pipeline: {
stage: 'validated',
attempt: 1,
branch_name: 'fleet/fix-lex-exec-42',
feedback_history: [
{ verdict: 'rejected', issues: ['Missing nil check on timeout value'], round: 0 }
],
review_result: { verdict: 'rejected', issues: ['Missing nil check on timeout value'] }
}
}
)
result[:success] # => true
result[:work_item][:pipeline][:attempt] # => 2
result[:work_item][:pipeline][:stage] # => 'implemented'When attempt >= max_iterations - 1, the method escalates instead:
result[:escalate] # => true
result[:work_item][:pipeline][:stage] # => 'escalated'Finalizes a validated work item: checks consent, marks the draft PR ready for review, adds labels, posts a summary comment, removes the worktree, clears Redis refs, and writes an audit record.
result = Legion::Extensions::Developer::Runners::Ship.finalize(
work_item: {
work_item_id: 'uuid-001',
source_ref: 'LegionIO/lex-exec#42',
config: {
escalation: { consent_domain: 'fleet.shipping' }
},
pipeline: {
stage: 'validated',
pr_number: 99,
branch_name: 'fleet/fix-lex-exec-42',
changes: ['lib/sandbox.rb', 'spec/sandbox_spec.rb'],
review_result: { verdict: 'approved', score: 0.94 }
}
}
)
result[:success] # => true
result[:work_item][:pipeline][:stage] # => 'shipped'If the consent domain requires human approval, finalize suspends itself and submits to the approval queue:
result[:awaiting_approval] # => trueWhen the approval is granted and the message is re-delivered with pipeline[:resumed]: true, the consent gate is skipped and finalization completes.
Parses LLM output into structured file changes. Recognizes fenced code blocks with a # file: path/to/file comment as the first line.
changes = Legion::Extensions::Developer::Helpers::ChangeParser.parse(content: llm_response)
# => [
# { path: 'lib/sandbox.rb', content: "# frozen_string_literal: true\n..." },
# { path: 'spec/sandbox_spec.rb', content: "# frozen_string_literal: true\n..." }
# ]
Legion::Extensions::Developer::Helpers::ChangeParser.file_paths_only(changes: changes)
# => ['lib/sandbox.rb', 'spec/sandbox_spec.rb']Builds structured LLM prompts for implementation and feedback revision rounds.
prompt = Legion::Extensions::Developer::Helpers::PromptBuilder.build_implementation_prompt(
work_item: work_item,
context: { docs: 'README contents', file_tree: ['lib/', 'lib/sandbox.rb'] }
)
feedback_prompt = Legion::Extensions::Developer::Helpers::PromptBuilder.build_feedback_prompt(
work_item: work_item_with_history
)
# Thinking budget scales with attempt number
Legion::Extensions::Developer::Helpers::PromptBuilder.thinking_budget(attempt: 0) # => 16_000
Legion::Extensions::Developer::Helpers::PromptBuilder.thinking_budget(attempt: 1) # => 32_000
Legion::Extensions::Developer::Helpers::PromptBuilder.thinking_budget(attempt: 2) # => 64_000 (cap)Generates deterministic branch names and stores them in Redis under fleet:worktree:<work_item_id>. In production, delegates repo clone/fetch to lex-exec's RepoMaterializer.
Legion::Extensions::Developer::Helpers::RepoMaterializer.branch_name(
repo_name: 'lex-exec',
source_ref: 'LegionIO/lex-exec#42'
)
# => 'fleet/fix-lex-exec-42'
Legion::Extensions::Developer::Helpers::RepoMaterializer.repo_cache_path(
owner: 'LegionIO',
name: 'lex-exec'
)
# => '/Users/you/.legionio/fleet/repos/LegionIO/lex-exec'AALP (Adaptive Accumulating Loss Prevention) pattern — collapses growing feedback history into a single deduplicated summary entry to prevent O(n²) context growth across rejection rounds.
history = [
{ verdict: 'rejected', issues: ['Missing nil check', 'No test'], round: 0 },
{ verdict: 'rejected', issues: ['No test', 'Timeout too short'], round: 1 },
{ verdict: 'rejected', issues: ['Timeout too short'], round: 2 }
]
Legion::Extensions::Developer::Helpers::FeedbackSummarizer.needs_summarization?(
feedback_history: history, threshold: 2
)
# => true
Legion::Extensions::Developer::Helpers::FeedbackSummarizer.summarize(
feedback_history: history
)
# => [{ verdict: 'rejected', issues: ['Missing nil check', 'No test', 'Timeout too short'],
# round: 2, summarized: true, source_rounds: [0, 1, 2] }]| Queue | Routing Key | Purpose |
|---|---|---|
lex.developer.runners.developer |
lex.developer.runners.developer.implement |
Incoming implement jobs |
lex.developer.runners.feedback |
lex.developer.runners.developer.incorporate_feedback |
Feedback revision jobs |
lex.developer.runners.ship |
lex.developer.runners.ship.# |
Finalization jobs |
Exchange: lex.developer (topic, durable)
All settings read from Legion::Settings.dig(:fleet, ...):
| Key | Default | Description |
|---|---|---|
:fleet, :github, :token |
— | GitHub token for PR creation |
:fleet, :implementation, :max_iterations |
5 |
Max LLM attempts before escalation |
:fleet, :feedback, :summarize_after |
2 |
Rounds before AALP summarization kicks in |
:fleet, :llm, :thinking_budget_base_tokens |
16_000 |
Base thinking budget |
:fleet, :llm, :thinking_budget_max_tokens |
64_000 |
Cap on thinking budget |
:fleet, :workspace, :worktree_base |
~/.legionio/fleet/worktrees |
Worktree directory |
bundle install
bundle exec rspec # 57 examples, 0 failures
bundle exec rubocop # 0 offensesMIT. See LICENSE.