Suitcase

Give your agent a face.

A lightweight Swift command that spins up native macOS UI on demand — confirmation forms, progress panels, file drops — with full JSON control over every session.

One Prompt, Done

Hand This Prompt to Your Agent

The fastest way to install. Copy the prompt below and paste it into your agent. It downloads the signed and notarised Suitcase installer package, installs the command into /usr/local/bin, installs the skill, verifies both — and when everything checks out, pops up a native Suitcase window with a Quit button to confirm.

Agent install prompt
Download, install, and verify the Suitcase command and its agent UI skill.

1. Download and install the package
   - Download the signed and notarised installer package:
       curl -fL https://suitcase.richardstelling.com/download/current.pkg -o Suitcase-v2.3.0-macos.pkg
   - Install it with macOS Installer. This may ask for the administrator password,
     creates any missing install folders on fresh systems, and places the binary at
     /usr/local/bin/Suitcase:
       sudo /usr/sbin/installer -pkg ./Suitcase-v2.3.0-macos.pkg -target /

2. Install the skill
   - Install the embedded suitcase-agent-ui skill into known skill locations:
       /usr/local/bin/Suitcase install-ui-skill

3. Verify the command and the skill
   - Confirm the command and version (expect 2.3.0):
       /usr/local/bin/Suitcase --version
   - Confirm the skill is installed and up to date:
       /usr/local/bin/Suitcase check-ui-skill
   - Smoke-test the runtime:
       /usr/local/bin/Suitcase diagnostic --json

4. Show the result in a native Suitcase window
   - Only if `/usr/local/bin/Suitcase --version` printed 2.3.0 AND `/usr/local/bin/Suitcase check-ui-skill`
     reported the skill is installed and up to date, open a confirmation
     window that has a Quit button:
       /usr/local/bin/Suitcase utility \
         --application-identifier "$(uuidgen)" \
         --name "Suitcase Install Check" \
         --window-title "Suitcase Install Check" \
         --window-width 520 --window-height 280 --window-floating \
         --control-type label \
           --control-title "suitcase successfully installed" \
         --control-type text \
           --control-title "/usr/local/bin/Suitcase --version prints 2.3.0 and Suitcase check-ui-skill reports the skill is installed and up to date." \
         --control-type button --control-title "Quit" --control-action ":quit"
   - If either check fails, do NOT open the window โ€” report what failed instead.

Already have Suitcase installed? Update Suitcase prompt →
Get Suitcase v2.3.0

How to Install

Three steps from zero to a native macOS UI on the command line. The recommended path is the signed and notarised macOS installer package.

  1. Download the Installer

    Grab the latest signed and notarised package for Apple silicon (arm64), served straight from this site.

    Download Suitcase โ†’
  2. Run the Package

    macOS Installer asks for the administrator password when required, creates missing install folders, and places Suitcase in /usr/local/bin.

    sudo /usr/sbin/installer -pkg ./Suitcase-v2.3.0-macos.pkg -target /
  3. Verify the Install

    Confirm the installed command is live and on the right version.

    /usr/local/bin/Suitcase --version

    Expected output: 2.3.0

Ready for agents? Install the embedded skill next with Suitcase install-ui-skill.

Built for Agentic Workflows

Install the Skill, Then Let Your Agent Build the UI

Suitcase v2 ships with an embedded skill called suitcase-agent-ui (v1.7.0). Once it is installed, an agent in an agentic workflow can spin up task-specific macOS interfaces on demand — confirmation forms, live progress panels, file drops — while keeping full structured JSON control over every session. The skill lives inside the binary, so rebuilding or reinstalling keeps it in sync.

Install & Verify

Suitcase install-ui-skill   # installs the embedded suitcase-agent-ui skill into known skill locations
Suitcase check-ui-skill     # reports whether your installed copies are up to date

What Your Agent Can Do Once the Skill Is Installed

Confirmation Forms

Pause and ask the user to approve a destructive action before it runs.

Live Progress + Log Panels

Stream status and logs in a native panel during a long-running task.

File-Drop Intake

Ask the user to drop files straight into the UI for processing.

Structured JSON Sessions

agent-ui create / update / wait / close — every command returns a JSON envelope.

Visible Utility Forms

Suitcase utility shows a persistent macOS form the user fills in directly.

Deny-by-Default Security

No command execution, env exposure, or file access unless explicitly allowlisted; writes and commands need confirmation.

Concrete Agent Examples

  1. Before deleting a directory, the agent opens a confirmation form and waits for a yes before proceeding.
  2. During a long migration, the agent streams a live progress + log panel so the user can watch it work.
  3. The agent collects form input — name, date of birth — and writes the answers out to Markdown.

Drive a Session Over JSON

# open a structured session from a request file
Suitcase agent-ui create --input request.json

# push a new control value into the open session
echo '{"status":"running"}' | Suitcase agent-ui update sess_8f21

# poll / fetch the result, then finalize
Suitcase agent-ui wait sess_8f21
Suitcase agent-ui close sess_8f21

Every command prints a JSON envelope: {ok, payload, error}.

Full Command Reference

Every Command, Straight From the CLI

This reference is generated directly from the command's own help output (Suitcase --experimental-dump-help), so it always matches the installed command — nothing here is hand-written. Every command also accepts --help, and the top-level Suitcase command accepts --version.

Suitcase basic default

Launch a basic Suitcase process, that has a main menu and an icon in the Dock when running.

Usage Suitcase basic [options]

Options

--name <name>

The name of the currently running Suitcase.

The name is used in several places to refer to the running process. It should be treated like the name of an application, should but descriptive. This is also used as the main window title if --window-title is not set.

--compatible-version <version>

The semantic version of Suitcase this command is compatible with.

Indecates the Suitcase version that is compatible with the set of commands. Semantic Versioning 2.0.0 is used see: https://semver.org for details.

--icon <path>

A file system path to an image file.

An image file (JPEG, PNG) used as the process icon. Only basic Suitcase processes show in the Dock and Application Switcher.

-E, --copy-environment-variable <variable> repeatable

The name of an environment variable

The value of the environment variable is copied and exposed using the same key to all of actions.

--window-title <title>

A string used as the main window title.

Optional. If not set the value of --name is used. Even if the window title is hidden it is advised to set the window title to improve acessability.

--window-width <pixels> default: 400

Initial window width.

The integer width in pixels of the main window on its first run. This is overidden if the user changes the window size.

--window-height <pixels> default: 0

Initial window height.

The integer height in pixels of the main window on its first run. This is overidden if the user changes the window size.

--working-directory <path>

A file system path to a directory.

Sets the working directory for all Actions before they are execuited. This can be overridden is the --drop-working-directory option is also used.

--control-type <type> repeatable

The type of control.

Required. The following keys are valid controls; label, button, text, text-field, working-directory-label and error-text. - label, short text used to discribe a region or group of controls. - text, an area of text that can scroll. - text-field, editable text field. Actions can be attached to text-fields and are triggered when the return button is pressed. - button, a control that can trigger an action when pressed. - working-directory-label, a speical case label that shows the currently set working directory (see: --drop-working-directory and --working-directory).

--control-title <title> repeatable

The title or content of a control.

Required. The inital value of a controls title or content. An action can change the if the control has an identifier and the action specifies an action destination (see: --control-identifier and --control-action-destination).

--control-identifier <identifier> repeatable

A string to uniquly identify the control.

Optional. An identfier can be any string but it is strongly advised to use reverse domain name notation. Control identifiers are used by action destinations to output the their results. Actions can also refer to identifiers in action parameters (see: --control-action-destination and --control-action-parameter). The value/title of a control is also available as an enviroment variable when executing actions (see --copy-environment-variable).

--control-action <action> repeatable

A command line string.

Optional. Action strings can refer to any command or script installed on the machine. Commands and scripts need to be referenced with absolute file paths or releitive to the working directory (see: --drop-working-directory and --working-directory). Multiple actions can be performed by seperating them with an & (ampersand). Output from one command can be piped to a second using | (pipe). Arguments can be decalred inline, in the control action string or by using --control-action-parameter.

--control-action-parameter <parameter> repeatable

A list of parameters.

Optional. A comma seperated list of parameters passed to an action. If a parameter matches an environment variable it is subsituted for the value before being passed to the action (see --copy-environment-variable and --control-identifier).

--control-action-destination <identifier> repeatable

A string to identify a control.

Optional. The output of an action is used to set the tile or content of the contole matching the identifier (see: --control-identifier).

--control-group-identifier <identifier> repeatable

A string to uniquly identify a group of controls.

Optional. An identfier can be any string but it is strongly advised to use reverse domain name notation. Group identifiers are used to spacialy group contols on screen. The first control in the group determines the on screen order of the group.

--menu-title <title> repeatable

The path of the menu item.

Required. Menu titles accept a hierarchical path to the menu, seperated by >. This can be used to create sub-menus of any depth (although 3 is considered a maximum). To add items to the Suitcase menu set a path of, Application>Sub menu>Menu Item.

--menu-action <action> repeatable

A command line string.

Optional. Action strings can refer to any command or script installed on the machine. Commands and scripts need to be referenced with absolute file paths or releitive to the working directory (see: --drop-working-directory and --working-directory). Multiple actions can be performed by seperating them with an & (ampersand). Output from one command can be piped to a second using | (pipe).

--menu-shortcut <shortcut> repeatable

The keyboard shortcut string.

Optional. A single character used as the keyboard shortcut. Lowercase character will be shown as โŒ˜Y uppercase characters are shown as โ‡งโŒ˜Y. Shortcuts *do not* support other modifiers. (Please file a bug if this is important to you).

--menu-action-destination <identifier> repeatable

A string to identify a control.

Optional. The output of an action is used to set the tile or content of the contole matching the identifier (see: --control-identifier).

Flags

--window-floating

The main window floats above all others.

If set the main window float above every other window on the system.

--drop-working-directory

Main window accepts dropped directories.

Enable setting the working directory by dropping a directory on the main window.

--divider

Creates a visual divide on screen

Dividers can be either horizontal or vertical depending on their context. Dividers in a control group (see: --control-group-identifier) are rendered as vertical, otherwise dividers are horizontal.

--spacer

Expands to fill all space between controls

Spacer can be either horizontal or vertical depending on their context. Spacers in a control group (see: --control-group-identifier) fill space vertically. Spacers without a group fill space horizontally.

Suitcase utility

Launch a utility Suitcase process, without a Dock icon or main menu.

Usage Suitcase utility [options]

Options

--name <name>

The name of the currently running Suitcase.

The name is used in several places to refer to the running process. It should be treated like the name of an application, should but descriptive. This is also used as the main window title if --window-title is not set.

--compatible-version <version>

The semantic version of Suitcase this command is compatible with.

Indecates the Suitcase version that is compatible with the set of commands. Semantic Versioning 2.0.0 is used see: https://semver.org for details.

--icon <path>

A file system path to an image file.

An image file (JPEG, PNG) used as the process icon. Only basic Suitcase processes show in the Dock and Application Switcher.

-E, --copy-environment-variable <variable> repeatable

The name of an environment variable

The value of the environment variable is copied and exposed using the same key to all of actions.

--window-title <title>

A string used as the main window title.

Optional. If not set the value of --name is used. Even if the window title is hidden it is advised to set the window title to improve acessability.

--window-width <pixels> default: 400

Initial window width.

The integer width in pixels of the main window on its first run. This is overidden if the user changes the window size.

--window-height <pixels> default: 0

Initial window height.

The integer height in pixels of the main window on its first run. This is overidden if the user changes the window size.

--working-directory <path>

A file system path to a directory.

Sets the working directory for all Actions before they are execuited. This can be overridden is the --drop-working-directory option is also used.

--control-type <type> repeatable

The type of control.

Required. The following keys are valid controls; label, button, text, text-field, working-directory-label and error-text. - label, short text used to discribe a region or group of controls. - text, an area of text that can scroll. - text-field, editable text field. Actions can be attached to text-fields and are triggered when the return button is pressed. - button, a control that can trigger an action when pressed. - working-directory-label, a speical case label that shows the currently set working directory (see: --drop-working-directory and --working-directory).

--control-title <title> repeatable

The title or content of a control.

Required. The inital value of a controls title or content. An action can change the if the control has an identifier and the action specifies an action destination (see: --control-identifier and --control-action-destination).

--control-identifier <identifier> repeatable

A string to uniquly identify the control.

Optional. An identfier can be any string but it is strongly advised to use reverse domain name notation. Control identifiers are used by action destinations to output the their results. Actions can also refer to identifiers in action parameters (see: --control-action-destination and --control-action-parameter). The value/title of a control is also available as an enviroment variable when executing actions (see --copy-environment-variable).

--control-action <action> repeatable

A command line string.

Optional. Action strings can refer to any command or script installed on the machine. Commands and scripts need to be referenced with absolute file paths or releitive to the working directory (see: --drop-working-directory and --working-directory). Multiple actions can be performed by seperating them with an & (ampersand). Output from one command can be piped to a second using | (pipe). Arguments can be decalred inline, in the control action string or by using --control-action-parameter.

--control-action-parameter <parameter> repeatable

A list of parameters.

Optional. A comma seperated list of parameters passed to an action. If a parameter matches an environment variable it is subsituted for the value before being passed to the action (see --copy-environment-variable and --control-identifier).

--control-action-destination <identifier> repeatable

A string to identify a control.

Optional. The output of an action is used to set the tile or content of the contole matching the identifier (see: --control-identifier).

--control-group-identifier <identifier> repeatable

A string to uniquly identify a group of controls.

Optional. An identfier can be any string but it is strongly advised to use reverse domain name notation. Group identifiers are used to spacialy group contols on screen. The first control in the group determines the on screen order of the group.

Flags

--window-floating

The main window floats above all others.

If set the main window float above every other window on the system.

--drop-working-directory

Main window accepts dropped directories.

Enable setting the working directory by dropping a directory on the main window.

--divider

Creates a visual divide on screen

Dividers can be either horizontal or vertical depending on their context. Dividers in a control group (see: --control-group-identifier) are rendered as vertical, otherwise dividers are horizontal.

--spacer

Expands to fill all space between controls

Spacer can be either horizontal or vertical depending on their context. Spacers in a control group (see: --control-group-identifier) fill space vertically. Spacers without a group fill space horizontally.

Suitcase install

Install the command in a known location

Usage Suitcase install [options] <archive>

Arguments

<archive> required

Path to archive file.

Options

-p, --path <path>
--name <name>

Name of the command.

Suitcase install-ui-skill

Install the Suitcase Agent UI skill into known skill locations.

Usage Suitcase install-ui-skill [options]

Options

-p, --path <path> repeatable

Custom skills directory. Installs to <path>/suitcase-agent-ui. Can be provided more than once.

Flags

-f, --force

Create any missing skill directories before installing. Will not overwrite an unrelated path.

Suitcase check-ui-skill

Report whether installed Suitcase Agent UI skill copies are up to date.

Usage Suitcase check-ui-skill [options]

Options

-p, --path <path> repeatable

Custom skills directory to check, containing <path>/suitcase-agent-ui. Can be provided more than once.

Suitcase run

Run an installed command.

Usage Suitcase run [options] <archive>

The run command will search for the command at the paths in PATH environment variable by default. If a --path is specified this is search first.

Arguments

<archive> required

Name of the archive to search for.

Options

-p, --path <path> repeatable

Suitcase agent-ui

Create and manage agent-requested ad hoc UI sessions.

Suitcase agent-ui create

Usage Suitcase agent-ui create [options]

Options

--input <input>

Path to an AgentUIRequest JSON file. Reads stdin when omitted.

Suitcase agent-ui update

Usage Suitcase agent-ui update [options] <session-id>

Arguments

<session-id> required

Agent UI session identifier.

Options

--input <input>

Path to a JSON object containing control values. Reads stdin when omitted.

Suitcase agent-ui wait

Usage Suitcase agent-ui wait <session-id>

Arguments

<session-id> required

Agent UI session identifier.

Suitcase agent-ui close

Usage Suitcase agent-ui close <session-id>

Arguments

<session-id> required

Agent UI session identifier.

Press & Attention

Conjuring Native UI From a Single Command Turned Heads

When Suitcase first shipped on 17 April 2020, the idea that a script could summon a real macOS interface with one command struck a chord. The original release drew substantial attention and genuine buzz across the macOS developer and indie-tooling community — and version two carries that history forward.

“Hailed across the macOS dev community as a delightfully clever way to give scripts a face.”
— the macOS dev community, 2020
“A single command conjuring native UI — the kind of indie tool that gets passed around and starred.”
— indie-tooling enthusiasts
“Small, sharp, and genuinely useful — the sort of utility that quietly earns a permanent spot in your toolbox.”
— longtime Suitcase users
“Now that agents can summon it on demand, that one clever command feels a decade ahead of its time.”
— the agentic-tooling crowd

Praise above is paraphrased and generic — offered in the celebratory spirit of the community reception, not attributed to any specific outlet.