Receber por email
← Voltar para o catálogo

brewtools:skill-toggle

Disables or enables individual plugin skills by writing skillOverrides to ~/.claude/settings.json (survives plugin updates). Modes: off, user-invocable-only, name-only. Triggers: disable skill, enable skill, toggle skill, hide skill, skill-toggle.

28estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: NOASSERTION

Como adicionar

/plugin marketplace add kochetkov-ma/claude-brewcode

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/brewtools-skill-toggle/svg)](https://www.skillteca.com.br/skills/brewtools-skill-toggle)

Alerta por categoria

Receba novas skills de Escrita e Conteúdo toda segunda

1 email curto, só com as skills novas de Escrita e Conteúdo. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Skill Toggle

Disable/enable individual plugin skills via the stable skillOverrides mechanism in ~/.claude/settings.json (Claude Code 2.1.115+). State survives plugin updates — no SessionStart reapply hook needed. See also: /brewtools:agent-toggle for agents (uses file-rename, different mechanism).

<instructions>

Robustness Rules

| Rule | Applies | |------|---------| | Every Bash call ends with && echo "OK ..." \|\| echo "FAILED ..." | ALL | | Never use Write/Edit on ~/.claude/settings.json — use Bash + Node helper | ALL | | This skill mutates skills only (skillOverrides) — never agents | ALL | | Atomic writes via lockfile + temp + rename (handled by helper) | P2 |

Paths (substitute literally in Bash):

  • Helper: $CLAUDE_PLUGIN_ROOT/skills/skill-toggle/helpers/overrides.mjs
  • Settings: ~/.claude/settings.json (resolved to $HOME/.claude/settings.json)
  • Legacy global state (read-only, backwards visibility): $CLAUDE_PLUGIN_DATA/toggle-state.json

Override Modes

| Mode | Effect | |------|--------| | off | Fully disabled — invisible to user and LLM | | user-invocable-only | Only via /plugin:skill slash; LLM cannot auto-invoke | | name-only | Name visible in autocomplete, instructions/body not loaded | | on | (Re-enable) — entry removed from settings.json |

Default for "disable" intent without explicit mode: off.

Phase I — Interactive Flow (entry gate)

Full spec: _shared/toggle/interactive-flow.md (phases I0-I4). Read on entry. This skill hardcodes kind='skill'.

Enter interactive flow when:

  • No args given, OR
  • User prompt is freeform without concrete plugin:name (e.g. "отключи лишнее"), OR
  • Parsed target missing from cache.

Skip interactive (go straight to P0 → P2 → P4) when op AND target both explicit: /brewtools:skill-toggle disable brewui:image-gen.

| Phase | Action | Tool | |-------|--------|------| | I0 | Decide branch from input shape | — | | I1 | Op picker — single AskUserQuestion, options: status, disable, enable, list, pre-selected: disable | AskUserQuestion | | I2 | Catalog one-liner — Bash+Node imports enumeratePlugins from $CLAUDE_PLUGIN_ROOT/skills/_shared/toggle/cache.mjs, emit AVAILABLE TO {OP} (N total): then space-separated plugin:name tokens (filter: disable→not in overrides; enable→in overrides; kind=skill) | Bash | | I3 | Resolve + confirm: exact plugin:name or unique name→no confirm; fuzzy→AskUserQuestion [yes / pick different / cancel]; multiple→AskUserQuestion 2-4 options. For disable, also ask mode if not specified | AskUserQuestion | | I4 | Execute (P2) then ALWAYS print current state | Bash |

Terminal ops (list, status) skip to I4 directly.

I4 status format (always printed):

DISABLED RIGHT NOW (via skillOverrides)
---------------------------------------
brewui:image-gen        off
brewdoc:md-to-pdf       user-invocable-only
(none)  <-- if empty
ENABLED (M skills across P plugins)

P0: Parse Intent

Parse $ARGUMENTS (or NL prompt) into:

{ action: disable|enable|toggle|status|list, plugin?, skill?, mode?: off|user-invocable-only|name-only }

Rules:

  • Default mode for disable = off. User can specify e.g. --mode=user-invocable-only or "make it slash-only".
  • Target format: plugin:name (e.g., brewui:image-gen). Bare name → AskUserQuestion which plugin.
  • status, list take no targets.
  • Multiple targets allowed for disable/enable — iterate P2 per target.
  • No --scope flag — skillOverrides is global-only (per Claude Code design).

If ambiguous (no plugin prefix for disable/enable) → AskUserQuestion with candidate plugins from enumeratePlugins.

P1: Validate Target

EXECUTE using Bash tool:

node --input-type=module -e "
import {enumeratePlugins, resolveTarget} from '$CLAUDE_PLUGIN_ROOT/skills/_shared/toggle/cache.mjs';
import fs from 'node:fs';
const p = enumeratePlugins().get('PLUGIN_NAME');
if (!p) { console.log(JSON.stringify({error:'plugin_not_installed', plugin:'PLUGIN_NAME'})); process.exit(0); }
const t = resolveTarget(p, 'skill', 'SKILL_NAME');
const exists = fs.existsSync(t.visible) || fs.existsSync(t.hidden);
if (!exists) { console.log(JSON.stringify({error:'skill_not_found', plugin:p.plugin, name:'SKILL_NAME'})); process.exit(0); }
console.log(JSON.stringify({plugin:p.plugin, latest:p.latest, name:'SKILL_NAME'}));
" && echo "OK validate" || echo "FAILED validate"

Replace PLUGIN_NAME, SKILL_NAME. On error → stop, report.

P2: Write Override

EXECUTE using Bash tool (disable):

node --input-type=module -e "
import {writeOverride} from '$CLAUDE_PLUGIN_ROOT/skills/skill-toggle/helpers/overrides.mjs';
const r = await writeOverride('PLUGIN','NAME','MODE');
console.log(JSON.stringify(r));
" && echo "OK override" || echo "FAILED override"

For disable → MODE ∈ off | user-invocable-only | name-only (default off). For enable → MODE='on' (deletes the entry).

Substitute PLUGIN, NAME, MODE literally.

P3 — DELETED (no rename step needed)

Persistence: ~/.claude/settings.json survives plugin updates — no SessionStart reapply hook needed for skill-toggle. The old file-rename approach (P3 in earlier versions) is removed. Plugin cache files are no longer touched by this skill.

Agent-toggle still uses file-rename (_shared/toggle/state.mjs + apply.mjs) — that flow is untouched.

P4: Verify + Notify

EXECUTE using Bash tool:

node --input-type=module -e "
import {readOverrides} from '$CLAUDE_PLUGIN_ROOT/skills/skill-toggle/helpers/overrides.mjs';
const o = readOverrides();
console.log(JSON.stringify(o));
" && echo "OK verify" || echo "FAILED verify"

Confirm PLUGIN:NAME present (for disable) or absent (for enable). Render result table:

# Skill Toggle — <action>

| Plugin | Name | Mode | Action | File |
|--------|------|------|--------|------|
| brewui | image-gen | off | written | ~/.claude/settings.json |

> Restart session or `/reload-plugins` for the change to take effect.
> Persisted to ~/.claude/settings.json — survives plugin updates.

Sub-operations

status — merged view

Reads both skillOverrides (current mechanism) AND legacy toggle-state.json (backwards visibility, read-only).

EXECUTE using Bash tool:

node --input-type=module -e "
import {listOverrides} from '$CLAUDE_PLUGIN_ROOT/skills/skill-toggle/helpers/overrides.mjs';
import {readState, globalStatePath, projectStatePath} from '$CLAUDE_PLUGIN_ROOT/skills/_shared/toggle/state.mjs';
const overrides = listOverrides();
const legacyG = readState(globalStatePath()).disabled || {};
const legacyP = readState(projectStatePath(process.cwd())).disabled || {};
const legacy = [];
for (const [k,v] of Object.entries({...legacyG, ...legacyP})) {
  if (v && v.kind === 'skill') legacy.push({key:k, ...v, scope: legacyP[k] ? 'project' : 'global'});
}
console.log(JSON.stringify({overrides, legacy}));
" && echo "OK status" || echo "FAILED status"

Render two tables:

  1. Current (skillOverrides): plugin | name | mode
  2. Legacy (toggle-state.json, read-only): plugin | name | scope | disabled_at — with note: "Legacy state — migrate by re-running disable; legacy file is no longer authoritative for skills."

list — enumerate all skills

EXECUTE using Bash tool:

node --input-type=module -e "
import {enumeratePlugins, resolveTarget} from '$CLAUDE_PLUGIN_ROOT/skills/_shared/toggle/cache.mjs';
import {readOverrides} from '$CLAUDE_PLUGIN_ROOT/skills/skill-toggle/helpers/overrides.mjs';
import fs from 'node:fs';
import path from 'node:path';
const overrides = readOverrides();
const out = [];
for (const [plugin, e] of enumeratePlugins()) {
  const dir = path.join(e.path, 'skills');
  let entries = [];
  try { entries = fs.readdirSync(dir, {withFileTypes:true}).filter(d=>d.isDirectory() && !d.name.startsWith('_')); } catch {}
  for (const d of
Compartilhar X LinkedIn