The plugin supervisor now answers to the configured kind, which fabro's
plugin test expects of the provider it holds.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The driver branch gained equality on statuses and events, a git failure
that says when a command timed out, and lost the misleading
GitAttempt::succeeded; nothing in fabro used the method.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The driver's section-4-driver-items branch (lithoscomputer/sandbox-driver#20)
carries the provider-owned scopes, the supervisor as provider, Host attach
by directory, the BASH_ENV launch rule, git retry and verbs, the status
image/snapshot/network split, Daytona snapshot caching in create, the
services port verbs, and RFC 3339 wire timestamps. This commit only moves
the pin and follows the two API changes that no longer compile: the status
projection reads image and snapshot instead of source, and the plugin
supervisor is launched rather than constructed. The deletion rounds follow
one item per commit.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The driver branch adds `Git::set_ambient_credentials`, classifies a
missing `git` executable as `GitFailureKind::GitUnavailable`, and runs
Daytona's pinned clones through the derived clone after a new
conformance check caught the toolbox pin failing. The project notes
follow the last change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both sides rewrote the same crates. This branch replaced fabro's sandbox
layer with the sandbox driver: one RunSandbox, no Sandbox trait, driver
events consumed directly, MockSandbox over the driver's doubles. Main
replaced fabro's LLM layer with lithos-llm: fabro-model deleted, the
catalog and provider ids from lithos, credentials through the lithos
CredentialProvider, clients built with build_client.
Every conflict was one of those two renames meeting in an import list or
a signature, so the rule was mechanical: sandbox names resolve to this
branch, LLM names to main. Where main's newer code still used the old
sandbox API — new session tests over Arc::new(MockSandbox), the SDK
example's LocalSandbox, test fakes typed as Arc<dyn Sandbox> — it is
ported to RunSandbox and the mock helper. Where this branch still used
fabro-model or Client::from_source, main's replacement stands. One
combined future in the CLI runner crossed clippy's size budget and is
boxed at its call.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pull request #18 on the driver is merged as a merge commit, so the
commit fabro was pinned to is an ancestor of main. Follow main.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fabro's run-branch setup and its pushes were the last git it assembled
by hand: two rev-parse calls, a checkout -B, and a push built as shell
and run through exec. Because those failures never passed through the
driver, fabro kept a second classifier that read git's stderr for the
same auth and not-found shapes the driver already classifies for a
clone.
Both now call the facet. Setup reads the current branch and head commit
from the driver's status and creates or moves the run branch at that
base; a push sends its refspec with what remains of the retry plan's
attempt budget as the push timeout. The retry plan, the credential
lease, and the drift repair stay as they were — they are fabro's
policy — but the decision they act on comes from the driver's failure
class, the same way the clone's does. The output-shaped classifiers and
the auth hint matchers are deleted; the message classifier remains for
the host-side repository probe and metadata push, which never run
inside a sandbox. A git failure's captured output now renders as the
attempt's output tail, as an exec failure's did.
The driver pin moves to lithoscomputer/sandbox-driver#18, which adds the
push refspec and timeout, the checkout start point, and the status head
this relies on.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Delete fabro-llm's attachments, reasoning, and structured modules and
the LlmError newtype and ErrorFacts trait. lithos-llm now provides all
of them: InlineLocalFiles under the local-files feature, ReasoningOutput
with Response::reasoning(), Client::complete_object, and the retry,
auth, cancel, and failover predicates directly on Error and ErrorData.
fabro-llm keeps only failure_signature_hint, which is Fabro's own loop
detection policy.
Store ErrorData directly in the agent and workflow error enums, boxed
where the variant would otherwise dominate the enum size. Repin
lithos-llm to a1e3fd3 for these additions.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lithos-llm ba2f418 adds provider readiness, catalog queries, error policy
predicates, one-call structured output, local-file inlining, the reasoning
normalizer, the nearest supported effort, and built-in provider ids. Every
addition is additive, so this pin changes nothing yet; the commits that
follow adopt each one and delete Fabro's copy.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The second-wave driver work — the tag pin, classified git failures, the
stop ladder, snapshot ensure, owner scoping, and the testing crate — is
merged as pull requests #10 through #15, so fabro follows the merge
commit on main instead of the head of the open stack. The content is
the same; the commits were rebased, so every hash changed.
CI installs the driver's plugin executables at the rev it reads from
Cargo.toml, so this also moves the executables the plugin scenarios run.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fabro carried its own Sandbox trait long after every implementation
became a thin layer over the sandbox driver: one production type
implemented it, a delegation macro forwarded it, and each consumer crate
kept hand-written fakes of its thirty methods for tests. The trait
existed to be mocked, and the mocks pinned behavior that no provider
had — canned walk listings that ignored the traversal root, opaque
provider paths, activation failures with no lifecycle behind them.
There is now one sandbox type. RunSandbox keeps fabro's semantics — path
resolution against the run's working directory, the Bash exec policy,
git setup and push, credential refresh — as inherent methods over the
driver's exec, filesystem, search, and git facets, and every consumer
takes Arc<RunSandbox>. The directory, grep, and walk types are the
driver's own, re-exported from fabro-sandbox. The exec policy reports
the provider's measured duration rather than its own clock.
Tests script a sandbox through fabro-sandbox's MockSandbox: a struct of
fields (seeded files, the result every command returns, the platform,
a runtime directory) that hands out a RunSandbox over the driver's
scripted doubles and reads back what the code did — commands, timeouts,
environment, term stops, writes, deletes, existence probes. The
hand-written fakes in fabro-agent, fabro-acp, fabro-hooks,
fabro-workflow, and fabro-server are gone; the one wrapper a git
integration test still needs sits at the driver level, hiding a path
from a real Host sandbox. The refresh-ahead loop takes the refresh as a
closure so its schedule is tested without a sandbox at all.
The driver pin moves to the testing-crate stack head, which gained the
double behavior these ports needed: retention caps on scripted output,
canned walks narrowed to the requested base, upload and download on the
memory filesystem, and recorders for deletes, existence probes, and
term stops. One test that modelled a provider handing back opaque object
paths from a walk is removed: the driver contract has no such thing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sandbox-driver stack fabro pins now carries five things fabro used
to do itself, so fabro stops doing them. A tag pin is a clone option,
so the exec-based init, fetch, and checkout path for tags is gone and
every pin goes through the driver's clone; the shell command builders
and the hermetic git proofs that only served that path go with it. The
driver classifies every git failure it produces, so the retry module
keeps only the decision (a rejected credential is retried while a fresh
App token may still be replicating; an unreachable remote is retried
whatever the credential; everything else is permanent) and its hint
tables are gone. The provider runs the TERM, grace, KILL ladder for the
timeout and for the caller's cancellation, so the exec wrapper sets the
grace on the spec, passes the cancellation token as the term stop, and
reads the driver's verdict instead of racing its own timer. Daytona's
snapshot is ensured by the driver, so the list, activate, create, and
poll sequence and its back-off loop are gone. Every provider is
connected through the driver's ownership scope, narrowed to the run when
one is known, so creates carry fabro's labels and attaches to anything
else are refused by the driver; the label module keeps only the label
names, and the inventory provider reads the scope's answers instead of
checking labels itself.
The pin moves to the stack head with the driver's fix for a command
that honours the TERM inside the grace, which fabro's own tests caught
as a timeout reported as a cancellation. The Docker checkpoint
integration tests now create their container through the driver, since
the driver attaches only to containers it created; they were reaching
for a hand-run container since the Docker cutover.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The plugin scenarios launched two executables fabro built itself,
`fabro-sandbox-host` and `fabro-sandbox-docker`, that only wrapped the
driver's providers in a stdio server the driver already ships as
`sandbox-driver-host` and `sandbox-driver-docker`. Fabro now finds the
driver's executables on PATH: CI installs them at the rev the workspace
pins, read from Cargo.toml so the plugins and the in-process providers
are one build, and a developer installs them the same way. The plugin
proof in fabro-sandbox skips without the executable unless the CI
environment forbids skipping; it was also never running in CI, which
ran it under `--run-ignored only` although it is not ignored, so the
job now runs it on its own.
The pin moves to the head of the sandbox-driver PR stack #9 through
#15: tag pins, classified git failures, the stop grace ladder, snapshot
ensure, the ownership scope, and the testing doubles, which the next
commits adopt. The `sandbox-driver-testing` crate joins the workspace
dependencies for them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sandbox-driver PR #9 removes the check that a plugin's declared kind match
the configured one: an operator who configures a path and pins its
checksum has already chosen the executable, so the configured kind is
fabro's name for whatever it serves. With that in the driver, fabro no
longer needs plugin settings on a bundled kind to reach Docker over the
wire. Bundled kinds reject plugin keys again, `connect_provider` links a
bundled kind in-process and launches everything else, and the CLI
scenarios run the Docker executable under the non-bundled `docker-plugin`
kind. The driver pin moves to the PR head until it merges.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The `daytona` provider kind now maps onto the sandbox-driver Daytona
provider instead of fabro's own SDK client. Fabro keeps what is its own:
the HMAC-named snapshot built from the environment's image or Dockerfile,
the explicit 120 minute auto-stop default, the managed labels that gate
destructive operations, the clone decision and layout, and push
credentials. The driver creates the sandbox, clones natively, and serves
exec, files, search, terminal, SSH, preview, and VNC through its facets.
- `daytona.rs` builds the driver `SandboxSpec` (snapshot source,
`/home/daytona/workspace`, labels, timers, network policy, run name),
ensures the snapshot through the driver `SnapshotProvider`, attaches by
persisted id with fabro's label guard, and probes credentials through
the provider health check under fabro's 20 second budget.
- `DriverSandbox` gains a create plan that settles the spec right before
the provider call, records the snapshot a sandbox came from, and
reports the provider console URL on `Ready`.
- Terminals use the driver `Pty` facet; the server's SSH, preview, and
VNC endpoints use the `SshAccess`, `PreviewUrls`, and `Vnc` facets
through the driver-typed reconnect. The preview endpoint now answers
for every provider with a preview facet, so the local sandbox returns
its loopback URL.
- Daytona credentials travel as `DaytonaCredentials` built from the
vault key plus configured URL and organization; nothing reads the
process environment implicitly. The inventory registry uses the shared
`DriverInventoryProvider`.
- The SDK-based `daytona/mod.rs`, `provider/daytona.rs`, the Daytona
terminal, the `daytona` cargo feature, and the direct daytona-sdk,
git2 (in fabro-sandbox), tungstenite, and rustls dependencies are
gone. The live Daytona tests run against the driver-backed sandbox.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add lithos-llm as a pinned git dependency and replace the in-repo
`test/twin/openai` crate with the published `twins` revision that
lithos-llm verifies its codecs against. Move the Fabro policy overlay
(`fabro-policy.toml`) into fabro-llm so Fabro owns its own catalog
policy layer.
Drop the twin-openai nextest overrides and CI package filter now that the
crate is no longer a workspace member.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fabro's Docker provider kind now maps onto the sandbox-driver Docker
provider instead of its own bollard implementation. Fabro keeps what is
its own: the clone decision and repository layout, the GitHub App push
credentials embedded in origin, git retry classification, the managed
labels that gate destructive operations, and the run-facing events.
- `clone.rs` performs fabro's clone over the driver `Git` and `Exec`
facets. An exact commit goes through the driver's pinned clone; a tag
pin runs fabro's init/fetch/attach sequence through `Exec` so the
fully qualified tag ref is the only revision consulted. Network
failures retry through `git_retry`, which now classifies driver errors
(exec output, provider retryability) and never replays an operation
whose outcome is unknown.
- `DriverSandbox` gains a pending-create state, a `RepoWorkspace` with
push-credential state, path resolution against the cloned working
directory, git lifecycle methods, image-pull progress mapped from
driver events, and an embedded terminal over the driver `Pty` facet.
- `docker.rs` builds the driver `SandboxSpec` (image, `/workspace`,
fabro labels, env, cpu/memory, network policy, run name) and attaches
by persisted container id, refusing containers without fabro's labels.
- Inventory, details, diagnostics, terminal, and reconnect run over the
driver: a `DriverInventoryProvider` lists by fabro's managed label and
projects `SandboxStatus` into fabro's inventory and details shapes.
- The bollard-based `docker.rs`, `provider/docker.rs`, Docker terminal,
Docker error variants, the `docker` cargo feature, and the bollard and
tar dependencies are gone. The Docker integration tests, the agent
shell test, the workflow artifact test, and the driver benchmark run
against the driver-backed sandbox.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fabro pins the sandbox-driver workspace the same way it pins the
Daytona SDK: every crate at one commit on main. The bundled Host,
Docker, and Daytona provider libraries link in-process, and the
protocol crate reaches third-party providers over stdio. Nothing uses
the crates yet; the following commits move fabro onto them one layer
at a time.
The driver pins tracing-subscriber exactly, so the lockfile settles on
that version for the whole workspace.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both fabro and sandbox-driver now pin the same daytona-sdk-rust commit
on main. The newer SDK adds region and sandbox class fields to snapshot
creation; fabro leaves both unset and keeps its current behavior.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>