Skip to content

Add free-tier cloud models as a probed, liveness-gated subagent placement pool #79

Closed

Description

@androidand
Proposal

Why

The fleet already has two placement pools: local llama-skein hosts (ctx-aware-subagent-placement,
role-placement-policy) and other live opencode-skein sessions (session-peer-awareness). llama-
skein hosts are frequently busy running their own opencode-skein sessions. The user's own
workaround, done manually today: open /models, search "free", pick a free-tier cloud provider,
send it a throwaway "hi" to check it actually responds, and if so use it as an extra subagent
target when the local fleet is saturated. This proposal makes that workflow a placement source
instead of a manual routine.

This must not repeat the exact failure class subagent-notification-reliability exists to fix or
ctx-aware-subagent-placement already hardened against for local hosts: a placement source that
looks available but silently isn't (rate-limited, cold, revoked) must never be selected, and the
parent must never block synchronously on an uncertain candidate. That is why this change depends
on subagent-notification-reliability landing first — a third, inherently less reliable
placement pool is a bad idea to add on top of a wake-up path that isn't already trustworthy.

What Changes

1. Discover free-tier cloud providers via existing /models search

Reuse whatever provider/model catalog /models already queries to filter for a "free" tag or
zero-cost pricing metadata, rather than a hardcoded list — provider free tiers change.

2. Liveness handshake before eligibility, not before every placement

A discovered free-tier candidate is not placement-eligible until it passes a strict, cheap
handshake: send a short deterministic prompt (e.g. "Are you available? If so, answer exactly
'yes'.") and require an exact-match response within a short timeout. This mirrors exactly the
manual test the user already does. Handshake results are cached with a short TTL (candidates are
re-probed periodically, not on every placement decision, to avoid spending free-tier quota on
liveness checks alone) and a candidate that fails the handshake is not offered again until its
next probe window.

3. Extend placement scoring, don't replace it

LocalPlacement.pick (placement.ts) gains a lower-priority pool: local llama-skein hosts and
live opencode peers are preferred (residency/warmth already scores them highly); a free-tier
cloud candidate is only offered when no local/peer target is eligible, consistent with the
existing "silently moving a cloud parent's subagents onto local weights is a quality surprise, the
opposite is not" framing from role-placement-policy. A free-tier target is always cloud, so none
of the residency/VRAM-fit machinery applies to it — it is either liveness-passed and eligible, or
not offered.

4. Never select an unverified candidate

Selection MUST require a passed handshake within the current TTL window. A candidate whose probe
failed, is stale, or was never run MUST NOT be selected — including as a last-resort fallback.
Falling through to "no eligible target, run it yourself" is always safe; silently placing on an
unverified candidate is not.

Non-Goals

  • Not adding paid/metered cloud providers to placement — free-tier discovery only.
  • Not building general cloud-provider health monitoring — the handshake is a placement gate, not
    observability infrastructure.
  • Not the Claude-Code cross-session peer protocol (claude-peer-protocol-spike) — that is a
    different kind of peer entirely (another live agent session, not a model endpoint) and is
    explicitly out of scope here.

Dependencies

  • Depends on subagent-notification-reliability shipping first (see Why).
  • Extends the scoring machinery from ctx-aware-subagent-placement and role-placement-policy;
    does not modify their local-host logic.

Impact

  • New: free-tier discovery + handshake probing, likely packages/opencode/src/local/free-provider.ts
    or alongside existing model catalog code (exact location TBD by whatever already backs /models
    search — investigate before creating a new module if one fits).
  • Modified: packages/opencode/src/local/placement.ts (pool extension, eligibility gate),
    packages/opencode/src/tool/task.ts (candidate pool now includes free-tier when applicable).

Disposition (2026-09-18)

Archived — superseded/obsolete. Folded into skein-pool: an idle peer on a cloud model is a delegation target when every local host is full. No separate liveness-probed pool.

Tasks

Slice 1: Discovery

  • 1.1 Locate the catalog/query /models already uses; investigate whether "free" is exposed
    as a tag, zero pricing, or must be inferred from provider metadata.
    • Validation: manual — list at least the free-tier providers reachable in this environment
  • 1.2 Add a discovery function returning candidate free-tier providers/models from that
    catalog, with no hardcoded provider list.
    • File: TBD by 1.1 (existing model-catalog module preferred over a new one)
    • Validation: unit test with a mocked catalog response

Slice 2: Liveness handshake

  • 2.1 Implement the handshake: send a short deterministic prompt, require an exact-match
    response within a bounded timeout, on a per-candidate basis.
    • File: packages/opencode/src/local/free-provider.ts (new, or co-located per 1.1)
    • Validation: unit test — matching response passes, non-matching/timeout fails
  • 2.2 Cache handshake results with a short TTL; re-probe on expiry, not on every placement
    decision.
    • Validation: unit test — a cached pass is reused within TTL; expired entries are re-probed

Slice 3: Placement integration

  • 3.1 Extend LocalPlacement.pick with a lower-priority free-tier pool, offered only when no
    local/peer candidate is eligible.
    • File: packages/opencode/src/local/placement.ts
    • Validation: unit test — a free-tier candidate is never selected while a local candidate is
      eligible
  • 3.2 Hard-gate selection on a currently-passed handshake (within TTL); no fallback selection
    of an unverified or stale-probe candidate.
    • File: packages/opencode/src/local/placement.ts
    • Validation: unit test — an unverified candidate is never selected, even as last resort
  • 3.3 Wire the pool into task.ts candidate resolution alongside existing local/peer sources.
    • File: packages/opencode/src/tool/task.ts
    • Validation: bun run typecheck

Slice 4: Verification

  • 4.1 bun run typecheck and bun test test/local/ test/tool/ green.
    • Validation: bun run typecheck && bun test test/local/ test/tool/
  • 4.2 Live check: with local fleet saturated (or simulated as such), a subagent placed on a
    free-tier candidate completes and its result reaches the parent via the
    subagent-notification-reliability wake-up path.

Unchecked items above: see Disposition in proposal.md (2026-09-18).

Activity

  1. androidand commented on Sep 17, 2026

    @androidand
    OwnerAuthor

    Archived 2026-09-18 — see the change's Disposition section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions