Skip to main content
Project scripts allow you to define custom commands that can be executed from the T3 Code interface and bound to keyboard shortcuts. These are perfect for common development tasks like running tests, building, linting, and starting dev servers.

Overview

Project scripts are configured per-project and can:
  • Execute any shell command
  • Be triggered via keyboard shortcuts (see Keybindings)
  • Run automatically when creating new worktrees
  • Display with custom icons in the UI

Script Configuration

Scripts are configured through the T3 Code UI in project settings. Each script has the following properties:

Script Properties

id
string
required
Unique identifier for the script.
  • Must be 1-24 characters
  • Start with lowercase letter or digit
  • Can contain lowercase letters, digits, and hyphens
  • Used in keybinding commands: script.{id}.run
Examples: test, build, dev, lint-fix
name
string
required
Display name shown in the UI.This is what users see in the interface. Can contain spaces and special characters.Examples: Run Tests, Build Production, Start Dev Server
command
string
required
The shell command to execute.This can be any valid shell command. It runs in the project’s workspace root.Examples:
  • npm test
  • bun run build
  • cargo test --all
  • python -m pytest
icon
'play' | 'test' | 'lint' | 'configure' | 'build' | 'debug'
required
Icon displayed in the UI.Choose an icon that best represents the script’s purpose:
  • play - General execution, start commands
  • test - Test runners
  • lint - Linters, formatters
  • configure - Setup, configuration scripts
  • build - Build commands
  • debug - Debugging tools
runOnWorktreeCreate
boolean
required
Whether to automatically run this script when creating a new worktree.Useful for setup scripts that need to run in fresh worktrees (e.g., installing dependencies).Default: false

Creating Scripts via UI

1

Open Project Settings

Navigate to your project and click the settings icon.
2

Add New Script

Click “Add Script” in the Scripts section.
3

Configure Script

Fill in the script details:
  • ID (for keybindings)
  • Display name
  • Command to execute
  • Icon
  • Auto-run on worktree creation (optional)
4

Save

Click Save to persist the script configuration.

Example Scripts

Testing

{
  "id": "test",
  "name": "Run Tests",
  "command": "npm test",
  "icon": "test",
  "runOnWorktreeCreate": false
}

Building

{
  "id": "build",
  "name": "Build Production",
  "command": "npm run build",
  "icon": "build",
  "runOnWorktreeCreate": false
}

Linting and Formatting

{
  "id": "lint",
  "name": "Lint Code",
  "command": "npm run lint",
  "icon": "lint",
  "runOnWorktreeCreate": false
}

Development Servers

{
  "id": "dev",
  "name": "Start Dev Server",
  "command": "npm run dev",
  "icon": "play",
  "runOnWorktreeCreate": false
}

Setup and Installation

{
  "id": "install",
  "name": "Install Dependencies",
  "command": "npm install",
  "icon": "configure",
  "runOnWorktreeCreate": true
}

Binding Scripts to Keybindings

Once you’ve created a script, you can bind it to a keyboard shortcut using the script.{id}.run command format. In your ~/.t3/keybindings.json:
[
  { "key": "mod+shift+t", "command": "script.test.run" },
  { "key": "mod+shift+b", "command": "script.build.run" },
  { "key": "mod+shift+l", "command": "script.lint.run" },
  { "key": "f5", "command": "script.dev.run" }
]
The script ID in the keybinding must exactly match the ID configured in your project settings.
See the Keybindings documentation for more details.

Script Execution Context

Working Directory

Scripts execute in the project’s workspace root directory. For worktree-based threads, scripts run in the worktree directory.

Environment Variables

Scripts inherit the environment from the T3 Code server process. This includes:
  • System environment variables
  • Shell profile variables (if the server was started from a shell)
  • Any custom environment variables set when launching T3 Code

Shell

Scripts are executed using the system’s default shell:
  • /bin/sh on Unix-like systems
  • cmd.exe on Windows (when not using WSL)
Shell-specific features (like bash arrays or zsh plugins) may not work unless you explicitly invoke that shell in your command.Example: bash -c 'your command here'

Output and Logging

Script output (stdout and stderr) is displayed in the T3 Code terminal. You can:
  • View real-time output
  • See exit codes
  • Cancel running scripts

Best Practices

Choose IDs that clearly indicate what the script does:
✅ test, build, lint-fix
❌ s1, script2, x
If your command is complex, consider moving it to a shell script:
{
  "id": "deploy",
  "name": "Deploy to Staging",
  "command": "./scripts/deploy.sh staging",
  "icon": "play",
  "runOnWorktreeCreate": false
}
Only enable auto-run for scripts that are:
  • Fast (< 30 seconds)
  • Idempotent (safe to run multiple times)
  • Required for the worktree to function
Good candidates:
  • npm install
  • git submodule update
Bad candidates:
  • Long-running dev servers
  • Database migrations
  • Deployment scripts
Run scripts manually from the UI first to ensure they work correctly before binding them to shortcuts.
Instead of duplicating commands, reference scripts defined in your package.json:
package.json
{
  "scripts": {
    "test:unit": "jest",
    "test:e2e": "playwright test",
    "test:all": "npm run test:unit && npm run test:e2e"
  }
}
T3 Code script
{
  "id": "test-all",
  "name": "Run All Tests",
  "command": "npm run test:all",
  "icon": "test",
  "runOnWorktreeCreate": false
}

Common Use Cases

Full Stack Project

[
  {
    "id": "install",
    "name": "Install Dependencies",
    "command": "npm install",
    "icon": "configure",
    "runOnWorktreeCreate": true
  },
  {
    "id": "dev",
    "name": "Start Dev Server",
    "command": "npm run dev",
    "icon": "play",
    "runOnWorktreeCreate": false
  },
  {
    "id": "test",
    "name": "Run Tests",
    "command": "npm test",
    "icon": "test",
    "runOnWorktreeCreate": false
  },
  {
    "id": "lint",
    "name": "Lint Code",
    "command": "npm run lint",
    "icon": "lint",
    "runOnWorktreeCreate": false
  },
  {
    "id": "build",
    "name": "Build Production",
    "command": "npm run build",
    "icon": "build",
    "runOnWorktreeCreate": false
  }
]

Python Data Science Project

[
  {
    "id": "setup",
    "name": "Setup Environment",
    "command": "python -m venv venv && source venv/bin/activate && pip install -r requirements.txt",
    "icon": "configure",
    "runOnWorktreeCreate": true
  },
  {
    "id": "test",
    "name": "Run Tests",
    "command": "pytest",
    "icon": "test",
    "runOnWorktreeCreate": false
  },
  {
    "id": "notebook",
    "name": "Start Jupyter",
    "command": "jupyter notebook",
    "icon": "play",
    "runOnWorktreeCreate": false
  },
  {
    "id": "lint",
    "name": "Lint with Black",
    "command": "black .",
    "icon": "lint",
    "runOnWorktreeCreate": false
  }
]

Rust Project

[
  {
    "id": "build",
    "name": "Build Debug",
    "command": "cargo build",
    "icon": "build",
    "runOnWorktreeCreate": false
  },
  {
    "id": "build-release",
    "name": "Build Release",
    "command": "cargo build --release",
    "icon": "build",
    "runOnWorktreeCreate": false
  },
  {
    "id": "test",
    "name": "Run Tests",
    "command": "cargo test --all",
    "icon": "test",
    "runOnWorktreeCreate": false
  },
  {
    "id": "lint",
    "name": "Run Clippy",
    "command": "cargo clippy --all-targets --all-features",
    "icon": "lint",
    "runOnWorktreeCreate": false
  },
  {
    "id": "format",
    "name": "Format Code",
    "command": "cargo fmt",
    "icon": "lint",
    "runOnWorktreeCreate": false
  }
]

Schema Reference

The ProjectScript type from the source code:
export const ProjectScript = Schema.Struct({
  id: TrimmedNonEmptyString,
  name: TrimmedNonEmptyString,
  command: TrimmedNonEmptyString,
  icon: ProjectScriptIcon, // 'play' | 'test' | 'lint' | 'configure' | 'build' | 'debug'
  runOnWorktreeCreate: Schema.Boolean,
});
Source: ~/workspace/source/packages/contracts/src/orchestration.ts:118-125

Troubleshooting

Script Not Found in Keybindings

If your keybinding command script.{id}.run isn’t working:
  1. Verify the script ID matches exactly (case-sensitive)
  2. Check that the script is saved in project settings
  3. Ensure the ID follows naming rules (lowercase, alphanumeric, hyphens only)

Script Fails to Execute

If your script runs but fails:
  1. Check the command: Test it manually in a terminal first
  2. Verify working directory: Ensure paths are relative to workspace root
  3. Check permissions: Scripts may need execute permissions
  4. Review environment: Some tools require specific environment variables

Auto-run Scripts Not Running

If runOnWorktreeCreate scripts don’t execute:
  1. Check server logs for errors
  2. Verify the script command is valid
  3. Ensure the worktree creation completed successfully

Limits and Constraints

Script ID length
1-24 characters
Must match pattern: ^[a-z0-9][a-z0-9-]*$
Maximum scripts per project
No hard limit
However, performance may degrade with excessive scripts. Recommended: < 20 scripts.
Command length
No hard limit
Limited by your shell’s command length limit (typically 128KB+).

Keybindings

Bind scripts to keyboard shortcuts

Server Options

Server configuration and CLI flags

Build docs developers (and LLMs) love