## Merge order Merge first; then republish the docs; then coder/coder.com#1100 (the redirects). ## Summary The nine pages under `docs/about/contributing/` are for people working in this repository, not for Coder users or administrators, so they leave the published documentation. The repository becomes their canonical home. Until now the root `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` were two-line stubs that only linked to the docs site, so contributors on GitHub were bounced out to read them. A companion PR in `coder/coder.com` adds redirects from every retired `/docs/about/contributing/*` URL to the new GitHub location. It must merge only after this PR has merged and the docs have republished. ## Changes | Old path | New path | | -- | -- | | `docs/about/contributing/CONTRIBUTING.md` | `CONTRIBUTING.md` (replaces the stub) | | `docs/about/contributing/CODE_OF_CONDUCT.md` | `CODE_OF_CONDUCT.md` (replaces the stub) | | `docs/about/contributing/SECURITY.md` | deleted; the root `SECURITY.md` already holds the policy | | `docs/about/contributing/AI_CONTRIBUTING.md` | `contributing/AI_CONTRIBUTING.md` | | `docs/about/contributing/backend.md` | `contributing/backend.md` | | `docs/about/contributing/frontend.md` | `contributing/frontend.md` | | `docs/about/contributing/modules.md` | `contributing/modules.md` | | `docs/about/contributing/templates.md` | `contributing/templates.md` | | `docs/about/contributing/documentation.md` | `contributing/documentation.md` (see note below) | For every moved file: the docs front matter is stripped and its `title` becomes the H1, relative links are rewritten for the new depth (`../../../foo` becomes `./foo` at the root and `../foo` under `contributing/`; the two links into `docs/admin/` become `../docs/admin/...`), and the docs-only `<div class="tabs">` wrapper in `CONTRIBUTING.md` is removed. `CONTRIBUTING.md` gains a short intro that links the code of conduct, the security policy and the area guides, since GitHub only auto-surfaces the root files. `docs/manifest.json` loses the About → Contributing group and `docs/images/icons/contributing.svg`, which only that group used. Inbound references updated: - `README.md`: contribution guide link now points at `CONTRIBUTING.md` on GitHub. - `docs/tutorials/example-guide.md` and `docs/install/releases/feature-stages.md`: link to `contributing/documentation.md` on GitHub, since a docs page cannot link to a repo-only file. - `docs/.style/style-guide/README.md`: the "Relationship to" section names the new location. - `scripts/docshtmlcheck/main.go`: both the package comment and the user-facing error string name `contributing/documentation.md`. - `scripts/docshtmlcheck/README.md`: relative link to the new location. - `coderd/database/migrations/migrate_test.go`: `t.Log` link now points at `contributing/backend.md#database-fixtures-for-testing-migrations`. - `.github/pull_request_template.md`: AI contribution guidelines link. - `.github/workflows/contrib.yaml`: commit-message guidelines link in the PR title check. - `.github/workflows/test-docs-preview-mapper.sh`: the mapper test case that used `docs/about/contributing/CONTRIBUTING.md` now uses `docs/admin/security/audit-logs.md`. - `.claude/docs/{ARCHITECTURE,PR_STYLE_GUIDE,WORKFLOWS,DOCS_STYLE_GUIDE}.md`: links to `CONTRIBUTING.md`. `git grep about/contributing` is empty after this change. `CODEOWNERS` had no entry for the old paths. Note on `documentation.md`: it is docs-authoring guidance and is parked in `contributing/` for now. Folding it into `docs/.style/` is tracked separately and is deliberately not attempted here. ## Testing - `go run ./scripts/docshtmlcheck` over `docs/`, and again over `contributing/`, `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`: clean. - `go vet ./scripts/docshtmlcheck/...` and `go test ./scripts/docshtmlcheck/...`: 47 tests pass. - `go vet ./coderd/database/migrations/...`: clean. `go test` for that package fails to link on this machine (`tailscale.com/tstime/mono: invalid reference to runtime.nanotime1`) identically on unmodified `main`, so it is a local toolchain issue and not exercised here; the change is a string in a `t.Log`. - `pnpm check-docs` (markdownlint-cli2 and markdown-table-formatter over `docs/`, `.claude/docs/`, root `*.md`): 495 files, 0 errors. The same two tools over `contributing/*.md`: 0 errors. - Every relative link in the eight moved files resolves to an existing path (scripted check). - `bash .github/workflows/test-docs-preview-mapper.sh`: the changed `assert_maps_to` case passes; the six `resolve_ref`/`pages_for_image` failures it reports are identical on unmodified `main` on macOS. Linear: [DOCS-975](https://linear.app/codercom/issue/DOCS-975) --- 🤖 Built with AI assistance.
11 KiB
Contribute modules
Learn how to create and contribute Terraform modules to the Coder Registry. Modules provide reusable components that extend Coder workspaces with IDEs, development tools, login tools, and other features.
What are Coder modules
Coder modules are Terraform modules that integrate with Coder workspaces to provide specific functionality. They are published to the Coder Registry at registry.coder.com and can be consumed in any Coder template using standard Terraform module syntax.
Examples of modules include:
- Desktop IDEs:
jetbrains,cursor,devin-desktop,zed - Web IDEs:
code-server,vscode-web,jupyter-notebook,jupyter-lab - Integrations:
devcontainers-cli,vault-github,jfrog-oauth,jfrog-token - Workspace utilities:
git-clone,dotfiles,filebrowser,coder-login,personalize
Prerequisites
Before contributing modules, ensure you have:
- Basic Terraform knowledge
- Terraform installed
- Docker installed (for running tests)
- Bun installed (for running tests and tooling)
Setup your development environment
-
Fork and clone the repository:
git clone https://github.com/your-username/registry.git cd registry -
Install dependencies:
bun install -
Understand the structure:
registry/[namespace]/ ├── modules/ # Your modules ├── .images/ # Namespace avatar and screenshots └── README.md # Namespace description
Create your first module
1. Set up your namespace
If you're a new contributor, create your namespace directory:
mkdir -p registry/[your-username]
mkdir -p registry/[your-username]/.images
Add your namespace avatar by downloading your GitHub avatar and saving it as avatar.png:
curl -o registry/[your-username]/.images/avatar.png https://github.com/[your-username].png
Create your namespace README at registry/[your-username]/README.md:
---
display_name: "Your Name"
bio: "Brief description of what you do"
github: "your-username"
avatar: "./.images/avatar.png"
linkedin: "https://www.linkedin.com/in/your-username"
website: "https://your-website.com"
support_email: "support@your-domain.com"
status: "community"
---
# Your Name
Brief description of who you are and what you do.
Note
The
website, andsupport_emailfields are optional and can be omitted or left empty if not applicable.
2. Generate module scaffolding
Use the provided script to generate your module structure:
./scripts/new_module.sh [your-username]/[module-name]
cd registry/[your-username]/modules/[module-name]
This creates:
main.tf- Terraform configuration templateREADME.md- Documentation template with frontmatterrun.sh- Optional execution script
3. Implement your module
Edit main.tf to build your module's features. Here's an example based on the git-clone module structure:
terraform {
required_providers {
coder = {
source = "coder/coder"
}
}
}
# Input variables
variable "agent_id" {
description = "The ID of a Coder agent"
type = string
}
variable "url" {
description = "Git repository URL to clone"
type = string
validation {
condition = can(regex("^(https?://|git@)", var.url))
error_message = "URL must be a valid git repository URL."
}
}
variable "base_dir" {
description = "Directory to clone the repository into"
type = string
default = "~"
}
# Resources
resource "coder_script" "clone_repo" {
agent_id = var.agent_id
display_name = "Clone Repository"
script = <<-EOT
#!/bin/bash
set -e
# Ensure git is installed
if ! command -v git &> /dev/null; then
echo "Installing git..."
sudo apt-get update && sudo apt-get install -y git
fi
# Clone repository if it doesn't exist
if [ ! -d "${var.base_dir}/$(basename ${var.url} .git)" ]; then
echo "Cloning ${var.url}..."
git clone ${var.url} ${var.base_dir}/$(basename ${var.url} .git)
fi
EOT
run_on_start = true
}
# Outputs
output "repo_dir" {
description = "Path to the cloned repository"
value = "${var.base_dir}/$(basename ${var.url} .git)"
}
4. Write complete tests
Create main.test.ts to test your module features:
import { runTerraformApply, runTerraformInit, testRequiredVariables } from "~test"
describe("git-clone", async () => {
await testRequiredVariables("registry/[your-username]/modules/git-clone")
it("should clone repository successfully", async () => {
await runTerraformInit("registry/[your-username]/modules/git-clone")
await runTerraformApply("registry/[your-username]/modules/git-clone", {
agent_id: "test-agent-id",
url: "https://github.com/coder/coder.git",
base_dir: "/tmp"
})
})
it("should work with SSH URLs", async () => {
await runTerraformInit("registry/[your-username]/modules/git-clone")
await runTerraformApply("registry/[your-username]/modules/git-clone", {
agent_id: "test-agent-id",
url: "git@github.com:coder/coder.git"
})
})
})
5. Document your module
Update README.md with complete documentation:
---
display_name: "Git Clone"
description: "Clone a Git repository into your Coder workspace"
icon: "../../../../.icons/git.svg"
verified: false
tags: ["git", "development", "vcs"]
---
# Git Clone
This module clones a Git repository into your Coder workspace and ensures Git is installed.
## Usage
```tf
module "git_clone" {
source = "registry.coder.com/[your-username]/git-clone/coder"
version = "~> 1.0"
agent_id = coder_agent.main.id
url = "https://github.com/coder/coder.git"
base_dir = "/home/coder/projects"
}
Module best practices
Design principles
- Single responsibility: Each module should have one clear purpose
- Reusability: Design for use across different workspace types
- Flexibility: Provide sensible defaults but allow customization
- Safe to rerun: Ensure modules can be applied multiple times safely
Terraform conventions
- Use descriptive variable names and include descriptions
- Provide default values for optional variables
- Include helpful outputs for working with other modules
- Use proper resource dependencies
- Follow Terraform style conventions
Documentation standards
Your module README should include:
- Frontmatter: Required metadata for the registry
- Description: Clear explanation of what the module does
- Usage example: Working Terraform code snippet
- Additional context: Setup requirements, known limitations, etc.
Note
Do not include variables tables in your README. The registry automatically generates variable documentation from your
main.tffile.
Test your module
Run tests to ensure your module works correctly:
# Test your specific module
bun test -t 'git-clone'
# Test all modules
bun test
# Format code
bun fmt
Important
Tests require Docker with
--network=hostsupport, which typically requires Linux. macOS users can use Colima or OrbStack instead of Docker Desktop.
Contribute to existing modules
Types of contributions
Bug fixes:
- Fix installation or configuration issues
- Resolve compatibility problems
- Correct documentation errors
Feature additions:
- Add new configuration options
- Support additional platforms or versions
- Add new features
Maintenance:
- Update dependencies
- Improve error handling
- Optimize performance
Making changes
- Identify the issue: Reproduce the problem or identify the improvement needed
- Make focused changes: Keep modifications minimal and targeted
- Maintain compatibility: Ensure existing users aren't broken
- Add tests: Test new features and edge cases
- Update documentation: Reflect changes in the README
Backward compatibility
When modifying existing modules:
- Add new variables with sensible defaults
- Don't remove existing variables without a migration path
- Don't change variable types or meanings
- Test that basic configurations still work
Versioning
When you modify a module, update its version following semantic versioning:
- Patch (1.0.0 → 1.0.1): Bug fixes, documentation updates
- Minor (1.0.0 → 1.1.0): New features, new variables
- Major (1.0.0 → 2.0.0): Breaking changes, removing variables
Use the version bump script to update versions:
./.github/scripts/version-bump.sh patch|minor|major
Submit your contribution
-
Create a feature branch:
git checkout -b feat/modify-git-clone-module -
Test thoroughly:
bun test -t 'git-clone' bun fmt -
Commit with clear messages:
git add . git commit -m "feat(git-clone): add git-clone module" -
Open a pull request:
- Use a descriptive title
- Explain what the module does and why it's useful
- Reference any related issues
Common issues and solutions
Testing problems
Issue: Tests fail with network errors
Solution: Ensure Docker is running with --network=host support
Module development
Issue: Icon not displaying
Solution: Verify icon path is correct and file exists in .icons/ directory
Documentation
Issue: Code blocks not syntax highlighted
Solution: Use tf language identifier for Terraform code blocks
Get help
- Examples: Review existing modules like
code-server,git-clone, andjetbrains - Issues: Open an issue at github.com/coder/registry
- Community: Join the Coder Discord for questions
- Documentation: Check the Coder docs for help on Coder.
Next steps
After creating your first module:
- Share with the community: Announce your module on Discord or social media
- Iterate based on feedback: Improve based on user suggestions
- Create more modules: Build a collection of related tools
- Contribute to existing modules: Help maintain and improve the ecosystem
Happy contributing! 🚀