Tasks tools (TaskCreate/TaskList/TaskUpdate) disappeared today, looks like a remote config flip

Status Open
Reported on v2.1.217
Maintainer reply None cached
Activity 5 comments · opened Jul 21, 2026

The task list tools (TaskCreate, TaskGet, TaskList, TaskUpdate) vanished from my sessions today. They worked fine yesterday and even earlier this morning.

What I found digging in:

  • Not a version thing. The same 2.1.217 binary had the tools in a session around 3pm PT and lost them in sessions started about 20 minutes later. The tool code is still in the binary.
  • The tools register with isEnabled(){return TH()&&!xZ()}. TH is the CLAUDE_CODE_ENABLE_TASKS env check. xZ reads a remote config called tengu_vellum_ash and disables the tools when the current model matches an entry in it.
  • My cached value now shows tengu_vellum_ash = ["claude-opus-4-8", "claude-sonnet-5", "claude-fable-5"], fetched today at 15:20 PT. So the tools are off for basically every model I'd actually use.

Is this an intentional rollback of the tasks feature or a flag misfire? I use these tools daily, so I'd love to know if they're coming back or if there's a supported way to re-enable them.

Setup: Claude Code 2.1.217, macOS arm64, native install. Happy to share more env details if useful.

View original on GitHub ↗

4 Comments

hw5511 · 1 month ago

Reproduced on a third platform, and there is a working workaround. Details below in case it helps others hitting this.

Repro (Windows)

  • Claude Code 2.1.217, native install, Windows 11.
  • Cached gate value in ~/.claude.json: "tengu_vellum_ash": ["claude-opus-4-8", "claude-sonnet-5", "claude-fable-5"]
  • Tools were present earlier in the same long-running session and disappeared mid-session — consistent with your remote-flip observation, not with the binary. (My binary was also replaced by an update on the same day, but the running process kept the pre-update image, so that wasn't the trigger either.)

Same gate as you described, still present in 2.1.217:

function xZ(){
  try {
    let e = Ke("tengu_vellum_ash", []);
    if (!Array.isArray(e) || e.length === 0) return !1;
    let t = Ii();                       // current model id
    return e.some(r => r.length > 0 && t.includes(r));
  } catch { return !1 }
}

Workaround: DISABLE_GROWTHBOOK=1

# Windows (PowerShell), user scope
[Environment]::SetEnvironmentVariable('DISABLE_GROWTHBOOK','1','User')
# revert: pass $null instead of '1'
# macOS / Linux
export DISABLE_GROWTHBOOK=1

Then fully restart Claude Code. Verified working: TaskCreate / TaskGet / TaskList / TaskUpdate came back on claude-opus-4-8.

Why it works — the flag reader short-circuits to the caller's default when GrowthBook evaluation is off:

function ZXn(e, t) {
  let r = X3r(); if (r && e in r) return { value: r[e], source: "override" };
  let n = zXt(); if (n && e in n) return { value: n[e], source: "override" };
  if (!Hne() && !Eug()) return { value: t, source: "disabled" };   // <-- returns the default
  ...
}
function Hne(){ return !Z.DISABLE_GROWTHBOOK && Cne() }

So Ke("tengu_vellum_ash", []) yields [] instead of the server list, xZ() returns false, and isEnabled(){ return TH() && !xZ() } passes.

Side effects — worth knowing before you set it

  • Remote Control stops working. The binary has a dedicated message for this: "Remote Control requires feature-flag evaluation, which is disabled because DISABLE_GROWTHBOOK is set. Unset it (or run in a shell without it) to use Remote Control." If you rely on Remote Control, don't set this.
  • All feature flags fall back to their defaults (~430 of them here), so other staged rollouts revert too. This is a blunt instrument, not a targeted opt-out.

Things that do not work (so nobody else burns time on them)

  • CLAUDE_CODE_ENABLE_TASKS=1 — it's a kill switch, not an enabler: function wD(){ if (Z.CLAUDE_CODE_ENABLE_TASKS === !1) return !1; return !0 }. It's already satisfied; xZ() is what blocks.
  • Editing the cached value in ~/.claude.json — a fresh fetch at startup overwrites it.
  • CLAUDE_INTERNAL_FC_OVERRIDES — the env-override path exists but is unreachable in the public build; X3r() returns before ever reading it, and the second override source zXt() is an empty function:

``js
function X3r(){ if (Z5i) return Int; return Z5i = !0, Int;
let e = process.env.CLAUDE_INTERNAL_FC_OVERRIDES; /* dead code */ }
function zXt(){ return }
``

The actual ask

A targeted opt-out would be much better than disabling feature-flag evaluation wholesale — e.g. honoring CLAUDE_CODE_ENABLE_TASKS=1 as an explicit override of tengu_vellum_ash, the way UQu(e){ if (e) return !1; return Ke("tengu_shale_finch", !1) } lets a caller-supplied flag bypass its gate. Right now the only way to keep Tasks is to give up Remote Control and every other flag's rollout state.

And the original question still stands: is the model kill-list an intentional rollback for these models, or a flag misfire? That determines whether this workaround is a stopgap or something we should stop relying on.

hw5511 · 1 month ago

Follow-up to my workaround above — I under-sold the cost. Now that I've measured it: DISABLE_GROWTHBOOK=1 is a 4-for-4 trade, not a free win. If you're about to apply it, read this first.

What actually breaks

These native tools disappear along with it:

  • Monitor — background event-stream monitoring
  • RemoteTrigger — create/manage scheduled cloud routines (/schedule) from the CLI
  • PushNotification
  • EndConversation

Monitor is the clearest example, because it's gated the opposite way from the Task tools:

// Monitor
isEnabled(){ return Soe() && _p() }
function Soe(){ return Ke("tengu_amber_sentinel", !1) }   // default false — the flag ENABLES it

// Task tools
isEnabled(){ return TH() && !xZ() }
function xZ(){ let e = Ke("tengu_vellum_ash", []); ... }  // default []   — the flag DISABLES them

Against my cached server values:

| | server value | default | with DISABLE_GROWTHBOOK=1 |
|---|---|---|---|
| Task tools ×4 | ["claude-opus-4-8","claude-sonnet-5","claude-fable-5"] → blocked | [] | ✅ on |
| Monitor | tengu_amber_sentinel: true → allowed | false | ❌ off |

So the server config was simultaneously switching Tasks off and Monitor on. Collapsing everything to defaults inverts both — there is no single setting that satisfies both, by construction.

(Note for anyone diagnosing this: the tools vanish silently, and in my client they were reported under a "MCP server disconnected" style notice alongside genuinely unrelated MCP servers, which made it look like a network blip rather than a consequence of the env var. Easy to misattribute.)

Practical impact

  • Monitor is replaceable — a background gh/shell poll loop covers the same ground. I swapped mine over and it works fine.
  • RemoteTrigger is the one that stings: you can't create or edit scheduled cloud routines from the CLI while this is set. Worth unsetting temporarily if you need to author one.

Why this sharpens the request

The targeted opt-out I asked for above isn't a nicety — right now the only way to keep the Task tools is to surrender Remote Control, Monitor, RemoteTrigger, PushNotification, EndConversation, and every other flag's rollout state. Honoring CLAUDE_CODE_ENABLE_TASKS=1 as an explicit override of tengu_vellum_ash would cost nothing and make all of this unnecessary.

Related: CLAUDE_CODE_ENABLE_TASKS reads like an enable switch but is implemented as a kill switch only — function wD(){ if (Z.CLAUDE_CODE_ENABLE_TASKS === !1) return !1; return !0 }. Setting it to 1 is a no-op, which is its own small trap for anyone trying to fix this the obvious way.

hw5511 · 1 month ago

Correcting my own advice above. I said the only way to get the Task tools back was DISABLE_GROWTHBOOK=1, and that you had to surrender Remote Control, Monitor, RemoteTrigger, PushNotification and every other flag's rollout state to do it. That trade is avoidable. There's a surgical route that neutralizes only tengu_vellum_ash and leaves the other ~429 flags at their real server values. Verified working on 2.1.217 / claude-opus-4-8 / Windows, native install.

The recipe

# Windows (PowerShell), user scope — unset the blunt one, set these two
[Environment]::SetEnvironmentVariable('DISABLE_GROWTHBOOK', $null, 'User')
[Environment]::SetEnvironmentVariable('CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', '1', 'User')
[Environment]::SetEnvironmentVariable('CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF', '1', 'User')
# macOS / Linux
unset DISABLE_GROWTHBOOK
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
export CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1

Then edit ~/.claude.json (back it up first) and set:

"cachedGrowthBookFeatures": { "tengu_vellum_ash": [], ... }

Leave every other key alone. Restart.

**Result on my machine: TaskCreate/TaskGet/TaskList/TaskUpdate and Monitor/RemoteTrigger/PushNotification/EndConversation are all present simultaneously.** With DISABLE_GROWTHBOOK=1 the latter four were gone.

Why it works

The flag reader has two ways to skip the network, and only one of them discards your cache:

function ZXn(e, t) {
  ...
  if (!Hne() && !Eug()) return { value: t, source: "disabled" };   // <-- caller's DEFAULT
  // otherwise falls through to the on-disk cachedGrowthBookFeatures
}
function Hne(){ return !Z.DISABLE_GROWTHBOOK && Cne() }
function Eug(){ return Z.CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF && !Z.DISABLE_GROWTHBOOK && hwe() && jc() }
function hwe(){ return wbl() !== "default" }
function wbl(){ if (process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC) return "essential-traffic"; ... return "default" }
function jc(){ return Cn() === "firstParty" }
  • DISABLE_GROWTHBOOK=1 forces both Hne() and Eug() false → every flag collapses to its hardcoded default. That's why Monitor died: it's gated the other way round, Soe(){ return Ke("tengu_amber_sentinel", !1) }, default false. The server was switching Tasks off and Monitor on; collapsing to defaults inverts both.
  • The combination above makes Hne() false (no live fetch, so your edit isn't overwritten) but Eug() true, so it reads the disk cache instead of defaults. Only the one key you edited changes.

jc() requires first-party API — if you're on Bedrock/Vertex this path won't engage.

The gotcha that will cost you a restart

Changing a user-scope env var does not reach an already-running editor. I set the variables, restarted Claude Code alone, and got the old behavior back (Tasks on, Monitor still missing) because the process inherited the stale environment block from VS Code. Fully quit the editor/terminal host and relaunch, then confirm with echo $CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC inside the session before concluding the workaround failed.

Cost of this route

  • Feature flags are frozen at your cached snapshot — no more rollouts reach you until you unset the env (at which point tengu_vellum_ash comes back and you'd re-edit).
  • Non-essential traffic is off, so /feedback and similar are disabled.

That's a far smaller blast radius than losing Remote Control, and it's fully reversible. Still, none of this should be necessary — honoring CLAUDE_CODE_ENABLE_TASKS=1 as an explicit override of tengu_vellum_ash would replace all of it with one documented switch. Note there's already precedent for exactly that shape elsewhere in the same binary: cron ships a dedicated opt-out, function TK(){ return !zt(process.env.CLAUDE_CODE_DISABLE_CRON) && kye("tengu_kairos_cron", !0, ...) }.

cmaga · 1 month ago

Posted consolidated evidence in #75577 (https://github.com/anthropics/claude-code/issues/75577#issuecomment-5058318002): the tengu_vellum_ash gate oscillates server-side (empty on 2026-07-15 and briefly on 2026-07-22, repopulated since), and the tool roster locks at session startup — so concurrent same-model sessions on one machine can disagree about whether the task tools exist. Includes verified dead ends for local workarounds.

Showing cached comments. Read the full discussion on GitHub ↗