Files
Profiles-for-Coder/README.md
T
octoturge a9583535f0 Add Gitea Actions workflow to auto-provision Coder templates
.gitea/workflows/coder-templates.yml pushes every templates/<env>/ dir
to Coder as profiles-<env> on every push to main that touches
templates/**, scripts/**, or profile-templates/** - coder templates push
creates the template on first run and updates it thereafter, so adding a
new templates/<env>/ directory is enough to provision it, no workflow
edits needed.

It also diffs templates/ against the previous commit and runs
`coder templates delete profiles-<env>` for any directory that was
removed. Deletion fails (loudly, as a job warning, not a hard failure)
rather than succeeding if the template still has active workspaces,
since coder templates delete already refuses that server-side.

Runs on the ubuntu-latest self-hosted Gitea runner already registered on
this instance (confirmed via gitea-runner-1's /data/.runner labels) and
installs the coder CLI itself. Needs CODER_URL and CODER_SESSION_TOKEN
as repo/org Actions secrets - documented in README, left for the user to
set up since token creation needs their own Coder login.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 11:49:56 +02:00

7.0 KiB

Profiles-for-Coder

Coder templates for per-discipline dev environments (Default, 3D Printing, COBOL, Python, TTRPG, Web). Each environment is its own Coder template - not a dropdown inside one shared container, which is what this repo used to do and which didn't actually work.

Layout

templates/
  default/main.tf        # Standard Default Dev
  3d-printing/main.tf     # 3D Printing & Engineering
  cobol/main.tf           # COBOL Modern Mainframe
  python/main.tf          # Python Engineering
  ttrpg/main.tf            # TTRPG & Lore Building
  web/main.tf              # Web Applications
scripts/
  cli-setup-wizard.sh      # shared first-run wizard, see below
  install-skills.sh         # shared Agent Skills installer, see below
profile-templates/         # VS Code .code-profile exports, one per env
extensions/                 # Agent Skills bundles, installed per env (see below)

Each templates/<env>/main.tf is a complete, independent Coder template (agent, docker container, code-server, JetBrains). They're deliberately not built from a shared Terraform module - only their locals block differs (which profile file to read). The naming convention is profiles-<dir> (matches what .gitea/workflows/coder-templates.yml does automatically - see below). To push by hand:

coder templates push profiles-default      -d templates/default
coder templates push profiles-3d-printing  -d templates/3d-printing
coder templates push profiles-cobol        -d templates/cobol
coder templates push profiles-python       -d templates/python
coder templates push profiles-ttrpg        -d templates/ttrpg
coder templates push profiles-web          -d templates/web

How the VS Code profile gets applied

profile-templates/*.code-profile is a real VS Code Profile export: a JSON file whose settings and extensions fields are themselves JSON-encoded strings (double/triple-nested). Each template's main.tf reads and decodes its matching file at terraform apply/push time (via file() + jsondecode()), then:

  • passes the extension ID list straight into the code-server module's extensions input, so code-server installs them on first boot - no interactive prompt needed, Terraform handles it declaratively;
  • writes the raw settings.json text (comments and all - VS Code tolerates JSONC) to ~/.local/share/code-server/User/settings.json via a coder_script.

This replaces the old approach, which downloaded a zip of this repo from Gitea inside the running container and tried to apply settings from ~/.local/share/profiles-cache/<profile>.json - a path that never matched the actual .code-profile file extension, so settings never applied. That bug (plus the single shared container) is why "one container, many envs" never really worked.

Bun

Every template installs Bun via a coder_script (curl -fsSL https://bun.sh/install | bash) and hooks ~/.bun/bin onto PATH in ~/.bashrc (the installer doesn't reliably do this itself in a non-interactive/scripted shell). The CLI setup wizard below uses bun install -g <pkg> instead of npm install -g <pkg> for everything it installs.

CLI setup wizard

scripts/cli-setup-wizard.sh is dropped onto every workspace and hooked into ~/.bashrc. It runs in every new interactive terminal - until the user finishes it - and offers to install + log into:

  • GitHub Copilot CLI (bun install -g @github/copilot, then copilot login)
  • Google Antigravity CLI (curl -fsSL https://antigravity.google/cli/install.sh | bash, binary agy)
  • Claude Code CLI (bun install -g @anthropic-ai/claude-code, then claude)

It does not ask about VS Code extensions, since those are handled by Terraform (see above). Once the user confirms completion it writes a sentinel file (~/.cache/coder-cli-wizard/done) and stops prompting. It can always be re-run manually: bash /opt/coder/cli-setup-wizard.sh --force.

extensions/ directory -> Agent Skills

extensions/awesome-skills-plugin and extensions/custom-specialty-plugin are Agent Skills bundles (plugin.json + SKILL.md files) - the old root main.tf copied this folder straight into code-server's VS Code extensions directory, which never worked since these aren't VS Code extension packages.

Each template now runs scripts/install-skills.sh (via a coder_script, pulling a fresh zip of this repo from Gitea rather than embedding ~2.5MB into Terraform state) to install skills into all three AI CLIs' personal skills directories:

CLI Skills directory
Claude Code ~/.claude/skills/<name>/
GitHub Copilot CLI ~/.copilot/skills/<name>/
Antigravity CLI ~/.gemini/config/skills/<name>/ (per antigravity.google/docs/skills - some third-party docs disagree on this path, worth a spot-check on a live workspace)

Every environment gets the full extensions/awesome-skills-plugin/skills/* bundle. On top of that, whichever env has a matching entry in extensions/custom-specialty-plugin/skills/ gets it installed too, set via the SPECIALTY_SKILLS env var passed to the script from each template's install_skills coder_script:

  • COBOL -> cobol-teacher
  • 3D Printing -> openscad-parametric
  • TTRPG -> foundryvtt-modding and ttrpg-lore-weaver
  • Default / Python / Web -> none (no matching specialty skill exists yet)

Auto-provisioning (Gitea Actions)

.gitea/workflows/coder-templates.yml keeps Coder in sync with this repo on every push to main that touches templates/**, scripts/**, or profile-templates/**:

  • Add a new templates/<env>/ directory -> next push creates a new Coder template profiles-<env> automatically. No workflow edits needed.
  • Edit an existing templates/<env>/main.tf (or a shared script/profile it references) -> next push updates that template with a new version.
  • Remove a templates/<env>/ directory -> next push deletes profiles-<env> from Coder. coder templates delete refuses if the template still has active workspaces, so this fails loudly instead of silently orphaning anyone's running workspace - that failure only shows up as a ::warning:: in the job log, it doesn't fail the whole run.

It runs on the ubuntu-latest self-hosted runner already registered on this Gitea instance and installs the coder CLI itself via coder.com/install.sh.

One-time setup required (not something this workflow can do for itself - needs a human with Coder access):

  1. Create a Coder API token - ideally under a dedicated service account rather than a personal login, since this token can create/delete templates:
    coder login https://code.octoturge.com
    coder tokens create --name gitea-ci --lifetime 8760h
    
  2. In Gitea, go to this repo's Settings -> Actions -> Secrets (or the org-level equivalent to share across repos) and add:
    • CODER_URL = https://code.octoturge.com
    • CODER_SESSION_TOKEN = the token printed by step 1

Until those secrets exist, the workflow will run and fail cleanly at the coder templates push step rather than doing anything destructive.