Remote Tasks
Provision and tear down per-task remote workspaces with your own infrastructure scripts
Remote Tasks let each agent run in its own isolated remote workspace. Your provision script creates the workspace, Emdash connects to it over SSH, and the task's terminals, agent processes, Git operations, and file browsing run inside that workspace.
When the workspace is terminated, Emdash runs your terminate command so your infrastructure can clean up the remote workspace.
This can work with cloud VMs, Kubernetes pods, Docker containers, internal dev environment platforms, or any backend that can expose an SSH-accessible workspace.


How It Works
- Configure a workspace provider for the project.
- Create a task with remote infrastructure enabled.
- Emdash runs your provision command from the project directory.
- Your command prints a JSON object to stdout with SSH connection details.
- Emdash connects to the workspace over SSH.
- Emdash starts task terminals and coding agents inside
worktreePath. - When the workspace is terminated, Emdash runs your terminate command.
After Emdash connects, remote task workspaces use the same remote workspace capabilities as remote projects.
Setup
1. Create Scripts
Create provision and terminate scripts in your project, for example:
scripts/provision-workspace.sh
scripts/terminate-workspace.shMake them executable:
chmod +x scripts/provision-workspace.sh scripts/terminate-workspace.shProvision Script
The provision script creates the workspace and prints SSH connection details as JSON to stdout.
Only the JSON object should be printed to stdout. Send logs to stderr.
#!/bin/bash
set -euo pipefail
echo "Provisioning workspace..." >&2
WORKSPACE_ID="ws-$(date +%s)"
HOST="localhost"
PORT="2222"
USERNAME="devuser"
PASSWORD="devpass"
WORKTREE_PATH="/home/devuser/workspace"
FORWARD_AGENT=false
# Create your VM, pod, container, or internal workspace here.
# Ensure SSH is reachable and the repository exists at WORKTREE_PATH.
cat <<EOF
{
"id": "$WORKSPACE_ID",
"host": "$HOST",
"port": $PORT,
"username": "$USERNAME",
"password": "$PASSWORD",
"worktreePath": "$WORKTREE_PATH",
"forwardAgent": $FORWARD_AGENT
}
EOFProvision output fields:
| Field | Required | Description |
|---|---|---|
id | Yes | External workspace identifier. Passed to terminate as REMOTE_WORKSPACE_ID. |
host | Yes | Hostname or IP address Emdash should connect to. |
port | No | SSH port. Defaults to 22. |
username | No | SSH username. Defaults to the current Emdash process user. |
password | No | SSH password. If omitted, Emdash attempts SSH agent auth using SSH_AUTH_SOCK. |
worktreePath | No | Repository path on the provisioned workspace. Defaults to the project path. |
forwardAgent | No | JSON boolean. Set to true to forward the local SSH agent into the workspace. Defaults to false. |
Terminate Script
The terminate command runs when Emdash terminates the workspace. Emdash sets REMOTE_WORKSPACE_ID to the id returned by the provision command.
#!/bin/bash
set -euo pipefail
echo "Terminating workspace $REMOTE_WORKSPACE_ID..." >&2
# Destroy your VM, pod, container, or internal workspace here.
# your-cli delete-workspace "$REMOTE_WORKSPACE_ID"
echo "Done." >&2Configure the workspace provider
- Open the project.
- Open Project Settings.
- Find Workspace provider.
- Enter the provision and terminate commands.
- Save.
Create A Remote Task
When the workspace provider feature is enabled in your Emdash build:
- Click New Task.
- Enable remote infrastructure.
- Create the task.
Emdash will run the provision command, parse the JSON output, connect to the remote workspace over SSH, and start the task inside the returned worktreePath.
Workspace Requirements
Provisioned workspaces should include:
- An SSH server reachable from the project host running the provision command.
- Git.
- Any CLI coding agents you want to use.
- Any credentials or environment variables needed by those agents.
Recommended:
tmux, if you want persistent sessions.gh, if you want GitHub workflows from inside the workspace.- Repository credentials for pushing and pulling.
SSH Authentication
Remote task SSH connections are ephemeral and are created from the JSON returned by your provision command.
If password is returned, Emdash uses password authentication.
If password is omitted, Emdash attempts SSH agent authentication using SSH_AUTH_SOCK.
SSH agent authentication and SSH agent forwarding are separate. Agent authentication lets Emdash use your local SSH agent to connect to the provisioned workspace. Agent forwarding exposes that local agent inside the provisioned workspace for nested SSH or Git commands.
To enable agent forwarding, return "forwardAgent": true from the provision command. Omitting forwardAgent or returning false keeps forwarding disabled. The value must be a JSON boolean, not the string "true" or "false".
When forwardAgent is true, Emdash requires a local SSH agent socket. If no socket is available, the SSH connection fails instead of silently starting without forwarding.
Only enable agent forwarding for provisioned workspaces you trust. It is useful when Git commit signing, private Git remotes, or nested SSH commands inside the workspace need access to your local SSH agent.
For the most predictable setup, return explicit host, port, username, and either password or ensure the SSH agent available to Emdash can authenticate to the workspace.
Script Contract Reference
Provision Command
| Aspect | Details |
|---|---|
| Execution | /bin/sh -c <provisionCommand> |
| Working directory | Project directory on the project host. For local projects, this is the local project root. For SSH projects, this is the remote project path. |
| Environment | Inherits the Emdash process environment for local projects, or the remote shell environment for SSH projects. Emdash does not currently inject remote task provision variables. |
| Stdout | A single JSON object with at least id and host |
| Stderr | Captured as process stderr |
| Success | Exit code 0 and valid JSON output |
| Failure | Non-zero exit code, empty stdout, invalid JSON, or failed SSH connection |
| Timeout | The task provisioning operation times out after 10 minutes |
Terminate Command
| Aspect | Details |
|---|---|
| Execution | /bin/sh -c <terminateCommand> |
| Working directory | Project directory on the project host |
| Environment | REMOTE_WORKSPACE_ID is set to the id returned by the provision command |
| Success | Exit code 0 |
| Failure | Logged during cleanup; Emdash continues task deletion cleanup |
| Timeout | The task teardown operation times out after 10 minutes |
Troubleshooting
Provision Fails
Run the provision command manually from the project directory:
./scripts/provision-workspace.shValidate stdout:
./scripts/provision-workspace.sh 2>/dev/null | jq .Check that:
- stdout contains only the JSON object.
idandhostare present.port, if present, is a number.- the command exits with code 0.
SSH Connection Fails
Use the values returned by the provision script and test SSH manually:
ssh -p <port> <username>@<host>Check that:
- the workspace is reachable from the machine running Emdash.
- the SSH server is running.
- password or SSH agent authentication works.
- if
forwardAgentistrue,SSH_AUTH_SOCKis available to Emdash andssh-add -llists the expected key. - the repository exists at
worktreePath.
Terminate Does Not Clean Up
Run the terminate command manually:
REMOTE_WORKSPACE_ID=<id-from-provision-output> ./scripts/terminate-workspace.shThe terminate script should tolerate repeated calls and missing infrastructure, since cleanup may be retried or run after partial failures.