Commit graph

446 commits

Author SHA1 Message Date
Bryan Helmkamp
8f48aa8b64
docs(digital-ocean): replace stub with Droplet + compose guide
App Platform has no persistent volumes, so Fabro's /storage directory
rules it out. Documents the Droplet path instead, using the existing
docker-compose.prod.yaml + Caddy setup for automatic TLS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:20:01 -04:00
Bryan Helmkamp
484a3dbc39
feat(fly): add fly.toml and full deploy guide
fly.toml points Fly directly at ghcr.io/fabro-sh/fabro:nightly (no
builder step), pins internal_port to 32276 since Fly does not inject
$PORT, declares a Volume mount at /storage, and disables autostop so
the run queue stays live under no HTTP traffic.

Replaces the deploy-fly-io.mdx stub with a CLI-first walkthrough
covering volume creation, secrets, dev token retrieval, and the
single-Machine / single-Volume caveats that apply to Fabro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:15:13 -04:00
Bryan Helmkamp
36e51237d4
docs(render): replace stub with full deploy guide
Documents the render.yaml blueprint flow end-to-end: one-click deploy,
disk verification, env vars, dev token retrieval, and the same
single-replica / amd64-only caveats as the Railway guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:08:18 -04:00
Bryan Helmkamp
8da81fdf9e
fix(release): build musl targets via cargo-zigbuild to fix arm64 SIGSEGV
The shipped aarch64-unknown-linux-musl binary segfaulted at startup on
every arm64 runtime (Apple Silicon, Graviton, Ampere, Docker arm64).
Root cause: a glibc-vs-musl .init_array calling-convention mismatch --
a C static library in the dep graph has an __attribute__((constructor))
that expects (argc, argv, envp) per glibc, but musl on aarch64 calls
it with no args, so register garbage propagates into pointer arithmetic
and faults before main runs.

Switch the musl compile steps to cargo-zigbuild (zig 0.13.0). Zig's
bundled cc + lld produce working static-PIE binaries for both musl
targets, sidestepping Ubuntu musl-tools' -no-pie quirk and the
init_array ordering that triggered the crash. Drop the CARGO_TARGET_*
linker overrides and the musl-tools apt install -- zig handles both.

bin/dev/docker-build.sh mirrors the same toolchain so the local Docker
image build matches CI.

Verified by running fabro version from the resulting arm64 image on
ghcr.io/fabro-sh/dhi-alpine-base:3.23-dev, alpine:3.22, and
debian:stable-slim -- all print the version banner with exit 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:01:45 -04:00
Bryan Helmkamp
8e4693ad8c
chore(docker): switch base to DHI Alpine, add cross-arch build support
Runtime image now builds FROM ghcr.io/fabro-sh/dhi-alpine-base (Docker
Hardened Images mirror, Alpine 3.23) instead of alpine:3.22. Same
runtime shape, CVE-minimized base. Changelog updated to reflect the
DHI migration.

bin/dev/docker-build.sh grows --arch {amd64,arm64} and --compile-only
flags so local multi-arch verification works regardless of host arch.
Cargo target cache is now per-arch to prevent arm64/amd64 artifacts
from stomping each other in one shared volume.
2026-04-18 15:42:23 -04:00
Bryan Helmkamp
184cddf8e0
feat(railway): deploy from prebuilt GHCR image instead of source build
Add Dockerfile.deploy as a thin wrapper that pulls
ghcr.io/fabro-sh/fabro:nightly, and point railway.toml at it. Railway
now skips Rust compilation entirely and deploys in seconds. The
upstream image already configures entrypoint, $PORT-aware CMD, volumes,
and the unprivileged fabro user, so nothing else is needed in the
wrapper.

Update docs/administration/deploy-railway.mdx to reflect the new flow
and call out that amd64 is the supported architecture (arm64 variant
of the image is being handled separately).

Verified locally: `docker build -f Dockerfile.deploy .` succeeds,
`fabro version` prints the expected banner, and PORT override + health
check work.
2026-04-18 15:24:22 -04:00
Bryan Helmkamp
b5e17ba082
ci(release): attest SLSA build provenance for binaries and image
Tarballs in each compile matrix and the multi-arch ghcr image now get
Sigstore-signed provenance attestations via GitHub's attest-build-provenance
action. Users can verify with `gh attestation verify` — covered in a new
docs/reference/verifying-releases.mdx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:05:32 -04:00
Bryan Helmkamp
6c57e17bb3
docs: add Homebrew as a first-class install method
Add Homebrew tab to the Quick Start install tabs and simplify the
agent-driven install.md to detect Homebrew and fall back to the install
script, dropping the gh/tar manual path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:37:15 -04:00
Bryan Helmkamp
dae8b635fc
plans 2026-04-18 12:36:41 -04:00
Bryan Helmkamp
bc3dcf3505
plan 2026-04-18 10:51:43 -04:00
Bryan Helmkamp
b0349e9873
feat(cli): surface debug build profile in version output
Non-release builds now append the profile to `fabro --version`
(`x.y (sha date debug)`), `fabro version`, and `fabro system info`,
so users can tell a local build apart from a shipped release. The
API's `SystemInfoResponse` gains a `profile` field so the client
can render the server's build profile too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 09:44:54 -04:00
Bryan Helmkamp
0d9f71d1cb
docs: add Apr 17–18 changelog entries and refresh CLI + Railway docs
Document bare `fabro` landing output in the CLI reference and remove
the now-obsolete multi-arch image caveat from the Railway deploy guide.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 09:44:54 -04:00
Bryan Helmkamp
eb3c6d5ce3
fix(docs): update billing endpoint reference in navigation
The billing refactor (6ca2833e7) renamed /api/v1/runs/{id}/usage to
/api/v1/runs/{id}/billing in the OpenAPI spec but left the stale path
in docs.json, which broke Mintlify deploys with "Failed to fetch
OpenAPI file for anchor or tab".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:35:59 -04:00
Bryan Helmkamp
2f2f14562d
fix(api): convert OpenAPI spec to valid 3.1 syntax
The spec declared openapi 3.1.0 but used nullable: true (3.0 idiom)
in 78 places, which Mintlify's parser rejected, breaking doc deploys.

Convert to proper 3.1 patterns (type arrays and oneOf with type: null),
switch the server conformance test from openapiv3 (3.0-only) to a
YAML-level walk so it accepts 3.1 input, and regenerate the typescript
client — it now correctly emits `| null` on nullable fields.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 01:11:19 -04:00
Bryan Helmkamp
5335f8bcb4
feat(deploy): add Railway deploy path, honor $PORT in container
Teach the Dockerfile CMD to bind 0.0.0.0:${PORT:-32276} so PaaS providers
(Railway, Fly, Render, Cloud Run) route traffic without manual port
configuration. Default 32276 preserves local docker / docker-compose
behavior.

Ship railway.toml pointing Railway at the Dockerfile with on_failure
restarts. Replace the "coming soon" stub in docs/administration/deploy-
railway.mdx with a real guide: deploy button, Volume-at-/storage setup,
env vars, dev-token retrieval, and CLI pointing. Surface the Railway
deploy button in README.md under a new "Self-host the Fabro server"
section that also links to the other deploy guides.

Locally verified: PORT env override binds the chosen port, default
falls back to 32276, and tini signal propagation still gives clean
docker stop. End-to-end Railway verification still needs a live click-
through before the template URL is finalized.
2026-04-18 00:44:15 -04:00
Bryan Helmkamp
e891cb3961
test(cli): cover Homebrew upgrade behavior end to end
Some checks are pending
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Add process-level upgrade tests that invoke the real fabro binary from a
fake Homebrew Cellar path so current_exe() detection is exercised end to
end. Update the CLI reference and changelog to document the Homebrew-managed
upgrade path and the flags that remain self-managed-only.
2026-04-17 18:28:54 -04:00
Bryan Helmkamp
0b77a3efa2
feat(cli): add --prerelease to fabro upgrade
Widens the candidate set to include prereleases, picks max semver across
stable + prereleases. Falls back to /releases/latest if no parseable
non-draft tag is returned. Conflicts with --version. Background
auto-upgrade notice remains stable-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 20:20:14 -04:00
Bryan Helmkamp
5570ff3bc0
docs: update changelog and docs for Apr 14–16 changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 08:01:59 -04:00
Bryan Helmkamp
c24b78d18d
plans 2026-04-16 07:43:01 -04:00
Bryan Helmkamp
a90038f7a7
refactor(web): rename board column pending → initializing
Clarifies that Submitted/Starting runs are initializing, not just
pending. Also refactors run-detail to display the actual run status
via runStatusDisplay instead of mapping to board columns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 09:22:17 -04:00
Bryan Helmkamp
84f3c80566
refactor(api): move features flags from /auth/me to /system/info
Features like session_sandboxes and retros are server-level capability
flags, not user settings. Expose them on GET /system/info where they
belong alongside other server metadata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:51:22 -04:00
Bryan Helmkamp
a147fecc00
feat(slatedb): add disk_cache setting for S3-backed deployments
When `disk_cache = true` in `[server.slatedb]`, Fabro enables SlateDB's
object-store cache at `<storage_root>/cache/slatedb`, caching raw S3
bytes on local disk to reduce read latency. All cache parameters use
SlateDB defaults (16 GB max, 4 MB parts). A warning is emitted if
enabled with `provider = "local"` since the cache adds overhead when
the object store is already on the local filesystem.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:02:46 -04:00
Bryan Helmkamp
fa73407b35 feat(cli): add fabro version command
Add a server-targeted `fabro version` command for checking client and
server build identity without reading local storage directly.

This also removes version data from `/health`, moves doctor parity checks
to diagnostics, and updates the API spec, docs, generated client, and
coverage for the new contract.
2026-04-14 16:30:53 -04:00
Bryan Helmkamp
ce26f66846 feat(release): support prerelease builds
Add prerelease-aware release automation and keep default install and upgrade
paths pinned to the latest stable tag unless an explicit prerelease version is
requested.
2026-04-14 15:43:00 -04:00
Bryan Helmkamp
05c7fedd31 refactor(server): remove implicit dry-run fallback
Remove the server startup path that inferred dry-run from provider
availability and let run.execution.mode inherit normally from
settings.

Model tests now return skip for unconfigured providers at request
time, completions use the real error path, and the CLI/docs/tests are
updated for the removed server --dry-run flag.
2026-04-14 12:28:55 -04:00
Bryan Helmkamp
829f2ae1d2 Merge remote-tracking branch 'origin/main' 2026-04-13 23:54:13 -04:00
Bryan Helmkamp
d22be78575 fix(server): honor server.listen when bind is omitted 2026-04-13 23:54:08 -04:00
Bryan Helmkamp
b3ae342a55 Merge branch 'vendor-graphviz-sys' 2026-04-13 23:42:45 -04:00
Bryan Helmkamp
15cf4d8640 refactor: wire vendored Graphviz into fabro-graphviz, remove dot dependency
Replace the Command::new("dot") shell-out in render_dot() with a direct
FFI call to the vendored Graphviz library. Drop PNG support (SVG only).
Remove GraphFormat enum, dot_is_available() helpers, dot-related
diagnostics/doctor checks, and the graphviz install prompt. Update
OpenAPI spec to remove png format and 502 responses. Update CLI help
text, snapshot tests, and documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 22:46:29 -04:00
Bryan Helmkamp
c8f09307d0 docs: update changelog and docs for auth, install, and settings changes
Add Apr 13 changelog entry (scripted install, dev-token local auth,
GITHUB_TOKEN rename). Regenerate Apr 12 entry with provider credential
auth and resolved settings. Update CLI reference for --non-interactive
install and device code auth. Fix vault path, deploy-server --bind flag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 22:24:29 -04:00
Bryan Helmkamp
f91923892c refactor(github): rename gh_cli strategy to token, GITHUB_CLI_TOKEN to GITHUB_TOKEN
The gh_cli strategy was named after its bootstrap mechanism, not what it
actually is at runtime: a stored token. This rename makes the abstraction
honest and decouples runtime behavior from the gh CLI.

- Rename GithubIntegrationStrategy::GhCli to Token (serialized as "token")
- Rename vault/env secret from GITHUB_CLI_TOKEN to GITHUB_TOKEN
- Accept GH_TOKEN as a fallback in both CLI and server
- CLI no longer shells out to `gh auth token` at runtime; reads from
  vault/env like the server already did
- fabro install still bootstraps from `gh auth token` as a one-time op

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 20:46:11 -04:00
Bryan Helmkamp
f4bae6e9bc refactor(setup): remove browser-based GitHub app bootstrap
Make fabro install the only supported GitHub App setup path. This removes
HTTP endpoints and browser routes that mutated local server config, rewrites
/setup as an operator instructions page, and aligns the installer manifest
with the live GitHub OAuth callback and setup URLs.
2026-04-13 18:25:29 -04:00
Bryan Helmkamp
a7e9dbe8b9 Merge origin/main into local main
Conflicts resolved:
- install.rs: kept simplified auth (port 32276, no TLS, no username
  in merge_server_settings), adapted to origin's input_source API by
  removing username from ServerConfigSelection::Write
- serve.rs: kept ProviderCredentials import from origin, dropped
  ClientAuth (removed with mTLS)
- server.rs: kept both imports (ServerAuthMethod + Provider)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:28:08 -04:00
Bryan Helmkamp
ce10169a49 refactor(auth): simplify server auth model
Replace the old strategy matrix with server.auth.methods, browser session
cookies, and raw dev-token bearer auth. Remove mTLS auth leftovers, auto-
provision local session secrets, and update tests and docs to the new auth
surface.
2026-04-13 11:25:30 -04:00
Bryan Helmkamp
a1d8b738d8 Add typed provider credential auth flow 2026-04-12 22:10:11 -04:00
Bryan Helmkamp
7d01c4e42b Merge branch 'dense-default-fabro-settings' 2026-04-12 19:06:41 -04:00
Bryan Helmkamp
c60d859c08 Default settings output to dense resolved view
Make `fabro settings` render dense resolved settings by default for local
inspection, add a resolved view to the server settings endpoint with an
explicit compatibility marker, and update tests plus generated API clients
to lock the new behavior.
2026-04-12 19:06:07 -04:00
Bryan Helmkamp
7f9f4e964e docs: update CLI reference and GitHub integration for recent changes
Add fabro uninstall, pr create --force, secret list metadata, and
install owner selection to CLI reference. Add GitHub App owner
selection step to integration setup flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:07:28 -04:00
Bryan Helmkamp
85e068ffa9 docs(changelog): add entries for Apr 7–12
Cover embedded web UI, settings v2, events schema v2, typed secrets,
fabro uninstall, unified templates, GitHub App owner selection, worker
lifecycle hardening, object-backed artifacts, and other changes since
Apr 6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 17:07:19 -04:00
Bryan Helmkamp
3fa7b65182 Split server runtime secrets from vault secrets 2026-04-12 14:03:54 -04:00
Bryan Helmkamp
cb9a82b8d0 feat: add typed secrets metadata and API 2026-04-12 12:47:08 -04:00
Bryan Helmkamp
2bf35ab184 feat(github): add gh cli integration strategy
Make gh_cli the default GitHub integration path across install, server,
workflow, and CLI surfaces while keeping app-based setup available when
explicitly selected.

Also defer GitHub reqwest client initialization until an HTTP request is
actually needed so missing-token and token-only paths do not trip workspace
test slow timeouts.
2026-04-11 21:35:16 -04:00
Bryan Helmkamp
dc93404e38 refactor(config): move project state under .fabro
Keep project config and checked-in workflows under .fabro so they stay out of
normal repo listings. Update config discovery, CLI project commands, fixtures,
docs, and checked-in workflow paths to use .fabro/project.toml and
.fabro/workflows/*.
2026-04-11 12:55:46 -04:00
Bryan Helmkamp
5ed04c3c57 feat(template): unify workflow and config template syntax
Add a shared MiniJinja-based template crate and migrate workflow prompts,
imports, hooks, and InterpString env references to the new {{ ... }}
syntax. This also threads typed run inputs through workflow rendering and
updates docs and tests to match the new templating model.
2026-04-11 10:58:50 -04:00
Bryan Helmkamp
2d8dea3454 Merge origin/main into main
Brings in the events schema v2 work (RunEvent envelope fields, ActorRef,
parallel branch ids, flattened EventEnvelope wire JSON) on top of the
local Stage 6 settings TOML redesign.

Conflict resolutions:
- fabro-types/src/lib.rs: keep new ParallelBranchId re-export from
  origin; drop the legacy Settings/ArtifactStorage* re-exports (the
  flat Settings struct was deleted in Stage 6.3b).
- fabro-server/src/server.rs: keep new ActorRef import from origin;
  drop the unused legacy Settings import that came along with it.
- fabro-api-client/src/models/web-settings.ts: keep our deletion. The
  remote modification was an incidental TS-client regeneration that
  Stage 6.6 already invalidated by collapsing settings DTOs to a
  freeform v2 shape.
- fabro-workflow/src/event.rs: rewrite the run_created actor test to
  use SettingsFile::default() instead of the deleted Settings type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 21:11:55 -04:00
Bryan Helmkamp
4a3549e8da docs(plans): commit stage 6 handoff 2 (previously untracked)
This doc was written at the end of the session that landed Stages
6.1-6.5 but never committed; it's been sitting untracked for three
follow-up sessions. Handoff docs 3 and 4 both point at it as their
predecessor, so it belongs in the tree alongside them.

No content change; the file is committed as originally written.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:51:44 -04:00
Bryan Helmkamp
0930c38602 docs(plans): write Stage 6 wrap-up handoff — all substages complete
Captures the full end-state after this session finished the
consumer-migration pass through 6.3b, flattened the v2 directory
(6.5b), rewrote the auth resolver (6.6g), and closed out the last
scoped TODOs from handoff-2.

Nothing left in Stage 6. Next work is either from the deferred list
(setup_register toml_edit upgrade, ModelRegistry for fallback
chains, goal_file schema decision, fail-closed server posture,
centralized env interp pass, optional OpenAPI formalization) or
driven by new requirements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 18:44:13 -04:00
Bryan Helmkamp
edd5a27a36 docs(plans): write stage 6.6 + 6.3b-partial handoff
Captures what landed in this session:

- Stage 6.6a/b/c: OpenAPI DTO collapse (commit 78c57d585)
- Stage 6.6d/e/f/i: Server handlers + CLI + demo migration (40c9aae29)
- Stage 6.6h: fabro-web literal rewrite (999f2a11c)
- Stage 6.3b first pass: delete fabro_types::Settings (fb04e1732)

Plus what still remains:

- Stage 6.3b runtime type module cleanup (blocked on consumer migration)
- Stage 6.5b directory flatten (blocked on 6.3b)
- Stage 6.6g auth resolver rewrite
- Stage 6.6j setup_register review
- 5 of 12 scoped TODOs still open; 7 resolved

Also records the consumer migration map — ~33 import sites across
8 crates that need individual per-crate migration. This is the bulk
of the remaining Stage 6 work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:35:23 -04:00
Bryan Helmkamp
c317603971 docs 2026-04-09 17:24:30 -04:00
Bryan Helmkamp
78c57d585c refactor(api): stage 6.6 collapse settings DTOs to freeform v2 shape
Replaces the legacy flat `ServerSettings` / `RunSettings` schemas in
`docs/api-reference/fabro-api.yaml` and 20+ supporting nested type
schemas (LlmSettings, SandboxSettings, HookDefinition, WebSettings,
ApiSettings, GitSettings, McpServerEntry, etc.) with two simple
`type: object, additionalProperties: true` schemas that declare the
wire shape as the v2 `SettingsFile` tree with secret-bearing subtrees
dropped before serialization.

Regenerates the Rust progenitor and TypeScript Axios clients against
the new spec. The progenitor generates `RunSettings` / `ServerSettings`
as `#[serde(transparent)]` newtypes over `serde_json::Map<String,
Value>`; the openapi-generator emits `{ [key: string]: any; }` inlined
into the API method signatures and no longer exports named model
types.

Updates fabro-web to define local `type ServerSettings =
Record<string, unknown>` / `type RunSettings = Record<string,
unknown>` aliases since the generated client no longer exports them.
The UI only `JSON.stringify`s these payloads into a CollapsibleFile,
so the opaque shape is fine.

All 3,756 workspace tests remain green. The OpenAPI conformance test
`server_settings_keys_match_openapi_spec` still passes because
`compare_schema` short-circuits on pure-map schemas (no `properties`);
it becomes a no-op that will be removed entirely when Stage 6.3b
deletes the legacy flat `Settings` struct it still builds.

Unblocks the server handler + CLI migration in the next commits of
Stage 6.6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:04:33 -04:00