Skip to content

Releases: mcp-tool-shop-org/offrig

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 17:17
8f0b59c

Changed

  • The project index embeds with EmbeddingGemma 2. The default model is now
    embeddinggemma-2:f32: Google DeepMind's google/embeddinggemma-2 at revision
    914f7f8, an open model under Apache-2.0 with no gate, text only, float32, on the CPU.
    It replaces nomic-embed-text. On a pre-registered benchmark of 93 studio queries over an
    11,525-chunk index it scored dense nDCG@10 +0.112 over nomic-embed-text, with a one-sided
    95% lower bound of +0.065 (code +0.174, prose +0.041). The 256-dimension cut lost 0.043,
    so vectors stay at 768. The record is in the rnd library, experiments/embeddinggemma-2/.
  • Documents are sent with title: none | text: and queries with
    task: search result | query: . The code-retrieval prefix scored no better on code
    queries (−0.008), so one query prefix serves every kind.

Added

  • tools/embed-serve, the CPU embed server. Ollama on Windows can't run EmbeddingGemma 2,
    so this small loopback server answers the part of Ollama's API that offrig's embed client
    uses, on the same default embed_url (http://127.0.0.1:11490).
    • It serves one name and answers 404 for any other, so no store can silently mix models.
    • It refuses to start when torch can see CUDA, and /api/ps reports size_vram: 0.
    • It encodes in sub-batches of 8.
    • It's built for a shared machine, after an outside review:
      • every thread pool (torch, OpenMP, MKL, OpenBLAS, the tokenizers) is capped before torch loads, by default to a quarter of the logical cores and at most 6 (--threads);
      • it runs at below-normal priority, single-threaded, one request at a time;
      • it bounds each request: 4 MiB, 256 texts, 12,000 characters a text, 2,048 tokens;
      • it refuses browser requests, non-loopback hosts, chunked or non-JSON bodies and a bad Content-Length.
    • Measured on a Core Ultra 9 285K with 6 threads on 6 efficiency cores: a 201-chunk rebuild took 163 s, the server used about 20% of the machine (never more than 22%), and peaked at 2.8 GiB. Its vectors match the benchmark's (cosine at least 0.9999999).
    • Python 3.12. requirements.txt pins every package exactly, with torch's CPU build.
    • Its tests use a stub encoder and run in CI's new embed-serve job, gated at 90% line
      coverage.
  • Atlas: tools/embed-serve is its own part.

Upgrading: what a nomic-indexed store does

A project index built with nomic-embed-text keeps its vectors, and nothing mixes them with
the new model's:

  • offrig index is refused: "the project index was built with nomic-embed-text, not
    embeddinggemma-2:f32; run offrig index --rebuild". It writes nothing.
  • Hybrid search, the default once an index exists, embeds the query with the index's
    own model. The new server doesn't serve that model, so the search is refused, never
    downgraded. The refusal names offrig index --rebuild and mode=keyword.
  • The side-car's background embed leaves new records keyword-only until the rebuild.

Re-embed each such project once, with embed-serve running:
offrig index --rebuild --project <dir>. Chunks are kept, and only vectors are replaced. A
project with no vectors yet needs nothing.

The refusal and start-line messages name embed-serve for the default model, and a CPU-only
Ollama for a model chosen with --model.

v1.1.3

Choose a tag to compare

@github-actions github-actions released this 15 Oct 04:13
8b7acf1

Fixed

  • The embed server cannot take the GPU without offrig refusing. On Ollama 0.40 a server started with only CUDA_VISIBLE_DEVICES=-1 still reaches an NVIDIA card through Vulkan, so the documented start line could load the embedding model onto it. The start line in the refusal message, the handbook and the design doc now also sets GGML_VK_VISIBLE_DEVICES=-1 OLLAMA_VULKAN=0 OLLAMA_IGPU_ENABLE=0. After each embedding call offrig reads the embed server's /api/ps; if the model sits in GPU memory it refuses, shows the start line and writes nothing. A server that does not answer /api/ps is not blocked.

v1.1.2

Choose a tag to compare

@github-actions github-actions released this 14 Oct 23:04
0600904
  • Build fake credentials at runtime in trace.rs unit tests so secret scanners do not flag test fixtures.

offrig 1.1.1

Choose a tag to compare

@github-actions github-actions released this 12 Oct 06:59
5397759

Draft. Windows x64 only. Verify the zip against SHA256SUMS before use; see CHANGELOG.md for what changed.

offrig 1.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 21:23
3cc277b

Draft. Windows x64 only. Verify the zip against SHA256SUMS before use; see CHANGELOG.md for what changed.

offrig 1.0.0

Choose a tag to compare

@github-actions github-actions released this 08 Oct 00:26
ab31154

The first release. offrig has run real work since 2026-10-02, and since 2026-10-07 two
projects have used it at once, each in its own lane: training runs on job pods and
singing renders on jam pods. This release adds downloadable Windows binaries, structured
errors and exit codes, and a handbook. Everything below the next list was built before the
first release and ships in it.

  • Windows release binaries. Each version tag builds offrig.exe, offrig-mcp.exe and
    offrig-app.exe in CI into offrig-<version>-windows-x64.zip, with SHA256SUMS. The
    workflow stages a draft release and never publishes it; a person checks the draft first.
    Windows only, because offrig relies on Windows' OpenSSH, %APPDATA% and Zed's paths.

  • Side-car errors carry a code. Every tool failure, including bad arguments and an
    unknown tool, returns ok:false, a stable code, the error text, a next_action and
    retryable. error and next_action are unchanged, so existing callers keep working.
    Budget refusals have their own code, budget_exceeded.

  • CLI exit codes: 0 success, 1 something to fix on your side, 2 a runtime
    failure. Bad arguments now exit 1 instead of clap's 2.

  • CLI log levels: -q (errors and a command's own results only), -v (each RunPod
    call and its timing, on stderr) and --debug (failed response bodies and full error
    chains). The API key and any Bearer token are redacted at every level, and a panic
    prints one line unless --debug is set.

  • offrig-mcp --help and --version answer instead of starting to serve stdio.

  • The app has its icon, in the window and on the .exe.

  • scripts/verify.sh and scripts/verify.ps1 run the format check, clippy, the tests
    and a smoke run of each binary in one command.

  • Every project can see the others' pods. offrig_status lists each other offrig
    pod with its lane, project, GPU, price and status, and the open plan behind it: plan id,
    note, deadline and committed worst case. The other project's store is read strictly
    read-only, leaving no files behind. Pods offrig did not create are only counted and
    named. Pods carry OFFRIG_LANE, and on side-car launches OFFRIG_PLAN and
    OFFRIG_DEADLINE, as environment variables visible in RunPod's console.

  • A failed launch says what it cost. offrig_job gives the failure's code,
    retryable, and whether a pod was rented and billed. The new code pod_not_ready means a
    pod was rented but never became ready, and was terminated; no_capacity means nothing was
    rented. rented is filled as soon as the pod exists. A job_id that is really a plan id
    gets a message naming the right call.

  • Turning auto-stop off now survives a restart. It used to be saved as a missing key,
    which reloads as the 30-minute default. It is now saved as auto_stop_idle_minutes = "off"; numbers, including 0, are still minutes.

  • Coverage of at least 90% of lines, enforced. The tests grew from about 250 to more
    than 450 and cover 94% of lines. CI fails below 90% (cargo llvm-cov --fail-under-lines 90), and codecov.yml sets 90% targets for the project and for each change.

  • CI adds an OSV scan of Cargo.lock, and uploads coverage to Codecov over OIDC.

  • A handbook and landing page at https://mcp-tool-shop-org.github.io/offrig/.

  • Launch follow-ups from the first real runs of the hardware-limits build (issue #15).

    • A narrowed plan waits for capacity instead of failing. offrig_plan takes
      wait_minutes (stored with the plan, shown in the reply; 0 fails at once), else the
      profile's wait_for_gpu_minutes, and the job profile now defaults to 20 minutes.
      Nothing is rented while waiting; the wait is cut to the plan's remaining time less a
      five-minute reserve, so it stays inside the plan's deadline and adds nothing to its
      worst case. Each retry is reported: offrig_job shows progress.capacity_wait and a
      step naming the check. The no capacity error now says how to set a wait.
    • offrig_job derives the step of a booting pod from the pod's state on each call (what
      RunPod reports, and whether sshd answers on the published port), instead of reading the
      launch thread's last event, which could be minutes stale on a slow host. The thread's
      own last step is kept beside it as progress.launch_step.
    • The host's CUDA version is measured: after ssh is up the launch runs nvidia-smi once
      through the lane, reads CUDA Version: 12.8 or the newer CUDA UMD Version: 13.4, and
      fills rented.cuda_version (rented.cuda_source says nvidia-smi). A host below the
      plan's floor keeps the loud warnings entry; nothing is terminated. If nvidia-smi
      gives nothing, rented.notes says the floor is unchecked.
  • Job-tool gaps from real runs (issue #12).

    • offrig_get creates missing local parent folders instead of refusing with "is not a
      directory", as offrig_put already does on the pod side. A path that exists but is a
      file is still refused.
    • offrig_exec action=run runs a short command synchronously with a timeout (default
      30 s, at most 120 s) and returns stdout, stderr, exit_code and timed_out. The
      command is sent as base64 and run under timeout with stdin closed; output is capped
      at 64 KB per stream. name is now optional (only start, status and stop need it).
    • offrig_exec action=status collapses carriage-return progress lines in its log tail to
      their last frame, and takes save_log to copy the job's whole log to a local file.
  • Lane names in the plan, stale ssh blocks, and a container disk size (issue #6 and a new
    need from a slow-/workspace host).

    • offrig_plan shows the lane's ssh_alias and the pod_name its launch will create
      (for example offrig-ai-jam-sessions and offrig-ai-jam-sessions-jam), so a session
      can confirm its lane before launching without reading lanes.toml. offrig_status
      shows ssh_alias on each open plan too.
    • offrig_shutdown removes the lane's own ~/.ssh/config block once the pod is gone, but
      only when the block's label names that plan's pod. Another lane's block, and a block
      already rewritten for a newer pod, are never touched. A launch that fails and terminates
      its pod does the same. The reply reports ssh_block_removed. A pod ended by the
      watchdog at its deadline still leaves its block, as before; the next launch rewrites it.
    • offrig_plan takes container_disk_gb (1 to 2000), overriding the profile's
      container_disk_gb for that plan. The plan stores it and the launch sends it as
      containerDiskInGb; the reply and offrig_status show the size in force. The disk is not
      priced into the worst case (offrig prices GPU time only).
  • Hardware limits on a plan (issues #9 and #10). A plan could land on a fallback card the
    work could not use: a job plan rented an A100 host on a CUDA 12.8 driver, and the job's
    CUDA 13 PyTorch failed after setup. Worst-case pricing also always used the profile's top
    price ($3.49/hr), so a 3.5 h pod expecting a $2.09 card committed $12.22 instead of $7.32.

    • Profiles gain min_cuda (oldest host CUDA; the pod create sends every version at or
      above it as allowedCudaVersions, and a job profile uses the newer of this and its
      image's floor) and min_vram_gb (least total VRAM; smaller offers are never chosen).
      Both default to unset, so existing config.toml files load unchanged. The job profile
      now sets min_cuda = "13.0".
    • offrig_plan takes max_price_hr (total $/hr; dearer offers are left out and the worst
      case is max_hours x min(max_price_hr, dearest listed price left)) and no_fallback
      (only the profile's first GPU family; the two RTX PRO 6000 Blackwell editions count as
      one). A plan with nothing left is refused with the reason for each dropped GPU. The reply
      lists the GPUs that were left out.
    • The plan stores its GPU list, price and CUDA floor, and offrig_launch now rents only
      from them. Before this the launch built the pod from the profile's full list and ignored
      what the plan priced.
    • offrig_job (and the launch result) report the GPU type and, when the pod API reports
      it, the host CUDA version rented. A host older than the plan's floor, a GPU outside the
      plan's list or a price above the plan's produces a warnings entry and a WARNING
      next_action; nothing is terminated automatically. offrig_status shows each open
      plan's GPU list, price and CUDA floor, and each pod's GPU.
    • Unverified: whether the pod API reports the host's CUDA version, and under what field
      name. offrig reads machine.cudaVersion if present and says so in rented.notes when it
      is not, rather than treating a missing report as a pass.
  • A per-project default side-car port (issue #11). The shell driver's default port, 11439,
    was shared by every project on the machine, so another script taking it silently took a
    running side-car down. A lane now has a side-car port derived from its slot the same way
    its tunnel port is: 11700 + slot (11700 to 11763), a range above every lane tunnel
    and runner port (11500 to 11627), the plain lane and the local Ollama. Nothing is
    stored in lanes.toml; existing registries work unchanged.

    • offrig-mcp --sidecar-port --project <dir> prints the project's port (allocating its
      lane if it has none), or OFFRIG_SIDECAR_PORT when set. That value is refused when it is
      not a port, is below 1024, or is 11434, 11435, 11436 or inside the lane tunnel range.
    • --check also exits 1 when the port is held, naming the port and, if an offrig side-car
      answers there, the project it reports. The probe is a request the driver refuses before
      calling any tool, so a running side-car is not touched.
    • offrig_status reports the lane's sidecar_port.
    • Not in this repository: t...
Read more