Add a fabro-llm input token counting API with provider-native counting for Anthropic, Gemini, and OpenAI. Include strict fallback behavior, deterministic local estimates, count-specific request filtering, and README documentation for privacy and billing semantics.
Expose TaskGet for Claude-style task inspection, refresh Anthropic prompt and tool guidance, and remind long-running sessions to use task tracking when those tools are available.
Use raw sandbox reads for memory and skills, keep line-numbered reads focused on display, and share retry-delay handling across agent and LLM code.
Trim task tool descriptions, bound multi-file read concurrency, restore Docker's text read path, and add the reviewed implementation plan docs.
Separate raw file reads from the line-numbered display API so apply_patch and edit_file operate on unformatted UTF-8 content. Keep read_file/read_many_files model-facing output numbered and cover regressions for prefix corruption.
Replay retryable stream failures from the last committed turn state, clear partial visible output before retry or terminal failure, and map Anthropic stream error events into structured provider errors.
Modularize the Anthropic system prompt into Claude-style sections and expand TaskCreate, TaskUpdate, and TaskList descriptions with task-management guidance adapted to Fabro's tool surface.
Allow fabro_run_create object specs to pass goal_file, reject goal and goal_file together, and preserve file-sourced goal semantics when building run manifests.
Replace the four built-in Ask Fabro welcome prompts with more detailed
prompt text covering errors, performance, run flow tracing, and workflow
improvement recommendations. Card headings and descriptions are
unchanged; only the verbatim prompt sent on click is expanded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The assistant-ui markdown defaults (heading margins up to 32px,
20px paragraph margins, 24px list indent, 24px blockquote padding,
16px code padding) are tuned for the full-page Thread and waste
space in the narrow sidebar column. Scope tighter spacing to
.ask-fabro-sidebar for headings, paragraphs, lists, blockquotes,
and code blocks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The assistant-ui markdown defaults size headings up to 36px (h1),
which dominated the narrow sidebar column. Scope smaller heading
sizes to .ask-fabro-sidebar: H1 18px bold, H2/H3 14px bold, H4-H6
14px normal (no special styling).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Show a "How can I help?" heading and four example prompt cards on the
empty Ask Fabro thread. Cards span four themes — errors, performance,
key decisions, and suggested improvements. Each card is a
ThreadPrimitive.Suggestion that sends its prompt on click, starting the
session via the existing lazy ensureSession() flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose only policy-allowed tool schemas to the model and block hidden tool calls before executor lookup. Give Ask Fabro a run-scoped read-only policy and prompt so it only advertises tools it can actually use.
Add a drag handle on the left edge of the docked Ask Fabro panel. The
user can widen the panel up to 2x its default width and no narrower than
the default. The chosen width persists across open/close.
An `isResizing` flag on the layout context lets `<main>` and the steer
bar drop their width transitions during a drag so the layout tracks the
cursor instead of trailing it.
Also bundles in-progress sidebar wiring: a collapsed tool-call summary
renderer and the remark-gfm dependency for GitHub-flavored Markdown.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## What
Makes the run-detail stage sidebar (shown on the Overview and Stages
tabs) collapsible with a slide animation.
- A toggle button slides the panel between full width (`w-56`) and an
icon-only rail (`w-12`), animating `width` over 300ms with the same
easing as the Ask Fabro panel.
- When collapsed, **stage status icons stay visible** — green check /
red X / spinning teal for running — so run progress is still scannable
at a glance. Workflow links (Graph Source, Run Logs, etc.) collapse to
icons too so they remain reachable.
- Labels and durations become `sr-only` with `title` tooltips for hover.
- The open/closed choice persists to `localStorage`
(`fabro:stage-sidebar-collapsed`), carrying across the Overview and
Stages tabs and reloads.
## Layout
- The collapse toggle is inline with the `STAGES` heading row (or
`WORKFLOW` when a run has no stages yet), so it doesn't push the stage
list down.
- The stage sidebar's top padding on the Stages tab was reduced (`pt-6`
→ `pt-3`) so the heading aligns with the adjacent content column and
sits closer to the tab nav.
## Notes
Self-contained in `StageSidebar` — `run-overview.tsx` and
`run-stages.tsx` render it inside flex layouts that already track its
width, so the slide works in both with no parent changes (aside from the
padding tweak).
Verified: `tsc` typecheck passes; `stage-sidebar` lib tests pass
(10/10).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: fabro-sh-0530[bot] <281434857+fabro-sh-0530[bot]@users.noreply.github.com>
Co-authored-by: Fabro <noreply@fabro.sh>
Fabro run tools are now gated behind an explicit per-run opt-in so
workflow agents only receive those capabilities when the run requests
them.
## What changed
- **`fabro_tools` setting** (`run.agent.fabro_tools`, default `false`)
is resolved through the existing TOML config layer stack.
- **Worker JWT scope** adds `agent:run_tools` only when the resolved
setting is `true`; default worker tokens carry only `run:worker`.
- **Worker tool registration** derives from the worker JWT scope claim.
The CLI worker locally decodes the token payload and registers
`FabroRunToolServices` only when the scope includes both `run:worker`
and `agent:run_tools`.
- **Server-side authorization remains authoritative**. The worker-side
decode is only a local tool-registration gate; the server still
validates token signature and scopes before accepting run-tool API
calls.
> **Behavior change:** existing runs that relied on Fabro run tools
being always available must add `[run.agent] fabro_tools = true` to
their workflow config.
## Verification
```sh
cargo +nightly-2026-04-14 fmt --all
cargo test -p fabro-cli fabro_run_tools_enabled_token_requires_run_tools_scope
cargo test -p fabro-server worker_command_
cargo test -p fabro-static
cargo +nightly-2026-04-14 clippy -p fabro-cli -p fabro-server -p fabro-static --all-targets -- -D warnings
git diff --check
```
---------
Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
## Summary
OpenAI-profile agents now receive `apply_patch` as a Codex-compatible
freeform custom tool instead of a JSON function with a `patch` field.
The model sends raw patch text validated by the vendored Lark grammar,
and Fabro round-trips OpenAI custom tool calls/results through the
Responses API.
## What Changed
- Added `fabro-llm` support for function and custom tool definitions
while preserving existing JSON function behavior for normal tools.
- Translated OpenAI custom tool calls, custom tool outputs, and
streaming `response.custom_tool_call_input.delta` events into Fabro tool
calls with raw arguments.
- Ported the Codex apply-patch grammar and adapted Codex-style patch
parsing/application semantics to Fabro's `Sandbox` trait, including
strict envelopes, fuzzy context matching, move/delete/add/update
behavior, trailing-newline normalization, and Codex-style
summaries/errors.
- Updated OpenAI agent prompt/tool registration so `apply_patch` is
freeform, and skipped JSON-schema validation/repair for custom tool
calls only.
- Updated file tracking to read Codex-style `A`/`M` result lines from
successful patch output.
## Verification
- `cargo nextest run -p fabro-llm -p fabro-agent`
- `cargo +nightly-2026-04-14 fmt --check --all`
- `cargo +nightly-2026-04-14 clippy --no-deps -p fabro-llm -p
fabro-agent --all-targets -- -D warnings`
- `git diff --check`
Note: the full non-`--no-deps` clippy command still surfaces an
unrelated existing `fabro-sandbox` `large_enum_variant` warning in
`lib/crates/fabro-sandbox/src/sandbox_spec.rs`.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
## Summary
Ships the Ask Fabro sidebar on run pages end-to-end: the agent now has
live `fabro_run_interact` and `fabro_run_events` tools scoped to its
owning run, and the web sidebar talks to real session APIs instead of a
scripted adapter. The `?ask=1` prototype gate is dropped in favour of
server-reported `run.ask_fabro.available`.
## What changed and why
### Rust — run-control tools in Ask Fabro sessions (`fabro-server`,
`fabro-workflow`, `fabro-tool`)
**Tool registration** (`fabro-workflow`): `register_fabro_run_tools` is
now `pub`; a new `register_named_fabro_run_tools` variant accepts a name
allowlist so callers can register a subset without forking the catalog
loop. Unknown names are silently ignored.
**Run-scoped backend** (`fabro-tool`): `ClientBackend` gains a
`run_scope: Option<RunId>` field set via `.with_run_scope(run_id)`.
Every method checks the scope before delegating to the HTTP client,
returning an error before a network call is made. `list_store_runs`
returns a single-element vec of the owning run when scoped;
`resolve_run` rejects non-parseable selectors rather than forwarding
them.
**Session wiring** (`fabro-server`): `build_profile` now returns
`Box<dyn AgentProfile>` (mutably accessible) instead of `Arc`;
`build_agent_session` mints a same-run worker token, builds a
`ClientBackend::with_run_scope`, constructs `FabroRunToolServices`, and
calls `register_named_fabro_run_tools` for the two tools before freezing
into an `Arc`. `AppState::self_server_target()` reads the bound address
from the runtime daemon record for the loopback HTTP call.
**Approval gate**: `build_ask_fabro_tool_approval` now fast-paths
`fabro_run_interact` and `fabro_run_events` to `Ok(())`; all other tools
remain subject to the `ReadOnly` auto-approve check. File/shell tools
are still denied.
### Web — real session adapter and sidebar wiring (`fabro-web`)
**`ask-fabro-runtime.ts`** (new): a `ChatModelAdapter` that creates a
session lazily on the first turn (`sessionsApi.createRunSession`),
caches the session id in `sessionStorage` keyed by run id, and streams
turns via `streamSessionTurn`. `applyTurnEvent` maps `run.session.*` SSE
events to assistant-ui `ThreadAssistantMessagePart[]` incrementally
(text deltas, tool-call started/completed pairs). A 404 on stream clears
the cached id so the next turn starts fresh.
**`ask-fabro-sidebar.tsx`**: drops `scriptIndexRef`, `EMPTY_CHAT`, and
the scripted adapter import; accepts `runId` and `defaultModel` props;
constructs the real adapter via `createAskFabroAdapter`.
**`run-detail.tsx`**: removes `?ask=1` / `askEnabled`; reads
`run.ask_fabro.{available, default_model}` from the summary; always
renders an `AskFabroTriggerButton` (disabled with a tooltip when
unavailable); passes `runId` and `defaultModel` to `<AskFabroSidebar>`.
### Architecture
```mermaid
graph TB
Browser -->|SSE turn stream| SessionsHandler
SessionsHandler -->|spawn| AskFabroAgent
AskFabroAgent -->|fabro_run_interact\nfabro_run_events| ClientBackend
ClientBackend -->|HTTP + same-run\nworker token| RunsAPI[Runs API\n/runs/:id]
ClientBackend -->|run_scope check| ClientBackend
RunsAPI -->|403 cross-run| ClientBackend
```
### Design decisions
- **Same-run scoping is double-enforced**: the `ClientBackend` scope
check fires before the HTTP call; the worker token's run scope causes a
403 at the API layer if the check were somehow bypassed.
- **`build_profile` → `Box` not `Arc`**: the profile needs mutable
access for tool registration after construction, so the `Arc` wrapping
is deferred until registration is complete.
- **`sessionStorage` per-run**: one session is reused across sidebar
open/close cycles for the same run tab; a page reload or different run
always starts clean.
- **Mutating actions included**: `interact` exposes
start/cancel/steer/archive/answer. This is intentional per the locked
decisions; the worker-token scope prevents cross-run blast radius.
### Fabro Details
<details>
<summary>Ran 9 stages in 74m 52s for $44.11</summary>
| Stage | Duration | Cost | Retries |
|---|---|---|---|
| start | 0s | – | 0 |
| toolchain | 1s | – | 0 |
| preflight_compile | 2m 11s | – | 0 |
| preflight_lint | 2m 22s | – | 0 |
| implement | 38m 37s | $32.02 | 0 |
| simplify_opus | 17m 40s | $6.55 | 0 |
| simplify_gpt | 9m 32s | $5.55 | 0 |
| verify | 3m 43s | – | 0 |
| fmt | 3s | – | 0 |
| **Total** | **74m 52s** | **$44.11** | **0** |
</details>
<details>
<summary>Ran <code>ImplementPlan.fabro</code> (12 nodes and 15
edges)</summary>
```dot
digraph ImplementPlan {
graph [
goal="Implement and simplify",
model_stylesheet="
* { model: claude-opus-4-7; }
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0]
preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check -q --workspace 2>&1", max_retries=0]
preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1", max_retries=0]
fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3]
implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD."]
simplify_opus [label="Simplify (Opus)", prompt="@prompts/simplify.md"]
simplify_gpt [label="Simplify (GPT-55)", prompt="@prompts/simplify.md", model="gpt-55"]
verify [label="Verify", shape=parallelogram, script="cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1 && cargo dev docs refresh 2>&1 && cargo dev docs check 2>&1", goal_gate=true, retry_target="fixup"]
fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings, test failures, and generated docs errors.", max_visits=3]
fmt [label="Format", shape=parallelogram, script="cargo +nightly-2026-04-14 fmt --all 2>&1", max_retries=0]
start -> toolchain
toolchain -> preflight_compile [condition="outcome=succeeded"]
toolchain -> exit
preflight_compile -> preflight_lint [condition="outcome=succeeded"]
preflight_compile -> exit
preflight_lint -> implement [condition="outcome=succeeded"]
preflight_lint -> fix_lints
fix_lints -> preflight_lint
implement -> simplify_opus -> simplify_gpt -> verify
verify -> fmt [condition="outcome=succeeded"]
verify -> fixup
fixup -> verify
fmt -> exit
}
```
</details>
⚒️ Generated with [Fabro](https://fabro.sh)
---------
Co-authored-by: Bryan Helmkamp <bryan@brynary.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Fabro <noreply@fabro.sh>
Co-authored-by: fabro <fabro@example.com>
Co-authored-by: fabro <fabro@fabro.sh>
## Summary
This branch improves several run-management surfaces that agents and
users rely on: archived runs now stay visible and ordered correctly in
the board view, pair-session messages appear in the stage Thread tab,
and the `fabro_run_create` MCP tool accepts the workflow-string
shorthand it advertises.
## Changes
- Updates the web board cache invalidation and archived-column handling
so archive/unarchive actions refresh both active and archived board
queries and keep archived runs in a predictable column position.
- Adds pair user/system message events to stage activity parsing, Thread
rendering, search, details, and DNA timeline items.
- Aligns `fabro_run_create` MCP runtime deserialization and `tools/list`
schema so each run entry may be either a workflow string or a full
create spec object.
## Test Plan
- `cargo nextest run -p fabro-tool -p fabro-mcp-server`
- `cargo nextest run -p fabro-cli
stdio_server_initializes_and_lists_run_tools
mcp_create_string_shorthand_deserializes_before_auth
mcp_create_validation_errors_happen_before_auth_or_network
mcp_create_and_search_manage_real_runs_with_cli_auth`
- `cargo +nightly-2026-04-14 fmt --check --all`
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
Adds the run-backed API surface needed for a real Ask Fabro sidebar: run
readiness metadata, detailed session projections, session-scoped event
listing/attach streaming, and turn control that exposes durable turn IDs
and machine-readable failures.
## What Changed
- Extended the OpenAPI contract and regenerated Rust/TypeScript clients
for `Run.ask_fabro`, `SessionDetail`, `SessionTurn`, paginated run
sessions, session event APIs, and optional client-supplied `turn_id`
values.
- Updated `fabro-types` and `fabro-store` so durable `run.session.*`
events project active turn state, transcript messages, and the latest
owning run event sequence.
- Implemented server routing for session details, `/events`, `/attach`,
turn conflict headers, typed turn failure codes, and cheap run readiness
decoration across run responses.
- Added browser helpers for POST turn streaming and session attach SSE
parsing, plus an exported generated `sessionsApi`.
## Verification
- `cargo +nightly-2026-04-14 fmt --check --all`
- `cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D
warnings`
- `cargo build --workspace`
- `cargo test -p fabro-types
run_session_turn_failed_defaults_code_for_old_events`
- `cargo test -p fabro-store run_sessions::tests`
- `cargo test -p fabro-api`
- `cargo test -p fabro-server --features test-support --test it
api::sessions`
- `cargo test -p fabro-server --features test-support --test it
api::runs`
- `cd apps/fabro-web && bun test app/lib/session-stream.test.ts`
- `cd apps/fabro-web && bun run typecheck`
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 Codex (context unknown, medium reasoning) via
[Codex](https://openai.com/codex/)
## What
Adds a **Context** tab to the stage detail view
(`/runs/:id/stages/:stageId`), beside the existing primary tab (Thread /
Logs / …) and Debug tab.
It surfaces a stage's *deliberate per-visit outputs* — the data the
workflow author makes a stage write into shared context, plus the
routing hints it emitted:
- **Routing** — `preferred_label` and `suggested_next_ids`
- **Context writes** — author-set `context_updates` keys
This data flow was previously invisible in the UI, which made it hard to
debug "why did the next stage get the wrong input / take the wrong
edge".
## Why no backend change
The per-visit `stage.completed` event already carries `context_updates`,
`preferred_label`, and `suggested_next_ids`, and the web UI already
fetches it via `useRunStageEvents`. The checkpoint's `node_outcomes` map
was rejected as a source: it is keyed by `node_id` only, so it is lossy
across visits (`implement@2` would overwrite `implement@1`).
## How
- `extractStageContext` (in `stage-renderers/helpers.ts`) reads the
`stage.completed` event and filters `context_updates` through an
engine-key denylist: `last_stage`, `last_response`, `response.*`,
`internal.*`, `current.*`, `command.output`, `human.gate.*`,
`parallel.*`. Those are bookkeeping or already shown in the stage's
primary tab.
- It returns `null` when nothing is left, so the tab stays
**conditional** — same pattern as Thread/Logs. It only appears when a
stage actually wrote something deliberate.
- New `stage-context.tsx` renders the result, reusing `CodeBlock` /
`JsonBlock`.
- `run-stages.tsx` gains a dynamic `availableTabs` list; `effectiveTab`
falls back to `primary` gracefully when the Context tab is absent.
## Verification
- `bun run typecheck` clean, `bun test` — 412 pass / 0 fail (4 new tests
for the denylist + routing extraction).
- Live run `01KS5WBZAE7K8321NHR7KFAHF9` (`context-demo` workflow): the
`emit@1` stage emitted `demo.greeting` / `demo.answer` / `demo.payload`
plus `preferred_label: "Done"` and `suggested_next_ids: ["exit"]`, and
the Context tab rendered them correctly.
## Notes
- The second commit adds a small `context-demo` workflow used for that
verification — kept separate so it can be dropped independently.
- Known limitations (acceptable for v1): data is read from
`stage.completed` only, so a stage ending in `stage.failed` shows no
tab; parallel stages write `parallel.*` directly to context
(denylisted), so they show no tab.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
API-backed Fabro agent sessions can now use the same five run-control
tools that were previously MCP-only, while the server uses a single
scoped `FABRO_WORKER_TOKEN` path for worker authorization. This lets
server-dispatched API agents create, gather, inspect, and interact with
runs without reintroducing a separate delegated run-agent token or
leaking credentials into sandboxed child environments.
## Changes
- Moved the reusable run-tool implementation into the new `fabro-tool`
crate so MCP and API agent backends share the same tool schemas and
client behavior.
- Registered the five `fabro_run_*` tools for API-mode agents, with ACP
sessions continuing to omit those tools.
- Replaced `FABRO_RUN_AGENT_TOKEN` with scoped worker-token auth: base
worker tokens keep same-run access, and `run:worker agent:run_tools`
tokens can call the run-control API across runs.
- Added server auth guards for run-tool actors and
run-scoped-or-run-tools routes, then applied them only to the routes
used by the run-tool client backend.
- Kept `FABRO_WORKER_TOKEN` scrubbed from sandbox commands, hooks, ACP
subprocesses, MCP env providers, and other child tool environments.
## Testing
- `cargo nextest run -p fabro-server worker_token principal_middleware
spawn_env --no-fail-fast`
- `cargo nextest run -p fabro-cli runner --no-fail-fast`
- `cargo nextest run -p fabro-workflow agent_run --no-fail-fast`
- `cargo nextest run -p fabro-static --no-fail-fast`
- `cargo +nightly-2026-04-14 fmt --check --all`
- `cargo +nightly-2026-04-14 clippy -p fabro-server -p fabro-cli -p
fabro-static --all-targets -- -D warnings`
- `git diff --check`
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
## Summary
Adds the prototype Ask Fabro docked sidebar to run detail pages behind
`?ask=1`, with app-shell layout coordination so opening the sidebar
shifts content instead of covering it. The branch also improves settings
visibility with active run concurrency on Resources and a Project
Management integrations placeholder.
## Changes
- Add a shared Ask Fabro layout context so the app shell can inset main
content by the docked sidebar width.
- Gate the run detail Ask Fabro button and sidebar behind `?ask=1`,
keeping the bottom steer/interview bar aligned while the sidebar is
open.
- Poll system info on the Resources page to show active runs against the
scheduler limit.
- Add a Project Management panel with Linear marked as coming soon.
## Verification
Not run; PR opened from the existing branch without changing code.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 (unknown context, medium reasoning) via
[Codex](https://openai.com/codex)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The left sidebar tracked when it first *observed* a running stage
(Date.now() on mount) instead of the stage's actual startedAt, so the
duration reset to 0s on every page load.
Compute elapsed time directly from stage.startedAt via a shared
elapsedSecsSince helper, dropping the runningStartRef tracking. The
stage meta bar already did this correctly but with a duplicated parser;
fold it onto the same helper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes Daytona sandbox network policy rendering so absent allow lists
with `networkBlockAll=false` are reported as open egress instead of
unknown, while Daytona ingress is always reported as blocked.
The mapper still reports blocked egress when Daytona blocks all
networking and CIDR allow-list egress when `networkAllowList` is
present. Tests cover blocked, allow-list, empty allow-list, and default
Daytona network data.
Verified with `cargo nextest run -p fabro-sandbox --features daytona`
and `cargo +nightly-2026-04-14 fmt --check --all`.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
`bun run generate` (openapi-generator typescript-axios) emits trailing
spaces and extra blank lines, so every regeneration produced a noisy
whitespace diff that masked real spec/client drift.
Add a normalize-generated.ts post-generation pass that strips trailing
whitespace and ends each file with exactly one newline, and chain it
into the `generate` script. Establishes the normalized baseline across
the generated client; running `generate` twice now yields no diff.
No content changes — the entire diff is whitespace.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hovering the run header items now reveals a popover with extra
context:
- Run status: failure reason and error message for failed runs;
archived timestamp for archived runs (no popover otherwise)
- Repository: full owner/repo name and the cloned branch
- Workflow: node and edge counts plus run labels
- PR: live GitHub details fetched lazily on hover — title, an
open/draft/merged/closed badge, and the head -> base branch arrow
Workflow node/edge counts are new: WorkflowRef now carries
node_count/edge_count, computed in build_summary from the parsed
graph that is already in hand there.
Adds a HoverCard primitive alongside Tooltip (shared useHoverAnchor
hook) for rich, viewport-aware popovers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hovering any token count on the run billing page now reveals a
popover splitting the `in / out` figure into its disjoint buckets:
cache read, cache creation, uncached input, and output. The data was
already in the billing response; only the UI lacked the breakdown.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User message bubbles used the muted token (panel-alt), which composites
almost identically to the translucent bg-panel/40 sidebar — bubbles
visually disappeared into the column. Give them a solid panel surface so
they read as raised cards.
Also drop the composer's horizontal margin so the pill spans the full
sidebar width.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Sandbox cell now renders a colored status dot before the resource
summary, with a tooltip explaining the state on hover. The dot reuses
the data already fetched for CPU/memory, so no new API call. Falls back
to the state label when resources are unavailable.
Lifts the per-state display map into a shared lib/sandbox-state module
so the overview panel and the dedicated sandbox page stay consistent.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The mount point added little over the storage path it already shows.
Remove it; the Storage root panel keeps Path, Fabro managed, and
Reclaimable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Large GiB values rendered without separators (2173 GiB). Format the
numeric part with toLocaleString so it reads 2,173 GiB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>