The junior hits Shift+Tab. The status bar leaves plan mode. The next turn still runs Bash from a skill with no prompt. Chat files the ticket: “plan mode is still on. always-ask is off.”
I stop the run there. A leftover allowed-tools rule is not you still in plan mode. Claude Code’s public notes that named this field are blunt: a skill’s or slash command’s allowed-tools rule used to come back in a later turn when you leave auto mode or plan mode partway through that turn. Official skills docs already say the grant is for the invoking turn and clears when you send the next message. The human left the mode. The second turn is not a stuck plan. [Source: https://code.claude.com/docs/en/changelog] [Source: https://code.claude.com/docs/en/skills]
I already refused to treat a repeated reply ID as a second approval in A Repeated Reply ID Is Not a Second Approval, a nested deny as a mod approval in A Nested Deny Is Not a Mod Approval, and an allowed-mail list as a Cloudflare account in An Allowed-Mail List Is Not a Cloudflare Account. This post is the same desk rule for a leftover skill pass. Print the allowed-tools line. Print whether the session already left plan or auto. Name who owns the Claude Code answers.
The question is not whether the status bar looked quiet. The question is whether the named owner can still tell a leftover allowed-tools rule from a stuck plan.

The ticket that looks like plan-mode-is-stuck
Juniors treat a quiet prompt the way they treat a skipped always-ask. Yesterday they invoked /deploy in auto mode. Today they left auto, then a later turn ran Bash from that skill with no dialog. They page the desk: “plan mode never dropped” or “always-ask broke.”
Two jobs collide on that row.
- Keep the grant one-turn. Official skills page:
allowed-toolslists tools Claude can use without asking during the turn that invokes the skill. The grant clears when you send your next message, even though the skill body stays in context. Invoking the skill again re-applies the grant for that new turn. [Source: https://code.claude.com/docs/en/skills] - Keep the leftover from riding a mode change. Official changelog, 6 October 2026: a skill’s or slash command’s
allowed-toolsrule coming back in a later turn when you leave auto mode or plan mode partway through that turn is the named miss. After that date the leftover is the field. It is not proof the human is still in plan mode. [Source: https://code.claude.com/docs/en/changelog]
If you only screenshot “I already left plan,” you will file always-ask-broken. You will not file the leftover rule.
I do not invent a fake overnight outage of every plan-mode session. I use the public contract. The leftover rule is the ticket, not a version pin in the title.
What Claude Code actually named
Read the 6 October 2026 changelog, then the skills frontmatter, then the permission-modes page that names how you leave plan. Do not trust a social recap. Do not trust this post without those pages.
The named field, published 6 October 2026:
Fixed a skill’s or slash command’s allowed-tools rule coming back in a later turn when you leave auto mode or plan mode partway through that turn
That sentence has three parts. Print all three on the ticket.
| Part | What it is | What it is not |
|---|---|---|
Leftover allowed-tools | A skill or slash-command grant that survived into a later turn | Proof always-ask is off |
| Mode already left | Status bar no longer shows plan or auto after Shift+Tab or an approved plan | The human still sitting in plan mode |
| Named owner | The human who answers Claude Code permission rows | A coding agent, a skill file, or a slash command |
Official skills docs keep the grant small. The field is optional. It accepts a space- or comma-separated string, or a YAML list. The grant is for the invoking turn. Sending the next message clears it. Skill content stays in context; the permission grant does not. [Source: https://code.claude.com/docs/en/skills]
Official permission-modes docs name the leave path. Enter plan with Shift+Tab, /plan, or claude --permission-mode plan. Press Shift+Tab again to leave plan without approving a plan. Approving a plan exits plan and switches to the mode each approve option describes. From auto, the first Shift+Tab goes to Manual (default). [Source: https://code.claude.com/docs/en/permission-modes]
The leftover is the miss that looks like this ticket. Right mode change, wrong grant lifetime. After 6 October 2026, a skill pass that returns on a later turn after you left auto or plan mid-turn is that miss, not a stuck plan. [Source: https://code.claude.com/docs/en/changelog] [Source: https://code.claude.com/docs/en/skills]
Where the pin sits after the decision, not in the title
/ultrareview staged copies. Do not put those tags in the title. Do not mix plan-mode classifier, extra-scope, redirected rm, nested deny, or repeated reply ID into this heading. [Source: https://code.claude.com/docs/en/changelog]Four checks before you file
A mid-senior screenshots this list. A junior who only has the agent log still has a ticket they can close.
- Print the
allowed-toolsline. Official docs: frontmatter on the skill or slash command. If the file has noallowed-tools, this is not the field. The session is using the normal permission mode. [Source: https://code.claude.com/docs/en/skills] - Print leftover versus still-in-plan. If the status bar still says plan, and you never left, the field is a live plan session. If you already left auto or plan mid-turn and a later turn still ran the skill tools with no prompt, the field is leftover. After 6 October 2026 that leftover is the named miss. [Source: https://code.claude.com/docs/en/changelog]
- Print who owns the session. Official permission-modes page: you change a running session’s mode at any time. A skill file does not own the answers. A coding agent does not own them. [Source: https://code.claude.com/docs/en/permission-modes]
- Write one human name.
CLAUDE_CODE_OWNER. That name answers “is this a leftoverallowed-toolsrule, or did we file plan-mode-stuck on a later turn.”

Probe the frontmatter before you file the ticket
Do not leave plan mode in production to “see if the grant still fires.” Classify the skill file. The probe below never talks to Claude Code. It never sends Shift+Tab. It never runs the skill.
1#!/usr/bin/env python3
2"""Classify a skill or slash-command allowed-tools line. Never invoke the skill."""
3from __future__ import annotations
4
5from pathlib import Path
6from typing import Any
7
8import yaml
9
10
11def parse_frontmatter(text: str) -> dict[str, Any]:
12 if not text.startswith("---"):
13 return {}
14 parts = text.split("---", 2)
15 if len(parts) < 3:
16 return {}
17 data = yaml.safe_load(parts[1]) or {}
18 return data if isinstance(data, dict) else {}
19
20
21def classify(path: Path) -> dict[str, Any]:
22 text = path.read_text(encoding="utf-8")
23 meta = parse_frontmatter(text)
24 raw = meta.get("allowed-tools")
25 has_grant = raw not in (None, "", [], ())
26 return {
27 "path": str(path),
28 "this_field": has_grant,
29 "allowed_tools": raw,
30 "reason": (
31 "skill grant exists — leftover is this ticket"
32 if has_grant
33 else "no allowed-tools — not this field"
34 ),
35 }
36
37
38def main() -> None:
39 samples = [
40 Path("fixtures/deploy-skill.md"),
41 Path("fixtures/readme-only.md"),
42 ]
43 for row in samples:
44 if not row.is_file():
45 print(row, {"this_field": False, "reason": "missing fixture"})
46 continue
47 print(row, classify(row))
48
49
50if __name__ == "__main__":
51 main()
A fixture with allowed-tools: Bash(git status *) prints this_field=True. A file with no frontmatter grant prints this_field=False. That second file is not this post. Do not file plan-mode-stuck on a skill that never had a grant. [Source: https://code.claude.com/docs/en/skills]
Print the three lines on the ticket
The printer below is the whole close-out. It never calls the network. It never changes permission mode.
1#!/usr/bin/env python3
2"""Print leftover allowed-tools vs still-in-plan vs named owner. Never switch modes."""
3from __future__ import annotations
4
5import os
6from pathlib import Path
7
8from classify_allowed_tools import classify
9
10
11def main() -> int:
12 owner = os.environ.get("CLAUDE_CODE_OWNER", "").strip()
13 skill = Path(os.environ.get("SKILL_PATH", "SKILL.md"))
14 mode_now = os.environ.get("PERMISSION_MODE_NOW", "").strip().lower()
15 mode_when_invoked = os.environ.get("PERMISSION_MODE_WHEN_INVOKED", "").strip().lower()
16 later_turn = os.environ.get("LATER_TURN", "false").strip().lower() == "true"
17 row = classify(skill) if skill.is_file() else {"this_field": False, "reason": "missing skill file"}
18 left_auto_or_plan = (
19 mode_when_invoked in {"auto", "plan"}
20 and mode_now not in {"auto", "plan"}
21 and later_turn
22 )
23 print(f"CLAUDE_CODE_OWNER={owner or 'MISSING'}")
24 print(f"this_field={row.get('this_field')}")
25 print(f"mode_when_invoked={mode_when_invoked or 'MISSING'}")
26 print(f"mode_now={mode_now or 'MISSING'}")
27 print(f"later_turn={later_turn}")
28 print(f"left_auto_or_plan={left_auto_or_plan}")
29 print(f"reason={row.get('reason')}")
30 if not owner:
31 print("ticket=owner-missing")
32 return 2
33 if row.get("this_field") and left_auto_or_plan:
34 print("ticket=leftover-allowed-tools-not-still-in-plan")
35 return 0
36 if mode_now == "plan":
37 print("ticket=still-in-plan-mode")
38 return 0
39 print("ticket=not-this-field")
40 return 1
41
42
43if __name__ == "__main__":
44 raise SystemExit(main())
Export CLAUDE_CODE_OWNER=Shinjae. Export SKILL_PATH=fixtures/deploy-skill.md. Export PERMISSION_MODE_WHEN_INVOKED=plan. Export PERMISSION_MODE_NOW=default. Export LATER_TURN=true. If the printer says ticket=leftover-allowed-tools-not-still-in-plan, close always-ask-broken. Open this field. If it says owner-missing, the ticket is a missing name, not a stuck plan.

Scan the log. Do not leave plan in production.
You do not need to sit on Shift+Tab. You need to know whether the agent log already left auto or plan, then ran a skill tool with no prompt. Scan text. Do not start claude --permission-mode plan from the scanner.
1#!/usr/bin/env python3
2"""Scan text logs for leftover allowed-tools after a mode leave. Never execute them."""
3from __future__ import annotations
4
5from pathlib import Path
6
7ROOT = Path("logs")
8NEEDLES = (
9 "allowed-tools",
10 "plan mode",
11 "auto mode",
12 "shift+tab",
13 "permission mode",
14 "/plan",
15)
16
17
18def main() -> int:
19 hits = 0
20 for path in ROOT.rglob("*"):
21 if path.suffix.lower() not in {".log", ".md", ".txt", ".jsonl"}:
22 continue
23 try:
24 text = path.read_text(encoding="utf-8", errors="replace")
25 except OSError:
26 continue
27 for i, line in enumerate(text.splitlines(), 1):
28 low = line.lower()
29 if not any(n in low for n in NEEDLES):
30 continue
31 leftover = "allowed-tools" in low and (
32 "later turn" in low or "leave auto" in low or "leave plan" in low
33 )
34 print(f"{path}:{i}:leftover={leftover} {line[:120]}")
35 hits += 1
36 print(f"hits={hits}")
37 return 0
38
39
40if __name__ == "__main__":
41 raise SystemExit(main())
If the scan prints leftover=True, the ticket is this post. If it only prints plan mode on with no later-turn grant, the ticket is still-in-plan. If it prints nothing, file a missing owner, a missing log, or a different permission field.
Official docs still name the neighbor you must not collapse into this heading. Skill content stays in context across later turns. That persistence is instructions, not permissions. A later turn that still “knows” the skill is not a leftover grant. Print both. Split instruction persistence onto its own ticket. [Source: https://code.claude.com/docs/en/skills]
Neighbor fields that are not this ticket
Keep the heading small. Neighbor fires from the same week are other URLs.
| Neighbor | What it is | Why it is not this post |
|---|---|---|
| Plan-mode classifier | Auto classifier approving a non-read-only connector while planning | Read-only pass versus plan, already a LinkedIn leftover |
| First-run plugin | Plugin install before managed settings loaded | Marketplace versus managed settings, already X and Threads |
| Repeated reply ID | A phone yes that reused an ID | Channel verdict versus leftover grant |
| Nested deny | A nested deny treated as a mod approval | Policy tree, already shipped |
Redirected rm | A redirected remove treated as always-ask off | Shell rewrite, already shipped |
| UNC path read | Network path treated as a local allow | Sandbox versus local, leftover social |
Do not steal those as a second heading. Do not clone A Repeated Reply ID Is Not a Second Approval or A Nested Deny Is Not a Mod Approval. GSC this week still has no striking-distance query that asks for another auto-start, green-deploy, /readyz, 2,500+, runner, sandbox-equals, lockfile, redirected-rm, ghs_, nested-deny, allowed-mail, or repeated-reply-ID refresh. This unused URL is the leftover grant.

What you must not do
Forbidden:
- File “plan mode is still on” or “always-ask is off” without printing the
allowed-toolsline, leftover versus still-in-plan, and one human name. - Put
2.1.292,2.1.293, or6 October 2026in the title as a version-style hook. The numbers are evidence after the decision. - Write an allowed-tools-bypass or plan-mode-bypass recipe: keeping a grant after the next message, forging Shift+Tab, stripping permission mode, or mapping a way around the prompt.
- Recommend buying a plan, a 20X badge, or a seat because a skill tool ran quiet after you left plan. Official permission-modes page lists modes as a tradeoff, not a purchase ticket. [Source: https://code.claude.com/docs/en/permission-modes]
- Treat plan-mode classifier, first-run plugin, extra-scope, redirected
rm, nested deny, or repeated reply ID as this field. - Mix this field with allowed-mail,
ghs_length, lockfile, or sandbox-equals. Do not clone those shipped URLs. - Start a live plan-mode session in front of production data to demo the leftover.
- Let a coding agent own
CLAUDE_CODE_OWNER, or collapse a leftover grant and a stuck plan into one ticket.
Allowed:
- Print the
allowed-toolsline. Redact the rest of the skill if a log leaked a command. - Classify synthetic fixtures with
classify_allowed_tools.py. Do not execute them against a live session. - Scan logs for
allowed-tools/plan mode/auto mode/Shift+Tab. - Name one human as
CLAUDE_CODE_OWNER. - Keep leftover grant, still-in-plan, and skill-content persistence as separate tickets.
- After the owner prints the four lines, treat the leftover as this field. Official changelog: the grant coming back after you leave auto or plan mid-turn is the named miss. Official skills docs: the grant clears on the next message. [Source: https://code.claude.com/docs/en/changelog] [Source: https://code.claude.com/docs/en/skills]
- Put one line in the agent instructions file you already own: when the agent leaves plan or auto mid-turn, it prints
allowed-toolsand refuses to treat a later quiet tool as plan-mode-stuck. Check the printed ticket. Do not trust the agent to follow the line.
If you need the broader habit, start at /ai-agent-operations/. Tooling notes live under /developer-tools/. Laravel plus Vue notes live under /laravel-vue-saas/. A first-week map is at /start-here/.
A changelog bullet about leftover allowed-tools is not permission to skip the four lines.
What you should do Monday morning
- Open the repo that actually runs Claude Code with a project skill. Export
CLAUDE_CODE_OWNERto a human name. Run the ticket printer against yesterday’s agent log and the skill file. Writethis_field=TrueorFalseon the ticket next to that name. - For every
this_field=Truerow, answer in one sentence: the session was still in plan, or it already left auto or plan and a later turn reused the grant, or the skill never hadallowed-tools. If you cannot answer, the ticket is “owner missing,” not “always-ask is off.” - Print leftover versus still-in-plan. If the status bar still says plan, official docs still say you are exploring before you edit. If you already left and a later turn ran the skill tools with no prompt, official changelog names that leftover. Split those tickets. [Source: https://code.claude.com/docs/en/permission-modes] [Source: https://code.claude.com/docs/en/changelog]
- Confirm coding-agent instructions on this desk name the same owner and forbid “plan mode is still on” without the four lines. Forbid starting a live plan session in front of production data to demo. Forbid writing a hide path that keeps a grant after the next message.
- Confirm the grant still uses the documented shape: frontmatter
allowed-tools, one invoking turn, clear on the next message. Do not invent a dashboard that mints grants. Do not display a fake status-bar screenshot as proof. [Source: https://code.claude.com/docs/en/skills] - Leave plan-mode classifier, first-run plugin, extra-scope, allowed-mail, nested deny,
ghs_length, redirectedrm, lockfile, repeated reply ID, and UNC path off this ticket. Those are neighbor fields. Do not steal them as a second heading.
The question is not whether the changelog demos well. The question is whether the named owner can still tell a leftover allowed-tools rule from a stuck plan after handoff.
Further reading
Source Claude Code Docs — Changelog
