Lesson
Build Better Tools in Claude Skills with Scripts
Learn how to overcome limitations in Claude's `allowed-tools` by abstracting complex CLI commands, especially those with redirects, into dedicated scripts for more reliable and powerful agent skills.
- Access
- Included
- Transcript
- Needs source
Errata
Please use the full script name in "allowed-tools" like below:
allowed-tools: Bash(bun run scripts/compress.ts:*)
Save the :* syntax for "arguments following a tool call", never treat it like a glob pattern.
Permissions are notoriously spotty and I've been having inconsistent behavior with the configuration in this lesson. We'll introduce stronger control in a "hooks" section in upcoming lessons.
Escape Claude Skill Limitations with Scripts
When building Claude Code skills, you may encounter limitations with the allowed-tools feature, particularly when a CLI tool's syntax includes special characters like shell redirects (>). This can cause parsing issues and prevent your agent from getting the necessary permissions to run the command.
This lesson demonstrates a powerful workaround: abstracting complex or problematic CLI commands into dedicated scripts. By doing this, you can create more robust, maintainable, and even cross-platform skills.
The Problem: allowed-tools and Shell Redirects
Directly allowing a tool like tar or gzip that requires output redirection can fail because the parser for allowed-tools may not correctly handle the special characters. This leads to the agent getting stuck and unable to proceed.
The Solution: Abstracting Logic into a Script
Instead of fighting with the syntax, we can move the complex logic into a script (e.g., a TypeScript script run with Bun). This approach offers several advantages:
- Bypasses Parsing Issues: The skill only needs permission to run the script (
bun run scripts/compress.ts), which is a much simpler command forallowed-toolsto handle. - Enhanced Control: Inside the script, you have full programmatic control over execution, error handling, and logging, providing richer feedback to the agent and user.
- Cross-Platform Compatibility: By using Node.js/Bun packages (like
tar-fs), you can replace system-specific commands (liketar) with JavaScript implementations that work consistently across Windows, macOS, and Linux. - Composability: Your skill can remain focused on its primary goal (e.g., "compress files") while delegating the low-level implementation details to one or more scripts.
Workflow Demonstrated
- Identify the Limitation: We start by showing how a
tarcommand with a redirect fails theallowed-toolspermission step in our compress skill. - Generate a Script: We prompt Claude to convert the problematic command into a Bun + TypeScript script that accepts arguments instead of using redirects.
- Refactor the Skill: We update the
SKILL.mdfile to remove the directtarcommand and replace it with a call to our new script, updating theallowed-toolsaccordingly (e.g.,Bash(bun run scripts:*)). - Iteratively Improve: We refine the script by removing redundant logic (like timestamp generation, which is already handled by the separate timestamp skill we built in earlier lessons) and fixing TypeScript errors.
- Achieve Cross-Platform Support: As a final step, we convert the script to use a cross-platform package (
tar-fs) instead of relying on the system'starcommand, making the skill universally usable.
This lesson provides a practical pattern for building sophisticated and reliable Claude Code skills, moving beyond simple CLI commands to create powerful, script-driven automations that work seamlessly with the skill stacking patterns learned in previous lessons.
Prompts
Please create a summary of @index.ts and then compress the summary.
tar -czvf <project-root>/compressions/<timestamp>-<file-name-based-on-the-user-request>.tar.gz <files-from-user-request>
---
Please convert this into a script in my scripts folder that uses bun and TypeScript that accepts arguments and avoids redirects
We don't need this script to be executable, we will be running it with bun.
In my @.claude/skills/compress/SKILL.md Please replace any references to tar with our script.
Please remove the timestamp logic from our script. We are still going to rely on the timestamp skill to format the name of the output compressed file
Please update our skill to represent that we're still using the timestamp skill and that our output name will have a timestamp in it just like we had before.
@compress.ts Without changing any of the logic of the script, please install the necessary packages to make this cross-platform so that anyone on Windows, Linux, or Mac can all run this same script.
Terminal Commands
node
zsh
chmod +x /Users/johnlindquist/dev/claude-lessons/scripts/compress.ts
bun run scripts/compress.ts 2025-10-23-10-13-37-index-summary.tar.gz index-summary.md
bun init
bun add tar-fs
bun run scripts/compress.ts test-archive.tar.gz compress.ts
Code Snippets
The initial compress skill's SKILL.md file uses a tar command that causes issues with allowed-tools:
---
name: compress
description: Compress the resulting files of a user's request
allowed-tools: [Write, Bash(tar:*)]
---
## Requirements
You must use the timestamp skill to create the timestamp.
## Usage
```bash
tar -czvf <project-root>/compressions/<timestamp>-<file-name-based-on-the-user-request>.tar.gz <files-from-user-request>
```
After creating the script, we update the allowed-tools to reference our script instead:
# allowed-tools syntax for running scripts
allowed-tools: Write, Bash(bun run scripts/compress.ts:*)
// Initial system-dependent tar command in script
await $`tar -czf ${outputPath} ${filesToCompress}`;