[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.
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗