Skip to content

Commit 6c1ab75

Browse files
committed
agentapi and ai task support
1 parent da67cd3 commit 6c1ab75

File tree

1 file changed

+136
-18
lines changed
  • registry/coder/modules/claude-code

1 file changed

+136
-18
lines changed

registry/coder/modules/claude-code/main.tf

Lines changed: 136 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,57 @@ variable "experiment_tmux_session_save_interval" {
9696
default = "15"
9797
}
9898

99+
variable "install_agentapi" {
100+
type = bool
101+
description = "Whether to install AgentAPI."
102+
default = true
103+
}
104+
105+
variable "agentapi_version" {
106+
type = string
107+
description = "The version of AgentAPI to install."
108+
default = "v0.2.2"
109+
}
110+
99111
locals {
100-
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
101-
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
112+
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
113+
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
114+
agentapi_start_command = <<-EOT
115+
#!/bin/bash
116+
set -e
117+
118+
# if the first argument is not empty, start claude with the prompt
119+
if [ -n "$1" ]; then
120+
prompt="$(cat ~/.claude-code-prompt)"
121+
else
122+
prompt=""
123+
fi
124+
125+
# use low width to fit in the tasks UI sidebar. height is adjusted to ~match the default 80k (80x1000) characters
126+
# visible in the terminal screen.
127+
agentapi server --term-width 67 --term-height 1190 -- bash -c "claude --continue --dangerously-skip-permissions \"$prompt\""
128+
EOT
129+
agentapi_wait_for_start_command = <<-EOT
130+
#!/bin/bash
131+
set -o errexit
132+
set -o pipefail
133+
134+
echo "Waiting for agentapi server to start on port 3284..."
135+
for i in $(seq 1 15); do
136+
if lsof -i :3284 | grep -q 'LISTEN'; then
137+
echo "agentapi server started on port 3284."
138+
break
139+
fi
140+
echo "Waiting... ($i/15)"
141+
sleep 1
142+
done
143+
if ! lsof -i :3284 | grep -q 'LISTEN'; then
144+
echo "Error: agentapi server did not start on port 3284 after 15 seconds."
145+
exit 1
146+
fi
147+
EOT
148+
agentapi_start_command_base64 = base64encode(local.agentapi_start_command)
149+
agentapi_wait_for_start_command_base64 = base64encode(local.agentapi_wait_for_start_command)
102150
}
103151

104152
# Install and Initialize Claude Code
@@ -176,9 +224,38 @@ resource "coder_script" "claude_code" {
176224
npm install -g @anthropic-ai/claude-code@${var.claude_code_version}
177225
fi
178226
227+
# Install AgentAPI if enabled
228+
if [ "${var.install_agentapi}" = "true" ]; then
229+
echo "Installing AgentAPI..."
230+
arch=$(uname -m)
231+
if [ "$arch" = "x86_64" ]; then
232+
binary_name="agentapi-linux-amd64"
233+
elif [ "$arch" = "aarch64" ]; then
234+
binary_name="agentapi-linux-arm64"
235+
else
236+
echo "Error: Unsupported architecture: $arch"
237+
exit 1
238+
fi
239+
wget "https://github.com/coder/agentapi/releases/download/${var.agentapi_version}/$binary_name"
240+
chmod +x "$binary_name"
241+
sudo mv "$binary_name" /usr/local/bin/agentapi
242+
fi
243+
if ! command_exists agentapi; then
244+
echo "Error: AgentAPI is not installed. Please enable install_agentapi or install it manually."
245+
exit 1
246+
fi
247+
248+
# save the prompt for the agentapi start command
249+
echo -n "$CODER_MCP_CLAUDE_TASK_PROMPT" > ~/.claude-code-prompt
250+
251+
echo -n "${local.agentapi_start_command_base64}" | base64 -d > ~/.agentapi-start-command
252+
chmod +x ~/.agentapi-start-command
253+
echo -n "${local.agentapi_wait_for_start_command_base64}" | base64 -d > ~/.agentapi-wait-for-start-command
254+
chmod +x ~/.agentapi-wait-for-start-command
255+
179256
if [ "${var.experiment_report_tasks}" = "true" ]; then
180257
echo "Configuring Claude Code to report tasks via Coder MCP..."
181-
coder exp mcp configure claude-code ${var.folder}
258+
coder exp mcp configure claude-code ${var.folder} --ai-agentapi-url http://localhost:3284
182259
fi
183260
184261
if [ -n "${local.encoded_post_install_script}" ]; then
@@ -257,17 +334,16 @@ EOF
257334
export LANG=en_US.UTF-8
258335
export LC_ALL=en_US.UTF-8
259336
337+
tmux new-session -d -s claude-code-agentapi -c ${var.folder} '~/.agentapi-start-command true; exec bash'
338+
~/.agentapi-wait-for-start-command
339+
260340
if [ "${var.experiment_tmux_session_persistence}" = "true" ]; then
261341
sleep 3
342+
fi
262343
263-
if ! tmux has-session -t claude-code 2>/dev/null; then
264-
# Only create a new session if one doesn't exist
265-
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
266-
fi
267-
else
268-
if ! tmux has-session -t claude-code 2>/dev/null; then
269-
tmux new-session -d -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions \"$CODER_MCP_CLAUDE_TASK_PROMPT\""
270-
fi
344+
if ! tmux has-session -t claude-code 2>/dev/null; then
345+
# Only create a new session if one doesn't exist
346+
tmux new-session -d -s claude-code -c ${var.folder} "agentapi attach; exec bash"
271347
fi
272348
fi
273349
@@ -297,9 +373,17 @@ EOF
297373
export LANG=en_US.UTF-8
298374
export LC_ALL=en_US.UTF-8
299375
376+
screen -U -dmS claude-code-agentapi bash -c '
377+
cd ${var.folder}
378+
# setting the first argument will make claude use the prompt
379+
~/.agentapi-start-command true
380+
exec bash
381+
'
382+
~/.agentapi-wait-for-start-command
383+
300384
screen -U -dmS claude-code bash -c '
301385
cd ${var.folder}
302-
claude --dangerously-skip-permissions "$CODER_MCP_CLAUDE_TASK_PROMPT" | tee -a "$HOME/.claude-code.log"
386+
agentapi attach
303387
exec bash
304388
'
305389
else
@@ -312,6 +396,20 @@ EOF
312396
run_on_start = true
313397
}
314398

399+
resource "coder_app" "claude_code_web" {
400+
slug = "ccw"
401+
display_name = "Claude Code Web"
402+
agent_id = var.agent_id
403+
url = "http://localhost:3284/"
404+
icon = var.icon
405+
subdomain = true
406+
healthcheck {
407+
url = "http://localhost:3284/status"
408+
interval = 5
409+
threshold = 3
410+
}
411+
}
412+
315413
resource "coder_app" "claude_code" {
316414
slug = "claude-code"
317415
display_name = "Claude Code"
@@ -324,31 +422,51 @@ resource "coder_app" "claude_code" {
324422
export LC_ALL=en_US.UTF-8
325423
326424
if [ "${var.experiment_use_tmux}" = "true" ]; then
425+
if ! tmux has-session -t claude-code-agentapi 2>/dev/null; then
426+
# start agentapi without claude using the prompt (no argument)
427+
tmux new-session -d -s claude-code-agentapi -c ${var.folder} '~/.agentapi-start-command; exec bash'
428+
~/.agentapi-wait-for-start-command
429+
fi
430+
327431
if tmux has-session -t claude-code 2>/dev/null; then
328432
echo "Attaching to existing Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
329-
# If Claude isn't running in the session, start it without the prompt
330-
if ! tmux list-panes -t claude-code -F '#{pane_current_command}' | grep -q "claude"; then
331-
tmux send-keys -t claude-code "cd ${var.folder} && claude -c --dangerously-skip-permissions" C-m
433+
# If agentapi attach isn't running in the session, start it
434+
if ! tmux list-panes -t claude-code -F '#{pane_current_command}' | grep -q "agentapi"; then
435+
tmux send-keys -t claude-code "cd ${var.folder} && agentapi attach" C-m
332436
fi
333437
tmux attach-session -t claude-code
334438
else
335439
echo "Starting a new Claude Code tmux session." | tee -a "$HOME/.claude-code.log"
336-
tmux new-session -s claude-code -c ${var.folder} "claude --dangerously-skip-permissions | tee -a \"$HOME/.claude-code.log\"; exec bash"
440+
tmux new-session -s claude-code -c ${var.folder} "agentapi attach; exec bash"
337441
fi
338442
elif [ "${var.experiment_use_screen}" = "true" ]; then
443+
if ! screen -list | grep -q "claude-code-agentapi"; then
444+
screen -S claude-code-agentapi bash -c '
445+
cd ${var.folder}
446+
# start agentapi without claude using the prompt (no argument)
447+
~/.agentapi-start-command
448+
exec bash
449+
'
450+
fi
339451
if screen -list | grep -q "claude-code"; then
340452
echo "Attaching to existing Claude Code screen session." | tee -a "$HOME/.claude-code.log"
341453
screen -xRR claude-code
342454
else
343455
echo "Starting a new Claude Code screen session." | tee -a "$HOME/.claude-code.log"
344-
screen -S claude-code bash -c 'claude --dangerously-skip-permissions | tee -a "$HOME/.claude-code.log"; exec bash'
456+
screen -S claude-code bash -c 'agentapi attach; exec bash'
345457
fi
346458
else
347459
cd ${var.folder}
348-
claude
460+
agentapi attach
349461
fi
350462
EOT
351463
icon = var.icon
352464
order = var.order
353465
group = var.group
354466
}
467+
468+
resource "coder_ai_task" "claude_code" {
469+
sidebar_app {
470+
id = coder_app.claude_code.id
471+
}
472+
}

0 commit comments

Comments
 (0)