Rename arc/ to fabro/ in git branch prefixes and workflow paths

Complete the rebrand by replacing hardcoded "arc/run/" branch prefixes
with a RUN_BRANCH_PREFIX constant ("fabro/run/") and updating
fabro init to create workflows under fabro/workflows/ instead of
arc/workflows/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-14 12:20:07 -04:00
parent 39191be1a5
commit 4ee215cada
No known key found for this signature in database
14 changed files with 55 additions and 43 deletions

View file

@ -82,5 +82,5 @@ When interpolating values into shell command strings (in `fabro-exe` and `fabro-
## Testing workflows
- `fabro run <name>` — run a workflow by name (resolves `arc/workflows/<name>/workflow.toml`), e.g. `fabro run repl`
- `fabro run <name>` — run a workflow by name (resolves `fabro/workflows/<name>/workflow.toml`), e.g. `fabro run repl`
- Use `--no-retro` to skip the retro step and finish faster

View file

@ -41,7 +41,7 @@ Launch a workflow from a `.fabro` workflow file or `.toml` task config.
```bash
fabro run <WORKFLOW>
fabro run run.toml
fabro run --run-branch arc/run/abc123
fabro run --run-branch fabro/run/abc123
```
| Argument / Flag | Description |

View file

@ -13,7 +13,7 @@ name = "imagegen-tools-v3"
cpu = 4
memory = 8
disk = 10
dockerfile = { path = "../../arc/workflows/imagegen/Dockerfile.imagegen" }
dockerfile = { path = "../../fabro/workflows/imagegen/Dockerfile.imagegen" }
[assets]
include = ["output/**"]

View file

@ -54,7 +54,7 @@ root = \"fabro/\"
eprintln!(" {} {}", green.apply_to("✔"), dim.apply_to("fabro.toml"));
// Create hello workflow directory
let workflow_dir = repo_root.join("arc/workflows/hello");
let workflow_dir = repo_root.join("fabro/workflows/hello");
std::fs::create_dir_all(&workflow_dir)
.with_context(|| format!("failed to create {}", workflow_dir.display()))?;
@ -79,7 +79,7 @@ root = \"fabro/\"
eprintln!(
" {} {}",
green.apply_to("✔"),
dim.apply_to("arc/workflows/hello/workflow.fabro")
dim.apply_to("fabro/workflows/hello/workflow.fabro")
);
// Create workflow.toml
@ -92,7 +92,7 @@ root = \"fabro/\"
eprintln!(
" {} {}",
green.apply_to("✔"),
dim.apply_to("arc/workflows/hello/workflow.toml")
dim.apply_to("fabro/workflows/hello/workflow.toml")
);
eprintln!(

View file

@ -449,7 +449,7 @@ mod tests {
owner: "owner".to_string(),
repo: "repo".to_string(),
base_branch: "main".to_string(),
head_branch: "arc/run/abc".to_string(),
head_branch: "fabro/run/abc".to_string(),
title: "Fix the thing".to_string(),
};
fs::write(
@ -544,7 +544,7 @@ mod tests {
owner: "owner".to_string(),
repo: "repo".to_string(),
base_branch: "main".to_string(),
head_branch: "arc/run/ccc".to_string(),
head_branch: "fabro/run/ccc".to_string(),
title: "Another fix".to_string(),
};
fs::write(
@ -690,7 +690,7 @@ mod tests {
"start_time": "2026-01-01T12:00:00Z",
"node_count": 1,
"edge_count": 0,
"run_branch": "arc/run/abc123"
"run_branch": "fabro/run/abc123"
}),
None,
Some("diff content"),
@ -718,7 +718,7 @@ mod tests {
"start_time": "2026-01-01T12:00:00Z",
"node_count": 1,
"edge_count": 0,
"run_branch": "arc/run/abc123"
"run_branch": "fabro/run/abc123"
}),
Some(serde_json::json!({
"timestamp": "2026-01-01T12:01:00Z",
@ -781,7 +781,7 @@ mod tests {
"start_time": "2026-01-01T12:00:00Z",
"node_count": 1,
"edge_count": 0,
"run_branch": "arc/run/abc123"
"run_branch": "fabro/run/abc123"
}),
Some(serde_json::json!({
"timestamp": "2026-01-01T12:01:00Z",
@ -813,7 +813,7 @@ mod tests {
"start_time": "2026-01-01T12:00:00Z",
"node_count": 1,
"edge_count": 0,
"run_branch": "arc/run/abc123"
"run_branch": "fabro/run/abc123"
}),
Some(serde_json::json!({
"timestamp": "2026-01-01T12:01:00Z",
@ -845,7 +845,7 @@ mod tests {
"start_time": "2026-01-01T12:00:00Z",
"node_count": 1,
"edge_count": 0,
"run_branch": "arc/run/abc123"
"run_branch": "fabro/run/abc123"
}),
Some(serde_json::json!({
"timestamp": "2026-01-01T12:01:00Z",

View file

@ -137,7 +137,7 @@ fn backfill_run_shas(store: &Store, run_id: &str, timeline: &mut [TimelineEntry]
return;
}
let run_branch = format!("arc/run/{run_id}");
let run_branch = format!("{}{run_id}", crate::git::RUN_BRANCH_PREFIX);
let sig = match Signature::now("Fabro", "noreply@fabro.sh") {
Ok(s) => s,
Err(_) => return,
@ -333,7 +333,7 @@ pub fn execute_rewind(
);
// Move run branch ref
let run_branch = format!("arc/run/{run_id}");
let run_branch = format!("{}{run_id}", crate::git::RUN_BRANCH_PREFIX);
match &entry.run_commit_sha {
Some(sha) => {
let oid =
@ -341,7 +341,11 @@ pub fn execute_rewind(
store
.update_ref(&run_branch, oid)
.map_err(|e| anyhow::anyhow!("failed to update run branch ref: {e}"))?;
eprintln!("Rewound run branch arc/run/{run_id} to {}", &sha[..8]);
eprintln!(
"Rewound run branch {}{run_id} to {}",
crate::git::RUN_BRANCH_PREFIX,
&sha[..8]
);
}
None => {
eprintln!(
@ -442,7 +446,11 @@ pub fn rewind_command(args: &RewindArgs, styles: &Styles) -> Result<()> {
execute_rewind(&store, &run_id, entry, !args.no_push)?;
eprintln!("\nTo resume: fabro run --run-branch arc/run/{}", run_id);
eprintln!(
"\nTo resume: fabro run --run-branch {}{}",
crate::git::RUN_BRANCH_PREFIX,
run_id
);
Ok(())
}
@ -814,7 +822,7 @@ mod tests {
let sig = test_sig();
// Create a run branch with some commits
let run_branch = "arc/run/run-2";
let run_branch = "fabro/run/run-2";
let empty_tree = store.write_empty_tree().unwrap();
let run_c1 = store
.write_commit(empty_tree, &[], "run commit 1", &sig)

View file

@ -1477,7 +1477,7 @@ fn setup_worktree(
run_id: &str,
) -> anyhow::Result<(PathBuf, PathBuf, String, String)> {
let base_sha = crate::git::head_sha(original_cwd).map_err(|e| anyhow::anyhow!("{e}"))?;
let branch_name = format!("arc/run/{run_id}");
let branch_name = format!("{}{run_id}", crate::git::RUN_BRANCH_PREFIX);
crate::git::create_branch(original_cwd, &branch_name).map_err(|e| anyhow::anyhow!("{e}"))?;
let worktree_path = run_dir.join("worktree");
@ -1525,7 +1525,7 @@ async fn setup_remote_git(
}
let base_sha = sha_result.stdout.trim().to_string();
let branch_name = format!("arc/run/{run_id}");
let branch_name = format!("{}{run_id}", crate::git::RUN_BRANCH_PREFIX);
// Create and checkout a run branch
let checkout_cmd = format!("git checkout -b {branch_name}");
@ -1557,12 +1557,13 @@ async fn run_from_branch(
run_defaults: RunDefaults,
github_app: Option<fabro_github::GitHubAppCredentials>,
) -> anyhow::Result<()> {
// Extract run_id from branch name: "arc/run/{run_id}" -> "{run_id}"
// Extract run_id from branch name: "fabro/run/{run_id}" -> "{run_id}"
let run_id = run_branch
.strip_prefix("arc/run/")
.strip_prefix(crate::git::RUN_BRANCH_PREFIX)
.ok_or_else(|| {
anyhow::anyhow!(
"invalid run branch format: expected 'arc/run/<run_id>', got '{run_branch}'"
"invalid run branch format: expected '{}<run_id>', got '{run_branch}'",
crate::git::RUN_BRANCH_PREFIX,
)
})?
.to_string();

View file

@ -162,7 +162,7 @@ pub struct DaytonaSandbox {
run_id: Option<String>,
/// Explicit branch to clone. When set, overrides the branch detected by
/// `detect_repo_info` — avoids cloning a local-only worktree branch
/// (e.g. `arc/run/...`) that was never pushed to origin.
/// (e.g. `fabro/run/...`) that was never pushed to origin.
clone_branch: Option<String>,
}
@ -570,7 +570,7 @@ impl Sandbox for DaytonaSandbox {
match detect_repo_info(&cwd) {
Ok((detected_url, detected_branch)) => {
// Use explicit clone_branch if provided (avoids cloning a local-only
// worktree branch like arc/run/... that hasn't been pushed).
// worktree branch like fabro/run/... that hasn't been pushed).
let branch = self.clone_branch.clone().or(detected_branch);
// Daytona clones over HTTPS with token auth, so rewrite SSH URLs.
let url = ssh_url_to_https(&detected_url);

View file

@ -764,7 +764,7 @@ pub struct RunConfig {
pub host_repo_path: Option<PathBuf>,
/// SHA of the commit the worktree branched from.
pub base_sha: Option<String>,
/// Git branch name for the run (e.g. `arc/run/{run_id}`).
/// Git branch name for the run (e.g. `fabro/run/{run_id}`).
pub run_branch: Option<String>,
/// Metadata branch name for git-native checkpoint storage (e.g. `refs/fabro/{run_id}`).
pub meta_branch: Option<String>,

View file

@ -8,6 +8,9 @@ use git2::{Repository, Signature};
use crate::checkpoint::Checkpoint;
use crate::error::{FabroError, Result};
/// Branch prefix for workflow run branches (e.g. `fabro/run/{run_id}`).
pub const RUN_BRANCH_PREFIX: &str = "fabro/run/";
/// Resolved git author identity for checkpoint commits.
#[derive(Debug, Clone, PartialEq)]
pub struct GitAuthor {
@ -340,7 +343,7 @@ pub fn scan_node_files(run_dir: &Path) -> Vec<(String, Vec<u8>)> {
/// Git-native metadata storage for pipeline runs.
///
/// Stores checkpoint data, manifests, and graph DOT on an orphan branch
/// (`arc/{run_id}`) so that runs can be resumed from git alone.
/// (`fabro/{run_id}`) so that runs can be resumed from git alone.
pub struct MetadataStore {
repo_path: std::path::PathBuf,
author: GitAuthor,

View file

@ -294,7 +294,7 @@ impl Handler for ParallelHandler {
let branch_key = &target_id;
let visit = crate::engine::visit_from_context(&branch_context);
let branch_name = format!(
"arc/run/parallel/{}/{}/pass{}/{}",
"fabro/run/parallel/{}/{}/pass{}/{}",
gs.run_id,
crate::git::sanitize_ref_component(&node.id),
visit,

View file

@ -861,7 +861,7 @@ mod tests {
owner: "owner".to_string(),
repo: "repo".to_string(),
base_branch: "main".to_string(),
head_branch: "arc/run/abc".to_string(),
head_branch: "fabro/run/abc".to_string(),
title: "Fix the thing".to_string(),
};
record.save(&path).unwrap();
@ -873,7 +873,7 @@ mod tests {
assert_eq!(content["owner"], "owner");
assert_eq!(content["repo"], "repo");
assert_eq!(content["base_branch"], "main");
assert_eq!(content["head_branch"], "arc/run/abc");
assert_eq!(content["head_branch"], "fabro/run/abc");
assert_eq!(content["title"], "Fix the thing");
}
@ -888,7 +888,7 @@ mod tests {
&creds,
"https://github.com/owner/repo.git",
"main",
"arc/run/123",
"fabro/run/123",
"Fix bug",
"",
"claude-sonnet-4-20250514",

View file

@ -492,7 +492,7 @@ async fn setup_daytona_git(sandbox: &dyn Sandbox) -> (String, String, String) {
let base_sha = sha_result.stdout.trim().to_string();
let run_id = ulid::Ulid::new().to_string();
let branch_name = format!("arc/run/{run_id}");
let branch_name = format!("fabro/run/{run_id}");
let checkout_cmd = format!("git checkout -b {branch_name}");
let checkout_result = sandbox

View file

@ -10632,7 +10632,7 @@ async fn git_checkpoint_host_emits_events_and_diff_patch() {
String::from_utf8_lossy(&out.stdout).trim().to_string()
};
std::process::Command::new("git")
.args(["branch", "arc/run/test-docker", "HEAD"])
.args(["branch", "fabro/run/test-docker", "HEAD"])
.current_dir(repo.path())
.output()
.unwrap();
@ -10640,7 +10640,7 @@ async fn git_checkpoint_host_emits_events_and_diff_patch() {
std::process::Command::new("git")
.args(["worktree", "add"])
.arg(&worktree_path)
.arg("arc/run/test-docker")
.arg("fabro/run/test-docker")
.current_dir(repo.path())
.output()
.unwrap();
@ -10693,7 +10693,7 @@ async fn git_checkpoint_host_emits_events_and_diff_patch() {
git_checkpoint_enabled: true,
host_repo_path: Some(worktree_path.clone()),
base_sha: Some(base_sha.clone()),
run_branch: Some("arc/run/test-docker".to_string()),
run_branch: Some("fabro/run/test-docker".to_string()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
@ -10822,7 +10822,7 @@ async fn git_checkpoint_host_writes_shadow_branch() {
String::from_utf8_lossy(&out.stdout).trim().to_string()
};
std::process::Command::new("git")
.args(["branch", &format!("arc/run/{run_id}"), "HEAD"])
.args(["branch", &format!("fabro/run/{run_id}"), "HEAD"])
.current_dir(repo.path())
.output()
.unwrap();
@ -10830,7 +10830,7 @@ async fn git_checkpoint_host_writes_shadow_branch() {
std::process::Command::new("git")
.args(["worktree", "add"])
.arg(&worktree_path)
.arg(format!("arc/run/{run_id}"))
.arg(format!("fabro/run/{run_id}"))
.current_dir(repo.path())
.output()
.unwrap();
@ -10885,7 +10885,7 @@ async fn git_checkpoint_host_writes_shadow_branch() {
git_checkpoint_enabled: true,
host_repo_path: Some(worktree_path.clone()),
base_sha: Some(base_sha),
run_branch: Some(format!("arc/run/{run_id}")),
run_branch: Some(format!("fabro/run/{run_id}")),
meta_branch: Some(meta_branch),
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),
@ -10995,7 +10995,7 @@ async fn parallel_git_branching_host_e2e() {
String::from_utf8_lossy(&out.stdout).trim().to_string()
};
let run_id = "par-git-test";
let run_branch = format!("arc/run/{run_id}");
let run_branch = format!("fabro/run/{run_id}");
std::process::Command::new("git")
.args(["branch", &run_branch, "HEAD"])
.current_dir(repo.path())
@ -11205,7 +11205,7 @@ async fn parallel_git_branching_host_e2e() {
);
// 10. Verify parallel branch refs still exist (for debugging)
let branch_ref_a = format!("arc/run/parallel/{run_id}/fan-out/pass1/branch-a");
let branch_ref_a = format!("fabro/run/parallel/{run_id}/fan-out/pass1/branch-a");
let ref_check = std::process::Command::new("git")
.args(["rev-parse", "--verify", &branch_ref_a])
.current_dir(repo.path())
@ -11292,7 +11292,7 @@ async fn git_checkpoint_host_skips_empty_diff_patch() {
String::from_utf8_lossy(&out.stdout).trim().to_string()
};
std::process::Command::new("git")
.args(["branch", "arc/run/empty-diff", "HEAD"])
.args(["branch", "fabro/run/empty-diff", "HEAD"])
.current_dir(repo.path())
.output()
.unwrap();
@ -11300,7 +11300,7 @@ async fn git_checkpoint_host_skips_empty_diff_patch() {
std::process::Command::new("git")
.args(["worktree", "add"])
.arg(&worktree_path)
.arg("arc/run/empty-diff")
.arg("fabro/run/empty-diff")
.current_dir(repo.path())
.output()
.unwrap();
@ -11350,7 +11350,7 @@ async fn git_checkpoint_host_skips_empty_diff_patch() {
git_checkpoint_enabled: true,
host_repo_path: Some(worktree_path.clone()),
base_sha: Some(base_sha.clone()),
run_branch: Some("arc/run/empty-diff".to_string()),
run_branch: Some("fabro/run/empty-diff".to_string()),
meta_branch: None,
labels: std::collections::HashMap::new(),
checkpoint_exclude_globs: Vec::new(),