Pre-run hooks allow you to run scripts before your main scripts execute. They're perfect for environment validation, dependency checking, authentication, and setup tasks.
Create a .hooks.d directory in your TOME_ROOT:
mkdir -p $TOME_ROOT/.hooks.dHooks come in two flavors:
These hooks run as independent processes, perfect for validation and checks.
How to create:
- Create a file in
.hooks.d/without.sourcesuffix - Add shebang:
#!/usr/bin/env bash - Make it executable:
chmod +x .hooks.d/hook-name - Use number prefixes to control order:
00-first,10-second,20-third
Example: .hooks.d/00-check-deps, .hooks.d/10-validate
Best for:
- Validation checks
- Running external commands
- Dependency verification
- Authentication checks
- Audit logging
These hooks run in the same shell as your target script, allowing them to modify the environment.
How to create:
- Create a file in
.hooks.d/with.sourcesuffix - Add number prefix to control order:
05-env.source,15-setup.source - No need to make executable (sourcing ignores execute permission)
Example: .hooks.d/05-set-env.source, .hooks.d/15-load-functions.source
Best for:
- Setting environment variables
- Defining shell functions
- Modifying PATH
- Loading secrets
- Conditional environment setup
All hooks receive these environment variables:
| Variable | Description | Example |
|---|---|---|
TOME_ROOT |
Root directory containing scripts | /home/user/scripts |
TOME_EXECUTABLE |
Name of the CLI command | tome-cli or kit |
TOME_SCRIPT_PATH |
Full path to script about to run | /home/user/scripts/deploy |
TOME_SCRIPT_NAME |
Name of script about to run | deploy |
TOME_SCRIPT_ARGS |
Arguments passed to the script | "production --force" |
Note: Variables exported by sourced hooks (.source suffix) are available to your main script.
#!/usr/bin/env bash
# .hooks.d/00-check-aws-creds
# Make executable: chmod +x .hooks.d/00-check-aws-creds
if ! aws sts get-caller-identity &>/dev/null; then
echo "Error: AWS credentials not configured" >&2
exit 1
fi
echo "✓ AWS credentials valid"# .hooks.d/05-set-aws-env.source
# Note the .source suffix - this will be sourced
# Set AWS environment based on script name
case "$TOME_SCRIPT_NAME" in
*-prod*)
export AWS_PROFILE="production"
export AWS_REGION="us-east-1"
;;
*-staging*)
export AWS_PROFILE="staging"
export AWS_REGION="us-west-2"
;;
*)
export AWS_PROFILE="development"
export AWS_REGION="us-west-1"
;;
esac
echo "✓ AWS environment: $AWS_PROFILE in $AWS_REGION"#!/usr/bin/env bash
# .hooks.d/10-check-deps
# Make executable: chmod +x .hooks.d/10-check-deps
required_tools=("jq" "curl" "aws")
for tool in "${required_tools[@]}"; do
if ! command -v "$tool" &>/dev/null; then
echo "Error: $tool not installed" >&2
exit 1
fi
done
echo "✓ All dependencies available"# .hooks.d/15-functions.source
# Note the .source suffix
# Log with timestamp
log() {
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] $*"
}
# Check if in production
is_production() {
[[ "$AWS_PROFILE" == "production" ]]
}
# Export functions so scripts can use them
export -f log
export -f is_production
echo "✓ Helper functions loaded"#!/usr/bin/env bash
# .hooks.d/20-audit-log
# Make executable: chmod +x .hooks.d/20-audit-log
log_file="$TOME_ROOT/.audit-log"
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$timestamp | $USER | $TOME_SCRIPT_NAME $TOME_SCRIPT_ARGS" >> "$log_file"
echo "✓ Execution logged"# .hooks.d/25-load-secrets.source
# Note the .source suffix
secrets_file="$TOME_ROOT/.secrets"
if [ -f "$secrets_file" ]; then
source "$secrets_file"
echo "✓ Secrets loaded"
else
echo "Warning: $secrets_file not found" >&2
fiValidate required environment variables before running scripts:
#!/usr/bin/env bash
# .hooks.d/00-validate-env
required_vars=("DATABASE_URL" "API_KEY")
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
echo "Error: $var not set" >&2
exit 1
fi
done
echo "✓ Environment validated"Provide sensible defaults using sourced hooks:
# .hooks.d/05-defaults.source
export LOG_LEVEL="${LOG_LEVEL:-info}"
export TIMEOUT="${TIMEOUT:-30}"
export RETRY_COUNT="${RETRY_COUNT:-3}"
echo "✓ Defaults set (LOG_LEVEL=$LOG_LEVEL)"Use TOME_SCRIPT_NAME to customize behavior per script:
# .hooks.d/10-script-setup.source
# Enable debug mode for test scripts
if [[ "$TOME_SCRIPT_NAME" == test-* ]]; then
export DEBUG=1
set -x
fi
# Require confirmation for production scripts
if [[ "$TOME_SCRIPT_NAME" == *-prod ]]; then
read -p "Running production script. Continue? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted" >&2
exit 1
fi
fiIf an executable hook exits with non-zero status:
- ❌ Main script will NOT execute
- ❌ tome-cli exits with the hook's exit code
- 📋 Error message shows which hook failed
Example error:
Error: pre-hook failed: 10-check-deps
If a sourced hook fails (bash errors, set -e triggered, etc.):
- ❌ Main script will NOT execute
- ❌ tome-cli exits with error
- 📋 Error message shows which hook failed
Example error:
Error: pre-hook failed: 05-env.source (sourcing failed)
Skip all hooks for a single execution:
tome-cli --skip-hooks exec my-scriptThis is useful for:
- Testing scripts without hooks
- Performance-critical operations
- Emergency maintenance
See detailed hook execution with the --debug flag:
tome-cli --debug exec my-scriptThis shows:
- Which hooks were discovered
- Hook execution order
- Environment variables set
- Wrapper script path
Hooks execute in lexicographic order by filename. Use number prefixes to control execution:
.hooks.d/
├── 00-validate-env # Runs first
├── 05-set-env.source # Runs second
├── 10-check-deps # Runs third
├── 15-functions.source # Runs fourth
└── 20-audit-log # Runs last
Recommended numbering:
00-09: Validation and checks10-19: Setup and configuration20-29: Logging and monitoring
- Executable permissions: Non-
.sourcehooks must be executable to run - Sourced hooks run in same context:
.sourcehooks can modify your shell environment - only use trusted code - Explicit suffix: The
.sourcesuffix makes it obvious which hooks modify environment - Hooks run before every script: Consider the security implications of automatic execution
- Hidden directory:
.hooks.dis hidden to prevent accidental modification
Best practices:
- Review hooks regularly
- Use version control for
.hooks.d/ - Document what each hook does
- Use
--debugto verify hook behavior - Test hooks in non-production first
Hooks add minimal overhead:
- ✅ Hook discovery: ~1ms (checks if
.hooks.d/exists) - ✅ Wrapper generation: ~1ms (simple string concatenation)
- ⏱️ Hook execution: Depends on your hooks
- 🗑️ Cleanup: Automatic (wrapper script removed after execution)
Tips for fast hooks:
- Keep validation hooks simple
- Cache expensive checks when possible
- Use
--skip-hooksfor performance-critical operations - Sourced hooks are slightly faster than executable hooks (no fork)
tome-cli uses syscall.Exec() which replaces the process, making post-run hooks technically challenging. Pre-run hooks cover the most common use cases:
✅ Environment validation ✅ Dependency checking ✅ Authentication ✅ Setup and configuration ✅ Audit logging (start)
Can't do with pre-hooks alone: ❌ Cleanup after script execution ❌ Capture script exit codes ❌ Post-execution notifications
If you need post-execution behavior, consider:
- Using trap in your scripts:
trap cleanup EXIT - Wrapper scripts that call tome-cli then do cleanup
- Process monitoring tools
Check:
- Is the hook in
.hooks.d/directory? - Is it executable (if not
.sourcesuffix)?chmod +x .hooks.d/hook-name - Is the filename correct? (no spaces, proper prefix)
- Run with
--debugto see what hooks are discovered
Remember:
- File must end with
.sourcesuffix - Use
exportfor variables:export VAR=value - Functions need
export -f:export -f function_name
This shouldn't happen. If a hook fails:
- ❌ Script should NOT run
- Check if you're using
--skip-hooks - Verify hook exit codes (
exit 1for errors)
Options:
- Rename hook to something that doesn't match pattern (add
.disabled) - Remove execute permission for executable hooks
- Move hook out of
.hooks.d/temporarily - Use
--skip-hooksto skip all hooks
If you're coming from:
- tome hooks are pre-execution, not commit-based
- Use
.hooks.d/not.git/hooks/ - No need for template installation
- Replace prerequisite targets with pre-hooks
- Hooks run automatically, no manual dependencies
- Move validation logic into hooks
- Cleaner separation of concerns
- Easier to share across team
Q: Can I use hooks with aliases?
A: Yes! Hooks work with both tome-cli exec and any aliases you create.
Q: Do hooks run for tab completion? A: No, hooks only run when executing scripts, not during completion.
Q: Can I have script-specific hooks?
A: Not yet. Currently only global .hooks.d/ is supported. Use TOME_SCRIPT_NAME to customize behavior per script.
Q: What shells are supported?
A: Hooks use #!/usr/bin/env bash by default. You can use any interpreter with proper shebang.
Q: Can hooks modify the script being executed? A: No, hooks run before execution but cannot modify the script file itself.
Q: Are there hook templates?
A: Not yet, but check the examples/.hooks.d/ directory for starter templates.
- Writing Scripts - Guide to creating tome scripts
- Completion Guide - Adding tab completion to scripts
- Examples - Sample scripts and hooks