mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Update changelog and docs for installer, devcontainers, arc pr, and preflight improvements
Regenerate 2026-03-10 changelog with full commit set (installer, devcontainer support, arc pr subcommands, --no-dotenv removal). Add 2026-03-11 changelog for shadow branch run records and arc diff improvements. Update docs: CLI reference (arc pr list/view/merge/close, --shortstat), devcontainers page (replace placeholder with full content), run-configuration (devcontainer field), checkpoints (per-node files on metadata branch), models catalog (gemini-3.1-pro-preview-customtools). Improve preflight to show per-model LLM checks instead of a single merged provider line. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
35b6282e6d
commit
cfd7ea8c97
11 changed files with 220 additions and 58 deletions
|
|
@ -1 +1 @@
|
|||
485f2a5718b6d983520aa5cccd39128d99bad7ae
|
||||
15a56263f52992592d97b904914626a366eee0d8
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
485f2a5718b6d983520aa5cccd39128d99bad7ae
|
||||
15a56263f52992592d97b904914626a366eee0d8
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
---
|
||||
title: "MCP servers in workflows, arc init, and arc diff"
|
||||
title: "One-line installer, MCP servers, and devcontainer support"
|
||||
date: "2026-03-10"
|
||||
---
|
||||
|
||||
## One-line installer and guided setup wizard
|
||||
|
||||
Getting Arc installed and configured previously required multiple manual steps — downloading binaries, setting API keys, and configuring GitHub integration individually. Now, a single command installs Arc and walks you through everything:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/brynary/arc/main/install.sh | bash
|
||||
arc install
|
||||
```
|
||||
|
||||
The installer detects your platform, installs to `~/.arc/bin`, and auto-configures your shell PATH. The `arc install` wizard then guides you through LLM provider setup with immediate API key validation, OpenAI OAuth for Codex compatibility, and GitHub App creation via manifest flow — all with styled terminal output showing progress at each step.
|
||||
|
||||
## MCP servers in workflows
|
||||
|
||||
Agents running inside sandboxes can now access MCP tools during workflow runs. A new `sandbox` transport type starts an MCP server inside the Daytona sandbox, waits for it to listen, and connects automatically — no host-side setup required. This means agents can use tools like Playwright for browser automation, or any other MCP server, directly from within their sandbox environment.
|
||||
|
|
@ -14,39 +25,50 @@ command = ["npx", "@playwright/mcp@latest", "--port", "3100", "--headless"]
|
|||
port = 3100
|
||||
```
|
||||
|
||||
## `arc init` — initialize a new project
|
||||
## Devcontainer support in sandboxes
|
||||
|
||||
Getting started with Arc previously meant creating `arc.toml` and workflow files by hand. Now, `arc init` scaffolds a project with a generated `arc.toml` that includes comments and a link to the docs.
|
||||
Workflows can now use your project's `devcontainer.json` to configure sandbox environments. When `devcontainer = true` is set in the sandbox config, Arc resolves the devcontainer from the repo, uses its Dockerfile for the Daytona snapshot, runs lifecycle hooks (`onCreateCommand`, `postCreateCommand`, `postStartCommand`), and merges devcontainer environment variables into the sandbox. Unsupported `COPY`/`ADD` instructions in base Dockerfiles are detected and reported.
|
||||
|
||||
```bash
|
||||
arc init
|
||||
```toml title="workflow.toml"
|
||||
[sandbox]
|
||||
devcontainer = true
|
||||
```
|
||||
|
||||
## `arc diff` — view workflow run diffs
|
||||
|
||||
You can now inspect the code changes from any workflow run without digging through log files. `arc diff` surfaces the final patch and per-node diffs from completed runs. For in-progress runs, it reconnects to the sandbox to show a live diff.
|
||||
|
||||
```bash
|
||||
arc diff <run-id>
|
||||
```
|
||||
<Warning>
|
||||
**`--no-dotenv` flag removed.** Arc now always loads `~/.arc/.env` and never loads a local `./.env` file. If you were relying on project-local `.env` files, move those values to `~/.arc/.env`.
|
||||
</Warning>
|
||||
|
||||
## More
|
||||
|
||||
<Accordion title="API">
|
||||
- New signoff resource in the verification system — stamps of approval for (control, repository, commit SHA) tuples via `POST /verification/signoffs`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="CLI">
|
||||
- Added `arc pr list/view/merge/close` subcommands for managing pull requests created by workflow runs
|
||||
- Added `arc init` command to scaffold new projects with a generated `arc.toml`
|
||||
- Added `arc diff` command to view code changes from workflow runs, with live diffs for in-progress runs
|
||||
- `arc setup` renamed to `arc install` for clarity
|
||||
- Added `arc ssh` command for direct SSH access to Daytona sandboxes
|
||||
- Added `arc preview` command to get preview URLs for ports exposed by Daytona sandboxes
|
||||
- `arc doctor` now runs live service probes by default; use `--dry-run` to skip
|
||||
- `arc doctor` now validates GitHub App configuration and private key
|
||||
- `arc doctor` now hides unconfigured LLM providers for a cleaner output
|
||||
- `arc doctor` sections reordered: Config, LLM, GitHub App, Cloud sandbox, Brave Search
|
||||
- `arc run --preflight` now shows a Repository section, merged LLM check, and truncated output
|
||||
- Added `[pull_request]` support to project config (`arc.toml`) for project-level PR defaults
|
||||
- Per-run data moved from `~/.arc/logs/` to `~/.arc/runs/`; daily CLI logs stay in `~/.arc/logs/`
|
||||
- Per-run tracing logs now written to `cli.log` inside each run directory
|
||||
- Asset paths now display full `~/...` paths after workflow run output
|
||||
- Hidden `arc ps`, `llm`, `exec`, and `parse` from CLI help output
|
||||
- PR body now includes Arc Details section even when retro is skipped
|
||||
- Bumped version to 0.2.0
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Fixes">
|
||||
- Fixed Daytona sandbox clone failing when the worktree branch hadn't been pushed to the remote
|
||||
- Fixed "Git clean: false" showing incorrectly for remote sandboxes by checking both clean and pushed status
|
||||
- Fixed LLM provider resolution to check the model catalog before falling back to the default provider
|
||||
- Fixed verbose mode breaking terminal rendering after many tool calls
|
||||
- Fixed `install.sh` prompt not showing when piped via stdin
|
||||
- Fixed race condition in git checkpoint push operations
|
||||
</Accordion>
|
||||
|
|
|
|||
27
docs/changelog/2026-03-11.mdx
Normal file
27
docs/changelog/2026-03-11.mdx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: "Shadow branch run records and arc diff improvements"
|
||||
date: "2026-03-11"
|
||||
---
|
||||
|
||||
## Shadow branch as a complete run record
|
||||
|
||||
The shadow branch now stores the full execution trace for each workflow run — prompts, responses, status files, diffs, and retro data per node — alongside the existing checkpoint and manifest data. This makes the shadow branch a self-contained, git-native record of everything that happened during a run, browsable with standard git tools.
|
||||
|
||||
## More
|
||||
|
||||
<Accordion title="API">
|
||||
- Added `devcontainer` field to `SandboxConfiguration` OpenAPI schema
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="CLI">
|
||||
- Added `--shortstat` flag to `arc diff` for compact summary output
|
||||
- `arc diff` now includes uncommitted changes for in-progress runs, not just committed ones
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Improvements">
|
||||
- Added `gemini-3.1-pro-preview-customtools` to model catalog
|
||||
- Parallel fan-out branches now render like subagent info lines in the progress UI
|
||||
- Tool call paths now display relative to the sandbox working directory
|
||||
- Remote sandbox runs skip unnecessary local worktree creation
|
||||
- Added `last_file_touched` as a third fallback for status extraction
|
||||
</Accordion>
|
||||
|
|
@ -24,6 +24,7 @@ No single model is best at everything. Arc lets you assign the right model to ea
|
|||
| `gpt-5.4` | openai | `gpt54` | 1M | $2.50 / $15.00 | 70 tok/s |
|
||||
| `gpt-5.4-pro` | openai | `gpt54-pro` | 1M | $30.00 / $180.00 | 20 tok/s |
|
||||
| `gemini-3.1-pro-preview` | gemini | `gemini-pro` | 1M | $2.00 / $12.00 | 85 tok/s |
|
||||
| `gemini-3.1-pro-preview-customtools` | gemini | `gemini-customtools` | 1M | $2.00 / $12.00 | 85 tok/s |
|
||||
| `gemini-3-flash-preview` | gemini | `gemini-flash` | 1M | $0.50 / $3.00 | 150 tok/s |
|
||||
| `gemini-3.1-flash-lite-preview` | gemini | `gemini-flash-lite` | 1M | $0.20 / $1.50 | 200 tok/s |
|
||||
| `kimi-k2.5` | kimi | `kimi` | 262K | $0.60 / $3.00 | 50 tok/s |
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@
|
|||
"group": "March 2026",
|
||||
"icon": "clock-rotate-left",
|
||||
"pages": [
|
||||
"changelog/2026-03-11",
|
||||
"changelog/2026-03-10",
|
||||
"changelog/2026-03-09",
|
||||
"changelog/2026-03-08",
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ After each node, the metadata branch is updated with:
|
|||
|
||||
- **`checkpoint.json`** — Full execution state (see below)
|
||||
- **`artifacts/*.json`** — Any offloaded artifact data (large context values over 100KB)
|
||||
- **`nodes/{node_id}/`** — Per-node execution trace files (prompts, responses, status, diffs — files under 512KB from an allowlist)
|
||||
|
||||
## What's in a checkpoint
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,41 @@ title: "Devcontainers"
|
|||
description: "Run Arc workflows inside development containers"
|
||||
---
|
||||
|
||||
<Warning>
|
||||
Devcontainer support is **under development** and not yet available for use. This page will be updated when the feature ships.
|
||||
</Warning>
|
||||
Arc can use your project's [devcontainer](https://containers.dev/) configuration to set up sandbox environments. When enabled, Arc resolves `devcontainer.json` from the repository, uses its Dockerfile to build the Daytona sandbox snapshot, runs lifecycle hooks inside the sandbox, and merges devcontainer environment variables into the sandbox environment.
|
||||
|
||||
## Enabling devcontainer support
|
||||
|
||||
Set `devcontainer = true` in the `[sandbox]` section of your run config:
|
||||
|
||||
```toml title="run.toml"
|
||||
version = 1
|
||||
graph = "workflow.dot"
|
||||
|
||||
[sandbox]
|
||||
provider = "daytona"
|
||||
devcontainer = true
|
||||
```
|
||||
|
||||
Arc looks for `.devcontainer/devcontainer.json` in the repository root. If found, it extracts the Dockerfile, lifecycle commands, and environment variables from the configuration.
|
||||
|
||||
## What Arc uses from devcontainer.json
|
||||
|
||||
| Field | How Arc uses it |
|
||||
|---|---|
|
||||
| `build.dockerfile` | Used as the Dockerfile for the Daytona sandbox snapshot. A deterministic snapshot name is generated from a hash of the Dockerfile content. |
|
||||
| `onCreateCommand` | Runs inside the sandbox after it's created |
|
||||
| `postCreateCommand` | Runs after `onCreateCommand` completes |
|
||||
| `postStartCommand` | Runs after the sandbox starts |
|
||||
| `containerEnv` | Merged into sandbox environment variables (TOML `[sandbox.env]` values take precedence on key collisions) |
|
||||
|
||||
Lifecycle commands (`onCreateCommand`, `postCreateCommand`, `postStartCommand`) execute sequentially inside the sandbox. If any command fails, the run aborts before the workflow starts.
|
||||
|
||||
## Dockerfile limitations
|
||||
|
||||
Arc detects and reports unsupported `COPY` and `ADD` instructions in devcontainer base Dockerfiles. These instructions reference files from the build context, which isn't available when building Daytona snapshots. If your Dockerfile uses `COPY` or `ADD`, you'll need to restructure it to use `RUN` commands that fetch files at build time (e.g., via `curl` or `wget`).
|
||||
|
||||
## Interaction with other sandbox settings
|
||||
|
||||
When `devcontainer = true`, the devcontainer Dockerfile overrides any `snapshot.dockerfile` setting in `[sandbox.daytona]`. Other Daytona settings (`cpu`, `memory`, `disk`, `auto_stop_interval`, `labels`) still apply.
|
||||
|
||||
Environment variables from `containerEnv` in the devcontainer config are merged with `[sandbox.env]` from the TOML config. On key collisions, the TOML config wins.
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ preserve = true
|
|||
|---|---|
|
||||
| `provider` | Sandbox mode: `local` (default), `docker`, `daytona`, or `exe`. |
|
||||
| `preserve` | When `true`, keep the sandbox alive after the run finishes. Useful for debugging. |
|
||||
| `devcontainer` | When `true`, use the repo's `devcontainer.json` to configure the sandbox. See [Devcontainers](/execution/devcontainers). |
|
||||
|
||||
#### `[sandbox.daytona]`
|
||||
|
||||
|
|
|
|||
|
|
@ -252,9 +252,13 @@ arc cp -r <run-id>:/output ./results # recursive download
|
|||
|
||||
Run IDs support prefix matching — you can use the first few characters instead of the full ID.
|
||||
|
||||
## `arc pr create`
|
||||
## `arc pr`
|
||||
|
||||
Create a GitHub pull request from a completed workflow run. Uses the run's persisted manifest, conclusion, and diff. Requires a [GitHub App](/integrations/github) to be configured.
|
||||
Manage GitHub pull requests created by workflow runs. Requires a [GitHub App](/integrations/github) to be configured.
|
||||
|
||||
### `arc pr create`
|
||||
|
||||
Create a GitHub pull request from a completed workflow run. Uses the run's persisted manifest, conclusion, and diff.
|
||||
|
||||
```bash
|
||||
arc pr create <run-id>
|
||||
|
|
@ -268,6 +272,57 @@ arc pr create <run-id> --model claude-opus-4-6
|
|||
|
||||
The run must have completed successfully (or with partial success) and have a `final.patch` with changes.
|
||||
|
||||
### `arc pr list`
|
||||
|
||||
List all pull requests created by workflow runs. Shows PR number, title, status, and the associated run ID.
|
||||
|
||||
```bash
|
||||
arc pr list
|
||||
arc pr list --all
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `--all` | Include closed and merged PRs (default: open only) |
|
||||
|
||||
### `arc pr view`
|
||||
|
||||
Show details of a pull request from a specific run.
|
||||
|
||||
```bash
|
||||
arc pr view <run-id>
|
||||
```
|
||||
|
||||
| Argument | Description |
|
||||
|---|---|
|
||||
| `<RUN_ID>` | Run ID or prefix (required) |
|
||||
|
||||
### `arc pr merge`
|
||||
|
||||
Merge a pull request from a specific run.
|
||||
|
||||
```bash
|
||||
arc pr merge <run-id>
|
||||
arc pr merge <run-id> --method rebase
|
||||
```
|
||||
|
||||
| Argument / Flag | Description |
|
||||
|---|---|
|
||||
| `<RUN_ID>` | Run ID or prefix (required) |
|
||||
| `--method <METHOD>` | Merge method: `squash` (default), `merge`, or `rebase` |
|
||||
|
||||
### `arc pr close`
|
||||
|
||||
Close a pull request from a specific run without merging.
|
||||
|
||||
```bash
|
||||
arc pr close <run-id>
|
||||
```
|
||||
|
||||
| Argument | Description |
|
||||
|---|---|
|
||||
| `<RUN_ID>` | Run ID or prefix (required) |
|
||||
|
||||
---
|
||||
|
||||
## `arc system df`
|
||||
|
|
@ -338,6 +393,7 @@ arc diff <run-id> --stat
|
|||
| `<RUN>` | Run ID or prefix (required) |
|
||||
| `--node <NODE>` | Show diff for a specific node instead of the full run |
|
||||
| `--stat` | Show diffstat instead of full patch (live diffs only) |
|
||||
| `--shortstat` | Show only files-changed/insertions/deletions summary (live diffs only) |
|
||||
|
||||
Output is colorized when writing to a terminal.
|
||||
|
||||
|
|
|
|||
|
|
@ -1911,11 +1911,6 @@ async fn run_preflight(
|
|||
CheckDetail::new(format!("Nodes: {}", graph.nodes.len())),
|
||||
CheckDetail::new(format!("Edges: {}", graph.edges.len())),
|
||||
CheckDetail::new(format!("Goal: {}", graph.goal())),
|
||||
CheckDetail::new(format!("Model: {model}")),
|
||||
CheckDetail::new(format!(
|
||||
"Provider: {}",
|
||||
provider.as_deref().unwrap_or("anthropic")
|
||||
)),
|
||||
],
|
||||
remediation: None,
|
||||
});
|
||||
|
|
@ -2006,62 +2001,85 @@ async fn run_preflight(
|
|||
});
|
||||
}
|
||||
|
||||
// 4. LLM check (merged providers + provider parse)
|
||||
let resolved_provider = provider.as_deref().unwrap_or("anthropic");
|
||||
// 4. Per-model LLM checks
|
||||
let default_provider = provider.as_deref().unwrap_or("anthropic");
|
||||
let llm_ok = match arc_llm::client::Client::from_env().await {
|
||||
Ok(c) => {
|
||||
let names: Vec<String> = c.provider_names().iter().map(|s| s.to_string()).collect();
|
||||
if names.is_empty() {
|
||||
checks.push(CheckResult {
|
||||
name: "LLM".into(),
|
||||
status: CheckStatus::Error,
|
||||
summary: "no API keys".into(),
|
||||
details: vec![],
|
||||
remediation: Some("Set at least one LLM provider API key".into()),
|
||||
});
|
||||
false
|
||||
} else {
|
||||
match resolved_provider.parse::<Provider>() {
|
||||
let configured: Vec<String> =
|
||||
c.provider_names().iter().map(|s| s.to_string()).collect();
|
||||
|
||||
// Collect all distinct (model, provider) pairs from LLM nodes
|
||||
let mut model_providers = std::collections::BTreeSet::new();
|
||||
for node in graph.nodes.values() {
|
||||
if !crate::graph::types::is_llm_handler_type(node.handler_type()) {
|
||||
continue;
|
||||
}
|
||||
let node_model = node.llm_model().unwrap_or(&model);
|
||||
let node_provider = node.llm_provider().unwrap_or(default_provider);
|
||||
|
||||
// Resolve through catalog to get canonical model ID and provider
|
||||
let (resolved_model, resolved_provider) =
|
||||
if let Some(info) = arc_llm::catalog::get_model_info(node_model) {
|
||||
(info.id, info.provider)
|
||||
} else {
|
||||
(node_model.to_string(), node_provider.to_string())
|
||||
};
|
||||
|
||||
// Use node-level provider override if explicitly set, otherwise catalog provider
|
||||
let final_provider = if node.llm_provider().is_some() {
|
||||
node_provider.to_string()
|
||||
} else {
|
||||
resolved_provider
|
||||
};
|
||||
|
||||
model_providers.insert((resolved_model, final_provider));
|
||||
}
|
||||
|
||||
// If no LLM nodes found, fall back to the default model/provider
|
||||
if model_providers.is_empty() {
|
||||
let (resolved_model, resolved_provider) =
|
||||
if let Some(info) = arc_llm::catalog::get_model_info(&model) {
|
||||
(info.id, info.provider)
|
||||
} else {
|
||||
(model.clone(), default_provider.to_string())
|
||||
};
|
||||
model_providers.insert((resolved_model, resolved_provider));
|
||||
}
|
||||
|
||||
let mut all_ok = true;
|
||||
for (model_id, provider_name) in &model_providers {
|
||||
match provider_name.parse::<Provider>() {
|
||||
Ok(_) => {
|
||||
let mut status = CheckStatus::Pass;
|
||||
if !names.iter().any(|n| n == resolved_provider) {
|
||||
if !configured.iter().any(|n| n == provider_name) {
|
||||
status = CheckStatus::Warning;
|
||||
all_ok = false;
|
||||
}
|
||||
checks.push(CheckResult {
|
||||
name: "LLM".into(),
|
||||
status,
|
||||
summary: resolved_provider.to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"Configured: {}",
|
||||
names.join(", ")
|
||||
))],
|
||||
summary: model_id.clone(),
|
||||
details: vec![CheckDetail::new(format!("Provider: {provider_name}"))],
|
||||
remediation: if status == CheckStatus::Warning {
|
||||
Some(format!(
|
||||
"Provider \"{resolved_provider}\" not in configured providers"
|
||||
))
|
||||
Some(format!("Provider \"{provider_name}\" is not configured"))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
});
|
||||
status == CheckStatus::Pass
|
||||
}
|
||||
Err(e) => {
|
||||
checks.push(CheckResult {
|
||||
name: "LLM".into(),
|
||||
status: CheckStatus::Error,
|
||||
summary: resolved_provider.to_string(),
|
||||
details: vec![CheckDetail::new(format!(
|
||||
"Configured: {}",
|
||||
names.join(", ")
|
||||
))],
|
||||
remediation: Some(format!(
|
||||
"Invalid provider \"{resolved_provider}\": {e}"
|
||||
)),
|
||||
summary: model_id.clone(),
|
||||
details: vec![CheckDetail::new(format!("Provider: {provider_name}"))],
|
||||
remediation: Some(format!("Invalid provider \"{provider_name}\": {e}")),
|
||||
});
|
||||
false
|
||||
all_ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
all_ok
|
||||
}
|
||||
Err(e) => {
|
||||
checks.push(CheckResult {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue