Task-list tools (TaskCreate/TaskUpdate/TaskList/TaskGet) no longer exposed to the model after recent update (tasks still visible in UI)

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

Summary

As of the most recent Claude Code update, task-list tools are no longer exposed to the model in any session. Tools such as TaskCreate / TaskUpdate / TaskList / TaskGet are simply not present in the tool set, so the model can no longer create, read, or modify tasks. This affects every session, across all worktrees of the project.

Crucially, the tasks are still fully visible in the user-facing UI — so the task list and its data are intact. The regression is specifically that the model-facing tools to interact with that list have disappeared. This narrows it to a tool-exposure regression, not data loss or a bad task-list configuration.

Environment

  • Claude Code 2.1.217 (regression observed after updating to this version)
  • Windows 11 Pro (win32)
  • Project configured with a persistent task list: CLAUDE_CODE_TASK_LIST_ID=kibitzr is set in the environment

Observed behavior

  • The task-list tools (TaskCreate, TaskUpdate, TaskList, TaskGet) are absent from the available/deferred tool set. A tool lookup for those names returns "No matching tools."
  • The tasks themselves remain visible and correct in the user-facing UI, confirming the underlying list is unaffected — only the model's tool access is gone.
  • Only TaskOutput and TaskStop are present, and those are the deprecated background-process controls (for background shells/agents), not task-list tools.
  • CLAUDE_CODE_TASK_LIST_ID is still correctly set (kibitzr), so the task list itself is configured — but there is no tool surface to interact with it.
  • The model therefore cannot add or update tasks; the on-disk task list can only be hand-edited, which was previously discouraged in favor of the native tools.

Expected behavior

Sessions should expose the native task-list tools (as they did prior to this update) so the model can create and modify tasks in the configured task list.

Impact

Any workflow that relies on the shared/persistent task list as the source of truth is broken — the model can no longer record new tasks, mark progress, or update task state. Multiple concurrent sessions are all affected simultaneously, which points to a global (build/config) regression rather than a per-session or per-project issue.

Notes

  • CLAUDE_CODE_TASK_LIST_ID being set but no task tools appearing suggests the tools were dropped from the exposed tool set (or gated off) in this release, rather than a bad task-list-id configuration.

View original on GitHub ↗

7 Comments

DrunkOnJava · 1 month ago

Confirming this on macOS arm64 (native install, Ghostty, Max plan) — with evidence that it is not a 2.1.217 client regression. It's a remote flag flip, and the title's "after recent update" framing will mislead the bisect.

Not version-specific

  • Fresh interactive sessions on 2.1.217 AND 2.1.216 (pinned binary, launched directly from ~/.local/share/claude/versions/2.1.216) both come up without TaskCreate/TaskUpdate/TaskList/TaskGet and without the TodoWrite fallback. ToolSearch select:TaskCreate,... returns no match in either.
  • Sessions started before Jul 21 ~15:20 PT keep their tools, including across a 2.1.215 → 2.1.217 resume (one of mine logged 46 TaskUpdate calls on 2.1.217 turns hours after fresh 2.1.217 sessions had lost the tools).
  • Affected on claude-fable-5 AND claude-opus-4-8, in multiple projects, with a clean env (no CLAUDE_CODE_ENABLE_TASKS, no deny rules, no --agent/--bare/--tools, no proxy).
  • Headless (claude -p) is unaffected on both versions — consistent with #78769's finding that print mode skips the live flag fetch.

Cache evidence

~/.claude.json on my machine, fetched Jul 21:

cachedGrowthBookFeatures.tengu_vellum_ash = ["claude-opus-4-8","claude-sonnet-5","claude-fable-5"]

This matches the gating #78769 extracted from the binary: the TaskCreate family registers with isEnabled = VR() && !XJ() and TodoWrite with !VR() && !XJ(), where XJ() matches the current model against the tengu_vellum_ash list — so when the flag fires, both task-tracking families disappear with no fallback, and CLAUDE_CODE_ENABLE_TASKS=1 cannot override it.

Workaround verified (including hot-reload)

Per #78769:

  1. ~/.claude/settings.json env: "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
  2. Clear cachedGrowthBookFeatures.tengu_vellum_ash to [] in ~/.claude.json

The tools came back in an already-running session via config hot-reloadToolSearch resolved all four schemas and TaskCreate worked immediately, no restart. Downside of the workaround: it also disables update checks, /bug, and error reporting, which is a heavy price for a documented core feature.

Likely duplicates of the same flip

#79949 (calls it a remote config flip, same cached value, "not a version thing"), #79900 (2.1.216), #79695 (2.1.216, GrowthBook), #79836 (intermittent "exists but is not enabled"), #79791 (remote-control sessions, Jul 21), #80034 (mid-session loss after /login re-fetch), and #78769 (mechanism; filed Jul 18 when the flag apparently covered fewer models).

Ask

If tengu_vellum_ash is an intentional A/B for the task system, the current state still looks like a misfire: it hides both the Task family and the TodoWrite fallback simultaneously, leaving no task tracking at all, and no env override wins. Either keep the fallback alive under the experiment, let CLAUDE_CODE_ENABLE_TASKS=1 override the gate, or revert the Jul 21 flip.

NubeBuster · 1 month ago
[!IMPORTANT] Updated 2026-07-28 — the one-shot script in this comment has changed. Do not use a copy you saved earlier. It now also sets CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1, applying @hw5511's two-variable recipe from #79949. The original set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC alone, which fixes the Task tools but collapses every GrowthBook flag to its hardcoded default — silently taking unrelated features down with it. It cost me plugin channels six days later; write-up in Collateral damage at the bottom. If you already ran the old version, adding that one env var is the entire delta — or just re-run the current script, it is idempotent. The superseded original is preserved further down, collapsed.

---

Linux x86_64, native install, claude-opus-4-8. Adding a pre-flip counter-example, a version data point, a repo-side check — and, as of 2026-07-28, what the workaround itself breaks.

---

I had some claude code sessions with model Fable open since 2.1.214 was latest.
Resuming them by sending a new message today made me switch to opus-4.8 because fable is no longer provided in my subscription plan.

Correction: Fable 5 is still included with your Max plan. If you see a prompt to set up usage credits for it, restart Claude Code.

Applying the workarounds mentioned in this issue discussion fixed the issue in the live sessions without requiring claude code to restart.

One-shot for anyone else hitting this. Paste into a terminal — it is idempotent, backs up every file it touches to *.bak, preserves all other keys, honours CLAUDE_CONFIG_DIR, refuses to touch unparseable JSON, and warns if a higher-precedence scope would override the fix. Takes effect in already-running sessions via hot-reload; no restart needed.

Two caveats on that "no restart", both learned since: it holds because the script writes the env block in settings.json, which Claude Code re-reads — if you instead export these at the OS level, an already-running editor keeps its stale environment block and you get the pre-fix behaviour, as @hw5511 describes above. And it applies to flag evaluation only: channel registration happens once at session start, so anything channel-related needs a fresh session regardless of hot-reload.

Edited 2026-07-28 — second env var added, applying @hw5511's two-variable recipe from #79949; see the banner at the top of this comment. The superseded original is collapsed below.

<details>
<summary><b>Current script</b> — updated 2026-07-28 (click to expand, run at own risk)</summary>

python3 - <<'PY'
import json, os, shutil, sys

FLAG = "tengu_vellum_ash"
VARS = {
    # stops the startup fetch that would re-populate the flag
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
    # ...and makes the remaining ~429 flags read your disk cache instead of
    # collapsing to hardcoded defaults. First-party auth only (see note below).
    "CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF": "1",
}
home = os.path.expanduser("~")
cfg = os.environ.get("CLAUDE_CONFIG_DIR") or os.path.join(home, ".claude")


def load(path):
    """Return (data, ok). ok=False means present-but-unparseable: never overwrite those."""
    if not os.path.exists(path):
        return {}, True
    try:
        with open(path) as fh:
            return json.load(fh), True
    except Exception as e:
        print(f"  ! {path} is not valid JSON ({e}) — skipped, fix it by hand")
        return None, False


def save(path, data):
    if os.path.exists(path):
        shutil.copy2(path, path + ".bak")
    os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
    tmp = path + ".tmp"
    with open(tmp, "w") as fh:
        json.dump(data, fh, indent=2)
    os.replace(tmp, path)


changed = []

# 1. Clear the cached flag. .claude.json may sit next to the config dir or in $HOME.
for path in {os.path.join(home, ".claude.json"), os.path.join(os.path.dirname(cfg) or home, ".claude.json")}:
    if not os.path.exists(path):
        continue
    d, ok = load(path)
    if not ok:
        continue
    feats = d.get("cachedGrowthBookFeatures") or {}
    if feats.get(FLAG):
        print(f"  flag was: {json.dumps(feats.get(FLAG))}")
        feats[FLAG] = []
        d["cachedGrowthBookFeatures"] = feats
        save(path, d)
        changed.append(path)
    else:
        print(f"  flag already empty or absent in {path}")

# 2. Set the env vars in user settings (env blocks merge across scopes, so this suffices).
settings = os.path.join(cfg, "settings.json")
d, ok = load(settings)
if ok:
    env = d.setdefault("env", {})
    missing = {k: v for k, v in VARS.items() if env.get(k) != v}
    if not missing:
        print(f"  env vars already set in {settings}")
    else:
        env.update(missing)
        save(settings, d)
        changed.append(settings)
        for k in missing:
            print(f"  set {k}={missing[k]} in {settings}")

# 3. Warn if a higher-precedence scope explicitly disables it (would beat the write above).
higher = [
    "/etc/claude-code/managed-settings.json",
    "/Library/Application Support/ClaudeCode/managed-settings.json",
    "C:\\ProgramData\\ClaudeCode\\managed-settings.json",
    os.path.join(os.getcwd(), ".claude", "settings.json"),
    os.path.join(os.getcwd(), ".claude", "settings.local.json"),
]
for path in higher:
    if not os.path.exists(path) or os.path.abspath(path) == os.path.abspath(settings):
        continue
    d, ok = load(path)
    if not ok:
        continue
    for k, v in VARS.items():
        cur = d.get("env", {}).get(k)
        if cur not in (None, v):
            print(f"  !! {path} sets {k}={cur} and outranks user settings — change it there too")

# 4. DISABLE_GROWTHBOOK outranks the disk-cache path entirely — it must be UNSET.
KILL = "DISABLE_GROWTHBOOK"
hits = []
if os.environ.get(KILL):
    hits.append("the process environment")
for path in [settings, *higher]:
    if not os.path.exists(path):
        continue
    dd, dok = load(path)
    if dok and dd.get("env", {}).get(KILL):
        hits.append(path)
if hits:
    print(f"  !! {KILL} is set in: " + ", ".join(hits))
    print("     While it is set, CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF cannot engage,")
    print("     so every flag still collapses to its hardcoded default. Unset it.")

# 5. The disk-cache path is first-party only; on Bedrock/Vertex it never engages.
if os.environ.get("CLAUDE_CODE_USE_BEDROCK") or os.environ.get("CLAUDE_CODE_USE_VERTEX"):
    print("  !! Bedrock/Vertex detected — CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF")
    print("     has no effect there, so your other flags will still fall back to defaults.")

print()
if changed:
    print("patched (backups alongside as *.bak):")
    for p in changed:
        print("  -", p)
    print("\nTakes effect in already-running sessions via hot-reload; no restart needed.")
else:
    print("nothing to change — already applied, or the flag was never set for you.")
    sys.exit(0)
PY

</details>

All three pieces matter, and they do different jobs:

  • Clearing the cached flag alone is undone by the next startup fetch.
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 suppresses that fetch — but on its own it also stops flag evaluation, so every other flag falls back to its hardcoded default.
  • CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1 puts evaluation back on the disk cache, so only tengu_vellum_ash — the value you just edited — differs from what the server last sent you.

Two conditions on that last one, both from @hw5511's gate dump above and both now checked by the script: it requires first-party auth (no effect on Bedrock/Vertex), and it requires DISABLE_GROWTHBOOK to be unset — that variable short-circuits the disk-cache path as well as the fetch, so setting it alongside gets you the hardcoded defaults anyway.

env blocks merge across settings scopes, so writing user settings.json works even if you also have /etc/claude-code/managed-settings.json — verified here by observing managed-only and user-only vars simultaneously present in the session environment.

Revert by restoring the *.bak files once this is fixed upstream — the traffic var also disables update checks, /bug, and error reporting, and while it is set your flag cache is frozen at its last live fetch, so genuinely new server-side features will not reach you.

<br>

<details>
<summary>~~Original script~~ — superseded 2026-07-28, kept for reference (do not run)</summary>

⚠️ Do not run this one. It is the version the confirmations above refer to, kept so those comments still point at something real. It sets CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC only, which fixes the Task tools while silently disabling every other default-off flag-gated feature. Use the current script above.
python3 - <<'PY'
# !! SUPERSEDED 2026-07-28 — this version sets CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
# !! only, which disables other flag-gated features (channels, Monitor, ...).
# !! Use the current script in the comment above instead.
import json, os, shutil, sys

FLAG = "tengu_vellum_ash"
VAR = "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC"
home = os.path.expanduser("~")
cfg = os.environ.get("CLAUDE_CONFIG_DIR") or os.path.join(home, ".claude")


def load(path):
    """Return (data, ok). ok=False means present-but-unparseable: never overwrite those."""
    if not os.path.exists(path):
        return {}, True
    try:
        with open(path) as fh:
            return json.load(fh), True
    except Exception as e:
        print(f"  ! {path} is not valid JSON ({e}) — skipped, fix it by hand")
        return None, False


def save(path, data):
    if os.path.exists(path):
        shutil.copy2(path, path + ".bak")
    os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
    tmp = path + ".tmp"
    with open(tmp, "w") as fh:
        json.dump(data, fh, indent=2)
    os.replace(tmp, path)


changed = []

# 1. Clear the cached flag. .claude.json may sit next to the config dir or in $HOME.
for path in {os.path.join(home, ".claude.json"), os.path.join(os.path.dirname(cfg) or home, ".claude.json")}:
    if not os.path.exists(path):
        continue
    d, ok = load(path)
    if not ok:
        continue
    feats = d.get("cachedGrowthBookFeatures") or {}
    if feats.get(FLAG):
        print(f"  flag was: {json.dumps(feats.get(FLAG))}")
        feats[FLAG] = []
        d["cachedGrowthBookFeatures"] = feats
        save(path, d)
        changed.append(path)
    else:
        print(f"  flag already empty or absent in {path}")

# 2. Set the env var in user settings (env blocks merge across scopes, so this suffices).
settings = os.path.join(cfg, "settings.json")
d, ok = load(settings)
if ok:
    if d.get("env", {}).get(VAR) == "1":
        print(f"  {VAR} already set in {settings}")
    else:
        d.setdefault("env", {})[VAR] = "1"
        save(settings, d)
        changed.append(settings)

# 3. Warn if a higher-precedence scope explicitly disables it (would beat the write above).
higher = [
    "/etc/claude-code/managed-settings.json",
    "/Library/Application Support/ClaudeCode/managed-settings.json",
    "C:\\ProgramData\\ClaudeCode\\managed-settings.json",
    os.path.join(os.getcwd(), ".claude", "settings.json"),
    os.path.join(os.getcwd(), ".claude", "settings.local.json"),
]
for path in higher:
    if not os.path.exists(path) or os.path.abspath(path) == os.path.abspath(settings):
        continue
    d, ok = load(path)
    if ok and d.get("env", {}).get(VAR) not in (None, "1"):
        print(f"  !! {path} sets {VAR}={d['env'][VAR]} and outranks user settings — change it there too")

print()
if changed:
    print("patched (backups alongside as *.bak):")
    for p in changed:
        print("  -", p)
    print("\nTakes effect in already-running sessions via hot-reload; no restart needed.")
else:
    print("nothing to change — already applied, or the flag was never set for you.")
    sys.exit(0)
PY

</details>

~~Both steps matter: clearing the cached flag alone is undone by the next startup fetch, which is what the env var suppresses. env blocks merge across settings scopes, so writing user settings.json works even if you also have /etc/claude-code/managed-settings.json — verified here by observing managed-only and user-only vars simultaneously present in the session environment.~~ ~~Revert by restoring the *.bak files once this is fixed upstream — the env var also disables update checks, /bug, and error reporting.~~

---

2.1.214 is affected, and pre-flip sessions do _not_ keep their tools

A session whose transcript starts 2026-07-18 04:08 UTC — three days before the flip — is stamped version: 2.1.214 on every entry including today's. The installed version here is 2.1.217, so a fresh launch or --continue would be stamped 2.1.217: this is the original long-lived 2.1.214 process, not a resume onto a new binary.

| When (UTC) | What |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Jul 18 04:09 – 08:45 | 76 successful TaskCreate/TaskUpdate calls |
| Jul 18 08:45 → Jul 22 05:04 | idle (~4 days) |
| Jul 22 05:04:17 | resumed with a new user message |
| Jul 22 05:06:57 | TaskUpdate, TaskListNo such tool available: TaskUpdate. TaskUpdate exists but is not enabled in this context. |

So the gate is re-evaluated mid-process, not pinned at process start, and 2.1.214 is below the range tested so far. "Started before Jul 21 ~15:20 PT" is not the discriminator — being idle across the flip and used again is enough.

Three follow-ons:

  • #79836 is not a separate intermittent bug — its "exists but is not enabled" wording is exactly this.
  • /login is not required for mid-session loss (cf. #80034); grep for /login in that transcript returns 0.
  • The TUI still rendered the existing task list while the model could not read or modify it, matching the title.

---

No client release could have caused this

The published v2.1.214...v2.1.217 diff touches only CHANGELOG.md, feed.xml, and a new examples/gateway/aws/ tree:

curl -sL https://github.com/anthropics/claude-code/compare/v2.1.214...v2.1.217.diff \
  | grep -cE 'TaskCreate|TaskUpdate|TaskList|TaskGet|TodoWrite'   # -> 0

The title's "after recent update" framing should probably be dropped.

---

Still being served as of 2026-07-22 05:09 UTC

A fresh startup fetch wrote tengu_vellum_ash = ["claude-opus-4-8","claude-sonnet-5","claude-fable-5"] — identical to the Jul 21 macOS value, so it had not been reverted ~14h later and the same list goes out across platforms. Note the 05:06:57 failure above _precedes_ that 05:09:47 cache write, so the cache timestamp is not the moment the gate takes effect.

---

Notes

  • The workaround also works from /etc/claude-code/managed-settings.json, not just user settings.json, and restored all four tools via hot-reload in an already-running session — useful if you're deploying it fleet-wide.
  • CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 does not exempt you. With teams enabled the task list is the coordination surface between teammates, so the flag takes that out too.
  • TaskOutput/TaskStop survive — background-process tools, unrelated to the gated family. Reports saying "the task tools are gone" are ambiguous without that split.
  • claude-fable-5 stopped being offered on resume, forcing sessions onto claude-opus-4-8 — also on the list, so switching models doesn't dodge the gate.

---

Collateral damage: the traffic var alone silently kills plugin channels (added 2026-07-28)

Six days after applying my own workaround I lost inbound MCP channel notifications and spent a while looking for the wrong culprit, because the only trace is one --debug line that names no cause:

[DEBUG] MCP server "<plugin>": Channel notifications skipped: channels feature is not currently available

Channel registration is gated on tengu_harbor, whose hardcoded default is false — so with CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 and nothing else, it evaluates false no matter what the server sent you. My cache held tengu_harbor: true the entire time; it was simply never consulted. Everything else on the registration path was fine — the plugin declares the capability, channelsEnabled: true is set, the plugin is on the allowlist and passed via --channels — the flag was the only blocker. Adding CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1 restored it on the next launch (Linux x86_64, native, 2.1.220, first-party, Max).

To be clear about what this does and doesn't fix: it restores channels that worked before you set the traffic var. If channels never worked for you, this changes nothing — that's #74303 / #36460 territory.

Same collapse @hw5511 documented, reached by a different route: theirs came from DISABLE_GROWTHBOOK=1, mine from CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 on its own. Two triggers, one outcome — and the traffic var is the one this thread hands out, so it is the path most people here are on.

Counting the reports scattered across these threads, that collapse now has five known casualties, every one found by accident days later:

| What dies | Gate | Reported in |
| --- | --- | --- |
| Monitor, RemoteTrigger, PushNotification, EndConversation | tengu_amber_sentinel | #79949 — @hw5511 |
| Remote Control (/rc absent) | — | #78769 — @aschoettler |
| Hosted Artifacts (Artifact tool + artifact-design / artifact-capabilities skills) | — | #78769 — @gulp |
| Opus 4.6 1M context on eligible plans | — | #34178 |
| Plugin channels (inbound MCP notifications) | tengu_harbor | this comment |

The oldest is #34178, filed at 2.1.75 asking that feature entitlements not depend on telemetry configuration. Auto-closed as inactive, argued against in comments, closed again, locked. #45918 later filed the channels case by name ("CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC blocks channels feature flag (tengu_harbor)") and was auto-closed as a duplicate — of that locked issue. Neither mentions the disk-cache var, so anyone routed there today is still told the choice is telemetry-or-no-channels.

Which is the wider point for this issue: telling users to disable nonessential traffic to dodge an A/B flip hands them an unbounded, unannounced feature regression. The blast radius is every default-off flag in the build, nothing in the UI says so, and no user can enumerate what they lost.

Fuller write-up, including why Tasks and Artifacts//rc are not actually mutually exclusive (cf. @gulp above): my follow-up comment.

hw5511 · 1 month ago

Confirming the CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC workaround from the script above on Windows 11 / 2.1.217 / native / claude-opus-4-8, plus two things that aren't obvious from the script and cost me a wasted restart.

1. Why that combination works — and why it beats DISABLE_GROWTHBOOK=1

There are two ways to stop the live fetch, and only one of them keeps your cache:

if (!Hne() && !Eug()) return { value: t, source: "disabled" };   // caller's DEFAULT, cache ignored
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"; ... }

DISABLE_GROWTHBOOK=1 forces both false → all ~430 flags collapse to hardcoded defaults. Concretely that killed Monitor, RemoteTrigger, PushNotification and EndConversation for me, because they're gated the opposite way (Soe(){ return Ke("tengu_amber_sentinel", !1) } — default false, server value true). The server was switching Tasks off and those on; collapsing to defaults inverts both.

Adding CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1 alongside CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 (and leaving DISABLE_GROWTHBOOK unset) makes Eug() true, so it reads your edited disk cache instead of defaults. Only tengu_vellum_ash changes; the other 429 keep their real server values. I now have the Task tools and Monitor/RemoteTrigger/PushNotification/EndConversation at the same time.

If you're on Bedrock/Vertex this path won't engage — Eug() also requires jc(){ return Cn()==="firstParty" }.

2. Restart the editor, not just Claude Code

A user-scope env var doesn't reach an already-running editor. I set the variables, restarted Claude Code alone, and got the pre-fix behavior — the process had inherited VS Code's stale environment block. Fully quit VS Code (or your terminal host) and relaunch. Verify inside the session with echo $CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC before deciding the workaround didn't work; I nearly wrote it off on that basis.

3. Re: the title

Agreeing with @DrunkOnJava — "after recent update" will misdirect a bisect. My cache shows tengu_vellum_ash: ["claude-opus-4-8","claude-sonnet-5","claude-fable-5"], and in my case the tools vanished mid-session on an unchanged running binary, which no client version can explain. Full write-up of the gating and the trade-offs: #79949.

mokelly · 1 month ago

I confirm that the Clear cachedGrowthBookFeatures.tengu_vellum_ash to [] in ~/.claude.json proposal fixed the problem for me, and agree that the root problem was not a version bump -- just coincident. Thanks to all for the help!

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.

fqx · 1 month ago

I can see todo list now, is it solved?

NubeBuster · 1 month ago

I've edited my one-shot script above to apply @hw5511's two-variable recipe from #79949CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 plus CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1. My original set the traffic var alone, which fixes the Task tools but collapses every flag to its hardcoded default.

Two things worth having in this thread: a casualty of that collapse nobody had named yet, and the fact that the decoupling several people here have asked for already exists.

The unnamed casualty: plugin channels

One --debug line, no warning, no UI change:

[DEBUG] MCP server "<plugin>": Channel notifications skipped: channels feature is not currently available

Channel registration is gated on tengu_harbor, hardcoded default false. My disk cache held tengu_harbor: true the whole time — it was simply never consulted. Nothing else was wrong: capability declared, channelsEnabled: true, plugin allowlisted and passed via --channels. The flag was the only blocker. The two-var recipe restored it on the next launch (Linux x86_64, native, 2.1.220, first-party, Max).

Scope: this restores channels that worked before you set the traffic var. If channels never worked for you it changes nothing — that's #74303 / #36460.

Tasks vs. Artifacts / /rc is not mutually exclusive

@gulp reported (#78769) that the workaround forces a choice — Task tools or hosted Artifacts and Remote Control — and asked for "a per-flag local override (bootstrapping tengu_vellum_ash: [] without blocking all nonessential traffic)".

That override exists today. CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF=1 is exactly it: evaluation reads your on-disk cachedGrowthBookFeatures instead of collapsing to defaults, so the one array you edited is the only value that differs from what the server last sent. Tasks and Artifacts and /rc at once. It is undocumented, which is why this thread converged on the blunt lever instead.

Two conditions, both from @hw5511's Eug() dump (above) and both now enforced by my script:

  • first-party auth only — no effect on Bedrock/Vertex;
  • DISABLE_GROWTHBOOK must be unsetEug() contains !Z.DISABLE_GROWTHBOOK, so it kills the disk-cache path too. Set both and you are back on defaults with nothing indicating the rescue var did nothing.

One channels-specific caveat: flag changes hot-reload, but channel registration happens once at session start, so channels need a fresh session either way.

Five casualties, five people who found them by accident

| What silently dies | Gate | Reported in |
| --- | --- | --- |
| Monitor, RemoteTrigger, PushNotification, EndConversation | tengu_amber_sentinel | #79949 — @hw5511 |
| Remote Control (/rc) | — | #78769 — @aschoettler |
| Hosted Artifacts (Artifact tool + artifact-design / artifact-capabilities skills) | — | #78769 — @gulp |
| Opus 4.6 1M context on eligible plans | — | #34178 |
| Plugin channels (inbound MCP notifications) | tengu_harbor | this comment |

Not one was found by looking — each surfaced days later when something unrelated stopped working.

The oldest is #34178, filed at 2.1.75 asking that feature entitlements not depend on telemetry configuration. Auto-closed as inactive, argued against in comments, closed again, locked. #45918 later filed the channels case by name and was auto-closed as a duplicate — of that locked issue. Neither mentions the disk-cache var, so anyone routed there today is still told the choice is telemetry-or-no-channels.

So: the recipe in this thread works and I've updated mine to match. The remaining ask is documentation and decoupling. CLAUDE_CODE_GB_DISK_CACHE_WHEN_TELEMETRY_OFF is currently discoverable only by decompiling the binary, and the lever people find first has an unbounded blast radius with no in-product signal about what it took away.

Showing cached comments. Read the full discussion on GitHub ↗