space-architect 7.0.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +88 -0
- data/README.md +5 -3
- data/lib/space_architect/architect_project.rb +128 -200
- data/lib/space_architect/cli/architect.rb +114 -105
- data/lib/space_architect/cli/research.rb +1 -1
- data/lib/space_architect/harness.rb +97 -344
- data/lib/space_architect/pi/builder-guard.ts +103 -0
- data/lib/space_architect/research/mux.rb +47 -32
- data/lib/space_architect/research/pi_events.rb +70 -0
- data/lib/space_architect/research/renderer.rb +39 -39
- data/lib/space_architect/research/supervisor.rb +35 -14
- data/lib/space_architect/research.rb +1 -6
- data/lib/space_architect.rb +0 -1
- data/lib/space_core/version.rb +1 -1
- data/skill/architect/SKILL.md +34 -26
- data/skill/architect/dispatch.md +137 -115
- data/skill/architect/research.md +14 -8
- data/skill/architect-research/SKILL.md +18 -11
- data/skill/architect-vocabulary/SKILL.md +1 -1
- metadata +3 -2
- data/lib/space_architect/dispatcher.rb +0 -25
|
@@ -178,18 +178,10 @@ module Space::Architect
|
|
|
178
178
|
nn = s["ordinal"] ? format("%02d", s["ordinal"]) : "-"
|
|
179
179
|
lane_list = s["lanes"] || []
|
|
180
180
|
lanes_str = lane_list.map do |l|
|
|
181
|
-
h = l["harness"] || "
|
|
182
|
-
m = l["model"] || Harness
|
|
181
|
+
h = l["harness"] || "pi"
|
|
182
|
+
m = l["model"] || Harness::DEFAULT_MODEL
|
|
183
183
|
eff = l["effort"] ? "·#{l['effort']}" : ""
|
|
184
|
-
#
|
|
185
|
-
# values — only when it diverges from the harness default, to keep the
|
|
186
|
-
# common case (no lane touches it) uncluttered. Meaningless outside
|
|
187
|
-
# claude-code (no equivalent grant mechanism), so shown only there.
|
|
188
|
-
tools = if h == "claude-code"
|
|
189
|
-
resolved = Harness::ClaudeCodeHarness.resolve_tools(replace: l["allowed_tools"], append: l["append_allowed_tools"])
|
|
190
|
-
resolved == Harness::ClaudeCodeHarness::ALLOWED_TOOLS ? "" : "·tools:#{resolved}"
|
|
191
|
-
end
|
|
192
|
-
"#{l['name']}(#{l['repo']}·#{h}·#{m}#{eff}#{tools})"
|
|
184
|
+
"#{l['name']}(#{l['repo']}·#{h}·#{m}#{eff})"
|
|
193
185
|
end.join(", ")
|
|
194
186
|
lanes = lane_list.any? { |l| l["variant"] } ? "variant: #{lanes_str}" : lanes_str
|
|
195
187
|
lanes = "#{lanes} → winner: #{s['winner']}" if s["winner"]
|
|
@@ -262,17 +254,29 @@ module Space::Architect
|
|
|
262
254
|
|
|
263
255
|
private
|
|
264
256
|
|
|
257
|
+
# I01: inline output is bounded — one identity line per gate, ≤ 20
|
|
258
|
+
# lines of tail output — because the full report always lands in the
|
|
259
|
+
# transcript #render_gate points at. The summary block is emitted last
|
|
260
|
+
# (after the disclaimer) so a `tail` of stdout captures it whole.
|
|
265
261
|
def render_rehearsal(result)
|
|
266
262
|
if result[:empty]
|
|
267
263
|
reason = result[:placeholder] ? "the scaffold placeholder '#{ArchitectProject::AC1_PLACEHOLDER}' with no active gate" : "no gates drafted yet"
|
|
268
264
|
terminal.say "EMPTY — #{reason}. Nothing to rehearse; the pre-freeze look is still stamped."
|
|
269
|
-
|
|
270
|
-
terminal.say
|
|
271
|
-
|
|
272
|
-
render_scope_asymmetry(result[:scope_asymmetry])
|
|
265
|
+
terminal.say ""
|
|
266
|
+
terminal.say discrimination_note
|
|
267
|
+
return
|
|
273
268
|
end
|
|
269
|
+
|
|
270
|
+
terminal.say rehearsal_header(result)
|
|
271
|
+
result[:gates].each { |g| render_gate(g, result[:transcript]) }
|
|
272
|
+
render_scope_asymmetry(result[:scope_asymmetry])
|
|
274
273
|
terminal.say ""
|
|
275
|
-
terminal.say
|
|
274
|
+
terminal.say discrimination_note
|
|
275
|
+
render_summary(result)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def discrimination_note
|
|
279
|
+
"Discrimination report only — this runs and reports; it never judges whether these gates are good, bad, or ready."
|
|
276
280
|
end
|
|
277
281
|
|
|
278
282
|
# #90/AC7: with a single defaultable repo, name it as before; a cross-repo
|
|
@@ -286,17 +290,45 @@ module Space::Architect
|
|
|
286
290
|
end
|
|
287
291
|
end
|
|
288
292
|
|
|
289
|
-
|
|
293
|
+
# I01/AC "bounded terminal report": identity (AC label, gate id, verdict,
|
|
294
|
+
# exit code) always lands on one stdout line, however many lines `cmd`
|
|
295
|
+
# spans — the command itself is shown as at most its first line,
|
|
296
|
+
# truncated; the full command lives in the transcript.
|
|
297
|
+
CMD_LINE_MAX = 100
|
|
298
|
+
OUTPUT_LINE_CAP = 20
|
|
299
|
+
|
|
300
|
+
def render_gate(g, transcript_path)
|
|
290
301
|
terminal.say ""
|
|
291
|
-
terminal.say "── #{g[:ac].empty? ? "(gate)" : g[:ac]}: #{g[:cmd]} (exit #{g[:exit_code].inspect}) [#{g[:rehearsal].to_s.upcase}]"
|
|
302
|
+
terminal.say "── #{g[:ac].empty? ? "(gate)" : g[:ac]} #{g[:id]}: #{truncated_cmd(g[:cmd])} (exit #{g[:exit_code].inspect}) [#{g[:rehearsal].to_s.upcase}]"
|
|
292
303
|
terminal.say " dir: #{terminal.path(g[:dir])}"
|
|
293
304
|
terminal.say " reason: #{g[:reason]}" unless g[:reason].to_s.empty?
|
|
305
|
+
if g[:shared_with]&.any?
|
|
306
|
+
terminal.say " shared execution with: #{g[:shared_with].join(', ')} (identical cmd+dir, captured once)"
|
|
307
|
+
end
|
|
294
308
|
if g[:rehearsal] == :broken
|
|
295
309
|
terminal.say " BROKEN is advisory, not certain — a correct RED can look broken (e.g. a file the lane " \
|
|
296
310
|
"hasn't written yet). Confirm before treating it as a defect."
|
|
297
311
|
end
|
|
298
|
-
|
|
299
|
-
|
|
312
|
+
render_gate_output(g, transcript_path)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def truncated_cmd(cmd)
|
|
316
|
+
first, *rest = cmd.to_s.each_line.map(&:chomp)
|
|
317
|
+
clipped = first.length > CMD_LINE_MAX ? "#{first[0, CMD_LINE_MAX]}…" : first
|
|
318
|
+
rest.any? || clipped != first ? "#{clipped} …" : clipped
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def render_gate_output(g, transcript_path)
|
|
322
|
+
combined = [g[:stdout], g[:stderr]].map { |s| s.to_s.rstrip }.reject(&:empty?).join("\n")
|
|
323
|
+
return if combined.empty?
|
|
324
|
+
|
|
325
|
+
lines = combined.lines(chomp: true)
|
|
326
|
+
if lines.size > OUTPUT_LINE_CAP
|
|
327
|
+
terminal.say lines.last(OUTPUT_LINE_CAP).join("\n")
|
|
328
|
+
terminal.say " … #{lines.size - OUTPUT_LINE_CAP} more line(s) elided — full output in #{terminal.path(transcript_path)}"
|
|
329
|
+
else
|
|
330
|
+
terminal.say lines.join("\n")
|
|
331
|
+
end
|
|
300
332
|
end
|
|
301
333
|
|
|
302
334
|
# I12/AC3-AC4: reports scope asymmetry only — never affects RED/GREEN/
|
|
@@ -325,6 +357,22 @@ module Space::Architect
|
|
|
325
357
|
report[:not_analyzable].each { |na| terminal.say " #{na[:id]}: #{na[:reason]}" }
|
|
326
358
|
end
|
|
327
359
|
|
|
360
|
+
# I01: always-on, positioned last so a `tail` of stdout captures it
|
|
361
|
+
# whole — one line per gate (AC label, gate id, verdict; reason
|
|
362
|
+
# appended for RED/BROKEN), a tally by verdict, and the transcript path.
|
|
363
|
+
def render_summary(result)
|
|
364
|
+
terminal.say ""
|
|
365
|
+
terminal.say "Summary:"
|
|
366
|
+
result[:gates].each do |g|
|
|
367
|
+
line = " #{g[:ac].empty? ? "(gate)" : g[:ac]} #{g[:id]} [#{g[:rehearsal].to_s.upcase}]"
|
|
368
|
+
line += " — #{g[:reason]}" if %i[red broken].include?(g[:rehearsal]) && !g[:reason].to_s.empty?
|
|
369
|
+
terminal.say line
|
|
370
|
+
end
|
|
371
|
+
tally = result[:gates].group_by { |g| g[:rehearsal] }.transform_values(&:size)
|
|
372
|
+
terminal.say " #{%i[green red broken].filter_map { |v| "#{v.to_s.upcase}: #{tally[v]}" if tally[v] }.join(', ')}"
|
|
373
|
+
terminal.say " transcript: #{terminal.path(result[:transcript])}"
|
|
374
|
+
end
|
|
375
|
+
|
|
328
376
|
def render_record(result)
|
|
329
377
|
return "> Rehearsed #{result[:iteration]} — no gates drafted; nothing to record." if result[:empty]
|
|
330
378
|
|
|
@@ -437,107 +485,68 @@ module Space::Architect
|
|
|
437
485
|
argument :lane, required: true, desc: "Lane name"
|
|
438
486
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
439
487
|
option :prompt, default: nil, desc: "Read the lane prompt from this file (copied byte-for-byte to build/<id>-<lane>/prompt.md)"
|
|
440
|
-
option :model, default: nil, desc: "Builder model to pin (default: the lane's stored model, else space.yaml project.model, else the
|
|
488
|
+
option :model, default: nil, desc: "Builder model to pin (default: the lane's stored model, else space.yaml project.model, else the pi default #{Harness::DEFAULT_MODEL}). Any provider/tier; pin a full id, not a floating alias"
|
|
441
489
|
option :max_turns, default: "200", desc: "Max turns for the builder"
|
|
442
|
-
option :harness, default: nil, desc: "Harness
|
|
443
|
-
option :
|
|
444
|
-
option :
|
|
445
|
-
option :
|
|
446
|
-
option :
|
|
447
|
-
option :
|
|
448
|
-
option :
|
|
449
|
-
option :force_thinking, default: nil, desc: "Force the literal level onto the harness flag, skipping architect's clamp — alias for --force-effort/--force-reasoning (dispatch only; the binary's rejection is final)"
|
|
450
|
-
option :force_reasoning, default: nil, desc: "Force the literal level onto the harness flag, skipping architect's clamp — alias for --force-effort/--force-thinking (dispatch only; the binary's rejection is final)"
|
|
490
|
+
option :harness, default: nil, desc: "Harness (pi)"
|
|
491
|
+
option :effort, default: nil, desc: "Thinking/reasoning effort level — alias for --thinking/--reasoning (off, minimal, low, medium, high, xhigh, max)"
|
|
492
|
+
option :thinking, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--reasoning (off, minimal, low, medium, high, xhigh, max)"
|
|
493
|
+
option :reasoning, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--thinking (off, minimal, low, medium, high, xhigh, max)"
|
|
494
|
+
option :force_effort, default: nil, desc: "Force the literal level onto the --thinking flag, skipping architect's validation — alias for --force-thinking/--force-reasoning (dispatch only; the binary's rejection is final)"
|
|
495
|
+
option :force_thinking, default: nil, desc: "Force the literal level onto the --thinking flag, skipping architect's validation — alias for --force-effort/--force-reasoning (dispatch only; the binary's rejection is final)"
|
|
496
|
+
option :force_reasoning, default: nil, desc: "Force the literal level onto the --thinking flag, skipping architect's validation — alias for --force-effort/--force-thinking (dispatch only; the binary's rejection is final)"
|
|
451
497
|
option :quiet, type: :boolean, default: false, desc: "Suppress thinking-translation and harness run-time warn lines (liveness/push) on $stderr for this dispatch"
|
|
452
498
|
option :detach, type: :boolean, default: false, desc: "Detach the builder process (returns immediately with PID; poll report for completion)"
|
|
453
499
|
option :timeout, default: "14400", desc: "Wall-clock timeout in seconds (0 disables; default 4h); foreground only"
|
|
454
500
|
option :push_url, default: nil, desc: "HTTP endpoint for streaming push (POST body to this URL)"
|
|
455
501
|
option :push_token, default: nil, desc: "Bearer token for push endpoint authorization"
|
|
456
502
|
option :push_host, default: nil, desc: "Base URL of the ingest server; the CLI creates a run via POST <host>/runs and streams to /runs/<id>/ingest (requires --push-token)"
|
|
457
|
-
option :as_job, type: :boolean, default: false, desc: "Submit the run as a job to the space-server's queue instead of running locally (sandboxed executor; requires --host/--token/--backend-url)"
|
|
458
|
-
option :host, default: nil, desc: "Base URL of the space-server (required with --as-job)"
|
|
459
|
-
option :token, default: nil, desc: "Bearer token for authorization (required with --as-job)"
|
|
460
|
-
option :backend_url, default: nil, desc: "Base URL of the harness backend the sandboxed job talks to (required with --as-job)"
|
|
461
|
-
option :job_model, default: nil, desc: "Model pinned for the sandboxed job's harness — distinct from --model, which is meaningless against a non-Anthropic backend"
|
|
462
|
-
option :api_key_ref, default: nil, desc: "op:// reference resolved into ANTHROPIC_API_KEY server-side (--as-job only; omit for keyless backends)"
|
|
463
503
|
|
|
464
504
|
def call(iteration:, lane:, space: nil, prompt: nil, model: nil,
|
|
465
505
|
max_turns: "200", harness: nil, effort: nil, thinking: nil, reasoning: nil,
|
|
466
|
-
allowed_tools: nil, append_allowed_tools: nil,
|
|
467
506
|
force_effort: nil, force_thinking: nil, force_reasoning: nil, quiet: false, detach: false,
|
|
468
|
-
timeout: "14400", push_url: nil, push_token: nil, push_host: nil,
|
|
469
|
-
as_job: false, host: nil, token: nil, backend_url: nil, job_model: nil, api_key_ref: nil, **opts)
|
|
507
|
+
timeout: "14400", push_url: nil, push_token: nil, push_host: nil, **opts)
|
|
470
508
|
setup_terminal(**opts.slice(:color, :colors))
|
|
471
509
|
handle_errors do
|
|
472
510
|
level = resolve_thinking_alias(effort: effort, thinking: thinking, reasoning: reasoning)
|
|
473
511
|
forced_level = resolve_force_thinking_alias(force_effort: force_effort,
|
|
474
512
|
force_thinking: force_thinking, force_reasoning: force_reasoning)
|
|
475
513
|
|
|
476
|
-
if as_job
|
|
477
|
-
Jobs.require_credentials!(host, token)
|
|
478
|
-
raise Space::Core::Error, "--backend-url is required with --as-job" unless backend_url
|
|
479
|
-
raise Space::Core::Error, "--job-model is required with --as-job" unless job_model
|
|
480
|
-
raise Space::Core::Error, "--as-job cannot be combined with --push-url/--push-token/--push-host/--detach" \
|
|
481
|
-
if push_url || push_token || push_host || detach
|
|
482
|
-
end
|
|
483
|
-
|
|
484
514
|
render(store.find(space)) do |sp|
|
|
485
515
|
project = ArchitectProject.new(space: sp)
|
|
486
516
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
terminal.say "
|
|
502
|
-
terminal.say "
|
|
517
|
+
kwargs = { max_turns: max_turns.to_i, detach: detach }
|
|
518
|
+
kwargs[:prompt] = prompt if prompt
|
|
519
|
+
kwargs[:model] = model if model
|
|
520
|
+
kwargs[:harness] = harness if harness
|
|
521
|
+
kwargs[:effort] = forced_level || level if forced_level || level
|
|
522
|
+
kwargs[:force] = true if forced_level
|
|
523
|
+
kwargs[:quiet] = true if quiet
|
|
524
|
+
kwargs[:timeout] = timeout.to_i unless detach
|
|
525
|
+
kwargs[:push_url] = push_url if push_url
|
|
526
|
+
kwargs[:push_token] = push_token if push_token
|
|
527
|
+
kwargs[:push_host] = push_host if push_host
|
|
528
|
+
res = project.dispatch(iteration, lane, **kwargs)
|
|
529
|
+
terminal.say "Prompt: #{prompt} → #{terminal.path(res[:prompt_copied])}" if res[:prompt_copied]
|
|
530
|
+
if detach
|
|
531
|
+
terminal.say "PID: #{res[:pid]}"
|
|
532
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
533
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
534
|
+
terminal.say "Dispatched detached — poll #{terminal.path(res[:report])} for completion"
|
|
503
535
|
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
536
|
+
elsif res[:timed_out]
|
|
537
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
538
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
539
|
+
terminal.say "Builder TIMED OUT after #{timeout}s — process group killed. Re-dispatch (lanes are cheap)."
|
|
540
|
+
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
504
541
|
else
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
kwargs[:append_allowed_tools] = append_allowed_tools if append_allowed_tools
|
|
512
|
-
kwargs[:force] = true if forced_level
|
|
513
|
-
kwargs[:quiet] = true if quiet
|
|
514
|
-
kwargs[:timeout] = timeout.to_i unless detach
|
|
515
|
-
kwargs[:push_url] = push_url if push_url
|
|
516
|
-
kwargs[:push_token] = push_token if push_token
|
|
517
|
-
kwargs[:push_host] = push_host if push_host
|
|
518
|
-
res = project.dispatch(iteration, lane, **kwargs)
|
|
519
|
-
terminal.say "Prompt: #{prompt} → #{terminal.path(res[:prompt_copied])}" if res[:prompt_copied]
|
|
520
|
-
if detach
|
|
521
|
-
terminal.say "PID: #{res[:pid]}"
|
|
522
|
-
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
523
|
-
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
524
|
-
terminal.say "Dispatched detached — poll #{terminal.path(res[:report])} for completion"
|
|
525
|
-
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
526
|
-
elsif res[:timed_out]
|
|
527
|
-
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
528
|
-
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
529
|
-
terminal.say "Builder TIMED OUT after #{timeout}s — process group killed. Re-dispatch (lanes are cheap)."
|
|
530
|
-
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
531
|
-
else
|
|
532
|
-
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
533
|
-
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
534
|
-
terminal.say "Ingest URL: #{res[:push_url]}" if res[:push_url]
|
|
535
|
-
terminal.say "Builder exited with status #{res[:exit_code]}"
|
|
536
|
-
unless res[:report].exist? && !res[:report].read.strip.empty?
|
|
537
|
-
terminal.say "WARNING: no report at #{terminal.path(res[:report])} — the lane produced no deliverable."
|
|
538
|
-
end
|
|
539
|
-
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
542
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
543
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
544
|
+
terminal.say "Ingest URL: #{res[:push_url]}" if res[:push_url]
|
|
545
|
+
terminal.say "Builder exited with status #{res[:exit_code]}"
|
|
546
|
+
unless res[:report].exist? && !res[:report].read.strip.empty?
|
|
547
|
+
terminal.say "WARNING: no report at #{terminal.path(res[:report])} — the lane produced no deliverable."
|
|
540
548
|
end
|
|
549
|
+
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
541
550
|
end
|
|
542
551
|
end
|
|
543
552
|
end
|
|
@@ -802,7 +811,7 @@ module Space::Architect
|
|
|
802
811
|
class InstallSkills < BaseCommand
|
|
803
812
|
desc "Install bundled skills (architect, architect-research, architect-vocabulary) for a harness"
|
|
804
813
|
phase 53, "Project"
|
|
805
|
-
option :provider, default: "claude", desc: "
|
|
814
|
+
option :provider, default: "claude", desc: "Skill install target (default: claude; validated by the installer)"
|
|
806
815
|
option :project, type: :boolean, default: false, desc: "Install to CWD instead of global"
|
|
807
816
|
option :force, type: :boolean, default: false, desc: "Overwrite existing skills that differ"
|
|
808
817
|
option :dry_run, type: :boolean, default: false, desc: "Print what would happen without writing files"
|
|
@@ -830,11 +839,11 @@ module Space::Architect
|
|
|
830
839
|
argument :lane, required: true, desc: "Lane name"
|
|
831
840
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
832
841
|
option :base, default: nil, desc: "Base ref (default: HEAD of repo)"
|
|
833
|
-
option :harness, default: nil, desc: "Harness (
|
|
834
|
-
option :model, default: nil, desc: "Model; a trailing :<level> suffix (e.g. foo:high) is parsed into --effort (default: space.yaml project.model, else the
|
|
835
|
-
option :effort, default: nil, desc: "Thinking/reasoning effort level — alias for --thinking/--reasoning (off, minimal, low, medium, high, xhigh, max)
|
|
836
|
-
option :thinking, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--reasoning (off, minimal, low, medium, high, xhigh, max)
|
|
837
|
-
option :reasoning, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--thinking (off, minimal, low, medium, high, xhigh, max)
|
|
842
|
+
option :harness, default: nil, desc: "Harness (pi; default: space.yaml project.harness, else pi)"
|
|
843
|
+
option :model, default: nil, desc: "Model; a trailing :<level> suffix (e.g. foo:high) is parsed into --effort (default: space.yaml project.model, else the pi default #{Harness::DEFAULT_MODEL})"
|
|
844
|
+
option :effort, default: nil, desc: "Thinking/reasoning effort level — alias for --thinking/--reasoning (off, minimal, low, medium, high, xhigh, max)"
|
|
845
|
+
option :thinking, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--reasoning (off, minimal, low, medium, high, xhigh, max)"
|
|
846
|
+
option :reasoning, default: nil, desc: "Thinking/reasoning effort level — alias for --effort/--thinking (off, minimal, low, medium, high, xhigh, max)"
|
|
838
847
|
option :quiet, type: :boolean, default: false, desc: "Suppress the thinking-translation inform line on $stderr"
|
|
839
848
|
option :touch, default: nil, desc: "Comma-separated file globs the lane may touch (records its touch_set for in-bounds + merge checks)"
|
|
840
849
|
option :force, type: :boolean, default: false, desc: "Clear and re-create a stale (unregistered) worktree directory"
|
|
@@ -914,7 +923,7 @@ module Space::Architect
|
|
|
914
923
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
915
924
|
argument :iteration, required: true, desc: "Iteration name"
|
|
916
925
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
917
|
-
option :pairs, required: true, desc: "Comma-separated harness[:model] pairs (e.g.
|
|
926
|
+
option :pairs, required: true, desc: "Comma-separated harness[:model] pairs (e.g. pi,pi:#{Harness::DEFAULT_MODEL})"
|
|
918
927
|
option :base, default: nil, desc: "Base ref (default: HEAD of repo)"
|
|
919
928
|
option :prompt, default: nil, desc: "Prompt file to fan-out byte-identical to each variant"
|
|
920
929
|
|
|
@@ -8,7 +8,7 @@ module Space::Architect
|
|
|
8
8
|
desc "Dispatch detached read-only research lanes (one per prompt file)"
|
|
9
9
|
argument :prompts, type: :array, required: true,
|
|
10
10
|
desc: "Prompt file(s) to dispatch (space-separated paths)"
|
|
11
|
-
option :model, default: nil, desc: "Researcher model override (default: the
|
|
11
|
+
option :model, default: nil, desc: "Researcher model override (default: the pi default #{Space::Architect::Harness::DEFAULT_MODEL})"
|
|
12
12
|
option :max_turns, default: "40", desc: "Max turns per researcher"
|
|
13
13
|
|
|
14
14
|
def call(prompts:, model: nil, max_turns: "40", **opts)
|