relates to #21335 Enables the agent socket by default and updates docs to strike references to having to enable it. The PRs in this stack change the MCP server that Tasks use to update their status to rely on the agent socket, rather than directly dialing Coderd with the agent token. Default disable was a reasonable default when it was only used for the experimental script ordering features, but now that we want to use it for Tasks, it should be default on.
7.2 KiB
Workspace Startup Coordination Examples
Script Example
This example shows a complete, production-ready script that starts Claude Code only after a repository has been cloned. It includes error handling, graceful degradation, and cleanup on exit:
#!/bin/bash
set -euo pipefail
UNIT_NAME="claude-code"
DEPENDENCIES="git-clone"
REPO_DIR="/workspace/repo"
# Track if sync started successfully
SYNC_STARTED=0
# Declare dependencies
if [ -n "$DEPENDENCIES" ]; then
if command -v coder > /dev/null 2>&1; then
IFS=',' read -ra DEPS <<< "$DEPENDENCIES"
for dep in "${DEPS[@]}"; do
dep=$(echo "$dep" | xargs)
if [ -n "$dep" ]; then
echo "Waiting for dependency: $dep"
coder exp sync want "$UNIT_NAME" "$dep" > /dev/null 2>&1 || \
echo "Warning: Failed to register dependency $dep, continuing..."
fi
done
else
echo "Coder CLI not found, running without sync coordination"
fi
fi
# Start sync and track success
if [ -n "$UNIT_NAME" ]; then
if command -v coder > /dev/null 2>&1; then
if coder exp sync start "$UNIT_NAME" > /dev/null 2>&1; then
SYNC_STARTED=1
echo "Started sync: $UNIT_NAME"
else
echo "Sync start failed or not available, continuing without sync..."
fi
fi
fi
# Ensure completion on exit (even if script fails)
cleanup_sync() {
if [ "$SYNC_STARTED" -eq 1 ] && [ -n "$UNIT_NAME" ]; then
echo "Completing sync: $UNIT_NAME"
coder exp sync complete "$UNIT_NAME" > /dev/null 2>&1 || \
echo "Warning: Sync complete failed, but continuing..."
fi
}
trap cleanup_sync EXIT
# Now do the actual work
echo "Repository cloned, starting Claude Code"
cd "$REPO_DIR"
claude
This script demonstrates several best practices:
- Checking for Coder CLI availability before using sync commands
- Tracking whether
coder exp syncstarted successfully - Using
trapto ensure completion even if the script exits early - Graceful degradation when
coder exp syncisn't available - Redirecting
coder exp syncoutput to reduce noise in logs
Template Migration Example
Below is a simple example Docker template that clones Miguel Grinberg's example Flask repo using the git-clone module and installs the required dependencies for the project:
- Python development headers (required for building some Python packages)
- Python dependencies from the project's
requirements.txt
We've omitted some details (such as persistent storage) for brevity, but these are easily added.
Before
data "coder_provisioner" "me" {}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
resource "docker_container" "workspace" {
count = data.coder_workspace.me.start_count
image = "codercom/enterprise-base:ubuntu"
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
entrypoint = ["sh", "-c", coder_agent.main.init_script]
env = [
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
]
}
resource "coder_agent" "main" {
arch = data.coder_provisioner.me.arch
os = "linux"
}
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.3"
agent_id = coder_agent.main.id
url = "https://github.com/miguelgrinberg/microblog"
}
resource "coder_script" "setup" {
count = data.coder_workspace.me.start_count
agent_id = coder_agent.main.id
display_name = "Installing Dependencies"
run_on_start = true
script = <<EOT
sudo apt-get update
sudo apt-get install --yes python-dev-is-python3
cd ${module.git-clone[count.index].repo_dir}
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
EOT
}
We can note the following issues in the above template:
- There is a race between cloning the repository and the
pip installcommands, which can lead to failed workspace startups in some cases. - The
aptcommands can run independently of thegit clonecommand, meaning that there is a potential speedup here.
Based on the above, we can improve both the startup time and reliability of the template by splitting the monolithic startup script into multiple independent scripts:
- Install
aptdependencies - Install
pipdependencies (depends on thegit-clonemodule and the above step)
After
Here is the updated version of the template:
data "coder_provisioner" "me" {}
data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
resource "docker_container" "workspace" {
count = data.coder_workspace.me.start_count
image = "codercom/enterprise-base:ubuntu"
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
entrypoint = ["sh", "-c", coder_agent.main.init_script]
env = [
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
]
}
resource "coder_agent" "main" {
arch = data.coder_provisioner.me.arch
os = "linux"
}
module "git-clone" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/git-clone/coder"
version = "1.2.3"
agent_id = coder_agent.main.id
url = "https://github.com/miguelgrinberg/microblog/"
post_clone_script = <<-EOT
coder exp sync start git-clone && coder exp sync complete git-clone
EOT
}
resource "coder_script" "apt-install" {
count = data.coder_workspace.me.start_count
agent_id = coder_agent.main.id
display_name = "Installing APT Dependencies"
run_on_start = true
script = <<EOT
trap 'coder exp sync complete apt-install' EXIT
coder exp sync start apt-install
sudo apt-get update
sudo apt-get install --yes python-dev-is-python3
EOT
}
resource "coder_script" "pip-install" {
count = data.coder_workspace.me.start_count
agent_id = coder_agent.main.id
display_name = "Installing Python Dependencies"
run_on_start = true
script = <<EOT
trap 'coder exp sync complete pip-install' EXIT
coder exp sync want pip-install git-clone apt-install
coder exp sync start pip-install
cd ${module.git-clone[count.index].repo_dir}
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
EOT
}
A short summary of the changes:
- We've broken the monolithic "setup" script into two separate scripts: one for the
aptcommands, and one for thepipcommands.- In each script, we've added a
coder exp sync start $SCRIPT_NAMEcommand to mark the startup script as started. - We've also added an exit trap to ensure that we mark the startup scripts as completed. Without this, the
coder exp sync waitcommand would eventually time out.
- In each script, we've added a
- We have used the
post_clone_scriptfeature of thegit-clonemodule to allow waiting on the Git repository clone. - In the
pip-installscript, we have declared a dependency on bothgit-cloneandapt-install.
With these changes, the startup time has been reduced significantly and there is no longer any possibility of a race condition.