skills/into-trustable-script/SKILL.md
Convert a command that needed permission approval into a standalone script (Python or Bash) with hardcoded operations and parameterized inputs, then add it to the allowlist so future invocations run without prompting.
npx skillsauth add AMindToThink/claude-code-settings into-trustable-scriptInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Convert a command that required (or would require) permission approval into a standalone script with fixed behavior and parameterized inputs, saved to .claude-tools/ in the project root and added to the Claude Code permission allowlist.
/into-trustable-script after a command that needed permissionLong-running or resource-intensive commands are poor candidates. The point of a trustable script is that it runs without prompting — but that also means it runs without a gut-check. A script that ties up a GPU for 30 minutes or saturates memory for an hour can silently block other work.
Before converting a command that you expect to be long-running or resource-heavy (GPU training, large-scale data processing, batch inference, etc.), estimate the runtime and resource cost, tell the user, and ask whether they still want it auto-approved. A command that takes 5 seconds to run 100 times is fine; a command that takes 20 minutes and locks a GPU is something the user probably wants to approve each time.
Prefer Python (.py) — it's simpler, easier to read, and avoids heredoc awkwardness. Use Python unless you have a reason not to.
Use Bash (.sh) only when the script primarily orchestrates shell commands — e.g., combining pgrep, nvidia-smi, curl, tail in a status checker. If the bash script would just be a wrapper around a single Python heredoc, skip the wrapper and write Python directly.
Look at the most recent command that needed approval (or the command the user points to). Identify:
Create a script at .claude-tools/<descriptive-name>.py (or .sh). The name should describe the operation, not the inputs (e.g., csv-summary.py, json-structure.py, vllm-status.sh).
#!/usr/bin/env python3
"""One-line description of what this script does.
Usage: .claude-tools/<name>.py <arg1> <arg2> ...
"""
import sys
def main() -> None:
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <arg1-description> <arg2-description> ...", file=sys.stderr)
sys.exit(1)
arg1 = sys.argv[1]
# --- Validate inputs ---
# e.g., check files exist, values are in expected range
import os
if not os.path.isfile(arg1):
print(f"Error: file not found: {arg1}", file=sys.stderr)
sys.exit(1)
# --- Precondition checks ---
# Verify the environment can support this operation.
# See "Precondition Checks" section below.
# --- Do the work ---
# Fixed logic using validated inputs
...
if __name__ == "__main__":
main()
Use this only for shell-heavy scripts that orchestrate multiple CLI tools.
#!/usr/bin/env bash
set -euo pipefail
# <One-line description>
# Usage: .claude-tools/<name>.sh <arg1> <arg2> ...
if [[ $# -lt <N> ]]; then
echo "Usage: $0 <arg1-description> ..." >&2
exit 1
fi
ARG1="$1"
[[ -f "$ARG1" ]] || { echo "Error: file not found: $ARG1" >&2; exit 1; }
# --- Precondition checks ---
# --- Do the work ---
# When embedding Python in bash, use heredocs with single-quoted delimiters:
python3 << 'PYTHON_END' "$ARG1"
import sys
filepath = sys.argv[1]
# ...
PYTHON_END
Every generated script MUST satisfy ALL of these:
/tmp are acceptable for intermediate data, but clean up after yourself.pip install, uv add, apt-get, etc.eval(), no exec(), no subprocess.run(user_string, shell=True). In bash: no eval, no python3 -c "$1", no bash -c "$1". Arguments are DATA, never CODE.#!/usr/bin/env bash and set -euo pipefail. When embedding Python, use << 'PYTHON_END' (single-quoted delimiter prevents shell interpolation).#!/usr/bin/env python3. Use argparse or sys.argv for inputs. Use type hints.If the desired operation cannot satisfy these invariants (e.g., it needs to write to the project directory or access external services), do not create the script. Explain why and suggest the user keep using the regular command with permission prompts.
Scripts should fail fast with a clear error if the environment isn't ready. Think about what resources the operation needs and verify them before doing work. Common examples:
GPU availability: Check that a GPU is free or has enough VRAM before launching a CUDA job.
import subprocess, sys
result = subprocess.run(
["nvidia-smi", "--query-gpu=memory.free", "--format=csv,noheader,nounits"],
capture_output=True, text=True,
)
if result.returncode != 0:
print("Error: nvidia-smi not available", file=sys.stderr); sys.exit(1)
free_mb = [int(x.strip()) for x in result.stdout.strip().split("\n")]
if not any(m > 20000 for m in free_mb):
print(f"Error: no GPU with >20GB free VRAM (available: {free_mb} MB)", file=sys.stderr)
sys.exit(1)
Required Python packages: Try importing before running main logic.
try:
import pandas, torch
except ImportError as e:
print(f"Error: missing required package: {e.name}", file=sys.stderr)
sys.exit(1)
Required CLI tools (bash):
command -v jq >/dev/null 2>&1 || { echo "Error: jq is required but not installed" >&2; exit 1; }
File size / memory: Check before loading large files.
import os, sys
size = os.path.getsize(filepath)
if size > 2 * 1024**3:
print(f"Error: file is {size // 1024**2}MB, exceeds 2GB limit", file=sys.stderr)
sys.exit(1)
The goal: never let a trustable script fail silently or waste resources on a doomed operation. If it can't succeed, it should say why immediately.
chmod +x .claude-tools/<name>.py # or .sh
Read the project's .claude/settings.json (or create the permissions section if needed). Add:
"Bash(.claude-tools/<name>.py *)"
to the permissions.allow array. This allows Claude Code to run the script with any arguments without prompting.
If .claude/settings.json doesn't exist for the project, check whether the user wants this in project settings or user settings (~/.claude/settings.json).
Tell the user:
Original command (needed approval):
python3 -c "import pandas as pd; df = pd.read_csv('data.csv'); print(df.describe())"
Resulting script (.claude-tools/csv-summary.py):
#!/usr/bin/env python3
"""Print summary statistics for a CSV file.
Usage: .claude-tools/csv-summary.py <csv-file>
"""
import os
import sys
def main() -> None:
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <csv-file>", file=sys.stderr)
sys.exit(1)
csv_file = sys.argv[1]
if not os.path.isfile(csv_file):
print(f"Error: file not found: {csv_file}", file=sys.stderr)
sys.exit(1)
try:
import pandas as pd
except ImportError:
print("Error: pandas is required but not installed", file=sys.stderr)
sys.exit(1)
df = pd.read_csv(csv_file)
print(df.describe())
if __name__ == "__main__":
main()
Allowlist entry: Bash(.claude-tools/csv-summary.py *)
Use case: Check vLLM server status across process, GPU, API, and logs.
Resulting script (.claude-tools/vllm-status.sh): Bash is appropriate here because it orchestrates pgrep, nvidia-smi, curl, and tail — tools that are natural in shell but awkward in Python.
Allowlist entry: Bash(.claude-tools/vllm-status.sh *)
development
Use when the user asks to check, audit, or improve a website or web project for accessibility (a11y), WCAG compliance, screen reader support, keyboard navigation, color contrast, or alt text. Triggers a plan-mode investigation against the TeachAccess design and code checklists, then implements approved fixes.
development
--- name: make-anonymous-branch description: Use when preparing a research repo for double-blind submission via anonymous.4open.science (ICML/NeurIPS/ICLR/workshop). Builds a single `anon-submission` branch with code+data+paper, scrubs identity leaks (author names, home paths, emails, wandb metadata, PDF author fields), patches LaTeX for pdf.js compatibility, and leaves `main` untouched. Triggers: "make an anonymous branch", "anonymize my repo for X submission", "set up anonymous.4open.science",
development
Translate math (formulas, estimators, algorithms) into code so the implementation faithfully matches what the source actually specifies. Use when writing code from a formula, reviewing an LLM-generated implementation of a formula, debugging a numerical mismatch with a paper, designing a new metric/estimator, or refactoring an existing math-heavy computation. Especially load-bearing whenever aggregation operators (sums, means, expectations, products, geometric means) appear over indices that can be reordered, or whenever the same English label can refer to multiple non-equivalent estimators (e.g. ratio-of-means vs mean-of-ratios, micro-average vs macro-average, sample-weighted vs unweighted). Prevents the failure mode where a code path silently implements the wrong estimator under the same name as the intended one.
development
Use when the user asks to review, find, summarize, or check Claude Code chat transcripts from a past date or time range ("review my chats from May 1st", "what was I working on yesterday", "any unfinished sessions this week"). Reads transcripts under `~/.claude/projects/`, handles local-time vs UTC correctly so late-evening sessions don't get dropped, and flags chats whose last assistant turn looks like an unanswered question.