The Specific Situation
Your skill runs a test suite with coverage analysis. The test suite takes 90 seconds. Claude’s Bash tool times out at 60 seconds. The skill reports a timeout error, but the underlying tests were actually passing. You need to either increase the timeout, break the execution into smaller parts, or restructure the skill to handle long-running operations.
Technical Foundation
Timeout errors in skills come from multiple sources:
- Bash tool timeout: Claude Code’s Bash tool has a configurable timeout for shell command execution. Long-running scripts (test suites, builds, large file scans) hit this limit.
- Dynamic context injection timeout: The
!command`` syntax runs commands before Claude sees the content. If these commands take too long, the skill load times out. - Subagent timeout: Skills with
context: forkrun in a subagent that has its own timeout based on the overall Claude Code session configuration. - Context window exhaustion: Not technically a timeout, but when the skill’s output consumes too much context window, Claude may appear to hang or truncate output.
Skills do not have their own timeout configuration field. Timeouts are controlled by the execution environment (Bash tool settings, Claude Code settings).
The Working SKILL.md
A timeout-resistant skill for test execution:
---
name: run-tests
description: >
Run the project test suite with timeout-safe execution. Use when
the user says "run tests", "check tests", or "test coverage".
argument-hint: "[file-or-pattern]"
allowed-tools: Bash(npx jest *) Bash(npx vitest *) Bash(npm test *) Read
effort: high
---
# Run Tests (Timeout-Safe)
Run tests for $ARGUMENTS with timeout protection.
## Strategy
For large test suites, run in chunks to avoid timeout:
### Step 1: Identify test files
```bash
# List test files (fast, no timeout risk)
find . -name "*.test.ts" -o -name "*.spec.ts" | head -50
Step 2: Run tests in batches
# Run one file at a time if the full suite times out
npx jest $ARGUMENTS --bail --forceExit --testTimeout=30000
Step 3: Coverage (separate step)
# Run coverage separately to avoid compounding timeout
npx jest --coverage --coverageReporters=text-summary
If Timeout Occurs
If any test command times out:
- Try running a single test file instead of the full suite
- Add –bail to stop at first failure
- Add –forceExit to prevent Jest from hanging
- Report which tests passed before the timeout ```
Fix 1: Increase Bash Timeout
The Bash tool timeout can be set on individual commands. When Claude runs a command, it can specify a timeout parameter. Instruct the skill to use a longer timeout:
---
name: long-build
description: Build the application (may take several minutes)
disable-model-invocation: true
allowed-tools: Bash(npm run build *)
---
# Build Application
Run the build command. This may take 2-5 minutes.
When running the build command, set the bash timeout to 300000
milliseconds (5 minutes):
```bash
npm run build
If the build times out, check:
- Is node_modules/ up to date? Run npm install first.
- Are there circular imports causing infinite build loops?
- Can the build be parallelized? Try npm run build – –parallel ```
Fix 2: Break Long Operations Into Steps
Instead of one long command, use multiple short commands:
# BROKEN: single long command
---
name: full-pipeline
---
Run the full CI pipeline:
```bash
npm test && npm run lint && npm run build && npm run deploy
FIXED: break into steps
name: full-pipeline — Run the pipeline step by step:
Step 1: Lint (fast, ~10s)
npm run lint
Step 2: Test (medium, ~60s)
npm test -- --bail
Step 3: Build (slow, ~120s)
npm run build
Step 4: Deploy (medium, ~30s)
npm run deploy
Each step runs as a separate Bash call with its own timeout window.
## Fix 3: Dynamic Context Injection Timeout
The `!`command`` syntax has its own timeout behavior. Commands that take too long cause the skill to load with incomplete context:
```yaml
# RISKY: slow command in dynamic injection
- Full git log: !`git log --all --oneline`
# FIXED: limit output and add timeout
- Recent commits: !`git log --oneline -20`
# ALTERNATIVE: let Claude run the command after loading
# Instead of !`command`, use instructions:
## Step 1
Run `git log --oneline -20` to see recent commits.
When dynamic injection is slow, move the command to the skill body as an instruction for Claude to execute. This gives Claude control over the timeout and allows retries.
Fix 4: Subagent Timeout
Skills with context: fork run in a subagent with limited time:
# If the subagent times out, reduce its workload:
---
name: analyze-codebase
context: fork
agent: Explore
---
# Analyze Codebase
Focus on the most critical files only.
Do NOT attempt to read every file in the repository.
1. Read the top-level directory structure
2. Read the main entry point (src/index.ts or similar)
3. Read the 5 most recently modified files
4. Summarize architecture based on these files only
Keep subagent tasks focused and bounded. An Explore agent that tries to read 500 files will timeout.
Fix 5: Effort Level Tuning
The effort field affects how much time Claude spends reasoning, not command execution time. But it can indirectly affect timeout behavior:
# High effort = more reasoning time per step
effort: high
# Max effort = maximum reasoning, useful for complex multi-step skills
effort: max
If a skill frequently times out due to complex reasoning (not slow commands), increase the effort level to give Claude more processing budget.
Common Problems and Fixes
Test suite times out but passes locally: The CI or Claude Code environment may be slower. Add --bail to stop at first failure and --forceExit to prevent hanging processes.
Build times out only on first run: First-time builds download dependencies. Add a prerequisite step: “Run npm install first, then build.”
Timeout only happens after compaction: After compaction, Claude may re-read files or re-run commands that were previously cached in context. Break the skill into smaller, independent steps.
Dynamic injection makes skill load slow: Replace !command`` with explicit instructions in the skill body. The tradeoff: Claude must run the command after loading instead of having the data immediately.
Production Gotchas
There is no global “skill timeout” setting. Timeouts are per-tool: Bash has its own timeout, HTTP requests have theirs, and the overall session has limits. A skill that runs multiple commands effectively gets multiple timeout windows.
The /batch bundled skill handles long operations by spawning parallel agents in worktrees. If your skill does something that takes 10+ minutes (large builds, comprehensive test suites), consider whether /batch would be more appropriate than a custom skill.
Scripts that produce continuous output (e.g., npm test with verbose logging) may not timeout but may exhaust the context window with log output. Add output limits: npm test 2>&1 | tail -100.
Checklist
- Long commands broken into separate steps
- Each step has bounded output (pipe to
headortail) - Dynamic injection uses fast commands only
- Scripts include
--bailor equivalent fail-fast flags - Subagent tasks scoped to specific files, not entire codebase