Scratchpads
On this page
A scratchpad runs code you write inside a site, with the app booted the way its own commands boot it. Ask the database a question, try a model method, check a config value, and see what came back: the value of the last line, anything it printed or dumped, and every query it ran.
Scratchpads are part of Short Leash Pro.
How do I open one?
Open a site and choose Scratchpads in its pages, then New scratchpad. Go to (⌘K, Ctrl+K on Windows) also has New scratchpad in … for each site. A site can have as many scratchpads as it needs (up to 100), listed down the left like its terminals. Filter narrows a long list, Rename names the one you're on, and Close forgets it.
A new scratchpad starts with a line that works in every site of its kind, such as config('app.name') in a Laravel app.
How do I run it?
Write your code and press Run, or ⌘↩ (Ctrl+Enter on Windows). Stop, or ⌘. (Ctrl+. on Windows), ends a run that's taking too long; a run stops by itself after 60 seconds. Nothing runs as you type.
Each run starts a new process with the site's own runtime, in the site's folder, with its environment variables and, for PHP, Short Leash's php.ini for its version. Nothing carries over from the run before, so the code that runs is always the code in your project: change a model and run again, no restart needed. The code is saved as you type.
Your code runs for real: rows it writes stay written, and mail it sends goes to Short Leash's mail as usual.
What does each kind of site give me?
Short Leash picks how to boot the app from what it detected for the site:
| Site | Booted with | Ready to use |
|---|---|---|
| Laravel, Statamic | The console kernel, as artisan boots it |
$app, your models by their short name (User, Order), facades and helpers |
| WordPress (Bedrock too) | wp-load.php |
$wpdb, every WordPress function, your plugins |
| Symfony | The kernel in its environment (usually dev) | $kernel, $container, $em when Doctrine is installed |
| Craft CMS | Craft's console app | Craft::$app, element queries |
| Other PHP | Composer's autoloader, when there is one | Your classes and packages |
| Django | django.setup() |
Every model, settings, connection, transaction, timezone |
| Flask | An app context, as flask shell gives you |
app and your shell context |
| Other Python (FastAPI too) | The project's environment, through uv | The project's packages |
| Rails | config/environment, in Rails' executor |
Your models, app, helper, Rails.cache |
| Other Ruby | The project's bundle | Its gems |
| Next.js, Nuxt and other Node projects | Node, with the project's .env files (Next.js's own loader for a Next app) |
Your packages and modules, top-level await |
| Bun, Deno | The site's Bun or Deno | Your packages, and deno.json's imports |
| Go | A small main package inside your module |
Your module's packages, internal ones too, and fmt |
The line under the code says what's ready in the site you're in.
- PHP doesn't need
<?php. - JavaScript and TypeScript run as a module in the project folder:
import { db } from "./src/lib/db"resolves from there. TypeScript needs Node 22 or later; older Node runs JavaScript. With tsx in the project's dependencies, its tsconfig paths (@/lib/db) work too. NestJS and AdonisJS run as plain Node: import their modules, but the app itself isn't booted. - Go has no value of a last line: print what you want to see. Imports go at the top, and
fmtis imported for you when you use it.
What does a run show?
The bar over the code says which framework version and runtime ran it, and how long it took to boot and to run. Below the code, in order:
- An error, when there was one: what was thrown, where, the line in your code it came from (marked in the editor; click it to go there) and the trace, folded.
- Result: the value of the last line. A list of records (models, rows, dicts, objects) shows as a Table; Inspect shows the whole value, as a dump does. Copy as JSON copies it.
- Output: what the code printed, as it prints. Warnings and other output on stderr are marked.
- Each dump() and dd() (PHP), with the line it came from. In a scratchpad,
dd()ends the run without counting as a failure. - Queries, with their time. Laravel apps also report jobs, views, HTTP calls and log messages. Queries on MySQL, MariaDB, PostgreSQL or an SQLite file have Explain, as on the Dumps screen: Short Leash asks the database for the plan without running the query again.
Query lists come from Laravel's query events, WordPress's $wpdb, Django's execute hooks, Flask's SQLAlchemy engine and Rails' notifications. Other frameworks run without a query list.
What's kept?
Each scratchpad's code and its last 50 runs (when, how it went and the code it ran) are kept in Short Leash's database, in Short Leash's folder, readable only by you. History lists the runs, and Restore puts a run's code back.
What a run produced (values, output, dumps, queries) stays in memory until the next run, for the 20 scratchpads run most recently, and is cleared when Short Leash restarts. A run keeps up to 2 MB and 2,000 items of output; past that, a note says the rest was left out, and an error still shows. Nothing is written into your project.
Can I run code from the terminal or an AI tool?
Yes, the same way:
leash scratchpad run --code "User::count()"
leash scratchpad run snippet.php --site northwind
It prints what came back, and exits with status 1 when the code failed, stopped or ran out of time. --json prints every event. AI coding tools connected to leash mcp have run_code, which returns the same things.
Is it safe?
A run listens on no port and runs as you, never as administrator, like everything Short Leash starts. It runs your code with your app's settings, so it can change your data, as php artisan tinker or rails console can.