diff --git a/apps/arc-web/app/routes/run-configuration.tsx b/apps/arc-web/app/routes/run-configuration.tsx
index f765e668b..1813b1603 100644
--- a/apps/arc-web/app/routes/run-configuration.tsx
+++ b/apps/arc-web/app/routes/run-configuration.tsx
@@ -97,7 +97,7 @@ export default function RunConfiguration({ loaderData }: Route.ComponentProps) {
{configText ? (
) : (
No configuration found.
diff --git a/apps/arc-web/app/routes/workflow-definition.tsx b/apps/arc-web/app/routes/workflow-definition.tsx
index d5f885ec4..927b3a299 100644
--- a/apps/arc-web/app/routes/workflow-definition.tsx
+++ b/apps/arc-web/app/routes/workflow-definition.tsx
@@ -27,7 +27,7 @@ export default function WorkflowDefinition() {
return (
{dotReady && (
diff --git a/crates/arc-api/src/demo/mod.rs b/crates/arc-api/src/demo/mod.rs
index 29fba1156..469fc6c71 100644
--- a/crates/arc-api/src/demo/mod.rs
+++ b/crates/arc-api/src/demo/mod.rs
@@ -867,7 +867,7 @@ mod workflows {
title: "Fix Build".into(), slug: "fix_build".into(), filename: "fix_build.dot".into(),
description: "Automatically diagnoses and fixes CI build failures by analyzing error logs, identifying root causes, and applying targeted code changes.".into(),
config: r#"version = 1
-task = "Diagnose and fix CI build failures"
+goal = "Diagnose and fix CI build failures"
graph = "fix_build.dot"
[llm]
@@ -917,7 +917,7 @@ disk = 10
title: "Implement Feature".into(), slug: "implement".into(), filename: "implement.dot".into(),
description: "Generates production-ready code from a technical blueprint, including tests, documentation, and a pull request ready for review.".into(),
config: r#"version = 1
-task = "Implement feature from technical blueprint"
+goal = "Implement feature from technical blueprint"
graph = "implement.dot"
[llm]
@@ -986,7 +986,7 @@ disk = 20
title: "Sync Drift".into(), slug: "sync_drift".into(), filename: "sync_drift.dot".into(),
description: "Detects configuration and code drift between environments, then generates reconciliation patches to bring everything back in sync.".into(),
config: r#"version = 1
-task = "Detect and reconcile configuration drift across environments"
+goal = "Detect and reconcile configuration drift across environments"
graph = "sync_drift.dot"
[llm]
@@ -1042,7 +1042,7 @@ disk = 10
title: "Expand Product".into(), slug: "expand".into(), filename: "expand.dot".into(),
description: "Evolves the product by analyzing usage patterns and specifications to propose and implement incremental improvements.".into(),
config: r#"version = 1
-task = "Propose and implement incremental product improvements"
+goal = "Propose and implement incremental product improvements"
graph = "expand.dot"
[llm]
diff --git a/crates/arc-workflows/src/cli/mod.rs b/crates/arc-workflows/src/cli/mod.rs
index 55edce9e3..50991e336 100644
--- a/crates/arc-workflows/src/cli/mod.rs
+++ b/crates/arc-workflows/src/cli/mod.rs
@@ -2,7 +2,7 @@ pub mod backend;
pub mod cli_backend;
pub mod run;
pub mod runs;
-pub mod task_config;
+pub mod run_config;
pub mod validate;
use std::path::Path;
diff --git a/crates/arc-workflows/src/cli/run.rs b/crates/arc-workflows/src/cli/run.rs
index b0d7b7fc7..0c4fc2451 100644
--- a/crates/arc-workflows/src/cli/run.rs
+++ b/crates/arc-workflows/src/cli/run.rs
@@ -25,8 +25,8 @@ use arc_llm::provider::Provider;
use super::backend::AgentApiBackend;
use super::cli_backend::{BackendRouter, AgentCliBackend};
-use super::task_config;
-use super::task_config::TaskConfig;
+use super::run_config;
+use super::run_config::WorkflowRunConfig;
use super::{
compute_stage_cost, format_cost, format_duration_human,
format_event_summary, format_tokens_human, print_diagnostics, read_dot_file,
@@ -52,13 +52,13 @@ fn default_model_for_provider(provider: Provider) -> &'static str {
fn resolve_model_provider(
cli_model: Option<&str>,
cli_provider: Option<&str>,
- task_cfg: Option<&TaskConfig>,
+ run_cfg: Option<&WorkflowRunConfig>,
graph: &crate::graph::types::Graph,
) -> (String, Option) {
- let toml_model = task_cfg
+ let toml_model = run_cfg
.and_then(|c| c.llm.as_ref())
.and_then(|l| l.model.as_deref());
- let toml_provider = task_cfg
+ let toml_provider = run_cfg
.and_then(|c| c.llm.as_ref())
.and_then(|l| l.provider.as_deref());
@@ -125,16 +125,16 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
.as_ref()
.ok_or_else(|| anyhow::anyhow!("--workflow is required unless --run-branch is provided"))?;
- // 0. Load task config if TOML, resolve DOT path, run setup
- let (dot_path, task_cfg) = if workflow_path.extension().is_some_and(|ext| ext == "toml") {
- let cfg = task_config::load_task_config(workflow_path)?;
- let dot = task_config::resolve_graph_path(workflow_path, &cfg.graph);
+ // 0. Load run config if TOML, resolve DOT path, run setup
+ let (dot_path, run_cfg) = if workflow_path.extension().is_some_and(|ext| ext == "toml") {
+ let cfg = run_config::load_run_config(workflow_path)?;
+ let dot = run_config::resolve_graph_path(workflow_path, &cfg.graph);
(dot, Some(cfg))
} else {
(workflow_path.clone(), None)
};
- if let Some(ref cfg) = task_cfg {
+ if let Some(ref cfg) = run_cfg {
if let Some(ref dir) = cfg.directory {
std::env::set_current_dir(dir)
.map_err(|e| anyhow::anyhow!("Failed to set working directory to {dir}: {e}"))?;
@@ -142,7 +142,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
}
// Collect setup commands — they'll be run inside the sandbox
- let setup_commands: Vec = task_cfg
+ let setup_commands: Vec = run_cfg
.as_ref()
.and_then(|c| c.setup.as_ref())
.map(|s| s.commands.clone())
@@ -150,8 +150,8 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
// 1. Parse and validate workflow
let source = read_dot_file(&dot_path)?;
- let source = match task_cfg.as_ref().and_then(|c| c.vars.as_ref()) {
- Some(vars) => task_config::expand_vars(&source, vars)?,
+ let source = match run_cfg.as_ref().and_then(|c| c.vars.as_ref()) {
+ Some(vars) => run_config::expand_vars(&source, vars)?,
None => source,
};
let (graph, diagnostics) = WorkflowBuilder::new().prepare(&source)?;
@@ -184,7 +184,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
// 2. Pre-flight: check git cleanliness before creating any files
// (must happen before logs dir is created, which may be inside the repo)
let sandbox_provider_preview = {
- let toml_exec = task_cfg
+ let toml_exec = run_cfg
.as_ref()
.and_then(|c| c.sandbox.as_ref())
.and_then(|e| e.provider.as_deref())
@@ -203,7 +203,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
};
if args.preflight {
- return run_preflight(&graph, &task_cfg, &args, git_clean, sandbox_provider_preview, styles).await;
+ return run_preflight(&graph, &run_cfg, &args, git_clean, sandbox_provider_preview, styles).await;
}
// 3. Create logs directory
@@ -219,7 +219,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
tokio::fs::write(logs_dir.join("run.pid"), std::process::id().to_string()).await?;
if workflow_path.extension().is_some_and(|ext| ext == "toml") {
if let Ok(toml_contents) = tokio::fs::read(workflow_path).await {
- tokio::fs::write(logs_dir.join("task.toml"), toml_contents).await?;
+ tokio::fs::write(logs_dir.join("run.toml"), toml_contents).await?;
}
}
@@ -368,7 +368,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
};
// 5. Resolve sandbox: CLI flag > TOML > default
- let toml_sandbox = task_cfg
+ let toml_sandbox = run_cfg
.as_ref()
.and_then(|c| c.sandbox.as_ref())
.and_then(|e| e.provider.as_deref())
@@ -400,7 +400,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
};
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
- let daytona_config = task_cfg
+ let daytona_config = run_cfg
.as_ref()
.and_then(|c| c.sandbox.as_ref())
.and_then(|e| e.daytona.clone());
@@ -554,7 +554,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
let (model, provider) = resolve_model_provider(
args.model.as_deref(),
args.provider.as_deref(),
- task_cfg.as_ref(),
+ run_cfg.as_ref(),
&graph,
);
@@ -1045,7 +1045,7 @@ async fn run_from_branch(
/// a structured report.
async fn run_preflight(
graph: &crate::graph::types::Graph,
- task_cfg: &Option,
+ run_cfg: &Option,
args: &RunArgs,
git_clean: bool,
sandbox_provider: SandboxProvider,
@@ -1055,7 +1055,7 @@ async fn run_preflight(
// 1. Sandbox boot check
let original_cwd = std::env::current_dir()?;
- let daytona_config = task_cfg
+ let daytona_config = run_cfg
.as_ref()
.and_then(|c| c.sandbox.as_ref())
.and_then(|e| e.daytona.clone());
@@ -1124,7 +1124,7 @@ async fn run_preflight(
let (model, provider) = resolve_model_provider(
args.model.as_deref(),
args.provider.as_deref(),
- task_cfg.as_ref(),
+ run_cfg.as_ref(),
graph,
);
@@ -1142,7 +1142,7 @@ async fn run_preflight(
};
// 5. Count setup commands for display
- let setup_command_count = task_cfg
+ let setup_command_count = run_cfg
.as_ref()
.and_then(|c| c.setup.as_ref())
.map_or(0, |s| s.commands.len());
@@ -1337,12 +1337,12 @@ mod tests {
#[test]
fn resolve_model_provider_cli_overrides_toml() {
let graph = crate::graph::types::Graph::new("test");
- let cfg = task_config::TaskConfig {
+ let cfg = run_config::WorkflowRunConfig {
version: 1,
- task: "test".to_string(),
+ goal: "test".to_string(),
graph: "test.dot".to_string(),
directory: None,
- llm: Some(task_config::LlmConfig {
+ llm: Some(run_config::LlmConfig {
model: Some("toml-model".to_string()),
provider: Some("openai".to_string()),
}),
@@ -1367,12 +1367,12 @@ mod tests {
graph.attrs.insert("default_model".to_string(), AttrValue::String("graph-model".to_string()));
graph.attrs.insert("default_provider".to_string(), AttrValue::String("gemini".to_string()));
- let cfg = task_config::TaskConfig {
+ let cfg = run_config::WorkflowRunConfig {
version: 1,
- task: "test".to_string(),
+ goal: "test".to_string(),
graph: "test.dot".to_string(),
directory: None,
- llm: Some(task_config::LlmConfig {
+ llm: Some(run_config::LlmConfig {
model: Some("toml-model".to_string()),
provider: Some("openai".to_string()),
}),
diff --git a/crates/arc-workflows/src/cli/task_config.rs b/crates/arc-workflows/src/cli/run_config.rs
similarity index 88%
rename from crates/arc-workflows/src/cli/task_config.rs
rename to crates/arc-workflows/src/cli/run_config.rs
index b24901695..4d793ba69 100644
--- a/crates/arc-workflows/src/cli/task_config.rs
+++ b/crates/arc-workflows/src/cli/run_config.rs
@@ -10,9 +10,9 @@ const SUPPORTED_VERSION: u32 = 1;
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
-pub struct TaskConfig {
+pub struct WorkflowRunConfig {
pub version: u32,
- pub task: String,
+ pub goal: String,
pub graph: String,
pub directory: Option,
pub llm: Option,
@@ -42,14 +42,14 @@ pub struct SandboxConfig {
pub daytona: Option,
}
-/// Load and validate a task config from a TOML file.
+/// Load and validate a run config from a TOML file.
///
/// The `graph` path in the returned config is resolved relative to the
/// TOML file's parent directory.
-pub fn load_task_config(path: &Path) -> anyhow::Result {
+pub fn load_run_config(path: &Path) -> anyhow::Result {
let contents = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read {}", path.display()))?;
- let config = parse_task_config(&contents)?;
+ let config = parse_run_config(&contents)?;
Ok(config)
}
@@ -67,13 +67,13 @@ pub fn resolve_graph_path(toml_path: &Path, graph: &str) -> PathBuf {
}
}
-fn parse_task_config(contents: &str) -> anyhow::Result {
- let config: TaskConfig =
- toml::from_str(contents).context("Failed to parse task config TOML")?;
+fn parse_run_config(contents: &str) -> anyhow::Result {
+ let config: WorkflowRunConfig =
+ toml::from_str(contents).context("Failed to parse run config TOML")?;
if config.version != SUPPORTED_VERSION {
bail!(
- "Unsupported task config version {}. Only version {SUPPORTED_VERSION} is supported.",
+ "Unsupported run config version {}. Only version {SUPPORTED_VERSION} is supported.",
config.version
);
}
@@ -163,14 +163,14 @@ mod tests {
fn parse_toml_with_vars() {
let toml = r#"
version = 1
-task = "Run tests"
+goal = "Run tests"
graph = "workflow.dot"
[vars]
repo_url = "https://github.com/org/repo"
language = "python"
"#;
- let config = parse_task_config(toml).unwrap();
+ let config = parse_run_config(toml).unwrap();
let vars = config.vars.unwrap();
assert_eq!(vars["repo_url"], "https://github.com/org/repo");
assert_eq!(vars["language"], "python");
@@ -223,13 +223,13 @@ language = "python"
fn parse_toml_with_sandbox() {
let toml = r#"
version = 1
-task = "Run tests"
+goal = "Run tests"
graph = "workflow.dot"
[sandbox]
provider = "daytona"
"#;
- let config = parse_task_config(toml).unwrap();
+ let config = parse_run_config(toml).unwrap();
let sandbox = config.sandbox.unwrap();
assert_eq!(sandbox.provider.as_deref(), Some("daytona"));
assert!(sandbox.daytona.is_none());
@@ -239,7 +239,7 @@ provider = "daytona"
fn parse_toml_with_daytona_config() {
let toml = r#"
version = 1
-task = "Run tests"
+goal = "Run tests"
graph = "workflow.dot"
[sandbox]
@@ -258,7 +258,7 @@ memory = 8
disk = 10
dockerfile = "FROM rust:1.85-slim-bookworm\nRUN apt-get update"
"#;
- let config = parse_task_config(toml).unwrap();
+ let config = parse_run_config(toml).unwrap();
let sandbox = config.sandbox.unwrap();
assert_eq!(sandbox.provider.as_deref(), Some("daytona"));
@@ -282,7 +282,7 @@ dockerfile = "FROM rust:1.85-slim-bookworm\nRUN apt-get update"
fn parse_toml_with_daytona_no_snapshot() {
let toml = r#"
version = 1
-task = "Run tests"
+goal = "Run tests"
graph = "workflow.dot"
[sandbox]
@@ -291,7 +291,7 @@ provider = "daytona"
[sandbox.daytona]
auto_stop_interval = 30
"#;
- let config = parse_task_config(toml).unwrap();
+ let config = parse_run_config(toml).unwrap();
let daytona = config.sandbox.unwrap().daytona.unwrap();
assert_eq!(daytona.auto_stop_interval, Some(30));
assert!(daytona.snapshot.is_none());
@@ -301,12 +301,12 @@ auto_stop_interval = 30
fn parse_minimal_toml() {
let toml = r#"
version = 1
-task = "Run tests"
+goal = "Run tests"
graph = "workflow.dot"
"#;
- let config = parse_task_config(toml).unwrap();
+ let config = parse_run_config(toml).unwrap();
assert_eq!(config.version, 1);
- assert_eq!(config.task, "Run tests");
+ assert_eq!(config.goal, "Run tests");
assert_eq!(config.graph, "workflow.dot");
assert!(config.directory.is_none());
assert!(config.llm.is_none());
@@ -317,7 +317,7 @@ graph = "workflow.dot"
fn parse_full_toml() {
let toml = r#"
version = 1
-task = "Full workflow"
+goal = "Full workflow"
graph = "workflow.dot"
directory = "/tmp/repo"
@@ -329,8 +329,8 @@ provider = "anthropic"
commands = ["pip install -r requirements.txt", "npm install"]
timeout_ms = 60000
"#;
- let config = parse_task_config(toml).unwrap();
- assert_eq!(config.task, "Full workflow");
+ let config = parse_run_config(toml).unwrap();
+ assert_eq!(config.goal, "Full workflow");
assert_eq!(config.directory.as_deref(), Some("/tmp/repo"));
let llm = config.llm.unwrap();
@@ -346,13 +346,13 @@ timeout_ms = 60000
fn unsupported_version_rejected() {
let toml = r#"
version = 2
-task = "x"
+goal = "x"
graph = "p.dot"
"#;
- let err = parse_task_config(toml).unwrap_err();
+ let err = parse_run_config(toml).unwrap_err();
assert!(
err.to_string()
- .contains("Unsupported task config version 2"),
+ .contains("Unsupported run config version 2"),
"unexpected error: {err}"
);
}
@@ -373,17 +373,17 @@ graph = "p.dot"
#[test]
fn missing_required_fields() {
- let no_task = r#"
+ let no_goal = r#"
version = 1
graph = "p.dot"
"#;
- assert!(parse_task_config(no_task).is_err());
+ assert!(parse_run_config(no_goal).is_err());
let no_graph = r#"
version = 1
-task = "x"
+goal = "x"
"#;
- assert!(parse_task_config(no_graph).is_err());
+ assert!(parse_run_config(no_graph).is_err());
}
#[tokio::test]
diff --git a/pipelines/daytona-check/task.toml b/pipelines/daytona-check/run.toml
similarity index 92%
rename from pipelines/daytona-check/task.toml
rename to pipelines/daytona-check/run.toml
index 824c38b36..4eb017cfb 100644
--- a/pipelines/daytona-check/task.toml
+++ b/pipelines/daytona-check/run.toml
@@ -1,5 +1,5 @@
version = 1
-task = "Run cargo check in a Daytona cloud sandbox"
+goal = "Run cargo check in a Daytona cloud sandbox"
graph = "check.dot"
[llm]