The Omakase Scaffold
The Omakase Scaffold: `rails new` for plans. You bring six lines of intent - a name and some steps. The generator brings the menu: journaling on, retries configured, concurrency chosen, a runnable file with your name on it. Convention over configuration isn't about taking choices away; it's about not making you answer forty questions before hello-world. And the output is JUST RUBY - a file you own, edit, and outgrow. The scaffold is a starting line, not a cage.
Scheduling & Concurrency
Round 17
DHH
exit 0
bundle exec ruby examples/omakase_scaffold.rb
a real captured run
THE OMAKASE SCAFFOLD (six lines of intent, a running plan back)
recipe "newsletter_digest" (4 steps declared)
generated: newsletter_digest.rb (46 lines you didn't write)
ran it: "newsletter_digest: completed, 4/4 steps, journal at /tmp/newsletter_digest.jsonl"
recipe "release_notes" (3 steps declared)
generated: release_notes.rb (40 lines you didn't write)
ran it: "release_notes: completed, 3/3 steps, journal at /tmp/release_notes.jsonl"
the recipe says WHAT (steps and order); the scaffold supplies the
HOW everyone forgets until 2am - journaling, retries with jittered
backoff, a sane concurrency ceiling. that's omakase: the chef
chooses, you eat well, and if you hate the fish you own the
kitchen - the generated file is plain Ruby with your name on it,
TODOs where your work goes, no framework umbilical. generators
are how conventions travel; a convention nobody scaffolds is a
convention nobody follows.
source
# frozen_string_literal: true # The Omakase Scaffold: `rails new` for plans. You bring six lines # of intent - a name and some steps. The generator brings the menu: # journaling on, retries configured, concurrency chosen, a runnable # file with your name on it. Convention over configuration isn't # about taking choices away; it's about not making you answer forty # questions before hello-world. And the output is JUST RUBY - a file # you own, edit, and outgrow. The scaffold is a starting line, not # a cage. # # bundle exec ruby examples/omakase_scaffold.rb # # Runs offline; two recipes are scaffolded, and the generated # programs are actually RUN - the proof of a generator is its output # booting, not its template compiling. require class="s">"bundler/setup" require class="s">"agentic" require class="s">"open3" require class="s">"rbconfig" require class="s">"tmpdir" ROOT = File.expand_path(class="s">"..", __dir__) # --- the whole interface: what a recipe author writes ------------------------------ RECIPES = [ {name: class="s">"newsletter_digest", steps: [ {step: class="s">"collect articles"}, {step: class="s">"rank by relevance", after: class="s">"collect articles"}, {step: class="s">"draft summary", after: class="s">"rank by relevance"}, {step: class="s">"format email", after: class="s">"draft summary"} ]}, {name: class="s">"release_notes", steps: [ {step: class="s">"gather merged prs"}, {step: class="s">"gather closed issues"}, {step: class="s">"write highlights", after: [class="s">"gather merged prs", class="s">"gather closed issues"]} ]} ].freeze # --- the generator: conventions poured around the recipe --------------------------- def scaffold(recipe, dir) vars = recipe[class="y">:steps].each_with_index.to_h { |s, i| [s[class="y">:step], class="s">"task_#{i}"] } task_lines = recipe[class="y">:steps].map do |s| deps = Array(s[class="y">:after]).map { |d| vars.fetch(d) } <<~RUBY.chomp #{vars[s[:step]]} = Agentic::Task.new(description: #{s[:step].inspect}, agent_spec: {"name" => #{s[:step].inspect}, "instructions" => "do it"}) orchestrator.add_task(#{vars[s[class="y">:step]]}, [#{deps.join(class="s">", ")}], agent: ->(t) { # TODO: replace this stub with your real work for #{s[:step].inspect} class="s">"#{s[class="y">:step]}: done#{" (given: \#{t.previous_output})class="s">" if deps.any?}" }) RUBY end source = <<~RUBY # frozen_string_literal: true # Generated by omakase_scaffold - and immediately YOURS. Edit freely. require class="s">"agentic" require class="s">"tmpdir" Agentic.logger.level = class="y">:fatal # Omakase defaults: a journal (so every run is replayable), a retry # policy (transient errors get three chances), a concurrency ceiling # (parallel where the graph allows, never a stampede). Disagree with # any of it? It's your file now - change it. journal = Agentic:class="y">:ExecutionJournal.new(path: File.join(Dir.tmpdir, class="s">"#{recipe[class="y">:name]}.jsonl")) orchestrator = Agentic:class="y">:PlanOrchestrator.new( concurrency_limit: 4, lifecycle_hooks: journal.lifecycle_hooks, retry_policy: {max_retries: 3, backoff_base: 0.05, backoff_jitter: class="y">:full} ) #{task_lines.join("\n\n").gsub("\n", "\n ").strip} result = orchestrator.execute_plan done = result.results.values.count(&class="y">:successful?) puts class="s">"#{recipe[class="y">:name]}: \#{result.status}, \#{done}/#{recipe[class="y">:steps].size} steps, journal at \#{journal.path}" exit(result.status == class="y">:completed ? 0 : 1) RUBY path = File.join(dir, class="s">"#{recipe[class="y">:name]}.rb") File.write(path, source) path end puts class="s">"THE OMAKASE SCAFFOLD (six lines of intent, a running plan back)" puts failures = 0 Dir.mktmpdir(class="s">"omakase") do |dir| RECIPES.each do |recipe| path = scaffold(recipe, dir) lines = File.read(path).lines.size # The generated program finds agentic through this repo's bundle out, err, status = Open3.capture3({class="s">"BUNDLE_GEMFILE" => File.join(ROOT, class="s">"Gemfile")}, RbConfig.ruby, class="s">"-rbundler/setup", path) ok = status.success? && out.include?(class="s">"#{recipe[class="y">:name]}: completed") failures += 1 unless ok puts class="s">" recipe #{recipe[class="y">:name].inspect} (#{recipe[class="y">:steps].size} steps declared)" puts class="s">" generated: #{File.basename(path)} (#{lines} lines you didn't write)" puts class="s">" ran it: #{ok ? out.strip.inspect : "FAILED: #{err.lines.last&.strip}class="s">"}" puts end end puts class="s">" the recipe says WHAT (steps and order); the scaffold supplies the" puts class="s">" HOW everyone forgets until 2am - journaling, retries with jittered" puts class="s">" backoff, a sane concurrency ceiling. that's omakase: the chef" puts class="s">" chooses, you eat well, and if you hate the fish you own the" puts class="s">" kitchen - the generated file is plain Ruby with your name on it," puts class="s">" TODOs where your work goes, no framework umbilical. generators" puts class="s">" are how conventions travel; a convention nobody scaffolds is a" puts class="s">" convention nobody follows." exit(failures.zero? ? 0 : 1)