crew: the Pareto crew's follow-ups — seat ceilings, unpriced calls at the cap, pins, landing line, limits, manual - #1518
Merged
Merged
Conversation
…s run The guard kept spend per model and keyed the checker's ceiling by model id, so CrewSeatCeilings dropped the ceiling whenever another seat shared the checker's model. A fresh profile's narrow fix puts one model in all three seats, so the checker ran with no ceiling at all. Spend is now attributed by seat. The run engine's crew factory is the one place that knows which seat a task sits, so it marks every call of the task with that seat (session.SeatCompleter, which keeps the model chain), and the guard holds the checker's own calls to max(3x its estimate, $0.05) whatever the worker and planner run. Worker and planner calls on the same model are neither counted toward it nor stopped by it, and the ceiling follows the checker onto a fallback model. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A call to a model the catalog could not price skipped the daily-cap check before it was sent, and was counted afterwards only when the provider reported a cost, so a task at the cap kept calling any unpriced model. Now, when the day's guarded spend is already at or over the cap, such a call is refused before it is sent, on the same sentence a priced call ends on. That covers a model with no catalog price, a free pool and a local model, the same way the task limit already stopped calls of every kind. Helper calls go through the same check. Below the cap nothing changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
codeaf do's crew lines, at the start and at the end of a run, drew a pinned seat with a literal pushpin emoji, the one pictograph on a surface scripts and plain terminals read, and outside the icon vocabulary. They now say `checker kimi-k3 (pinned)`, the word the models line above them already uses, and config.PinMark is gone. The -json output already carries each seat's `pinned`, and a test now asserts it. The chat's own pin mark is unchanged. The terminal page, docs/HEADLESS.md and the resident models page show the new spelling. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the code The $5 per-task default, the checker ceiling's three times its estimate and its $0.05 floor were copied into the chat manual as literals, and the ceiling's refusal sentence spelled "three" by hand. A changed constant would have left every page, and the sentence, quoting the old figure. The truth table in internal/manual now holds a row for each figure, interpolated from config.CrewTaskCapDefault, config.CrewCheckCeilingTimes and config.CrewCheckCeilingFloor (exported for it) and quoting every sentence that states them, so a moved constant fails naming the page. The refusal sentence spells the multiplier from the same constant. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s model@provider A `model@provider` pin was written into the seat's tier row (models.tiers.worker, mastermind or high). dev before #1436 and stable v0.4.x read that row verbatim as a model id, so a person who switched back would have had `model@provider` sent to the provider. The tier row now holds the model alone, and the route is kept as the whole pin in models.crew.route.<seat>, a profile-only row older builds do not read. This build reads the pin back unchanged. MigrateCrew splits a row this build wrote before, once and without a line, since nothing the person chose changed. A route is applied only to the model it was pinned with, so a row an older build rewrote is not paired with a stale route. Unpinning removes both rows, and the panel's undo carries the route rows too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The previous commit refused every call the guard could not price once the day was at its cap, and "could not price" included free pools and local models, whose price is known: nothing. A dollar cap has no business stopping a call that costs nothing. A free pool, and a call sent through a subscription plan or to a model on this machine (config.CrewCallPriceAt reads the profile's connections), is now priced at nothing, a known price, and passes the daily cap, the task limit and the checker's ceiling. Only a call whose price nobody knows, a model the catalog lists with no price, is refused at a line already reached. The manual sentence says the same. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A routed task's crew line was said when the task started and rewritten in place when it landed. The landing notice does carry the crew and the cost (session's beltRunNotice, kept by publishRunRow), and sayTaskCrew did rewrite the line, but by then the start line was far up the thread. The fresh-install check watched a 22-minute task land `done · branch kept` with no crew line anywhere in view, because the actual and `not right? /redo stronger` had been drawn in scrollback nobody was reading. The line is still rewritten in place while the task runs, for a seat that moved to its fallback. On landing it now moves to the end of the thread, beside the landing (feed.moveNote), and stays one line per task. The models and tasks pages say so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The /crew seat list and the allowed-models checklist drew each model's price as two bare figures, `$0.15/$0.50`, with nothing saying what they were, and in a spelling of their own. They now use the model picker's own words (priceWord), `$0.15/$0.5 per M`, dollars per million tokens in and out, so one price has one spelling. A model with no published price says nothing, as the picker's rows do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The first-run screen offers a `Daily limit` ($500 on a new profile), the day's limit on everything codeaf spends, while /crew's cap row said `per task $5 · daily none`. Side by side, a new user read `none` as "nothing limits the day". The crew's cap is now called the crew daily cap everywhere a person reads it: the panel's cap row, the /crew cap notes and the settings seats row. The panel names the daily limit under it with its figure (`the daily limit, $500, still covers everything codeaf spends · /budget`), wrapped and never clipped on a narrow frame. The first-run line says the daily limit covers everything codeaf spends, and its `?` detail points at the crew's own cap. The two limits stay separate. The manual, the truth table and docs/LIMITS.md follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Settings said the task model row "follows the conversation", while the manual, the row's hint, the proposal card and the receipt all taught one ladder: a model named in the ask, then the task model row, then the crew's worker. On the default task road (the run engine) neither the named model nor the row reached the router. The run was seated on the routed worker whatever was named, and the receipt still said `task N started on <the named model>`. The named model, or the task model row when nothing was named, now reaches the router as a one-task pin on the worker. A task that names nothing is routed as before. The row now reads `the crew's worker` when blank, and its hint says the crew picks it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… user asks The fresh-install check asked the chat three things in a new user's own words, and its manual answered from the wrong places. "how do I change the model the task worker uses?" got the per-task /model and never /crew pin worker. "is my code sent anywhere that logs it?" got "your code travels to the model provider, and nowhere else", which leaves out the crew's move onto free routes that may log prompts. "which model are you using and what does a task cost?" never named the crew or a task's estimate. Three models-and-cost sections now answer them under headings in the asker's words. Pinning the worker gives the ladder. Where content goes describes the free-route move as the code does it: when free routes are switched on, or when every paid route is out of reach (a low OpenRouter balance, a payment refusal, credit reported at zero), at most three pools per task, within the allowed models, with the crew line's notice. The chat model and the crew section covers the estimate and the landed cost. Each question is a probe that must reach the section that says the answer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
"When everything codeaf spends today" pushed the line onto a third row beside the example panel, and the forty-column controls test caught it. "When all codeaf spends today" says the same in the two rows the screen gives it. The getting-started page quotes the new line. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Sep 25, 2026
…he task room Brings in #1516, #1517, #1518 and #1519. The two conflicts were dev editing the inline run-road code that this branch had moved into helpers: the --one-model seat (#1517) now rides the precomputed crew factory in enginewire, and the hand-off's named model reaches the crew router as a worker pin (#1518) through the crew wish set before commitProposalToRun. That wish is read only by the ordinary task's crew routing, so a senior-dev run keeps the models it names. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Sep 25, 2026
…ary" Dev's #1518 pinned three sentences that carry the crew's default per-task limit ("No task may cost more than its limit: $5 ..."). With senior-dev in the tree those sentences are false for a senior-dev run, which is not a crew task and keeps its own ceiling, and the pages already say "an ordinary /task" there. The pins now match the qualified sentences; the figure still comes from config.CrewTaskCapDefault. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows #1429 / #1485 / #1494 / #1436 review. These are the Pareto crew's should-fixes from the review of #1436, plus four defects the fresh-install check found on the published dev build.
What was wrong, and what is true now
config.CrewCallPriceAtreads the connections).codeaf doprinted a literal 📌. The headless crew line now sayschecker kimi-k3 (pinned).-jsonalready carriedcrew.<seat>.pinned, and a test now asserts it.internal/manual's truth table, fed from the constants. The ceiling's refusal sentence spells the multiplier from the same constant.model@providerpin was stored in the tier row, which an older codeaf sends as a model id. The tier row now holds the model alone, and the route lives inmodels.crew.route.<seat>.MigrateCrewsplits rows this build already wrote, once and silently. A stale route is never applied to another model./crewsaiddaily nonenext to the first-run screen'sDaily limit $500. It now sayscrew daily cap, and the panel names the daily limit under it with its figure. Thetask modelrow said "follows the conversation", but on the run road neither that row nor a model named in the ask ever reached the router. Both now reach the router as a one-task pin on the worker, which is the ladder the manual already described. Blank, the row readsthe crew's worker. The two limits stay separate./crewprices had no unit. They now use the model picker's own spelling:$0.15/$0.5 per M.Out of scope: the exec / plan run spend guard, and the free-pool fallback policy, which is waiting on a ruling.
Validation contract
Each item has a test derived from the contract, and I checked that each one fails on origin/dev: the seat-attributed ceiling (config, session, and through
run.CrewFactory), unknown versus known-zero pricing at the cap,(pinned)on the headless report, the truth-table rows (by mutatingCrewTaskCapDefault), the raw tier row, migration and stale route, the landing line at the end of the thread, the crew-cap wording and the daily-limit line, the task-model ladder reaching the router, the three manual probes, and the price unit.Checked by hand
bin/codeafran on a throwaway home with every seat pinned to deepseek-v4-flash./tasklandeddone · branch keptwhile the conversation went on. The landing line ($0.002 (est $0.025) · not right? /redo stronger) sat directly above the landing card, and the start line was gone.codeaf dowith a pinned checker printed(pinned)and no emoji.@openrouterleft the tier row bare. The pre-crew: route the worker, planner and checker per task (Pareto crew) #1436 binary read that profile and ran on the bare id.make pr-readyis green except forinternal/runTestSupervisorLaunchesEveryReadyLeafAtOnceWithNoSlotBound. That test also fails on plain origin/dev on this box, and the review ledger already listed it as failing there.🤖 Generated with Claude Code