Skip to content

Conversation

@rothnic
Copy link
Owner

@rothnic rothnic commented Nov 20, 2025

This pull request introduces a new module for integrating the OpenCode AI-powered coding agent into the Coder platform, with robust configuration, authentication, and testing support. The main changes include the addition of module documentation, Terraform configuration, installation and setup scripts, and comprehensive tests to ensure expected behavior. Additionally, a profile for the module maintainer is added.

OpenCode module introduction and configuration:

  • Added a new opencode module under registry/rothnic/modules/opencode, including a detailed README.md with usage instructions, authentication options, configuration variables, and features.
  • Implemented the main Terraform configuration in main.tf, defining all variables, local values, integration with AgentAPI, and resources for environment variable management and app setup.

Installation and setup automation:

  • Added an installation script scripts/install.sh that ensures Node.js is present, installs OpenCode using either npm or curl, handles authentication (including GitHub Copilot), configures OpenCode, and sets up integration with Coder for task reporting.

Testing and validation:

  • Introduced a comprehensive test suite in opencode.tftest.hcl to validate default values, environment variable creation, configuration handling, versioning, and prompt logic for task reporting.

Documentation and registry updates:

  • Added a maintainer profile for "Nick Roth" in registry/rothnic/README.md, outlining expertise and notable projects.## Description

Type of Change

  • New module
  • New template
  • Bug fix
  • Feature/enhancement
  • Documentation
  • Other

Module Information

Path: registry/[namespace]/modules/[module-name]
New version: v1.0.0
Breaking change: [ ] Yes [ ] No

Template Information

Path: registry/[namespace]/templates/[template-name]

Testing & Validation

  • Tests pass (bun test)
  • Code formatted (bun fmt)
  • Changes tested locally

Related Issues

This commit creates:
- New rothnic namespace with contributor information
- OpenCode module for AI-powered terminal coding assistance
- Support for multiple AI providers (GitHub Copilot, Anthropic, OpenAI)
- GitHub Copilot authentication through Coder external auth
- AgentAPI integration for task reporting
- Comprehensive tests for module functionality

The OpenCode module is based on the copilot module pattern and provides:
- Automatic GitHub authentication via Coder external auth
- Multiple installation methods (npm, curl)
- Session resumption support
- Configurable AI providers
- Task reporting to Coder UI
Enhanced rothnic namespace README:
- Added comprehensive bio with professional background
- Included LinkedIn and website links
- Added expertise areas and notable projects
- Improved formatting with sections for better readability

Enhanced OpenCode module README:
- Added "What is OpenCode?" section with detailed explanation
- Included key features and benefits
- Expanded authentication documentation
- Added comprehensive troubleshooting section
- Included configuration variables table
- Added maintainer information and support links
- Improved examples with better explanations
- Added links to OpenCode documentation and resources
Adds task_app_id output to enable integration with Coder Tasks UI.
This allows users to run tasks through OpenCode using the coder_ai_task
resource in their templates.

Changes:
- Added task_app_id output that exposes the AgentAPI task app ID
- Enables chat sidebar integration for Coder Tasks feature
- Compatible with coder_task data source for prompt passing
The agentapi module doesn't expose task_app_id as an output.
Instead, construct it manually using the Coder app ID pattern:
{agent_id}_{app_slug}

This matches how Coder internally constructs app IDs and will work
correctly with the coder_ai_task resource.
The agentapi module (v1.2.0) creates the coder_ai_task resource
internally, so modules should not expose task_app_id outputs.
Following the pattern from copilot and goose modules, which have
no outputs and let agentapi handle all task integration.

This fixes the 'only one coder_ai_task resource can be provisioned'
error when templates try to create coder_ai_task resources.
OpenCode needs to be started with 'opencode acp' subcommand to enable
Agent Communication Protocol (ACP) mode for stdio communication with agentapi.

Changes:
- Use 'opencode acp' instead of plain 'opencode' command
- Remove '--type opencode' flag (not needed in ACP mode)
- Update terminal dimensions to 67x1190 (matching goose/claude-code)
- Add comment explaining ACP mode requirement

This fixes the 'agentapi server not responding' error by properly
enabling stdio/JSON-RPC communication between OpenCode and agentapi.
OpenCode is a TUI application that runs directly, not an ACP/stdio
agent. It doesn't have an 'acp' subcommand. This commit fixes the
start script to run 'opencode' directly with --type opencode flag,
following the same pattern as the copilot module.

Changes:
- Remove 'opencode acp' command (doesn't exist)
- Run 'opencode' directly like other TUI agents
- Add --type opencode flag for agentapi
- Update comments to reflect TUI nature
Reverting previous commit - OpenCode does have an 'acp' subcommand
for starting the ACP (Agent Client Protocol) server. The original
implementation was correct.
AgentAPI wraps the TUI application and handles the protocol layer
itself. The agent should run in normal TUI mode, not in ACP mode.
Following the copilot pattern: agentapi wraps the interactive agent.

Changes:
- Run 'opencode' instead of 'opencode acp'
- Add --type opencode flag for agent identification
- Let agentapi handle stdio/protocol communication
The install script now installs Node.js 20 automatically instead of
exiting with an error when Node.js is not found. This enables the
module to work in base Docker images without Node.js pre-installed.

Changes:
- Replace validate_prerequisites with install_nodejs function
- Auto-install Node.js via apt-get, yum, apk, or nvm
- Support multiple package managers and Linux distributions
- Attempt to upgrade if Node.js version < 18
- Only install for npm method (curl method includes Node.js)
Fixed npm permission error by configuring npm to install packages
to ~/.local instead of /usr/lib/node_modules which requires sudo.

Changes:
- Set npm prefix to $HOME/.local before installing
- Create ~/.local/bin directory
- Persist PATH to .bashrc for future sessions
- Add version output to installation success messages

This allows OpenCode to install in unprivileged containers without
requiring sudo access.
The default 'opencode' TUI mode exits with help text when run
through agentapi's pseudo-terminal. Use 'opencode acp' (Agent
Communication Protocol) mode instead, which is designed for
stdio communication with agent wrappers.

Changes:
- Run 'opencode acp' instead of 'opencode'
- Remove --type flag (not needed with acp mode)
- ACP mode handles protocol communication properly

This resolves the "non-zero exit code" error where OpenCode
was printing help and exiting immediately.
Updated to use the correct OpenCode command format as implemented
in agentapi. OpenCode requires --type=opencode flag and runs with
plain 'opencode' command, not acp/serve/run subcommands.

Changes:
- Use --type=opencode flag (required per PR coder#79)
- Run 'opencode' without subcommands
- Remove incorrect 'acp' subcommand usage
- Update comments to reference correct implementation

Reference: coder/agentapi#79
OpenCode's CLI changed since agentapi support was added. The default
'opencode' command now requires explicit subcommands. Use 'opencode acp'
(Agent Communication Protocol) which is designed for stdio-based agent
wrappers like agentapi.

Changes:
- Use 'opencode acp' subcommand for ACP protocol mode
- Keep --type=opencode flag for agentapi
- ACP mode handles interactive stdin/stdout communication
- Pass provider and other args to acp subcommand

The acp mode is specifically designed for agent protocol communication
via stdin/stdout, which is what agentapi provides.
…vider flag

The 'opencode acp' subcommand doesn't accept --provider argument.
Provider selection is configured via ~/.local/share/opencode/auth.json.

Changes to install.sh:
- Programmatically create auth.json with GitHub Copilot credentials
- Use GitHub token from Coder external auth
- Write proper JSON structure for OpenCode auth
- Create empty auth.json if no token available

Changes to start.sh:
- Remove --provider argument (not supported by acp)
- Simplify command to just 'opencode acp'
- Provider is auto-selected from auth.json

This enables automatic GitHub Copilot authentication without manual
'opencode auth login' interaction.
Agentapi sends plain text to stdin/stdout, NOT JSON-RPC protocol.
The 'opencode acp' mode expects JSON-RPC messages and fails when
receiving plain text from agentapi.

Use the default OpenCode TUI mode with working directory as the
project path argument, similar to how goose integration works.

Changes:
- Run 'opencode <workdir>' instead of 'opencode acp'
- OpenCode TUI reads plain text from stdin (matches agentapi)
- Remove ACP mode which expects JSON-RPC protocol
- Pass working directory as positional argument to avoid help screen

This matches the pattern used by goose and copilot modules.
Moving GitHub Copilot authentication setup from install.sh to start.sh
ensures the auth token is available when needed. The external auth token
may not be accessible during initial workspace build but is available
when the workspace starts.

Changes:
- Move auth.json configuration to setup_github_authentication() in start.sh
- Write credentials to auth.json every time workspace starts
- Ensures fresh token from Coder external auth on each start
- Fallback to empty credentials if no token available

This matches the pattern where authentication needs to happen at runtime,
not build time.
…tion

GitHub Copilot authentication in OpenCode requires a complex auth.json
format with refresh tokens and session metadata that can't be generated
from a simple OAuth token. The device flow ('opencode auth login') may
also fail in restricted network environments.

This adds support for providing a pre-configured auth.json obtained by
running 'opencode auth login' on a local machine with proper network access.

Changes:
- Add opencode_auth_config variable (sensitive) to main.tf
- Pass auth config to start script via ARG_OPENCODE_AUTH_CONFIG
- Check for pre-configured auth first in setup_github_authentication()
- Write provided auth.json directly to ~/.local/share/opencode/auth.json
- Add helpful error messages for obtaining auth.json locally

Usage:
1. Run 'opencode auth login' locally to authenticate
2. Copy ~/.local/share/opencode/auth.json content
3. Pass it to the module via opencode_auth_config variable
Simplified README to focus on essential information:
- Minimal quick start example
- Clear GitHub Copilot authentication options (all optional)
- Recommended approach: pre-configured auth.json via file()
- Note about TUI limitations through AgentAPI
- Concise configuration table

Authentication is completely optional - module works without it
and users can configure manually via 'opencode auth login'.
The wrapper scripts use 'set -o errexit' which causes them to exit
with code 1 if chmod fails. This marks the workspace as unhealthy
even though the actual service starts fine.

Changes:
- Add '|| true' to chmod commands to prevent script failure
- Use 'bash /tmp/script.sh' instead of '/tmp/script.sh' as fallback
- Fix source .bashrc to not fail on missing file

This ensures non-critical chmod failures don't prevent workspace startup.
@rothnic
Copy link
Owner Author

rothnic commented Nov 20, 2025

@copilot review code, run bun test, bun fmt

Copy link

Copilot AI commented Nov 20, 2025

@rothnic I've opened a new pull request, #2, to work on those changes. Once the pull request is ready, I'll request review from you.

APT operations can fail transiently due to:
- Lock contention from concurrent apt processes
- Network timeouts
- Repository unavailability

Changes:
- Add retry_apt() function with exponential backoff (5 attempts, 2s-32s delays)
- Wait for existing apt locks before proceeding (up to 30s)
- Retry NodeSource repo setup
- Retry apt-get install operations
- Retry yum and apk operations similarly

This prevents workspace build failures from transient apt issues,
especially common in task workspaces with concurrent installations.
Simplified the module to use the existing thezoker/nodejs module
rather than managing Node.js installation ourselves. This removes
all apt-get/yum/apk installation logic and retry mechanisms.

Changes:
- Replace install_nodejs() with validate_nodejs()
- Check for Node.js and provide helpful error if missing
- Update README to show using nodejs module as dependency
- Add depends_on in example
- Remove all apt-get retry logic (no longer needed)

This follows the pattern used by other modules like codex and
makes the module more maintainable.

Users should add:
  module "nodejs" {
    source   = "registry.coder.com/thezoker/nodejs/coder"
    agent_id = coder_agent.main.id
  }
- Install Node.js LTS via NVM instead of using thezoker/nodejs module
- Add pnpm for faster, more efficient package management
- Update install.sh to use pnpm instead of npm for OpenCode installation
- Update start.sh to load NVM and ensure pnpm is in PATH
- Update README to reflect automatic Node.js installation via NVM
- Remove nodejs module dependency from documentation

This change provides more reliable Node.js installation timing and
improves package installation performance with pnpm.
The start script was attempting to launch OpenCode before the install
script completed, causing timeouts. Now the start script waits up to
2 minutes for OpenCode to be installed, checking every 2 seconds and
reloading NVM/PATH on each check.

This gives the install script time to:
- Install NVM (~5-10s)
- Install Node.js LTS (~15-30s)
- Install pnpm (~5-10s)
- Install OpenCode via pnpm (~20-40s)

Total expected install time: ~45-90 seconds, well within timeout.
Changes:
- Renamed validate_opencode_installation to validate_environment
- Now checks for both Node.js AND OpenCode before proceeding
- Shows status of each component during wait loop
- Added detailed environment debug output before starting agentapi
- Shows which node, npm, pnpm, opencode paths and versions
- Tests opencode --version directly before handing to agentapi
- Better error messages showing final status if timeout occurs

This will help diagnose why agentapi server is timing out at port 3284.
The most likely issue is that Node.js isn't in PATH when opencode runs
under agentapi, even though it's installed.
The issue was that when agentapi spawns the opencode subprocess, it
doesn't inherit the NVM environment variables set in the start script.

Solution: Create a wrapper script (/tmp/opencode-wrapper-$$.sh) that:
- Loads NVM before running opencode
- Adds pnpm to PATH
- Uses exec to replace itself with opencode

The agentapi server now runs this wrapper instead of opencode directly,
ensuring Node.js and pnpm are available in the subprocess environment.

This is similar to how other modules handle environment setup for
subprocesses spawned by agentapi.
Changes to install.sh:
- Added final verification section that runs node --version,
  npm --version, pnpm --version, and opencode --version
- This ensures the script doesn't exit until installation is verified

Changes to start.sh:
- Removed wait loop - install script should complete first
- Simplified to match codex pattern: source NVM, verify, start
- Quick verification with opencode --version at startup
- Kept wrapper script for subprocess environment inheritance

The codex module pattern:
1. install.sh does ALL installation and verifies at the end
2. start.sh just sources environment and starts immediately

If start.sh can't find opencode, it means install.sh failed.
claude and others added 15 commits November 21, 2025 20:35
Changes:
- Removed pnpm installation - using npm like codex does
- Added setup_npm_global() to configure npm prefix to ~/.npm-global
- Persist PATH to ~/.bashrc for subprocess discovery
- Removed wrapper script from start.sh - run opencode directly
- Updated README to remove pnpm references

The codex module uses npm with a custom prefix, persists PATH to bashrc,
then agentapi can find the binary in subprocesses. Following this exact
pattern for reliability.
The key insight from the working commit (5d8541d):
- npm prefix is set to ~/.local, so opencode goes to ~/.local/bin
- start.sh just exports PATH="$HOME/.local/bin:$PATH" - no NVM loading!
- agentapi can find opencode because PATH is simple and inherited

What was wrong with previous NVM approach:
- NVM puts npm packages in ~/.nvm/versions/node/<ver>/bin/
- This requires sourcing NVM to find the binary
- agentapi subprocess doesn't source NVM, so it can't find opencode

The fix:
- install.sh: Use NVM to install Node.js (avoids apt-get issues)
- install.sh: Configure npm prefix to ~/.local (not NVM default)
- install.sh: Add ~/.local/bin to PATH and persist to bashrc
- start.sh: Just export PATH="$HOME/.local/bin:$PATH" (like working version)

Now opencode binary is in a simple, predictable location that works
in subprocess environments without NVM.
Key changes based on ChatGPT analysis of logs:

1. Background agentapi with & (like codex does)
   - Codex: agentapi server ... -- codex "${CODEX_ARGS[@]}" &
   - Now: agentapi server ... -- opencode "$ARG_WORKDIR" &
   - This allows the start script to complete, which the agentapi
     module's wrapper expects

2. Use /tmp/start.sh directly instead of bash /tmp/start.sh
   - Matches codex pattern exactly
   - Removed "|| true" from chmod to fail fast if there's an issue

3. Made NVM installation more robust
   - Verify nvm.sh exists before sourcing
   - Verify nvm command available after sourcing
   - Verify node command available after nvm install
   - Better error messages if any step fails

The ChatGPT analysis identified that the agentapi module's wrapper
scripts expect the start script to return quickly so it can run its
own wait-for-start loop AFTER the server begins starting.
Major simplification based on ChatGPT guidance:

1. Use official curl installer only
   - `curl -fsSL https://opencode.ai/install | bash`
   - OpenCode is now a Go CLI that handles its own runtime
   - No Node.js, npm, NVM, or apt-get needed

2. Simplified install.sh
   - Single install method: curl
   - Installs to ~/.local/bin with XDG_BIN_DIR
   - Persists PATH to bashrc
   - No auth.json fabrication (handled by start.sh)

3. Simplified start.sh
   - Uses pre-configured auth.json verbatim if provided
   - Does NOT try to synthesize auth.json from OAuth tokens
   - Clear warnings if no auth.json present
   - Backgrounds agentapi server with & so wrapper can run wait loop

4. Updated main.tf
   - Default install_method changed to "curl"
   - Removed validation (only curl supported now)

5. Updated README
   - Reflects curl-based installation
   - Notes that version pinning is not supported
   - Removed Node.js prerequisites

Trade-off: Cannot pin OpenCode version (always installs latest).
If version pinning is needed later, can add npm path back.
The curl installer was hanging on its own NVM/code-server installation.
Switch to direct Node.js tarball download + npm install for reliability.

Key changes:

1. install.sh - Node tarball approach:
   - Downloads Node.js 20.18.0 tarball from nodejs.org
   - Installs to /workspaces/.coder-tools (shared across workspaces)
   - Uses npm to install opencode-ai (pinnable version)
   - No apt, nvm, or curl installer dependencies
   - Shared npm cache for faster subsequent installs

2. main.tf:
   - Default install_method back to "npm"

3. README:
   - Updated to reflect tarball-based installation
   - Notes version pinning is now supported

Benefits:
- Predictable startup (no opaque installer scripts)
- Version pinning via opencode_version variable
- Shared Node.js cache across workspaces on same host
- No apt lock contention issues
- No nvm sourcing complexity
- Update namespace README with product/engineering focus and agentic systems
- Add comprehensive opencode module documentation with usage examples
- Document authentication methods (file-based GitHub Copilot auth recommended)
- Add complete template example for Coder task execution
- Document all configuration variables in organized tables
- Clarify task reporting and integration with Coder Tasks UI
Change agentapi terminal size from 67x1190 to 120x40 to fix scrolling issues.
Large terminal heights cause TUI apps to render huge interfaces, triggering
browser auto-scroll behavior. Standard dimensions ensure the interface fits
in the browser view with internal TUI scrolling (PgUp/PgDn) instead of
browser scrollbar jumps.
- Add mcp_servers variable for JSON MCP servers config (similar to claude-code)
- Add opencode_model variable for model selection
- Update install.sh to build opencode.json config with jq
- Update README with Model & MCP Configuration section
- Add MCP servers example with filesystem and github servers
… Start examples

- Add test cases for mcp_servers and opencode_model variables
- Add test for combined MCP + model configuration
- Add test verifying default empty values
- Simplify README Quick Start with cleaner examples
- Use /home/coder as default workdir in examples (more typical)
Changes:
- Remove OPENCODE_PROVIDER env var (OpenCode doesn't use it - provider is configured via auth.json)
- Remove empty configure_github_copilot_provider() function
- Remove verbose development comments from install.sh
- Update opencode_provider variable description to clarify it's documentation only
- Update README with accurate provider authentication documentation
- Clarify GitHub token is for git operations, not AI provider auth
- Remove unused ARG_OPENCODE_PROVIDER from start.sh

The key insight from OpenCode docs: authentication happens via 'opencode auth login'
which creates ~/.local/share/opencode/auth.json. Standard GitHub tokens don't work
for Copilot - it requires OAuth device flow.

Tests: 15 passed
Changes:
- Use 'mcp' key instead of 'mcpServers' in opencode.json config
- Update format: type='local' with command as array (not separate command/args)
- Update format: 'environment' for env vars (not 'env')
- Add remote MCP server example with type='remote' and url
- Update main.tf variable description with correct format
- Update README examples with correct OpenCode MCP format
- Link to OpenCode MCP documentation

OpenCode MCP format:
- Local: {type: 'local', command: ['npx', '-y', 'server-name'], environment: {...}}
- Remote: {type: 'remote', url: 'https://...'}

Tests: 15 passed
- Add link to wildcard DNS setup docs in subdomain variable description
- Add commented subdomain example in Complete Template Example
- Clarifies that subdomain=true requires wildcard DNS configuration
- Add opencode.png icon from VS Code marketplace
- Update icon default from code.svg to opencode.png
- Add minimal-agent-task example for testing with current branch
- Update README UI & Apps table with correct icon default
- Add workspace presets with system_prompt
- Include auth.json instructions for GitHub Copilot
- Add proper Docker volume and container labels
- Add agent metadata for CPU/RAM/disk monitoring
- Configure Git from workspace owner
- Use same container image parameter pattern as official templates
The DEV_ROOT default was /workspaces which may not exist or be writable.
Changed to use $HOME as the fallback for tool installation directory.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants