Skip to content

Add an optional per-project startup command for new terminal sessions #70

Description

@banozz0

Problem

A project has no way to declare a command that runs when a terminal session is
created in it. A project can set the working directory, but not what the shell
should do once it lands there.

This matters for projects whose whole purpose is "be a shell somewhere else" —
an SSH target, a container, a remote host, a different macOS account. Today the
only way to express that is to open a session and type the command every time,
or click a Terminal quick action, which spawns a second session next to the
plain one rather than making the project itself the thing you wanted.

The available building blocks each miss:

  • Project path sets cwd, nothing more.
  • Terminal quick actions run in a new Action tab on demand; they cannot
    define what a normal new session does.
  • Custom agents can run an arbitrary command, but they are presented as
    agents, and ghostex save-agent reports itself as an unsupported
    renderer-era writer, so they are not scriptable.
  • Agent hooks are a different mechanism: they are installed into the agent
    CLI's own settings (Claude, Cursor, Copilot, Droid) and fire on that agent's
    SessionStart/state events so Ghostex can track completion. A plain terminal
    session has no agent, so nothing fires.

Reproduction scenario

  1. Create a project intended to be a shell into another macOS account on the
    same Mac (see Fix SSH connections to another user account on the same Mac #61 for the SSH side of this).
  2. Open a new terminal session in that project.
  3. The session is a local shell in the project directory.
  4. There is no project setting that would have made it run ssh <host> first.

Expected behavior

A project can define an optional startup command that runs in each newly
created terminal session for that project, after the user's shell startup files
have been sourced.

Acceptance criteria

  • A project can store an optional startup command, empty by default.
  • New terminal sessions in that project run the command after normal shell
    initialization, so PATH and profile exports are already in effect.
  • Existing projects with no startup command behave exactly as they do today.
  • The command is readable and writable through the CLI, so project setup can be
    scripted alongside add-project and save-command.
  • When the startup command exits, the session does not silently disappear — the
    user is left with a usable shell or a clear indication of what ended.
  • The setting is visible in project settings, not only in state files.

Investigation notes

Sessions are created with a project-derived cwd; the natural place for this is
the same project record that already carries path, customCommands, and
launchSettings, applied at session creation rather than by injecting keystrokes
into an already-running shell. Injecting text after the fact is racy against
shell startup and would appear in shell history.

An adjacent, cheaper variant if a full startup command is too broad: allow a
project to nominate one of its existing Terminal quick actions as the default
for new sessions.

Workaround in use today

Gating on $PWD inside the user's ~/.zshrc, so any interactive shell opened in
that project's directory becomes the intended shell:

if [[ -o interactive && "$PWD" == "$HOME/ghostex/hermes" ]]; then
  ssh hermes
  cd "$HOME"
fi

This works, but it lives outside Ghostex, is shell-specific, and does not travel
with the project.

Source

User feedback while setting up a project that exists purely to be a shell into a
second macOS account on the same machine. Related: #61.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions