Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/outsourcerer/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "outsourcerer",
"displayName": "Outsourcerer",
"version": "0.12.2",
"version": "0.12.3",
"description": "Make your AI coding tools work as one team. Route jobs across Claude Code, Codex, Cursor, Devin, Gemini, OpenRouter, and local models; carry the user's setup into delegated work; track limits and cash cost; and convene multi-model reviews.",
"author": {
"name": "Alex Greenshpun",
Expand Down
40 changes: 40 additions & 0 deletions plugins/outsourcerer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,46 @@

All notable changes to the Outsourcerer plugin are documented here.

## 0.12.3

On a long Devin Pro session the **shared daily plan quota** can be exhausted, which blocks every
plan-included model (glm/swe/kimi) at once. Outsourcerer modeled only the paid ACU pool, so it read
that exhaustion as a "mis-gate, not a real limit" and pointed you back at the same dead lane.

### Fixed

- **Devin's plan-included daily/weekly quota is now modeled as a real, shared, exhaustible bucket**,
distinct from the paid ACU pool. On a genuine daily/weekly exhaustion, Outsourcerer marks the whole
`dv` lane down until Devin's own stated reset and steers **off** Devin (OpenRouter via `--provider
cc`, or a native lane), instead of the old dead-end "retry on glm/swe" advice. The reset time is
parsed from Devin's "resets in 11h26m" / "resets at 09:00 UTC" wording, never guessed.
- **The dead `devin usage` call is guarded.** The current Devin CLI has no `usage` subcommand; every
hint now points at the dashboard (`app.devin.ai/settings/usage`) instead of a command that errors.
- **`advise` no longer recommends a pure-reasoning model for edit-run-verify work.** Such tasks now
classify as agentic, and Kimi K3's near-frontier scoring bump is reasoning-shaped only, so it stops
floating to #1 on edit/agentic jobs (a hard pure-reasoning task still picks it).

### Added

- **Zero-write watchdog.** A live-but-writeless delegated run (a model burning its budget on reasoning
without touching a file) is now surfaced as `no-progress-writes` past `OSRC_NOPROGRESS_SECS` (default
600), for mutating verbs only; read-only and text-only lanes are exempt. Surface-only unless
`OSRC_NOPROGRESS_KILL_SECS` is set. Catches the reasoning-budget burn that motivated this release.
- **Per-session Devin-plan dispatch meter.** Warns past `OSRC_DEVIN_PLAN_JOBS_WARN` (default 8) that
glm/swe/kimi/deepseek share one daily bucket, so heavy stacking is visible before it runs out.
- **glm-5.3 family incl. `glm-5.3-flash-high`** in the model table, bench map, and Devin resolver;
`advise` prefers the cheaper capable variant within a family (flash-high over -high) unless
`--effort max`. `OSRC_ADVISE_VARIANT_PREF=0` disables the preference.
- Three new test suites (`test_devin_plan_quota`, `test_nowrite_watchdog`, `test_advise_task_shape`).

### Scope

- The plan-limit detection and lane-down-until-reset are **Devin-specific** in this release. The
general "any subscription harness (Warp, Droid, Cursor, Cline, native) hits its own plan limit and
fails the work over to another harness you have" mechanism is future work. Proactive conservation
(Claude / ChatGPT windows) and read-only transport-fallback already exist and are unchanged; the
zero-write watchdog and the `advise` routing changes are lane-agnostic.

## 0.11.1

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,25 @@ escalate one tier up or do it yourself. Stall/kill/timeout windows: budget 90/24
mid 150/420/1800s, frontier 300/900/3600s (override with `OSRC_STALL_WARN`/`OSRC_STALL_KILL`/`OSRC_TIMEOUT`).

**Job states** you'll see in `status`/`watch`: `launching` (detached, worker coming up) → `running` →
a terminal state. Terminals: `done` · `done?` · `blocked` · `permission-blocked` · `interrupted` ·
`timeout` · `wedged` · `failed` · `canceled`. Two need distinct handling:
a terminal state. Non-terminal flags while alive: `stalled?` (output silence past the stall warn),
`exploring?` (mutating verb, zero writes past `OSRC_NOWRITE_WARN`, default 180s), and
`no-progress-writes` (see the zero-write watchdog below). Terminals: `done` · `done?` · `blocked` ·
`permission-blocked` · `interrupted` · `timeout` · `wedged` · `failed` · `canceled`. Three need
distinct handling:
- **`no-progress-writes` (alive, talking, wrote nothing).** The stall timers measure SILENCE, so a
model that streams reasoning for 15 minutes while writing no file trips none of them (incident:
two ~17-min zero-write burns on an edit task, swapped by hand ~35 min in). The **zero-write
watchdog** tracks the no-write AGE instead: for a **write-expecting verb** (`edit`/`yolo`) that is
alive and has produced no qualifying write (structured Write/Edit tool call, or a file newer than
the job's `.startmark`) past `OSRC_NOPROGRESS_SECS` (default 600s; 0 disables), the job enters this
DISTINCT state, not `stalled?` (it is talking), not `wedged` (it is alive). `status` renders
`!no-writes(<age>s,alive)`; the fleet/heartbeat view surfaces it as MAYBE STUCK. It is
**surface-only by default**: nothing is killed unless you set `OSRC_NOPROGRESS_KILL_SECS`, which then
bounds a still-writeless job like a stall (`wedged`, reason `no-progress-writes-timeout:<age>s`,
exit 125). A qualifying write clears it back to `running`. Never flagged: read-only verbs
(`run`/`explore`), `research` (its deliverable is output, not a file), and text-delegation lanes
(`local`, `tokenrouter`; extend with `OSRC_TEXT_LANES`). Next step when you see it: steer the
delegate to a concrete "write file X now" target, swap the model, or cancel; do not just wait.
- **`permission-blocked` (exit 3, NOT the same as `blocked`).** A headless delegate hit a wall it can't
confirm interactively — repeated permission/sandbox denials, or a **devin print-mode hang**: in print
mode (`-p`) devin can't answer a tool-exec-requires-confirmation prompt, so it rejects the tool and
Expand Down Expand Up @@ -174,7 +191,9 @@ talk to the user; this is *how* to run the plumbing once they've said yes.)
- Surface the model used, the printed **tier**, and (for premium/native models) the cost implication.
- Dispatch anything expected to exceed ~60s as `bg`, then poll `status <id>` on your own cadence
(every 30-60s). Read `result <id>` only when state is `done`/`blocked`; never read `logs` into
your context unless diagnosing a wedge. `stalled?` = keep waiting but say so; `wedged`/`timeout`
your context unless diagnosing a wedge. `stalled?` = keep waiting but say so; `no-progress-writes`
= alive but write-free past the threshold, steer it to a concrete write target or swap the model
(it will NOT be killed for you unless `OSRC_NOPROGRESS_KILL_SECS` is set); `wedged`/`timeout`
= report the last progress line, then escalate one tier up or do it yourself (never auto-retry a
mutating verb against a half-mutated tree).
- Treat `done?` (exit 0, no `OSRC::DONE`) as unverified: check the output before presenting.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ ChatGPT / Claude subscription auth, so they are premium and are **never** auto-e
| `deepseek` | `deepseek/deepseek-v4-pro` | OpenRouter | **capable** | strongest cheap lane, pro reasoning flagship |
| any other OpenRouter id | itself | OpenRouter | by cached price, then name | see tiers below |
| `glm-5.2` under `--provider devin` | Devin's id | devin | table/name | Devin path unchanged |
| `glm-5.3` / `glm-5-3` | `glm-5-3` (Devin family; effort rungs `-low/-high/-max`) | devin | **capable** | GLM-5.3 full-size; plan-included |
| `glm-5.3-high` | `glm-5-3-high` | devin | **capable** | GLM-5.3 at the high rung |
| `glm-5.3-flash` | `glm-5-3-flash` (Devin family; rungs `-low/-high/-max`) | devin | **capable** | lighter GLM-5.3; `advise` prefers this family over full-size 5.3 below `--effort max` |
| `glm-5.3-flash-high` | `glm-5-3-flash-high` | devin | **capable** | the cheaper capable variant `advise` recommends for agentic/edit work at `--effort high` |
| `swe` / `swe-1.7` | `swe-1.7` | devin | **capable** | Devin's own SWE agent model (open-weight/free-lane class) |
| `swe-1.7-lightning` | itself | devin | mid | faster/cheaper SWE variant |
| `kimi` | `kimi-k3` | devin / droid / warp | **capable** | near-frontier hard-work lane; provider-specific dispatch resolves the accepted K3 id |
Expand Down Expand Up @@ -284,7 +288,10 @@ The free/cheap lane on Devin **shifts frequently**. To see what is selectable *r
```

Recommendation rules:
- Default to **`glm-5.2`** unless the user asks otherwise (it currently does not draw the user's Devin usage limits).
- Default to **`glm-5.2`** unless the user asks otherwise. It is **plan-included** on Devin: it does
not spend the paid ACU balance, but on Pro it DOES draw on the shared **daily plan quota** (see the
note below). For agentic/edit work `advise` now prefers **`glm-5.3-flash-high`** (lighter, same
capability class) when it is available.
- **Cheap ≠ dumb.** `glm-5.2`/`hy3`/`deepseek-v4-pro` are the **`capable`** tier: frontier capability
at budget price (~Opus-4.8 class). They are valid for high-stakes reasoning, security review, and
deep judgment, not just grunt work. See `effort-and-tiers.md`. Pair them with `--effort high`/`max`
Expand All @@ -303,4 +310,17 @@ Recommendation rules:

## Notes

- GLM and other open-weight models currently do **not** noticeably draw the user's Devin hourly limits; this is the reason GLM is the default. This can change, see the model cost note.
- **Devin has TWO pools, and the plan-included models are NOT free of limits.** The paid **ACU
balance** (what "0% remaining / 402 / payment required" refers to) does not gate a plan-included
model (`glm*`, `swe*`, `kimi*`, `deepseek*` on Devin): a paid-balance refusal against one of them
is a Devin-side mis-gate. But the **plan-included daily/weekly quota** is real, shared, and
exhaustible: on Pro, every plan-included model draws on ONE daily bucket, and when Devin says
"Your daily usage quota has been exhausted … resets in 11h26m" ALL of them are blocked at once
until that reset. Outsourcerer reads that refusal (`_devin_plan_quota_exhausted`), takes the whole
`dv` lane down for Devin's stated window (a labeled estimate, default 1h via
`OSRC_DEVIN_PLAN_DOWN_TTL`, when Devin gives no parseable reset), and points OFF Devin (OpenRouter
via `--provider cc -m glm|deepseek`, or a native lane), never at another Devin plan model. The
current devin CLI exposes no quota read; the live figure is at https://app.devin.ai/settings/usage.
`brief`/`status` show a proactive meter, "N Devin plan jobs today", with a WARN past
`OSRC_DEVIN_PLAN_JOBS_WARN` (default 8): routing advice only, never a block. The older claim that
GLM does not draw Devin limits described the ACU pool only; do not read it as "unlimited".
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,20 @@ The prompt is lowercased and matched against pipe-separated keyword phrases for
The category with the most distinct keyword hits wins. Ties break: code > reasoning > agentic >
creative > simple. Default (no keyword hits): simple.

**Task-shape rule (blended).** Before the tally, a prompt with at least one `code` hit AND two or
more `agentic` hits classifies as **agentic**. "Edit X to fix the bug, run the test suite, verify"
describes multi-step tool use (edit, run, observe, iterate), not one code operation; under
most-hits-wins it tied 2:2 and code won the tie, so it was scored on `coding_index` and a
reasoning-heavy model floated to #1 for a job that is all about turning tools quickly. The agentic
keyword list carries the edit-run-verify signals for this: `run the tests`, `run the test suite`,
`run tests`, `make the tests pass`, `verify the fix`, `iterate until`, `edit and run`,
`fix and verify`, `then verify`.

| Category | Keywords (sample) | Benchmark field | Threshold |
|---|---|---|---|
| code | function, class method, bug, fix, refactor, implement, compile, error, stack trace, debug, unit test, api endpoint, sql query, regex, algorithm, code review, pull request, merge conflict, lint, docker, kubernetes | `coding_index` | 60 |
| reasoning | analyze, compare, evaluate, assess, critique, reason, prove, derive, tradeoff, implication, consequence, strategy, architect, design system, decision, justify, deduce, infer, mathematical, proof, logical | `intelligence_index` | 45 |
| agentic | agent, tool use, tool call, multi-step, autonomous, execute command, run shell, file system, web search, browser, orchestrat, workflow, pipeline, subagent, delegate, parallel, fanout | `agentic_index` | 35 |
| agentic | agent, tool use, tool call, multi-step, autonomous, execute command, run shell, file system, web search, browser, orchestrat, workflow, pipeline, subagent, delegate, parallel, fanout, run the tests, run the test suite, make the tests pass, verify the fix, iterate until, edit and run, fix and verify | `agentic_index` | 35 |
| creative | write a story, write a blog, write an article, essay, creative, generate content, copywriting, headline, tagline, brand voice, narrative, storytelling, poem, screenplay, dialogue | `intelligence_index` | 45 |
| simple | (no keyword hits) | `intelligence_index` | 0 (no floor) |

Expand All @@ -51,8 +60,11 @@ For each model in the alias table (`OSRC_MODEL_TABLE`), the advisory:
agentic tasks, intelligence_index for everything else) and pricing (prompt + completion
per token).
3. Applies the task difficulty, requested effort, capability tier, and local outcome history to
the benchmark score. Capable models receive a value preference; Kimi K3 receives a hard-work
near-frontier adjustment; explicit frontier requirements outweigh those adjustments.
the benchmark score. Capable models receive a value preference; explicit frontier requirements
outweigh every adjustment. **Kimi K3's near-frontier adjustment (+20) is reasoning-shaped only:**
it applies to a `hard` task in the `reasoning` category, never to `code`/`agentic` work. Kimi's
edge is deep analysis; its long pure-reasoning bursts are the wrong shape for edit-run-verify,
where the old any-hard-task bump floated it to #1 (score 80) and cost two zero-write burns.
4. Calculates the **value ratio** = score / max(cost_per_m_input, 0.01). Free models (cost=0)
are floored to $0.01/M so they rank high but don't dominate infinitely.
5. Subscription lanes (cx/cc/dv/gm) have their price set to $0 BEFORE the value ratio
Expand All @@ -66,6 +78,25 @@ threshold. A frontier is selected when effort is `max` or the task explicitly re
handling. If neither preferred cohort clears the threshold, selection falls back to the best
qualifying subscription or paid candidate, then the highest score overall.

**Variant preference (cheaper capable variant within a family).** Devin ships families as
effort/size variants (`glm-5-3-high`, `glm-5-3-flash-high`, `deepseek-v4-pro-max`). When two
variants of ONE family both clear the threshold, the lighter one is recommended: a light member
(`flash`/`lightning`/`mini`/`lite`) always beats a full-size one, and within that the effort rung
closest to the requested `--effort` wins (so at `--effort high`, `glm-5.3-flash-high` beats
`glm-5.3-high`, and beats bare `glm-5.3-flash`). Heavier siblings stay listed as
`OK (lighter sibling preferred)` and, in `--json`, carry `lighter_sibling_preferred: true` and
leave the shortlist's top group. This is a shape rule, never a price (prices rot); on plan lanes
the cost column is a flat "plan limits", so this weight is also the tiebreak between candidates
with identical value ratios (proxy scores tie constantly), replacing the old table-order
accident. Off at `--effort max`, when the task requires the frontier, or with
`OSRC_ADVISE_VARIANT_PREF=0`.

Devin's GLM-5.3 family is in the table with Devin's real ids: `glm-5.3`/`glm-5-3` -> `glm-5-3`,
`glm-5.3-high` -> `glm-5-3-high`, `glm-5.3-flash` -> `glm-5-3-flash`, `glm-5.3-flash-high` ->
`glm-5-3-flash-high` (all `dv`, capable). Their benchmark mapping points at `z-ai/glm-5.3` /
`z-ai/glm-5.3-flash`; until OpenRouter lists them they score via the tier proxy like kimi/swe, and
`advise --refresh` picks up real scores the day they appear.

### 4. Graceful degradation

| Tier | Data available | Behavior |
Expand Down Expand Up @@ -159,3 +190,7 @@ the cheapest option. Use `estimate` when you already know the model and want a c
- **Subscription lane cost is qualitative**: subscription models (cx/cc/dv/gm) show "$0 (plan)"
because the user pays plan limits, not per-token. The value ratio treats them as free, which
is correct for the user's wallet but doesn't account for plan-limit exhaustion.
- **Tier proxy is calibrated on `intelligence_index`**: an unbenchmarked `capable` model scores a
proxy of 50, which exceeds a benchmarked capable model's REAL `agentic_index` (glm-5.2: 43.1).
On agentic tasks, unbenchmarked capable models therefore outrank benchmarked ones. A field-aware
proxy is the fix; until then, `advise --refresh` (more live rows) narrows the gap.
Loading
Loading