Skip to content

Releases: filipac/runlet

Runlet 0.2.0

Choose a tag to compare

@filipac filipac released this 03 Oct 01:10
5bcfae0

Runlet 0.2.0 lets AI clients run PHP with your approval, shows values inline with magic comments, profiles code with flame graphs, and runs on a Mac with no PHP installed. Website: https://filipac.github.io/runlet/

Highlights

  • No PHP? No problem. On a Mac with no PHP (no Herd, no Homebrew, no Docker), Runlet offers a one-click download of its own self-contained PHP 8.5.8 (about 26 MB, for your Mac's CPU). It's checked against a SHA-256 pinned in the app before it's installed. Your installed PHP always comes first. It includes Excimer, so Profile Run works out of the box.
  • Magic comments. End a line with //? to see its value next to the code. /*?*/ shows an intermediate value, /*?->count()*/ a projection, and /*?.*/ the elapsed time. Values stream in while the code runs, loops show ×N, and hovering shows the full value and every hit. They work on every target, with Run Selection, and can be switched off in Settings.
  • MCP server for AI clients. Claude Code, Claude Desktop, Cursor and other MCP clients can list your targets and snippets, save snippets, and ask to run PHP (runlet mcp). Every run asks you first, in a sheet showing the client, the target and all of the code. Only the sandbox can be allowed for a session, production always asks, and SSH never connects silently. It's off by default (Settings ▸ AI Clients).
  • Benchmark and profile.
    • Runlet\bench() times functions with min, median, p95, ops/s, memory and a distribution, and compares several side by side. Laravel's Benchmark::dd() gets the same card.
    • Profile Run (⌥⌘R) samples your snippet with Excimer and shows an interactive flame graph.
  • Open REPL. php artisan tinker, PsySH or php -a in a terminal tab, on any target: local, sandbox, Docker or SSH. Production asks every time.
  • Output, realtime or at once. Choose in Settings ▸ General. Large output is now fast in both modes: 5,000 dumps or 200,000 lines show in under half a second instead of freezing the window. Plain and Raw get a native text view with Find.
  • More:
    • Explain for captured SQL opens a ready-to-run tab with the query plan request.
    • String viewers: JSON trees, searchable text, images and HTML previews.
    • Run timing breakdown: bootstrap, execute, memory and queries.
    • Sandbox-only Auto-run.
    • Snippet descriptions.
    • Keep compiled PHP on the server is now on for new SSH profiles.
  • Fixes:
    • Pane dividers no longer draw behind the title bar and tabs.
    • The editor's gutter line no longer draws through banners.
    • A Metal validation assert no longer stops runs from Xcode.

Install

Download Runlet-0.2.0.dmg (drag Runlet to Applications) or Runlet-0.2.0.zip. Requires macOS 26 or later, on Apple silicon or Intel.

This build is ad-hoc signed and not notarized, so macOS blocks it the first time. Either right-click Runlet.app ▸ Open ▸ Open, or run:

xattr -dr com.apple.quarantine /Applications/Runlet.app

Checksums (SHA-256)

2702ffe07285ee5d6a3fa0dc55fcaa46fa3bc126d2281fbb4bcbfa966949fb23  Runlet-0.2.0.dmg
2888079b7418b8735bee0a2f6ffc994f07f606cb1c64ee00e64584d2c71f8b82  Runlet-0.2.0.zip

Notes

  • Early preview. Package tests passed in every pull request in this release; for this build the packaged self-test passed (6 of 6 checks). The UI test suite was not re-run.
  • Runlet's own PHP is published separately as the php-8.5.8-r2 pre-release and downloaded only when you click.
  • Free and open source under the MIT License.
Full changelog for 0.2.0

2026-10-03 — Output realtime or at once (#82)

  • Settings ▸ General ▸ Output: Realtime (the default) or At once. At once shows a
    run's printed output, dumps, result, errors, magic-comment values, and the inspector's
    queries, mail, logs, benchmarks, and profile together when it ends: completed, failed, dd(),
    exit, or stopped (what arrived before Stop is shown). The status bar, elapsed time, Stop, and
    the Run Log stay live; while it runs the output says "Output appears when the run ends". The
    app holds the output, so every target behaves the same, and AI clients over MCP get the full
    result in both modes.
  • It replaces the magic comments' Show values while the code runs switch (#10). A saved
    "off" becomes At once; older settings files open with Realtime.
  • Large output keeps up: before, 5,000 dump() calls or 200,000 echoed lines took minutes to
    appear and froze the window. The tab now takes events in batches (at most ten updates a
    second, fewer while drawing is slow), printed output is drawn a piece at a time, and the same
    runs show within a few hundred milliseconds of finishing. Structured shows the last 5,000
    lines of a printed output and the last 1,000 cards (Show All shows every card); Plain and
    Raw now use a native text view that appends new output, follows the end while scrolled to the
    bottom, and has Find. Plain, Raw, Copy Output, and Save Output always have everything.
  • New DEBUG step wait-run[:<seconds>]: waits for the selected tab's run and prints its timings.

2026-10-03 — Specialized string viewers (#7)

  • Structured strings offer JSON trees with Copy Pretty, searchable/wrapping text, PNG/JPEG/SVG images, and restricted HTML previews. Long strings open in Text; the original Tree stays available. Recognition and raster decoding are bounded, and incomplete strings retain their truncation notice. See the viewer guide.

2026-10-03 — Run timing breakdown (#9)

  • Finished output shows Bootstrap, Execute, and Started alongside labeled total time, peak memory, and query time. Hover the finished row or status to see the complete breakdown, including unavailable phases.
  • Completion events preserve runner phase timings through normal, error, cancellation, and transport-close paths. Old completion records remain readable. Query metrics survive Clear Output in the status tooltip and reset for the next run. See the timing guide.

2026-10-03 — Runlet's PHP r2 with Excimer (#79)

  • Runlet's own PHP is now build php-8.5.8-r2, which adds the Excimer extension, so Profile
    Run works on a Mac with no other PHP installed. Same PHP 8.5.8 and extensions otherwise.
  • Updating from r1: an installed older build keeps working, and Settings ▸ PHP ▸ Runlet's PHP
    shows "PHP 8.5.8 (r1) installed · Update to r2. Adds Excimer, so Profile Run works." Update
    downloads and verifies r2, moves the default PHP and projects' PHP from the old binary to the
    new one (also if Runlet quit in between), and removes r1. Nothing downloads without a click.
  • Remove now clears the default PHP and projects' PHP that pointed at any build of Runlet's PHP.

2026-10-03 — Xcode runs no longer stop on a Metal validation assert (#85)

  • Running from Xcode stopped at random on instanceCount(0) must be non-zero, raised by Metal API Validation while Core Animation replayed a line stroke with nothing to draw. Normal launches were unaffected. The Runlet scheme now runs with Metal API Validation off; turn it back on in Edit Scheme when debugging GPU issues.
  • The benchmark charts and the flame graph skip drawing at zero size, and the flame graph skips the hover outline on frames too small to show it, so Runlet's own views never ask for an empty stroke.

2026-10-03 — Magic comments (#10)

  • Magic comments show values in the editor while the code runs, without dump() calls or
    temporary variables. //? at the end of a line shows the line's value (an assignment's
    value, a return, an echo; ✓ on a line without a value, such as foreach (…) { //?).
    /*?*/ right after an expression shows that value, /*?->count()*/ (any -> or ?->
    chain) shows a projection while the code keeps the value itself, and /*?.*/ shows the
    milliseconds since the previous one (or since the snippet started).
  • Values appear as dim text after the line, ×N and the latest value for lines that run more
    than once. Hovering them (or Edit ▸ Show Inline Value) opens a panel with the value tree and
    the list of hits. Magic comments are highlighted, and the gutter marks lines whose comments
    ran. Values stream in while the code runs, on every target, and map back to the right lines
    for Run Selection. Edit ▸ Clear Inline Values and Clear Output remove them.
  • Adding magic comments never changes what the code does. The runner inserts probe calls at
    byte offsets on the same lines (it never re-prints the code), keeps references
    (by-reference arguments, =&, foreach (… as &$v), by-reference returns and yields) and
    nullsafe short-circuits, and refuses places where a call would change the code: assignment
    targets, isset()/empty()/?? operands, constant expressions, the start of "{$…}", and
    variables passed to methods that might take them by reference. Refused comments get one
    notice and a short reason on their line; the code runs as written. Semantics fixtures run
    each snippet with and without its magic comments and require the same results (PHP 8.4 and
    7.4).
  • Limits: the first 100 hits of each comment carry values, later hits are counted with a value
    sampled about four times a second, and values stop after 16 MiB per run. Projections run
    only for hits whose values are sent, and may query a database.
  • The next run clears values; a line edited since the run loses its values, and other lines
    keep theirs, moved with their text. Values never start a run.
  • Settings ▸ General ▸ Magic Comments: Show values of magic comments turned off m...
Read more

Runlet 0.1.0

Choose a tag to compare

@filipac filipac released this 02 Oct 19:15

Runlet 0.1.0 adds SSH servers, a run inspector, a Run Log, and a lot of polish since 0.0.1. Website: https://filipac.github.io/runlet/

Highlights

  • SSH targets. Run snippets on your servers with the system ssh. Logins from ~/.ssh/config, jump hosts, ssh-agent, and 1Password work as they do in your terminal. Password and 2FA logins are done once with Connect… and stay open until you Disconnect. Each host has:

    • a local project folder for completion, drivers, snippets, host commands, and clickable server paths;
    • Detect and Browse… to find its folder on the server;
    • project commands and Shell on Host;
    • optionally, a Docker container on that server.

    Manage Profiles… covers Docker and SSH and imports hosts from ~/.ssh/config. The opt-in Keep compiled PHP on the server speeds up large apps.

  • Production guard for every target: a red badge, and a confirmation before each run. Project commands always ask.

  • Run inspector. SQL queries with timings, bindings, and N+1 hints, from Laravel, Eloquent without Laravel, Doctrine, or WordPress. Mail and HTML previews in a locked-down viewer, with optional mail interception, and logs. Drivers can add their own sections. Output exports as JSON, PHP, CSV, or Markdown, and Run ▸ Save Output As… saves it.

  • Run Log (Run ▸ Show Run Log): the exact launch command, driver choice, boot timing (WordPress per phase and plugin), stderr, and the exit. An exit() during boot now says why: WordPress redirects and the last file loaded. WordPress runs use the site's real host, so plugins such as W3 Total Cache no longer redirect them.

  • Terminal:

    • commands wait until your shell is ready;
    • command tabs stay open after they exit;
    • ⌘W closes the focused terminal tab.
  • Palette:

    • a click outside closes it;
    • ⌘P and ⇧⌘P switch modes;
    • better matching;
    • ! searches history, and @ lists Docker and SSH.
  • Library: History per project or for all projects, without duplicates, and keyboard-first. You choose where double-click opens entries. The Commands pane shows the driver's variables. hostCommands() lets drivers add commands that run on your Mac, such as your own CLIs. There's also a gitRevision() helper.

  • More:

    • the runlet command-line tool;
    • file-backed tabs follow changes on disk;
    • Float on Top, and recent projects in the Dock menu;
    • the editor/output split is remembered.
  • Fixes:

    • focus stays in Runlet after closing a window;
    • no more crash when opening the sidebar;
    • quitting can't leave Runlet running in the background;
    • SSH connects only on the first run.

Install

Download Runlet-0.1.0.dmg (drag Runlet to Applications) or Runlet-0.1.0.zip. Requires macOS 26 or later, on Apple silicon or Intel.

This build is ad-hoc signed and not notarized, so macOS blocks it the first time. Either right-click Runlet.app ▸ Open ▸ Open, or run:

xattr -dr com.apple.quarantine /Applications/Runlet.app

Checksums (SHA-256)

dbdd689e087d78c1fb53b51e95c3032c2ecf1aa4686cffa6f2ab18f2de4b7aa1  Runlet-0.1.0.dmg
3342e1a00dba723aef40d45ac4cf63c796d3a3dee41dbce8a61e77ecd5609334  Runlet-0.1.0.zip

Notes

  • Early preview. Package tests (384) and the packaged self-test pass; the UI test suite was not re-run for this build.
  • Free and open source under the MIT License.
Full changelog for 0.1.0

2026-10-02 — Keep compiled PHP on the server (SSH)

  • SSH profiles have an opt-in Speed ▸ Keep compiled PHP on the server. Runs then use
    PHP's opcode cache with a file cache in ~/.cache/runlet/opcache (mode 0700, only the
    SSH user), so big apps such as WordPress with many plugins don't recompile every file on
    each run.
  • Timestamps are checked on every run, so edits are picked up. When the folder can't be
    created or PHP has no opcache extension, runs go on uncached.
  • Only Runlet's runs use the cache; the server's PHP settings are untouched. It's off by
    default because it writes to the server, and not offered with a container step.
  • The Run Log's WordPress boot line shows the file cache when it is in use.

2026-10-02 — Remembered for the session: driver and WordPress site URL

  • Runs remember what they worked out per target until Runlet quits, and the runner reuses
    it once it checks it still applies:
    • the built-in driver it chose, while no .runlet driver is added or edited;
    • a WordPress site URL, while wp-config.php has the same modification time and size.
      This skips the wp-config.php evaluation and database lookup, about 50 ms per run.
  • The Run Log says "remembered for this session". A run that fails while booting forgets
    that target's values, so the next run detects everything again.

2026-10-02 — Where WordPress's boot time goes

  • The Run Log has a WordPress boot breakdown:
    • time per phase: core and must-use plugins, plugins, plugins_loaded hooks, theme,
      user and init setup, init hooks, wp_loaded hooks, and Runlet's admin APIs;
    • the slowest plugins to load, by folder;
    • whether PHP's opcode cache is on for the command line. It is usually off
      (opcache.enable_cli), so every run compiles every file the site loads, while web
      requests keep them compiled.

2026-10-02 — Quitting really quits; SSH connects on the first run

  • Quitting closes the shared SSH connections that runs opened by themselves (profiles using
    ssh-agent, 1Password, or keys). Nothing stays connected after Runlet quits, and the next
    launch shows Disconnected until the first run on that host connects. Logins made with
    Connect… (passwords, 2FA) still stay open until Disconnect.
  • Quitting never waits more than 4 seconds for runs, language servers, or SSH connections to
    stop, so Runlet can't be left "Running in Background" after ⌘Q.

2026-10-02 — Profiles window for Docker and SSH, ~/.ssh/config import (SSH-7)

  • Library ▸ Manage Profiles… opens one Profiles window (formerly Docker Profiles) for every
    Docker and SSH profile: the list has Docker and SSH Hosts sections (SSH rows show the
    connection status, read on this Mac, and the environment); the left side edits the selected
    profile with its usual form. Same model as before: a draft until Save (↩/⌘S), Revert,
    Save / Don't Save / Cancel on switching or closing; + creates either kind (hold for the menu)
    or imports hosts; ⋯ duplicates, uses in the current tab, or connects and disconnects.
  • Import SSH Hosts from ~/.ssh/config… (Library menu, the Profiles window, Settings ▸
    Targets, the command palette): the config's Host aliases with their ssh -G summary;
    tick hosts, optionally enter each directory (or use Detect later), and check the
    environment, preselected from words such as prod and staging in the alias or host
    name. Nothing connects.
  • Settings ▸ Targets: Import and Manage Profiles… for SSH hosts, which also show when they're
    connected; SSH hosts can be the default target for new tabs (a new tab never connects).
  • Debug builds: RUNLET_SSH_EXECUTABLE replaces /usr/bin/ssh. Tests/Fixtures/fake-ssh/ssh is
    a loopback fake for screenshot tours (made-up ssh -G, a fake shared connection and password
    prompt, commands run on this Mac; never a server), and the visual tour uses it with a made-up
    SSH config and adds a Profiles-window shot.
  • Tests: the import helpers (environment guess, ssh -G with a test config) and the fake ssh
    driving a run, Test Connection, status, and Disconnect.

2026-10-02 — SSH: Docker on the server (SSH-6)

  • SSH profiles can run inside a Docker container on the host: turn it on in "Docker on
    This Host", click List Containers… (lists the server's running containers over SSH,
    grouped by Compose project), and choose one. Runs use docker exec into it through the
    profile's SSH connection (no prompts, strict host keys, the shared login), with the
    container's PHP, user, working directory, and TMPDIR, and an optional sudo -n docker.
  • The container is found the way Docker profiles find theirs: by Compose project and
    service (or name), checked again right before launch, and never switched silently; several
    replicas or a replaced container ask which one to use (the chosen replica stays chosen while
    it runs, also for Docker profiles).
  • Stop signals PHP inside the container on the server; the container keeps running. Test
    Connection also finds the container and probes it (a server without PHP of its own is
    fine). Browse… lists folders inside the container.
  • File links map container paths to the local folder through the server directory's bind
    mount. Project commands run inside the container (docker exec -it over ssh -t); the
    terminal's + menu offers a shell in the container and one on the server itself.
  • Tab cards show "SSH · Docker", the target's container appears in the production
    confirmation, ⌘P, Settings ▸ Targets, and the status bar, and workspace files carry the
    container step (by Compose identity or name, never an ID).
  • Docker problems on the server are explained (Docker not found, no permission on the Docker
    socket, sudo asking for a password, daemon not running).
  • Tests: a fake docker installed on the SSH fixture (made-up containers that are folders
    of the fixture) covers listing, resolution (replicas, recreation, a replaced name-only
    container), runs, Stop, a vanished container, probes, facts, folder listings, command
    listing, and a project command in the container; plus unit tests for the model,
    validation, workspaces, and path mapping.

2026-10-02 — SSH: project commands and shells on the server (SSH-5)

  • Commands listed for an SSH host now run on the server: a terminal tab runs ssh -t
    (still BatchMode, strict host keys, and the shared connection: no password prompts, no
    unknown host keys) with /bin/sh -lc 'cd <directory> …; <command>', a l...
Read more

Runlet 0.0.1

Choose a tag to compare

@filipac filipac released this 02 Oct 16:18

First public build of Runlet, a native macOS PHP scratchpad. It runs snippets against a bundled Laravel sandbox, your local projects, or applications running in Docker.

Highlights

  • Three kinds of target:
    • a bundled Laravel sandbox, using local PHP or a php:8.4-cli container;
    • local projects, using any PHP 7.4+;
    • running Docker / Compose containers, which Runlet docker execs into.
  • Framework drivers auto-detect Laravel, Lumen, Laravel Zero, WordPress, Symfony, and Composer projects. Project drivers in .runlet/ can boot custom apps and add variables, project commands, and host commands.
  • Structured output: dumps, results, and errors as Structured, Plain, or Raw output. The final expression is captured, and <?php is optional.
  • Editor:
    • PHPantom language server (completion, diagnostics, hover), aware of the project and the container;
    • tabs, horizontal or vertical (with target cards);
    • multiple windows and .runlet workspace files.
  • Library:
    • History per project or across all projects, without duplicate entries;
    • personal and project snippets;
    • a Commands pane with Artisan or console commands, Composer scripts, driver commands, and host commands such as a custom CLI.
  • Integrated terminal: tabs running your login shell. Commands wait for the shell's prompt, and command tabs stay open after they exit.
  • Palettes: Open Anything (⌘P) and the Command Palette (⇧⌘P), with customizable shortcuts.
  • Docker Profiles window: manage every Docker profile in one place.

See CHANGELOG.md for the full list.

Requirements

  • macOS 26 or later; universal build for Apple silicon and Intel.
  • The sandbox needs local PHP 8.2+ (for example from Herd or Homebrew), or Docker to use the php:8.4-cli image.
  • Docker targets need Docker Desktop or OrbStack.

Installing

This build is ad-hoc signed and not notarized, so macOS blocks it the first time you open it. Either:

  • Right-click (Control-click) Runlet.app ▸ Open ▸ Open; or
  • run xattr -dr com.apple.quarantine /Applications/Runlet.app after copying it to Applications.

Download Runlet-0.0.1.dmg (drag Runlet to Applications) or Runlet-0.0.1.zip.

Checksums (SHA-256)

19b76409d646c65a1b79557f57b631dd06cb5a461fa966b66ffff01cffc6d502  Runlet-0.0.1.dmg
8fc9b0a6d215fa6fb968b516fec94d8f581524ae2dcda7057a6ca065428a7bd4  Runlet-0.0.1.zip

Known limitations

  • This is an early preview. The UI test suite was not re-run against this exact build. The package tests (about 250) and the packaged self-test pass, covering resources, sandbox install and run, and language-server completion.
  • Not notarized (see Installing).

Runlet's PHP 8.5.8-r2

Runlet's PHP 8.5.8-r2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 03 Oct 00:09

Self-contained PHP CLI for Runlet (#2), built from scripts/php-runtime/craft.yml with static-php-cli 2.8.5. Runlet downloads it on request and verifies these checksums; it is not an app release.

Runlet's PHP 8.5.8-r1

Runlet's PHP 8.5.8-r1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Oct 21:34

Self-contained PHP CLI for Runlet (#2), built from scripts/php-runtime/craft.yml with static-php-cli 2.8.5. Runlet downloads it on request and verifies these checksums; it is not an app release.