Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351). > [!WARNING] > **DO NOT MERGE** until [DOCS-349](https://linear.app/codercom/issue/DOCS-349) ([coder.com#877](https://github.com/coder/coder.com/pull/877)) has shipped to production and baked for at least one Vercel cycle. > > Without DOCS-349, the relative links in this PR resolve to broken docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the rewriter to classify these as GitHub blob/tree URLs with the page's resolved ref. ## TL;DR Converts 121 absolute `https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39 docs markdown files to relative paths. After this lands AND DOCS-349 deploys, every one of these links will follow the displayed docs version (mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on `/@main/`) instead of always pointing to `main`. ## Why Today a reader on `/docs/@v2.30.0/install/docker` follows a `compose.yaml` link and arrives at `main`'s `compose.yaml`, which doesn't necessarily match what the docs page describes. Helm values, Terraform templates, and source-code references in particular drift across versions. The fix is to let the coder.com rewriter substitute the page's resolved ref into the URL; that only works on relative links. ## Example payoff (post-DOCS-349) | URL | Today (absolute, always `main`) | After (relative + rewriter) | |---|---|---| | `/docs/install/docker` | `https://github.com/coder/coder/blob/main/compose.yaml` | `https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's mainline) | | `/docs/@v2.30.0/install/docker` | same as above | `https://github.com/coder/coder/blob/v2.30.0/compose.yaml` | | `/docs/@main/install/docker` | same as above | `https://github.com/coder/coder/blob/main/compose.yaml` | ## Scope - **121 conversions** across **39 files**. - Verb breakdown: `tree/main` (directories) and `blob/main` (files), both flipped to relative paths. - Line anchors (`#L23-L24`) and query strings preserved verbatim. - Conversion is mechanical: relative path computed from the doc file's directory to the target via `os.path.relpath`. Any path starting at the same directory or below gets a `./` prefix; otherwise `../` chains. ## Rebased on main The branch was rebased onto `main` after the DOCS-350 hotfix ([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`, which then needed the same `main` -> relative conversion this PR is doing for the other 121 links. The conflict was resolved by reapplying the mechanical conversion to `backend.md` after taking the hotfix's content. Net result: those 3 links land here as relative, same as everything else. New HEAD `3f501cb622`. ## Inline fix folded in: dead `nix` link - `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix` The original absolute URL `https://github.com/coder/coder/tree/main/nix` already returned 404 today. Repointed to `flake.nix` (modern Nix entrypoint, what the prose "Nix environment" semantically refers to). Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since the `check-docs` Linkspector job surfaced it during rebase; cheaper to fix inline than in a separate single-line PR. ## Out of scope (filed separately) - [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead `docs-backend-contrib-guide` branch refs in `backend.md` ([#26339](https://github.com/coder/coder/pull/26339), merged). - [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned `(blob|tree)/<sha>` links pending intent review. - [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server analog (4 absolute `(blob|tree)/main` links in `coder/code-server`). - [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of this PR). ## Not triggering `/coder-agents-review` Docs-only edit; per `AGENTS.md` the bot review is reserved for product/CI changes. ## Pre-mortem | Concern | Mitigation | |---|---| | Merging before DOCS-349 deploys regresses ~120 currently-working links into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker in Linear. | | Relative path computed incorrectly (off-by-one `..`) | Verified all 114 newly-relative non-md/non-image paths resolve to existing files in the repo (only exception is the pre-existing dead `nix` link above). | | Line anchors stripped during conversion | Preserved by the substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and `speed-up-templates.md`. | | Future code reorgs change file locations | Relative links will start pointing to nothing. Same failure mode as absolute links pointing to renamed files; can be caught with a future link-checker job. | ## Validation ``` $ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l 0 $ git diff --stat origin/main | tail -1 39 files changed, 118 insertions(+), 118 deletions(-) ``` 114 newly-relative paths verified to resolve to existing repo files (Python `os.path.exists` check on each computed target). <details> <summary>Decision log + planning context</summary> **Why relative over `(blob|tree)/{{currentDocsVersion}}/...` templating**: relative paths require zero markdown-system support and zero upstream churn beyond this one PR. Templating would require a preprocessor on `coder.com` side AND a convention upstream authors have to remember; relative paths just work in a plain editor and `github.com`'s own renderer too. **Why `./` prefix on same-directory targets**: makes the conversion grep-able later (`grep -E '\((\.\./|\./)'`). **Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful to the linked file's content, not to the URL form; keeping it as-is preserves authorial intent. If the file later changes such that the line range drifts, that's a different problem the SHA-pin audit ([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface. </details> --- *Generated by Coder Agents on @nickvigilante's behalf.* ## Drive-by external link fix folded in `docs/about/contributing/CONTRIBUTING.md:296` cited `https://reflectoring.io/meaningful-commit-messages/` which is returning HTTP 503 (the host appears to be down site-wide right now). `check-docs` Linkspector flagged it after the rebase. Replaced with `https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this commit will..." article, confirmed 200), which is the original source of the rule the prose recites anyway.
4.2 KiB
Open in Coder
You can embed an "Open in Coder" button into your git repos or internal wikis to let developers quickly launch a new workspace.
How it works
To support any infrastructure and software stack, Coder provides a generic approach for "Open in Coder" flows.
1. Set up git authentication
See External Authentication to set up Git authentication in your Coder deployment.
2. Modify your template to auto-clone repos
The id in the template's coder_external_auth data source must match the
CODER_EXTERNAL_AUTH_X_ID in the Coder deployment configuration.
If you want the template to clone a specific git repo:
# Require external authentication to use this template
data "coder_external_auth" "github" {
id = "primary-github"
}
resource "coder_agent" "dev" {
# ...
dir = "~/coder"
startup_script =<<EOF
# Clone repo from GitHub
if [ ! -d "coder" ]
then
git clone https://github.com/coder/coder
fi
EOF
}
Note
The
dirattribute can be set in multiple ways, for example:
~/coder/home/coder/codercoder(relative to the home directory)
If you want the template to support any repository via parameters
# Require external authentication to use this template
data "coder_external_auth" "github" {
id = "primary-github"
}
# Prompt the user for the git repo URL
data "coder_parameter" "git_repo" {
name = "git_repo"
display_name = "Git repository"
default = "https://github.com/coder/coder"
}
locals {
folder_name = try(element(split("/", data.coder_parameter.git_repo.value), length(split("/", data.coder_parameter.git_repo.value)) - 1), "")
}
resource "coder_agent" "dev" {
# ...
dir = "~/${local.folder_name}"
startup_script =<<EOF
# Clone repo from GitHub
if [ ! -d "${local.folder_name}" ]
then
git clone ${data.coder_parameter.git_repo.value}
fi
EOF
}
3. Embed the "Open in Coder" button with Markdown
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace)
Be sure to replace YOUR_ACCESS_URL with your Coder access url (e.g.
https://coder.example.com) and YOUR_TEMPLATE with the name of your template.
4. Optional: pre-fill parameter values in the "Create Workspace" page
This can be used to pre-fill the git repo URL, disk size, image, etc.
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace?param.git_repo=https://github.com/coder/slog¶m.home_disk_size%20%28GB%29=20)
5. Optional: disable specific parameter fields by including their names as
specified in your template in the disable_params search params list
[](https://YOUR_ACCESS_URL/templates/YOUR_TEMPLATE/workspace?disable_params=first_parameter,second_parameter)
Security: consent dialog for automatic creation
When using mode=auto with prefilled param.* values, Coder displays a
security consent dialog before creating the workspace. This protects users
from malicious links that could provision workspaces with untrusted
configurations, such as dotfiles or startup scripts from unknown sources.
The dialog shows:
- A warning that a workspace is about to be created automatically from a link
- All prefilled
param.*values from the URL - Confirm and Create and Cancel buttons
The workspace is only created if the user explicitly clicks Confirm and Create. Clicking Cancel falls back to the standard creation form where all parameters can be reviewed manually.
Example: Kubernetes
For a full example of the Open in Coder flow in Kubernetes, check out this example template.

