From 22a1bba192d40f977c822cac3f9de5b0ff23ac69 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 7 Mar 2026 21:11:34 -0500 Subject: [PATCH] Add --goal CLI arg to `arc run start` Allows overriding the workflow goal from the command line, which is exposed as $goal in node prompts via VariableExpansionTransform. Co-Authored-By: Claude Opus 4.6 --- crates/arc-workflows/src/cli/mod.rs | 4 +++ crates/arc-workflows/src/cli/run.rs | 40 +++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/crates/arc-workflows/src/cli/mod.rs b/crates/arc-workflows/src/cli/mod.rs index 44e58fd9e..be4d6eb10 100644 --- a/crates/arc-workflows/src/cli/mod.rs +++ b/crates/arc-workflows/src/cli/mod.rs @@ -106,6 +106,10 @@ pub struct RunArgs { #[arg(long, conflicts_with = "resume")] pub run_branch: Option, + /// Override the workflow goal (exposed as $goal in prompts) + #[arg(long)] + pub goal: Option, + /// Override default LLM model #[arg(long)] pub model: Option, diff --git a/crates/arc-workflows/src/cli/run.rs b/crates/arc-workflows/src/cli/run.rs index c50cc1f2a..f59d834ee 100644 --- a/crates/arc-workflows/src/cli/run.rs +++ b/crates/arc-workflows/src/cli/run.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex}; use std::time::Instant; use anyhow::bail; +use tracing::debug; use arc_agent::{DockerSandbox, DockerSandboxConfig, LocalSandbox, Sandbox}; use arc_util::terminal::Styles; use chrono::{Local, Utc}; @@ -35,6 +36,17 @@ use super::{ RunArgs, SandboxProvider, }; +/// Apply a CLI `--goal` override to the graph, if provided. +fn apply_goal_override(graph: &mut crate::graph::types::Graph, cli_goal: Option<&str>) { + if let Some(goal) = cli_goal { + debug!(goal = %goal, "CLI --goal overriding graph goal"); + graph.attrs.insert( + "goal".to_string(), + crate::graph::types::AttrValue::String(goal.to_string()), + ); + } +} + /// Resolve model and provider through the full precedence chain: /// CLI flag > TOML config > run defaults > DOT graph attrs > provider-specific defaults. /// Then resolve through the catalog for alias expansion. @@ -230,7 +242,8 @@ pub async fn run_command( Some(vars) => run_config::expand_vars(&source, vars)?, None => source, }; - let (graph, diagnostics) = WorkflowBuilder::new().prepare(&source)?; + let (mut graph, diagnostics) = WorkflowBuilder::new().prepare(&source)?; + apply_goal_override(&mut graph, args.goal.as_deref()); eprintln!( "{} {} {}", @@ -959,7 +972,8 @@ async fn run_from_branch( source }; - let (graph, diagnostics) = crate::workflow::WorkflowBuilder::new().prepare(&source)?; + let (mut graph, diagnostics) = crate::workflow::WorkflowBuilder::new().prepare(&source)?; + apply_goal_override(&mut graph, args.goal.as_deref()); eprintln!( "{} {} from branch {}", @@ -1522,6 +1536,28 @@ async fn generate_retro( mod tests { use super::*; + #[test] + fn apply_goal_override_replaces_graph_goal() { + use crate::graph::types::{AttrValue, Graph}; + let mut graph = Graph::new("test"); + graph + .attrs + .insert("goal".to_string(), AttrValue::String("original".to_string())); + apply_goal_override(&mut graph, Some("CLI goal")); + assert_eq!(graph.goal(), "CLI goal"); + } + + #[test] + fn apply_goal_override_noop_when_none() { + use crate::graph::types::{AttrValue, Graph}; + let mut graph = Graph::new("test"); + graph + .attrs + .insert("goal".to_string(), AttrValue::String("original".to_string())); + apply_goal_override(&mut graph, None); + assert_eq!(graph.goal(), "original"); + } + #[test] fn resolve_model_provider_defaults() { let graph = crate::graph::types::Graph::new("test");