From 4572012bc367e547743da8ec4fd792e8f7c877e1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 28 Feb 2026 14:16:52 -0500 Subject: [PATCH] Use ULID instead of UUID for run IDs ULIDs are lexicographically sortable by creation time, making log directories and run lists naturally ordered without extra metadata. Co-Authored-By: Claude Opus 4.6 --- Cargo.toml | 1 + crates/arc-attractor/Cargo.toml | 1 + crates/arc-attractor/src/cli/run.rs | 4 ++-- crates/arc-attractor/src/server.rs | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aadf9fe4b..15791f0b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tokio = { version = "1", features = ["full"] } reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] } +ulid = "1" uuid = { version = "1", features = ["v4"] } rand = "0.8" dotenvy = "0.15" diff --git a/crates/arc-attractor/Cargo.toml b/crates/arc-attractor/Cargo.toml index 1575a1403..669be12e1 100644 --- a/crates/arc-attractor/Cargo.toml +++ b/crates/arc-attractor/Cargo.toml @@ -32,6 +32,7 @@ thiserror.workspace = true serde.workspace = true serde_json.workspace = true tokio.workspace = true +ulid.workspace = true uuid.workspace = true rand.workspace = true async-trait.workspace = true diff --git a/crates/arc-attractor/src/cli/run.rs b/crates/arc-attractor/src/cli/run.rs index a0883de63..2f38321a6 100644 --- a/crates/arc-attractor/src/cli/run.rs +++ b/crates/arc-attractor/src/cli/run.rs @@ -480,7 +480,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu let engine = PipelineEngine::with_interviewer(registry, Arc::clone(&emitter), interviewer, Arc::clone(&execution_env)); // 7. Execute - let run_id = worktree_run_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()); + let run_id = worktree_run_id.unwrap_or_else(|| ulid::Ulid::new().to_string()); let config = RunConfig { logs_root: logs_dir.clone(), cancel_token: None, @@ -602,7 +602,7 @@ fn setup_worktree( ) -> anyhow::Result<(String, PathBuf, PathBuf, String, String)> { let base_sha = crate::git::head_sha(original_cwd) .map_err(|e| anyhow::anyhow!("{e}"))?; - let run_id = uuid::Uuid::new_v4().to_string(); + let run_id = ulid::Ulid::new().to_string(); let branch_name = format!("arc/run/{run_id}"); crate::git::create_branch(original_cwd, &branch_name) .map_err(|e| anyhow::anyhow!("{e}"))?; diff --git a/crates/arc-attractor/src/server.rs b/crates/arc-attractor/src/server.rs index 4ce052568..a05f214d4 100644 --- a/crates/arc-attractor/src/server.rs +++ b/crates/arc-attractor/src/server.rs @@ -170,7 +170,7 @@ async fn start_pipeline( } }; - let run_id = uuid::Uuid::new_v4().to_string(); + let run_id = ulid::Ulid::new().to_string(); let interviewer = Arc::new(WebInterviewer::new()); let (event_tx, _) = broadcast::channel(256); let (cancel_tx, cancel_rx) = tokio::sync::oneshot::channel::<()>();