Repository navigation
feat: optional Claude Code self-hosted runner in the freeform template - #224
Merged
Merged
Conversation
…g the workspace Add modules/claude-self-hosted-runner, vendored into all three templates. A switch (default off) starts `claude self-hosted-runner` in a restart loop in tmux session `claude-runner` on every workspace start, once the user has saved ~/.claude-runner/environment-secret; the secret never goes through Terraform. A second parameter sets the number of concurrent sessions (1-4). The runner rewrites ~/.gitconfig and ~/.config/git before every session, so the session git identity and ignore list go in /etc/gitconfig, reinstalled on each start, and the runner refuses to start alongside remote control. It also installs: - ~/.claude/skills/coder-shared-workspace, copied into every session, with rules for sessions sharing one Docker daemon and DDEV install: worktrees instead of shared checkouts, no workspace-wide Docker/DDEV commands, and a flock around test suites that power off DDEV. - claude-sessions, listing live sessions with checkout, branch and unpushed commits, and --push-outcome-on-release, so commits from repositories that forbid agents to push still reach the session's claude/ branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
The coder-shared-workspace skill now tells sessions to set DDEV_XDG_CONFIG_HOME to a per-session directory seeded from ~/.ddev, so project lists and global settings stay separate. Container names and the shared router stay global, so unique project names and the test lock remain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
The Drupal templates set up one project for a person to work on; a runner workspace is a general-purpose host, which is what freeform is for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
|
The "already running" check used pgrep -f 'claude self-hosted-runner', which matched the startup script's own bash process, so on staging the runner never started. Anchor the pattern on the program name. The docs now use chmod 600 for the secret: the home directory's default ACL leaves a file created under umask 077 group-readable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
With a revoked or wrong secret the runner exits within a second, and the loop retried every 5s indefinitely. Wait 60s after a run shorter than a minute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
On staging, a runner with --use-anthropic-git-proxy and --capacity 2 exits at once: "--use-anthropic-git-proxy requires --capacity 1 (the proxy URL is per-session and linked worktrees share origin)". Start one runner per concurrent session instead, each with --capacity 1, its own base directory ~/workspace/runner-<n>, and its own GIT_CONFIG_GLOBAL, so one runner's git config rewrite cannot break another's clone. Tested by hand on staging with two runners and two sessions running at once. Drop --push-outcome-on-release: under Anthropic-managed git it pushes to the plain GitHub URL with the workspace's own git credentials, which a runner workspace does not have, so the push would fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional Claude Code self-hosted runner to the
freeformtemplate, so sessions started on claude.ai/code run in a Coder workspace with its Docker and DDEV. Today this takes a hand-written~/.coder-startup.sh. In one case its/tmpmarker survived a workspace stop/start and silently kept the runner from starting.Changes
modules/claude-self-hosted-runner, vendored intofreeformonly (make sync-claude-runner-module, part ofsync-shared).~/.claude-runner/environment-secret, so it never goes through Terraform. If the file is missing, the startup log and~/WELCOME.txtsay what to do.claude-runner, with--use-anthropic-git-proxyand--capacity 1. The runner refuses a larger capacity with Anthropic-managed git, so each runner gets its own base directory~/workspace/runner-<n>, its ownGIT_CONFIG_GLOBALand its own log/tmp/claude-runner-<n>.log.~/.gitconfigand~/.config/gitbefore every session, so the session git identity and ignore list go in/etc/gitconfig, reinstalled on every start. For the same reason, the runner refuses to start when Claude Code remote control is also on.~/.claude/skills/coder-shared-workspace, which the runner copies into every session. The skill covers:DDEV_XDG_CONFIG_HOMEflockaround test suites that runddev poweroffclaude-sessions, which lists live sessions with their checkout, branch and unpushed commits.docs/user/using-workspaces.md, and an OpenSpec change inopenspec/changes/add-claude-self-hosted-runner.Related: ddev/ddev#9022 proposes letting remote sessions push their own
claude/*branch.Testing
terraform fmt -check -recursive,make validateandmake test-templatespass. Newfreeformtests cover: off by default, capacity passed as--capacity, and refusal alongside remote control.bash -n. I ran the enabled snippet with a fake home and asudoshim, and it installed the skill, the loop script,claude-sessionsand the git config.freeformworkspace with the runner on and capacity 2. Then I checked three cases:WELCOME.txtsay how to add the secret.claude-runner, with capacity 2. The skill,claude-sessionsand/etc/gitconfigare installed.ddev/ddevand one onddev/coder-ddev. Each session has the skill, takes its git identity from/etc/gitconfig, and shows up inclaude-sessions.umask 077stayed group-readable because of the home directory's default ACL, so the docs now usechmod 600.--use-anthropic-git-proxy, hence one runner per session.--push-outcome-on-releasewould push with the workspace's own git credentials, which a runner workspace doesn't have, so I removed it.claude-sessionsand the skill.https://claude.ai/code/session_01UrTUMvjLtFGNseL9fh5s4o
Generated by Claude Code