Skip to content

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 18:03
· 1186 commits to main since this release
Immutable release. Only release title and notes can be modified.
949fe7d

Fugaro v0.8.0

Install:

  • Homebrew: brew install dimipaun/tap/fugaro
  • Go: go install github.com/dimipaun/fugaro/cmd/fugaro@v0.8.0
  • Or download an archive below and verify it against checksums.txt (see docs/release.md).

Highlights

  • A project's limits and its allow-list are now the project's own data instead of each job's environment: fugaro project policy publish writes the ceiling, the prices and the repositories that may run (allow_repos), fugaro project show and fugaro project repos ls|add|rm read and edit them, and a run reads the policy before it starts — one it cannot read halts the run rather than falling back to the job's own ceiling, for an installation whose rules and marker are in place (see the operator steps below). The policy's providers block is carried but not applied yet, and an installation that publishes nothing behaves exactly as it does today.
  • The operator can now write down where Claude goes: routing.claude in your own config takes an explicit list of Claude model IDs and via: direct | openrouter | auto (an absent switch means direct), and fugaro project policy publish copies it into the published policy, which is how a run receives it. Your config is its only definition site — a repository's fugaro.yaml has no routing key, and a project layer that writes one fails to load rather than half-applying it. A run resolves each named ID to the route's own ID (read by the pins, the price lookup and the recorded serving_model/priced_as), fugaro validate prints that resolution or says it is unresolved offline (and checks a routed pin with the same price, variant and alias rules the run applies), and fugaro doctor reports the same resolution; a Claude pin with no Anthropic key and no switch is a note from validate, never a refusal, since only the cloud knows which keys exist.
  • fugaro secrets set NAME now stores the project's copy by default for a name that has a project-wide meaning (a reserved secret such as anthropic-api-key, a provider key, a named Claude account), with --repo for a repository's own copy and --project-wide still accepted as a synonym; a repository copy still wins over the project's, and secrets ls follows the same default. A project-scope key mounts on the repository's job without an extra opt-in, and fugaro doctor gains a secret-scope check that lists which names are project-scope and warns when a repository copy shadows one.
  • A route may claim one exact anthropic/<id>, which is the operator's opt-in to have that one Claude model served through the provider route — from your project config or from the project layer's claude_models, never from a repository's fugaro.yaml. That stage needs agent.auth: api-key, budget.mode: enforce, the repository inside the route's allow_data_to and a price for the claimed ID (your own model_prices when the claim comes from the layer), and a routed Claude that reports no cache reads is charged at the full input rate.
  • A recipe can be mode: artifact — a run whose deliverable is a file rather than a pull request: it declares its outputs, runs the optional plan stage and then the repository's own commands.render command, ends with outcome: artifacts and neither pushes a branch nor opens a pull request. fugaro budget preview prints that run's compute ceiling beside the model ceiling and says it is not capped — the compute is bounded by timeouts.total, not by budget.per_run_usd. The outputs are selected, capped, hashed and uploaded to runs/<slug>/<run>/artifacts/ and recorded in result.json; the optional commands.probe runs over the staged set before the upload and fails closed; fugaro run --attach uploads files in with the launch; fugaro artifacts ls|get takes the files back, with runs ls and diagnose showing them; the user guide is docs/artifact-runs.md.

For operators

  1. Upgrade the CLI (brew upgrade dimipaun/tap/fugaro, or this release's archive with its cosign check).
  2. If your installation has a database, deploy the rules first: fugaro init --firebase <firebase-project-id> in the installation root writes the rules a policy is read under and the marker that records them. fugaro project policy publish refuses to publish without that marker, and an older CLI's init --firebase is exactly what redeploys the older rules under an unchanged marker — so use a 0.8.0 binary for this step. fugaro doctor reports the two skews separately, and only one of them halts: a marker whose generation is below this Fugaro's leaves no run reading a published policy — every run keeps the ceiling from its own job's environment, silently, and publish refuses until the marker is brought up — while deployed rules older than the marker make the policy node unreadable, so every budget-on run halts.
  3. Roll the runner out in this order, because neither fugaro upgrade nor fugaro image refresh writes a job's environment and only fugaro init --repo does: (a) build and publish each workflow's image from this release, (b) fugaro init --repo in each checkout to write FUGARO_RTDB_URL and FUGARO_FIREBASE_API_KEY into each job, (c) fugaro upgrade (its cloud step is fugaro image refresh) so the jobs point at the new image. A rollout that skips (b) leaves every run reading its ceiling from the job's environment and never seeing the policy, and no check reports that state — fugaro doctor's policy-vs-jobs reports the neighbouring one, jobs still on a runner image that predates this Fugaro, which is what skipping (c) leaves. Step 2 must come before (b): an init --repo planned from a local config with no budget.rtdb_url removes the backend from the jobs that have it, and the plan says so — pass the installation's --budget-mode (and --firebase) again if you use them.
  4. Then adopt the model, once per installation: fugaro project policy publish writes the policy (the ceiling, the prices and allow_repos) and fugaro project repos add|rm edits the allow-list afterwards. The first publish seeds allow_repos from your config's repos: map and the shared config's repository list, and a later publish keeps the node's own list — so removing an entry is how you un-enroll a repository. A published policy with an empty allow_repos admits no repository at all, which is not the same as an installation that has published nothing: fugaro run makes the same check before it creates an execution.

Nothing changes until step 4: an installation with no published policy spends and is capped exactly as it does today. The one change that lands earlier is step 2's: an installation whose local config has budget.rtdb_url now depends on Firebase and Cloud Storage at launch and at run start — every job carries the backend's address and key whatever the mode, the launch reads the policy and leaves a token object in the runs bucket, and each run reads it before it starts — so either service being down fails closed (the launch is refused, or the run halts) instead of running on the environment ceiling. --budget-mode off still stops only the cap session, and an installation that never configured a database keeps today's behaviour exactly.

Not in this release: project-centric phases 3 to 6 (shared project jobs, enrollment as data, the OAuth pool and the backing Git repository, including the monorepo-folder export), the Compute Engine/Cloud Batch execution backend (the code is inert and backend: cloud-batch is refused by the config), the desktop console, and checkout: clone — still not usable, exactly as 0.7.5's notes said: fugaro init --repo and fugaro image refresh refuse to deploy or move a clone workflow's job, and the flip belongs to the shared project jobs this release does not ship. Checks 44 to 46 — the price catalog and the two senior-reviewer checks — had not been run when this release was cut: they are run against the sandbox installation after the tag, and anything they find becomes a 0.8.0.x patch release, never a moved tag. Policy as data, the routing switch, project scope by default and artifact runs have no live check written yet, so they are not covered by one before the tag.

Changelog

  • cli: the routing resolution, printed when readable and said unresolved when not (#441)
  • cli: the secrets argv scan knows pflag's no-value flags, and routing joins the never-published check
  • merge: place next's project-scope section above "The assumption"
  • gitprov, runner, cli: refuse a remote the run's binding cannot read, and the negative rules marker (#443)
  • cli: fugaro artifacts ls|get, and the artifact display in runs ls and diagnose (artifact-runs Task 7) (#438)
  • Next: the phase-1 review findings, fixed on the tree that has them (#440)
  • runner: the probe — commands.probe on the staged set, fail closed (artifact-runs Task 5) (#439)
  • pricing: the canonical-to-route ID map, one resolver for pins, prices and records (#422)
  • attach: files in — --attach, the task spec and the download (artifact runs Task 6) (#425)
  • doctor, upgrade and the docs: what project scope changes (plan Task 2.3) (#430)
  • runner,runstore: an artifact run's outputs — select, sanitise, cap, hash, upload, record (artifact-runs Task 4) (#427)
  • cli: record why a mode with no database launches instead of refusing
  • cli: fix two doc comments in project_cmd.go
  • cli: compare the printed commands whole, not by substring
  • cli: find the secrets subcommand the way cobra does, not by searching for the word
  • infra: the drift note is asked before the mode note, and says what it means
  • backend: carry LaunchSpec.Env on Cloud Batch too, from one place
  • runner: refuse a remote that names another repository of the same host
  • projectpolicy: refuse a document that names one thing twice
  • spec: a project-scope key mounts on the repository's job (#431)
  • merge: record next's pflag promotion in the go.mod require baseline
  • merge: adapt the console docs test to the plan's five-column phase table
  • batch: the job definition, Launch and the socket (compute-backend Task 7) (#423)
  • secrets: project scope is the default (D2) — plan Task 2.1 (#400)
  • security follow-ups: policy-marker, skew-direction, missing-database and routing-comment fixes, plus the still-needed backup-399-code ports (#409)
  • runner: mode: artifact runs the optional plan stage and the render step (#418)
  • console: the Go/console boundary (desktop-console Task 0.3) (#420)
  • reaper: the job-first reaper, the queue deadline and the teardown paths (compute-backend Task 5) (#410)
  • config: routing.claude, an explicit ID list, absent means direct (#414)
  • console: what the watch feed guarantees to a child process (plan Task 0.2) (#412)
  • cli,recipe: budget preview's compute ceiling (artifact runs Task 8) (#419)
  • cli+runner: task 1.6's policy surface, and the eight review findings on it (marked job refuses before the clone, publish keeps routing it does not model, --delete under the etag it validated, doctor'… (#402)
  • recipe,config,runner,cli: the artifact format, and the two refusals that keep it safe alone (artifact runs Task 1) (#404)
  • projectpolicy: an explicit anthropic/ price or allowed model is accepted (main's P4), only the glob forms are refused
  • console: pin the JSON contract the app reads, field by field (#406)
  • blobx: PutFile and GetFile — the bytes, streamed (artifact-runs Task 3) (#403)
  • openrouter senior reviewer: the claim in the shared project layer (Task 7) (#397)
  • docs, policy: Check 52, the probes phase 3 depends on, and two policy-read fixes (plan Task 3.0) (#386)
  • logs: the Batch arm of the installation's sink and the labels.job_uid filter (compute-backend Task 4) (#396)
  • cli: fugaro project — policy publish/show, project show, repos ls/add/rm (task 1.6, part A) (#390)
  • runner: a claimed Claude senior, end to end (Task 6 of the OpenRouter senior-reviewer plan) (#394)
  • secrets: a project-wide copy covers the name in init's missing lists (Check 40 step 40i) (#395)
  • openrouter senior reviewer: the claim in pricing and config (Tasks 4 and 5) (#387)
  • cost: the VM price table, the machine type's quantities, the billing window (compute backend Task 3) (#389)
  • runner, cli: the slug binding and allow_repos, with the policySince launch gate (#382)
  • runner, cli: the project's policy is the ceiling, and a policy that cannot be read halts the run (#379)
  • projectpolicy: the policy object and the per-child read rules (phase 1, tasks 1.1 + 1.2) (#372)

Base images

Published by the images workflow for this tag:

  • ghcr.io/dimipaun/fugaro-history:0.8.0 and ghcr.io/dimipaun/fugaro-history:0 (the sweeper and history job's image)
  • ghcr.io/dimipaun/fugaro-base:0.8.0 and ghcr.io/dimipaun/fugaro-base:0 (one index for linux/amd64 and linux/arm64; per-architecture tags 0.8.0-amd64 and 0.8.0-arm64)

The images workflow then pulls each one with no login and fails if it is not public or lacks linux/amd64 (and, for fugaro-base, linux/arm64); each image's digest is in that run's summary.

The Terraform modules, the schemas and the plugin are versioned by this same tag.