[BUG] Task tools (TaskCreate/TaskGet/TaskList/TaskUpdate) silently disabled on Opus 4.8 / Sonnet 5 / Fable 5 by model-id gate `tengu_vellum_ash` — no error, no override, ToolSearch reports them as nonexistent
Summary
As of v2.1.204, the four Task tools — TaskCreate, TaskGet, TaskList, TaskUpdate — are silently unavailable in sessions running claude-opus-4-8, claude-sonnet-5, or claude-fable-5. They are not deferred, not permission-denied, and produce no error or warning: they are never registered, so ToolSearch cannot see them at all.
The cause is a model-id check against a GrowthBook flag named tengu_vellum_ash.
This may well be intentional. If so, this issue is a request to make it observable — right now there is no way for a user or an agent to discover why the tools vanished, and skills/subagents that declare them silently receive a smaller toolset. If it is not intentional, it is a regression affecting every user on the three newest models.
Reproduction
$ claude --version
2.1.204 (Claude Code)
# gated model -> tools absent
$ claude --model opus -p 'Call ToolSearch with query "select:TaskGet" max_results 3. Reply ONLY YES if a TaskGet schema came back, NO if not.'
NO
# ungated model, SAME machine, SAME binary, SAME MCP servers -> tools present
$ claude --model haiku -p 'Call ToolSearch with query "select:TaskGet" max_results 3. Reply ONLY YES if a TaskGet schema came back, NO if not.'
YES
In the gated session, ToolSearch with select:TaskGet returns the literal string No matching deferred tools found. A disabled tool never enters the deferred registry, so this is indistinguishable from the tool not existing.
Root cause
All of the following is read directly out of the shipped bin/claude.exe (v2.1.204, npm @anthropic-ai/claude-code).
Tool registration — identical for all four:
userFacingName(){return"TaskGet"},shouldDefer:!0,isEnabled(){return aR()&&!zY()}
The two predicates:
function aR(){ if (Bc(process.env.CLAUDE_CODE_ENABLE_TASKS)) return !1; return !0 }
function Bc(e){
if (e === void 0) return !1;
if (typeof e === "boolean") return !e;
let t = String(e).toLowerCase().trim();
return ["0","false","no","off"].includes(t);
}
function zY(){
try {
let e = Ze("tengu_vellum_ash", []);
if (!Array.isArray(e) || e.length === 0) return !1;
let t = Bi(); // resolves the MODEL ID
return e.some((r) => r.length > 0 && t.includes(r));
} catch { return !1 }
}
function Bi(){ let e = gQ(); if (e !== void 0 && e !== null) return ii(e); return uE() }
The flag value, as cached locally in .claude.json:
"tengu_vellum_ash": ["claude-opus-4-8", "claude-sonnet-5", "claude-fable-5"]
With CLAUDE_CODE_ENABLE_TASKS unset, aR() returns true. A model id of claude-opus-4-8[1m] substring-matches the entry claude-opus-4-8, so zY() returns true, so isEnabled() returns false, and the tool is never registered.
Note the matching is t.includes(r), i.e. substring, not equality — so the 1M-context variants (claude-opus-4-8[1m]) are caught by the base-id entry.
Evidence that this is the mechanism, and not something else
Exactly four tools in the binary carry the isEnabled(){return aR()&&!zY()} predicate: TaskCreate, TaskGet, TaskList, TaskUpdate — and exactly those four are the ones missing. TaskOutput and TaskStop do not use that registration form, and both remain present and callable in the same gated session.
This rules out a tool-count / schema-budget overflow (which would drop an arbitrary tail): the drop set coincides perfectly with a source-level predicate while 200+ later-registered MCP tools remain resolvable via ToolSearch.
There is no way for a user to re-enable the tools
CLAUDE_CODE_ENABLE_TASKS can only disable. Per Bc() above, it matches only "0"/"false"/"no"/"off"; setting it to 1 leaves aR() at true — which it already is — and has no effect on zY(). No environment variable clears zY().
This is a behavioural change from earlier builds. In v2.1.70 the same four tools registered as:
userFacingName(){return"TaskGet"},shouldDefer:!0,isEnabled(){return fK()}
function fK(){ if (f$(process.env.CLAUDE_CODE_ENABLE_TASKS)) return !0; return !xf() }
function xf(){ return !C$.isInteractive }
i.e. CLAUDE_CODE_ENABLE_TASKS was an opt-in force-enable that overrode the interactive/TTY gate (the gate reported in #23874). In v2.1.204 the variable's semantics are inverted to opt-out only, and the interactive gate has been replaced by the model gate. So the one escape hatch users previously had was removed in the same change that introduced the condition it would have escaped.
v2.1.70 contains zero occurrences of tengu_vellum_ash — and also zero occurrences of claude-opus-4-8 or claude-sonnet-5. There appears to be no released build in which these models and these tools coexist, so downgrading is not a workaround: it trades the model for the tools.
Why this is worth fixing even if the gate is intentional
The failure is silent and undiscoverable:
- No error, no warning, no log line. The tools simply are not there.
ToolSearchreturnsNo matching deferred tools found— identical to querying a tool that does not exist in the product.- Subagents and custom agent definitions that declare
TaskGet/TaskCreatein theirtools:frontmatter silently receive a smaller toolset, with no diagnostic. - Any skill or workflow that assumes
TaskCreateexists can partially execute. In our case a skill guarantees "external ticket mutations only fire after the local mirror task is created" — an atomicity property that assumesTaskCreateis callable. A silently-absent tool turns that guarantee into a half-applied state. - Tool registration is evaluated once per process, at session start, using the session model. A subagent spawned with
model: haikufrom a gated Opus session still inherits the gated registry — so "just use a different model for that subagent" does not work either. Only a fresh top-level session on an ungated model restores them.
Points 3–5 mean the blast radius is larger than "four tools missing": it silently degrades agent and skill behaviour in ways that look like logic bugs elsewhere.
Requests
Whichever applies:
- If the gate is unintentional (e.g. a flag that was meant to be cleared when these models shipped): please clear
tengu_vellum_ash, or scope it to the models it was actually meant to cover. - If the gate is intentional: please make it observable and overridable —
- emit a warning or a
/doctorline when Task tools are suppressed by model gating, naming the reason; - have
ToolSearchdistinguish "disabled on this model" from "no such tool"; - restore an env escape hatch (
CLAUDE_CODE_ENABLE_TASKS=1forcing enable, as in ≤2.1.70), or document that none exists; - document the model-support matrix for Tasks, since the
TeamCreatesystem-prompt text still instructs models to "Create tasks using the Task tools (TaskCreate, TaskList, etc.)" — the same documentation mismatch reported in #23816, now reachable by a different route.
Environment
- Claude Code 2.1.204 (npm
@anthropic-ai/claude-code, currentlatestat time of writing; published 2026-07-08T00:04:57Z) - Windows 11 Pro 26200, PowerShell 7 + Git Bash
- Models:
claude-opus-4-8[1m](gated),claude-haiku-4-5-20251001(not gated) - Reproduced independently on two separate Windows machines with different MCP server sets and different config roots, which is consistent with a server-side flag + model check and inconsistent with any per-machine cause.
- Compared against the locally-cached 2.1.70 build (published 2026-03-06), which lacks the gate entirely.
Related but distinct
- #23874 — Task tools disabled in the VSCode extension by the
isTTY/ interactive check. That is thexf()/!isInteractivegate, which no longer exists in the 2.1.204 enable path. Different mechanism. - #23816 — Task tools referenced in
TeamCreatedocs but absent at runtime, at v2.1.32–34. Same symptom, and the documentation mismatch it reports is still live, but the 2.1.204 cause is the model gate, not that one.
Showing cached comments. Read the full discussion on GitHub ↗
17 Comments
Correction from the reporter — the reproduction in the issue body was not executed as written
The repro block in the issue body shows:
I did not run that command before filing. I ran the
--model haikuhalf, saw the tools present, and wrote the--model opushalf from what the decompiled predicate implied instead of from execution. That was careless, and I apologise for putting an unexecuted line in front of triage as though it were observed.Having now run it, with
--output-format stream-jsonso the raw tool traffic is visible rather than the model's self-report:In headless (
-p) mode the Task tools are present onclaude-opus-4-8. The repro line as printed in the issue body is simply false, and I have struck it here.The symptom is still real, and still unexplained in a way that matters
In a long-running interactive session on this machine, same binary (2.1.204), same config root, model
claude-opus-4-8[1m]:ToolSearchwithselect:TaskGetreturns the literal stringNo matching deferred tools foundTaskCreate/TaskGet/TaskList/TaskUpdateare absentTaskOutputandTaskStopare present and callableSo the difference is interactive vs. headless, not model alone. This reconciles with the source:
zY()returns early on an empty array (if (!Array.isArray(e) || e.length === 0) return !1). So whenever GrowthBook evaluation is inactive —zQ()false, or the feature payload absent — the flag resolves to its[]default and the gate silently does not fire. My working reading is that this is why headless sessions retain the tools. I have not verified that, and I am not going to assert it as fact after having already asserted one thing I hadn't checked.What is directly verified
isEnabled(){return aR()&&!zY()}in 2.1.204;TaskOutput/TaskStopdo not carry that predicate. Exactly the four gated ones are the four missing in the affected session.zY()substring-matches the model id against flagtengu_vellum_ash(t.includes(r), soclaude-opus-4-8[1m]matches the entryclaude-opus-4-8).jq, not grepped) out of the affected config root's.claude.json, the cached flag is["claude-opus-4-8","claude-sonnet-5","claude-fable-5"]. A second config root on the same machine, belonging to a different account, caches the same flag as[]— and does not exhibit the symptom. The flag therefore appears to be identity-scoped, not global.tengu_vellum_ashnorzY(), andCLAUDE_CODE_ENABLE_TASKShas inverted from opt-in force-enable (if (f$(env)) return !0; return !xf()) to opt-out-only (if (Bc(env)) return !1; return !0). Users no longer have any way to force these tools back on.Requests, restated — these hold regardless of the trigger condition
ToolSearchreturningNo matching deferred tools foundis indistinguishable from the tool not existing in the product. Emit a reason.ToolSearchoutput, and surface suppressed-by-flag tools in/doctor.model:set to an ungated model still lacks the tools if the parent session was gated (verified). Worth documenting, since "run that step on another model" is the natural workaround and it does not work.CLAUDE_CODE_ENABLE_TASKS=1no longer force-enables. If Tasks are being withdrawn from these models deliberately, please say so in the changelog and in theTeamCreatesystem-prompt text, which still instructs the model to "Create tasks using the Task tools (TaskCreate, TaskList, etc.)" — the mismatch reported in #23816, reachable now by a different route.If a maintainer prefers I close this and re-file once I have a scripted reproduction of the interactive case, I am happy to. I would rather withdraw a report than defend a flawed one.
The most damaging part is not that the tools are gated; it is that the capability change is silent. From an agent-reliability standpoint, this changes the contract mid-run: skills or subagents can be written against TaskCreate/TaskGet, but the runtime presents the absence as “tool does not exist” rather than “tool exists but is disabled for this model/flag.”
A minimal fix would be to register a disabled descriptor in ToolSearch with structured metadata:
That keeps policy/control-plane behavior intact while making the runtime auditable. It also lets agents degrade safely: choose a filesystem or message-based fallback, or stop with a real blocker, instead of hallucinating that Task tools were never part of the environment.
This is the same distinction as authorization vs identity: denial is fine, but the caller needs a verifiable reason for the denial.
Follow-up: a working override, and the flag payload is not stable
Two further findings, both executed rather than inferred this time.
1.
DISABLE_GROWTHBOOK=1restores the toolsVerified in a live interactive session on the affected (gated) account, model
claude-opus-4-8[1m]:This matches the source.
Ze(name, default)resolves throughcpc():With
DISABLE_GROWTHBOOKset,zQ()is false,Ze("tengu_vellum_ash", [])returns[], andzY()hits its empty-array early return (if (!Array.isArray(e) || e.length === 0) return !1). The gate never fires and the four tools register normally.This is a poor workaround and I would not recommend it to other users. It is not a targeted override — it forces every feature flag to its compiled default. On this machine that is 382 cached flags, of which 113 are currently
trueand 41 are config objects. Disabling GrowthBook silently turns off every feature that a flag had enabled. The binary itself carries the string "…evaluation, which is disabled because DISABLE_GROWTHBOOK is set. Unset it…", so this is plainly a debug switch, not a supported configuration.It is nonetheless the only in-process way a user can recover the tools, since
CLAUDE_CODE_ENABLE_TASKSwas inverted to disable-only (see the original report). That asymmetry seems worth fixing on its own: there is a supported way to turn Tasks off, and no supported way to turn them on.2. The flag payload intermittently returns empty
Sampling the cached value on the affected account over ~25 minutes (parsed with
jq, not grepped — the file is pretty-printed and the key also appears in a manifest array, which makesgrepunreliable here):The
[]at 07:47:19Z was read from the raw file text, not through a parser that could have misrendered it. Roughly 5 minutes later the next fetch repopulated all three ids. Refetch cadence appears to be ~50 minutes normally, so this was an extra fetch that returned an empty array.Why this matters beyond curiosity: tool registration is evaluated once per process at session start. A session that happens to start inside an empty-payload window registers all four Task tools and keeps them for its entire life, while a session started a minute later does not. To a user this presents as nondeterministic tool availability on the same machine, same binary, same model, same account — with no diagnostic anywhere, because a suppressed tool is simply absent rather than reported as disabled.
That amplifies the observability request from the original issue. A user cannot currently answer "do I have Task tools right now, and if not, why not?" without decompiling the binary.
Scope note
The gate remains identity-scoped: on this machine a second Claude account caches
tengu_vellum_ashas[]and its interactive sessions callTaskUpdatenormally, same binary, same models, same hour. Nothing about the machine, the config directory, or the MCP server load is implicated — only the account.Correcting my own follow-up: the "intermittent empty payload" was self-inflicted, and my
zQ()explanation for headless is contradicted by evidenceTwo claims in my previous comment need withdrawing. Both were mechanisms I read in the decompiled source and then used to explain an observation, without testing that the mechanism actually produced it.
1. The flag payload does not "intermittently return empty" — a headless run rewrites the cache
I reported:
That empty value was caused by my own
claude -pprobes, which I had been running throughout that window to test the gate. Direct test, just now:A single headless invocation rewrote
tengu_vellum_ashin the config root's.claude.jsonfrom three model ids to[], and bumpedcachedGrowthBookFeaturesAt.This is a real finding, just not the one I reported. A headless run mutates the GrowthBook feature cache that every session on that config root reads. Consequences:
claude -pchanges the state it is measuring. Anyone debugging this by scripting headless probes will corrupt their own evidence, as I did.2. "Headless disables GrowthBook, so flags fall back to defaults" — withdrawn
I offered this reading of
cpc():The
DISABLE_GROWTHBOOK=1half stands — that was tested in a live interactive session and does restore the tools. The headless half does not. Evidence: after the headless run above, the cache still holds 382tengu_*flags (cachedGrowthBookFeatureshas 387 keys), with two unrelated flags flippedtrue → false. That is a re-fetch and persist, not a disabled evaluator — a session with GrowthBook disabled would not fetch 382 flags and write them to disk.So headless sessions evidently receive
tengu_vellum_ash = []from the server, presumably because targeting is evaluated under different attributes (the model id, plausibly, is absent or different in print mode). I have not established the mechanism and I am not going to assert another one. What is observed:What still stands from the original report
isEnabled(){return aR()&&!zY()}on exactly the four Task tools;TaskOutput/TaskStoplack the predicate and remain available.zY()substring-matches the model id againsttengu_vellum_ash.[]and its interactive sessions callTaskUpdatenormally.CLAUDE_CODE_ENABLE_TASKScan only disable (Bc()matches"0"/"false"/"no"/"off"), inverted from the opt-in force-enable of v2.1.70.model:-overridden subagent inherits a gated parent's registry.DISABLE_GROWTHBOOK=1restores the tools interactively, at the cost of forcing all ~382 flags to their compiled defaults.ToolSearchreportingNo matching deferred tools foundis indistinguishable from the tool not existing.The observability requests in the original report are unaffected by any of this — arguably strengthened, since even a determined user with a decompiler produced two wrong mechanisms before finding the observable facts.
Apologies for the churn on this issue. I would rather correct it three times than leave a plausible-sounding mechanism in front of someone who might act on it.
Independent data point: version bisection tighter than 2.1.70 vs 2.1.204, same model both sides
Reproduced the same silent suppression (
TaskCreate/TaskUpdateabsent,ToolSearchreports "No matching deferred tools found") onclaude-sonnet-5, native Linux install, npm-independent binary-switch setup (~/.local/share/claude/versions/<ver>, launcher symlink).Timeline (session-recorded app version, not just binary mtime):
TaskCreate/TaskUpdatecalls: session self-reported v2.1.199, 2026-07-08 ~18:30 UTC./statusmodel = Sonnet 5,ToolSearchforTaskCreate/TaskGet/etc. returns nothing).~/.local/share/claude/versions/, so switching is just repointing a symlink). Confirmed via/status: same model, Sonnet 5. Tools are present and working.So on this account, same model, same identity: 2.1.201 → tools present, 2.1.204/2.1.205 → tools absent. That's a narrower window than the 2.1.70-vs-2.1.204 comparison in the original report, and — unlike the "downgrading trades the model for the tools" concern raised there — this downgrade kept the exact same gated model and still restored the tools. I haven't checked the source code of 2.1.201 to confirm the
isEnabled()predicate is literally absent there rather than present-but-evaluating-differently due to a flag-payload difference at test time, so I can't rule that out as an alternative explanation — but the two-auto-updates-in-one-evening timing lines up cleanly with a code change landing in 2.1.202–2.1.204.Adds weight to the observability asks already in this thread —
/doctorandToolSearchboth had no way to surface why these were gone.Independent corroboration, without decompiling — same symptom, one more account affected.
Environment: Claude Code 2.1.211, native install, model Sonnet 5. Primary machine (this report) is Linux. Reproduced identically on a second machine (also Linux) and on Windows — three machines, two OSes, same account.
Symptom:
TaskCreate/TaskGet/TaskList/TaskUpdateabsent from both the resident tool list and theToolSearch-deferred list.TaskOutput/TaskStopremain present and callable. No error, no warning anywhere.Ruled out locally before concluding this was worth reporting:
CLAUDE_CODE_ENABLE_TASKSexplicitly set to1(both shell env and~/.claude/settings.json) — no effect.permissions.denyempty in every settings scope (user, project, local).managed-settings.jsonpresent on any of the three machines.hasSeenTasksHintwas alreadytruein~/.claude.json(client has shown a Tasks-feature hint before); manually resetting it tofalsehad no effect on tool availability.What corroborates the "identity-scoped, not local" framing in this thread: same account, three different machines (2 Linux + 1 Windows), three different installs, identical result. Nothing machine- or OS-specific implicated.
No decompiling done on our end — just wanted to add a clean data point confirming the symptom is real and not specific to one machine or install method. The observability asks already in this thread (surface why a tool is missing, distinguish "disabled" from "doesn't exist" in
ToolSearch, add a/doctorline) would have saved a fair amount of diagnostic time here too.Next step on our side: installing Claude Code fresh on a fourth, previously-untouched machine and logging into the same account there, to further isolate whether this really tracks the account (as this thread's scope note suggests) versus something correlated with these three particular installs. Will report back if that produces a different result.
Just confirmed it - installed claude on a fresh VM with fresh Linux system, no plugins, no additional skills,. nothing - Sonnet and Opus do not see task tools. And indeed Haiku does see the tools:
(Also setting CLAUDE_CODE_ENABLE_TASKS to 0 does not bring TodoWrite back)
Still present on v2.1.216 / macOS — plus a data point ruling out the subagent workaround
Independent reproduction on a setup not yet represented in the thread (all prior reports are Linux/Windows, ≤ 2.1.211), and one new finding about how far the gate reaches.
Environment: Claude Code 2.1.216, macOS (Darwin 25.5.0), native install (
~/.local/share/claude/versions/2.1.216), Claude Max. Affected models: Opus 4.8 and Fable 5 (claude-fable-5[1m]).Symptom (unchanged): In an interactive session,
TaskCreate/TaskGet/TaskList/TaskUpdateand the legacyTodoWriteare all absent from the tool roster;TaskOutput/TaskStopremain. No error, no warning.Mechanism is identical through 2.1.216. The predicates match the ones documented above for 2.1.204, only the minified names differ:
Local cache (
~/.claude.json), captured before running any headless probes:"claude-fable-5[1m]".includes("claude-fable-5")is true, so the 1M-context variant is caught by the base-id entry — same substring behavior noted upstream forclaude-opus-4-8[1m]. This confirms Fable 5 is gated in practice, not just listed.New: a
model:-scoped subagent does not escape the gate. Since Haiku is ungated, an obvious workaround is to route task management to a Haiku subagent from a gated parent session. It doesn't work. A subagent spawned withmodel: haikufrom a gated Fable 5 session received onlyTaskStop— noTaskCreate/TaskGet/TaskList/TaskUpdate, noTodoWrite. The task-tool registry is composed against the parent session and inherited by subagents; per-subagent model override does not re-evaluate the gate. So the only model-based escape is switching the whole session to an ungated model.Corroborating the headless-probe confound (hanuele's comment 4): reproduced here — running
claude -pprobes rewrote our localtengu_vellum_ashcache to[], after which any model trivially passes the gate. Anyone debugging this by scripting headless runs will corrupt their own evidence; the interactive tool roster is the reliable signal.Confirmed dead ends (matching prior reports):
CLAUDE_CODE_ENABLE_TASKS=1no-op and=0does not restoreTodoWrite; nopermissions.deny, notodoFeatureEnabled, no managed settings involved.DISABLE_GROWTHBOOK=1does restore the tools but forces the entire flag set to compiled defaults and disables Remote Control, so it isn't viable as a standing setting.The +1 on 0xbrainkid's suggestion stands: the damage is the silence. A disabled-but-visible descriptor in
ToolSearch(available:false, disabled_by:"growthbook:tengu_vellum_ash") would at least let agents and skills degrade deliberately instead of seeing "tool does not exist."Additional data point: account unaffected through Jul 20, gated on Jul 21 (supports gradual server-side rollout, independent of CLI version)
Environment: Claude Code 2.1.216, macOS (Darwin 25.5.0), native install, Claude Max. Models affected: Opus 4.8 and Fable 5.
Timeline from session transcripts (
"version"field):Since the gate predicate has existed since at least 2.1.204 per this thread, and this account was unaffected through 2.1.215 on Jul 20, the trigger was a change in the server-side flag payload for this account, not the CLI update (2.1.216 installed the previous evening, which initially misled our debugging).
Also corroborating the cache-rewrite finding above: headless
claude -pprobes on the same machine and model still list all four tools, and each headless run rewritescachedGrowthBookFeatureswithtengu_vellum_ash: [], so the on-disk cache cannot be used to observe what a gated interactive session actually received.Precise flip window from 13 same-day session transcripts (JST): rollout hit this account between 11:45 and 13:49 on Jul 21 — still gated on Jul 22
Environment: Claude Code 2.1.216, macOS (Darwin 25.5.0), model
claude-fable-5.Data point not yet in this thread — a precise per-account flip window, from comparing 13 session transcripts across 5 projects on the same day (Jul 21, all on 2.1.216, no local settings changes in between):
ToolSearch select:TaskListsucceeded and TaskCreate/TaskList/TaskGet/TaskUpdate calls are logged in the transcripts.ToolSearch select:TaskCreate,TaskList,TaskGet,TaskUpdatereturns "No matching deferred tools found".This narrows the account-level flip to a ~2h window and supports the gradual server-side rollout theory (CLI version identical on both sides of the window).
Two override observations, for the record:
CLAUDE_CODE_ENABLE_TASKS(either value) does not restore the tools — consistent with earlier comments.DISABLE_GROWTHBOOK=1does restore them, which further confirms the server-side flag mechanism — but it reverts hundreds of unrelated flags (e.g. breaks Remote Control), so it's not a usable workaround.Gate scope appears to be account+model and inherited by subagents: a
claude-haiku-4-5subagent spawned from a gated session also lacks the tools, even though haiku is not in the reportedtengu_vellum_ashmodel list.Still reproduces on v2.1.216 (12 releases after the 2.1.204 in the report), so the gate is still live.
claude agentsworker session, not just an interactive TTY session.claude-opus-4-8[1m]— substring-matches theclaude-opus-4-8entry intengu_vellum_ash, exactly as described.Same symptom set:
ToolSearchwithselect:TaskCreate,TaskUpdate,TaskList,TaskGetreturnsNo matching deferred tools found.TaskStopandTaskOutputremain present and callable in the same session — matching the "exactly those four" drop set.CLAUDE_CODE_ENABLE_TASKSdoes not restore them.Adding this mainly as a data point that it is still unfixed 12 versions later and not OS-specific. +1 on the request to at least make it observable — a
/doctorline, or aToolSearchresult that distinguishes "disabled on this model" from "no such tool", would have saved a lot of confusion. As-is, an agent that queries for the Task tools cannot tell they were gated rather than nonexistent.Additional data point (v2.1.216, WSL2,
claude-opus-4-8[1m], backgroundclaude agentsworker): in this session the gate did not present as a clean "absent from turn 1" — the task tools were present and then went away within the same session.A turn-1
ToolSearch({query: "select:TaskCreate,TaskUpdate,TaskList,TaskGet,TaskStop"})returned the full schema, and severalTaskCreate/TaskUpdatecalls succeeded. Later in the same run,ToolSearchfor the same tools returnedNo matching deferred tools found, whileTaskStop/TaskOutputstayed callable throughout.I can't say why it changed mid-session — whether
tengu_vellum_ashis evaluated per-request, or the worker's execution context shifts partway through the run — I have no measurement either way. But the observable effect is that a workflow can partially build on the task-list tools before they disappear, silently orphaning a task list that was already created. That's a worse failure mode than a clean, consistent absence, and it reinforces the ask for an observable signal (a/doctorline, orToolSearchdistinguishing "disabled on this model" from "no such tool").Additional evidence from a single machine (macOS, Claude Code 2.1.215-2.1.218) that this gate is both oscillating server-side and locked in per-session at startup, which produces confusing mixed behavior across concurrent sessions.
Flag value over time, read from
cachedGrowthBookFeatures.tengu_vellum_ashin~/.claude.json(times EDT):| When | Value |
| --- | --- |
| 2026-07-15 12:09 |
[]|| 2026-07-22 06:39-06:59 |
[]|| 2026-07-22 07:00 |
["claude-opus-4-8","claude-sonnet-5","claude-fable-5"]|| 2026-07-23 08:02 |
["claude-opus-4-8","claude-sonnet-5","claude-fable-5"]|Startup lock: the tool roster is evaluated once at session start and never re-evaluated. A session started 2026-07-21 16:11 UTC (v2.1.216, while the flag did not gate its model) has been using
TaskCreatecontinuously through 2026-07-23 (17 successful calls in its transcript), while sessions started 2026-07-23 on the same machine, same account, and same model (v2.1.218) do not have the task tools at all. Two concurrent same-model sessions disagreeing makes this look like a local install problem; it is not.No local escape hatch, verified against the 2.1.218 binary:
CLAUDE_INTERNAL_FC_OVERRIDES) exists in the code but is compiled out of release builds: the reading function returns unconditionally before the env var is touched.DISABLE_GROWTHBOOK=1is not a usable workaround: diffing the compiled defaults against cached server values on 2.1.218 flips 66 unrelated flags, including malformed-tool-use auto-retry and the push-notification tool group.api.anthropic.com(same host as the model API), so the fetch cannot be blocked at the network level, and hand-edited cache values are overwritten at the next session start.Diagnostic warning for anyone else debugging this: headless
claude -pdoes not fetch feature flags and always shows the task tools, even while interactive sessions are gated. Do not use it to test whether the gate is active.Given the silent removal, the oscillation, and the absence of any override, could a maintainer confirm whether this gate is intentional? If it is, surfacing an explicit notice when the tools are gated (instead of silent absence) and a working release-build override would resolve most of the confusion in this issue and its duplicates (#76076, #79949, #80015).
Additional same-session evidence from 2.1.218 (macOS 26.5, interactive terminal,
CLAUDE_CODE_ENABLE_TASKS=1), 2026-07-23 — two details I haven't seen reported yet:1. In-session
/modelswitches re-filter the tool roster live (no restart). A-B-A-B in one continuous session:TaskCreate/TaskGet/TaskList/TaskUpdate) loadable via ToolSearch; full CRUD cycle verified (create → get → update to in_progress → list → delete → empty list)./model→ Opus 4.8 [1m]: ToolSearch for the same four tools returns "No matching deferred tools found."/model→ Haiku 4.5: all four return immediately, verified loadable./model→ Fable 5: gone again.So on 2.1.218 the roster is not locked at session startup (contrast with the startup-lock behavior described in https://github.com/anthropics/claude-code/issues/75577#issuecomment-5058318002) — the gate is re-evaluated on model switch mid-session.
2. The client mis-attributes the removal to an MCP disconnect. On each switch to a gated model, the harness injected a system notice stating the four Task tools were "no longer available (their MCP server disconnected)," and on switching back, that they were available again ("MCP server reconnected"). These are native tools, not MCP-served — the framing sent our debugging down an MCP-stability dead end for several turns. Whatever the fix for the gate itself, the deferred-tool withdrawal message shouldn't present a feature-flag filter as an MCP server event.
Cache observation consistent with the oscillation reports: at time of writing,
~/.claude.jsoncachedGrowthBookFeatures.tengu_vellum_ashis[]on this machine, while the live Fable 5 session still lacks the tools — so the in-session evaluation isn't reading that cached value (or the server value flipped again after the roster updated).Additional data point (macOS 26.5, Claude Code 2.1.220, single machine, 2026-07-26): the gate currently appears inactive for all three listed models in a fresh discriminating test designed to separate "flag genuinely empty" from "per-session model targeting."
Test: for each of
claude-opus-5(control, never gated),claude-opus-4-8, andclaude-fable-5(the latter two via mid-session/modelswitch, consistent with @adgdei's re-evaluation-on-switch finding above), ran a full Task-tool write round-trip —TaskCreate×2 →TaskUpdate(status change +addBlockedByedge) →TaskList(confirming the edge rendered) → delete — and readcachedGrowthBookFeatures.tengu_vellum_ashfrom~/.claude.jsonimmediately before and after.Result, all three models:
blockedByedge showing correctly inTaskListoutput.tengu_vellum_ashwas[]before and after every test (441 other cached flags present and populated, so this isn't the wholesale-cache-wipe artifact mentioned upthread).This rules out the naive "model id doesn't substring-match the list" explanation outright — the list itself is empty, so no model-id check could be gating anything right now on this machine.
Caveat, per @adgdei's 07-23 comment above: a
[]cache is not sufficient on its own to prove the gate is off — that comment found[]cached locally while a live Fable 5 session in the same session still lacked the tools, implying the cached value and the live-session evaluation aren't always the same read. I didn't reproduce that discrepancy here (cache and live behavior were consistent both times), but I can't rule out that it's still possible under different timing. I also deliberately avoided testing via headlessclaude -p, per @cmaga's warning above that it always fetches with the tools present and would give a false negative.Given @cmaga's oscillation table (
[]→ gated list →[]over 2026-07-15 to 07-23) and this now-[]reading two days later, this looks consistent with either a global rollback of the flag or another oscillation cycle — not evidence the underlying gate mechanism/bug is fixed. Posting mainly so anyone else debugging this on a currently-ungated window doesn't mistake "tools work for me right now" for "the bug is resolved."Related follow-up filed: #85298.
This issue documents the
tengu_vellum_ashTask-tool gate and theDISABLE_GROWTHBOOK=1workaround (thank you for the binary analysis — it's been extremely useful for us reproducing and understanding this).#85298 reports the trade-off that workaround creates now that cross-session messaging (
ListAgents/SendMessage, shipped v2.1.224) exists:DISABLE_GROWTHBOOK=1restores Task tools by making the flag evaluator fall back to its per-flag code default, but that same suppression also disables Remote Control and cross-session messaging (per the current env-vars docs), which default the other way. So the workaround for this issue creates a new one — there's currently no supported way to have Task tools and RC/cross-session messaging in the same process.Filing separately since it's a distinct-but-related availability gap that only became reachable once cross-session messaging shipped, rather than a duplicate of the original Task-gate report.