Commit Graph
3115 Commits
Author SHA1 Message Date
Nick Vigilante 9eba637584 docs(docs/ai-coder/agents): reformat to one sentence per line (#30700)
Reformats the Coder Agents docs under `docs/ai-coder/agents` to one
sentence per line, as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

59 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (21 files changed, 870
insertions(+), 1294 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-15 14:38:40 -04:00
Steven Masley 7aef110ca2 feat: add workspace secrets table, queries, and RBAC (#30248)
Adds the database table, queries, and permissions for workspace secrets: secrets set on a workspace build and delivered to the agent, never to Terraform. 

Each secret belongs to one workspace build. A new build copies the previous build's secrets, then the old copies lose their values but stay as history.
2026-10-15 13:32:40 -05:00
Nick Vigilante c6a47c4428 docs: replace references to the retired Enterprise license tier (#30853)
## Summary

Coder has only Community and Premium license tiers, but several docs
pages, CLI help strings, and SDK field comments still called features
"Enterprise" or "enterprise-only".
This PR changes them to say Premium and regenerates the reference docs
built from those strings.

Resolves
[DOCS-1298](https://linear.app/codercom/issue/DOCS-1298/remove-references-to-the-retired-enterprise-license-tier).

## Changes

- `docs/admin/users/quotas.md`: Replace "scoped to Groups in Enterprise
and organizations in Premium" with a correct sentence. Quotas are
Premium, allowances are set on groups, and each user's budget is
calculated separately in each organization (per
`GetQuotaAllowanceForUser`).
- `docs/user-guides/workspace-lifecycle.md`: Replace "Enterprise" with
Premium, and correct the quotas sentence to match the quotas page.
- `docs/ai-coder/agents/platform-controls/mcp-servers.md`: Replace
"enterprise entitlement" with Premium license.
- `cli/templatecreate.go`, `cli/templateedit.go`: Update
`--require-active-version`, `--allow-user-autostart`, and
`--allow-user-autostop` help text. Point the `--require-active-version`
help at the renamed `#template-update-policies` section, because the old
`#require-automatic-updates-enterprise` anchor is broken. Make the
errors for these flags tier-neutral.
- `enterprise/cli/features.go`: `coder features` now says "List license
features and entitlements", and its AGPL error no longer names a tier.
- `codersdk/templates.go`, `codersdk/organizations.go`: Update field
comments that feed the API reference and TypeScript types.
- `docs/reference/glossary.md`: The Premium entry now says "paid license
tier" instead of "paid enterprise tier".
- `docs/.style/style-guide/voice-and-tone.md`: The example sentence now
says "Premium licensing".
- Regenerated: CLI golden files, `docs/reference/cli/`,
`docs/manifest.json`, `docs/manifest/generated/cli.json`,
`docs/reference/api/`, `coderd/apidoc/`, and
`site/src/api/typesGenerated.ts`.

## Testing

- `go test ./cli -run 'TestCommandHelp|TestCliTemplateCreate'` and `go
test ./enterprise/cli -run
'TestEnterpriseCommandHelp|TestTemplateCreate|TestTemplateEdit|TestFeaturesList'`
pass.
- The pre-commit hook passed, including `make gen`, `fmt`, `lint/go`,
`lint/ts`, `lint/markdown`, and a slim build.

<details>
<summary>Decisions and out-of-scope items</summary>

### Decisions

- **Premium wording and legacy Enterprise licenses:** Coder still
accepts existing Enterprise licenses, and `FeatureSetEnterprise`
includes the features labeled Premium here. Docs and help text say
"Premium" because that is the tier sold today, and about 25 other docs
pages already use "Premium feature". Error strings are tier-neutral, so
they're accurate for every license holder.
- **Glossary and style guide:** The issue marked these as borderline.
Both were one-word changes, so I made them.

### Not changed

- `docs/reference/api/enterprise.md` keeps the "Enterprise" sidebar
title. It comes from the swagger tag on the `enterprise/` Go package, so
renaming it is a larger change.
- Other "Enterprise" references the review flagged as out of scope: the
`coder server --help` option group, quiet hours SDK comments, internal
`coderd` comments, and the dashboard's "Enterprise" badge on the
require-active-version option.
- No docs page says that legacy Enterprise licenses are still valid.
- Uses that don't refer to the license tier: GitHub Enterprise, Red Hat
Enterprise Linux, "enterprise environments", and `enterprise/` package
paths.

</details>

---

_This PR was generated by Coder Agents on behalf of @nickvigilante._
2026-10-15 17:46:05 +00:00
Nick Vigilante 4ae1b7bd28 docs(docs/user-guides): fix tab block class typo on the remote desktops page (#30862)
## Summary

The VNC section of the Remote desktops page opened its nested tab block
with `<div class="tab">` instead of `<div class="tabs">`.

The new docs site converts only `class="tabs"` blocks into tabs, so
**Coder Desktop** and **CLI** rendered as `<h4>` headings directly under
the `## VNC` heading. The outer tab's **Desktop Client** label isn't a
heading, so the page skipped from h2 to h4, and axe reports
`heading-order`.

This was the only occurrence of the typo in `docs/`.

## QA

| Page | Production | Expected after merge |
| --- | --- | --- |
| Remote desktops, VNC section | [beta-docs
@main](https://coder.com/beta-docs/@main/user-guides/workspace-access/remote-desktops/#vnc)
| **Coder Desktop** and **CLI** render as tabs inside **Desktop
Client**, with no h4 headings |

The default version on beta-docs (v2.37.4) has the same typo, so the fix
shows there only after the next release.

A docs-engine change that warns on `class="tab"` at build time is
tracked separately.

Linear:
[DOCS-1306](https://linear.app/codercom/issue/DOCS-1306/fix-div-classtab-typo-that-leaves-stray-h4-headings-on-remote-desktops)

---

🤖 Built with AI assistance.
2026-10-15 13:33:27 -04:00
Nick Vigilante 0dc36786de docs(docs/.style): add compliance-claims wording rule to the style guide (DOCS-1256) (#30778)
Adds a "Describe what Coder does, not compliance outcomes" rule to the
docs style guide's word-choice page, so writers and reviewers have one
place for compliance-claim wording.

- The rule says to describe Coder's controls, not the reader's
compliance status, and to back every certification, audit, validation,
or authorization claim with a current artifact.
- A Do/Don't table covers SOC 2, ISO/IEC 27001, FIPS 140-3, FedRAMP and
DoD Impact Levels, DISA STIG, Iron Bank, CMMC, HIPAA, GDPR, DORA, and
the AI Act, with the reason behind each entry.
- The style guide README coverage counts move from 79 to 80 rules (Word
choice: 17 rules, 10 planned), and the Vale README lists the planned
`Coder.ComplianceClaims` rule.

Resolves DOCS-1256.

<details>
<summary>Decision log</summary>

- **Self-contained phrasing.** The approved phrasing comes from an
internal assessment that can't be linked from public docs, so the rule
states each term directly instead of pointing to it.
- **Facts checked before writing:**
- The AICPA issues no SOC 2 certificate; a CPA firm issues an
attestation report.
- ISO doesn't certify; a certification body certifies a management
system within a scope.
- CMVP validates modules under a certificate number; FIPS 140-2
certificates moved to the Historical list in September 2026.
- FedRAMP authorizes cloud service offerings, which a self-hosted
deployment isn't.
  - CMMC certifies organizations; HIPAA has no certification program.
- **Scope limits:** protocol conformance ("specification-compliant OIDC
provider") and sentences where the reader is the subject stay allowed,
so the planned lint rule doesn't flag them.
- **Enforcement:** the footer marks `Coder.ComplianceClaims` as planned.
The Vale rule itself is separate work.
- Checks: `make lint/style-claims`, `markdownlint-cli2`, `vale`,
`check_emdash.sh`, and the pre-commit hook pass locally.

</details>

<details>
<summary>CI note: Storybook failure is unrelated</summary>

The `Storybook` job failed when the Pixel snapshot service marked its
build as failed (31 snapshots awaiting review). This PR changes only
Markdown under `docs/.style/` and touches no `site/` code or stories.

</details>

---

_Generated by Coder Agents on behalf of @nickvigilante._
2026-10-15 11:33:15 -04:00
Nick Vigilante 1f61a290e7 docs(docs/ai-coder): reformat AI Gateway client and Agent Firewall docs to one sentence per line (#30702)
Reformats the AI Gateway client and proxy docs, the Agent Firewall docs,
and the top-level pages under `docs/ai-coder` to one sentence per line,
as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

1 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (27 files changed, 414
insertions(+), 513 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-15 15:31:32 +00:00
Nick Vigilante c58ac71ca3 docs(docs/tutorials): reformat to one sentence per line (#30703)
Reformats the tutorials under `docs/tutorials` to one sentence per line,
as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

9 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone. The two reverse
proxy tutorials also write `*.coder.example.com` in backticks instead of
escaping the asterisk, which the formatter would otherwise drop.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (19 files changed, 656
insertions(+), 1265 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-15 11:24:40 -04:00
Bobby Ho 603dd420d1 feat: add ServerTailnet logs and metrics for unreachable agents (#30133)
Add default-level metrics and warn-level diagnostics to investigate
ServerTailnet reachability failures causing agent-specific 502s, without
restarting coderd or enabling debug logging.

- Enrich request logs and PTY/chatd warnings with agent ID, failure
  reason, wait duration, coordinator state, WireGuard handshake and
  byte counts, and DERP regions.
- Add metrics for unreachable attempts by reason, reachability latency,
  embedded DERP connections, and offline app/terminal requests.
- Distinguish reachability failures from subsequent TCP dial failures,
  cap reverse proxy dials at one minute, and exclude expected chatd
  readiness polls and superseded-agent dials from unreachable counts.
- Report missing handshakes as zero time instead of 1970, also fixing
  `coder ping`.

Part of PLAT-680, a sub-issue of PLAT-360.
2026-10-14 14:55:29 -07:00
Nick Vigilante c647260901 docs(docs/ai-coder/ai-gateway): reformat to one sentence per line (#30701)
Reformats the AI Gateway docs directly under `docs/ai-coder/ai-gateway`
to one sentence per line, as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

4 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (10 files changed, 395
insertions(+), 570 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-14 15:24:49 -04:00
Nick Vigilante 1872b183ee docs(docs/admin): reformat setup and integrations docs to one sentence per line (#30704)
Reformats the setup and integrations docs under `docs/admin/setup` and
`docs/admin/integrations` to one sentence per line, as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

1 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (25 files changed, 380
insertions(+), 572 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-14 14:29:20 -04:00
Nick Vigilante ed6a8441dc docs(docs/user-guides): reformat to one sentence per line (#30705)
Reformats the user guides under `docs/user-guides` to one sentence per
line, as the [docs style
guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line)
requires. Hard-wrapped paragraphs are unwrapped and lines holding
several sentences are split, so a later edit to one sentence shows up as
a one-line diff.

Apart from the exception below, only whitespace inside paragraphs and
list items changes, and the rendered pages are the same. Comparing the
changed files against `main` word for word, ignoring whitespace and
blockquote `>` markers, finds differences only on the reworded lines.
`git diff --word-diff` is easier to read than the line diff.

7 lines that already contained an em or en dash were reworded by hand,
because `lint/emdash` treats every reflowed line as newly added. Each
uses a parenthetical, a separate sentence, or a colon after a lead-in.
Dashes on lines the reflow did not touch are left alone.

Applied with an in-progress formatter, limited to pages listed in
`docs/manifest.json` and excluding generated reference docs. This is one
of a batch of PRs that split the docs by area (29 files changed, 715
insertions(+), 1068 deletions(-)).

---
🤖 Built with AI assistance.
2026-10-14 14:04:33 -04:00
Nick Vigilante 935e076210 docs: delete unlisted pages and their screenshots (#30758)
Deletes seven docs files and 10 screenshots that are not in the docs
manifest and are superseded or empty:

- `docs/about/why-coder.md`: a TODO stub. The one link to it, a "Do"
example in the style guide, now names its source in plain text.
- `docs/tutorials/example-guide.md`: a contributor template with no
inbound links. Its guidance is recorded in DOCS-1207 for a tutorial
section in `contributing/documentation.md`, which is still to write.
- `docs/start/first-template.md` and six step 6 screenshots in
`docs/images/templates/`. Content is cataloged in DOCS-1209 for the
Templates landing page.
- `docs/start/first-workspace.md` and three screenshots in
`docs/images/start/`. Content is cataloged in DOCS-1208 for the
Workspaces landing page.
- `docs/start/local-deploy.md` and `docs/images/start/setup-page.png`.
Redundant with `get-started/` and `install/cli.md`.

The deleted files stay recoverable at `adcce66826`.

This replaces #30710, #30711, #30712, #30713 and #30714, which are
closed in favor of this PR.

Linear: DOCS-1205, DOCS-1206, DOCS-1207, DOCS-1211, DOCS-1212. Related:
DOCS-1208, DOCS-1209.

I ran `lint/docs-html`, `lint/docs-manifest`, `lint/docs-redirects` and
`lint/emdash` locally.

> Generated by Coder Agents on behalf of @nickvigilante.
2026-10-14 14:03:58 -04:00
dylanhuff-at-coder c856d5fb22 feat: accept template version IDs in --template-version (#30563)
Follow-up to #30199. `--template-version` on `coder create`, `start`,
`stop`, and `update` (plus `--stop-template-version` on `update`) now
takes a template version ID as well as a name. Passing a version UUID
used to 404 with a pretty unhelpful `get template version by name`
error.

`resolveTemplateVersionID` still looks up by name first, so a version
that happens to be named like a UUID resolves the same way it did
before. If that 404s and the input parses as a UUID, it falls back to
fetching the version by ID. Either way the version has to belong to the
selected template. That check matters most for `create`, which only
sends the version ID and lets the server derive the template from it, so
without it `coder create --template foo --template-version <id of a bar
version>` would quietly create a `bar` workspace.

The name is now path-escaped before the lookup. Previously something
like `../../../templateversions/<id>` could reach other API routes
through the name lookup and skip the template check entirely.

Not-found errors now read `template version "x" not found for template
"foo"` instead of the raw SDK error, so anything matching on the old
text will need updating. Flag help and the generated CLI docs say "name
or ID" now.
2026-10-14 08:52:36 -07:00
Garrett Delfosse 2b9fad8bba feat: add chat project sharing database layer (#30479)
Database and authorization layer for chat project sharing (experiment
`chat-projects`), part 1 of 2. #30439 adds the API on top of it. Nothing
here changes behavior: projects start with empty ACLs, no endpoint
writes them yet, and deleting a project still detaches its chats.
Project deletion is in #30683.

- **Schema:** migration `000621` adds `user_acl` and `group_acl` jsonb
columns to `chat_projects`, typed as `ChatACL` like chats, with GIN
indexes. It also adds the `chat_project:share` API key scope.
- **Queries:**
- `GetChatProjectsOwnedOrSharedWithUserID`: owned projects plus projects
with an ACL entry for the user directly, through a group, or through the
Everyone group (whose ID is the organization ID). Entries count only for
members of the project's organization. Keys match regardless of actions,
so dbauthz filters the rows.
- `IsChatProjectAccessibleByUserID`: whether a user owns a project or
holds a `read` or `*` grant on it, for code running under a system
subject. With sharing disabled, dbauthz answers owner-only.
- `GetChatProjectByIDForUpdate`: lets the ACL update read, modify, and
write in one transaction.
  - `UpdateChatProjectACLByID`.
- **RBAC:**
- New `share` action on `chat_project`. dbauthz requires it to update
the ACL.
- `ChatProject.RBACObject` attaches the project ACL. Memory objects get
a derived ACL: project `read` grants memory read, and `read` with
`update` grants memory create and delete. Wildcard grants count. Read
sharees change memories through their chats' agents, which #30439 gates.
Project instructions authorize through the same object, so a `read`
grant reads them and an `update` grant edits them.
- `--disable-chat-sharing` also covers projects: ACLs are ignored, the
ACL update is rejected, and roles deny `chat_project:share`. The help
text and chat sharing docs say so.
- **Audit:** `user_acl` and `group_acl` changes are tracked.
- **Tests:**
- Querier tests run the access queries both raw and through dbauthz
(owner, direct user, group, Everyone, wildcard grants, a member of
another org, grants without read).
- RBAC object and memory ACL tests, with an authorizer check, in both
sharing modes.
- dbauthz cases including the disabled guards, and the
`chat_project:share` negation in the roles test.

The generated TypeScript changes only add the new scope value.

> Generated by Coder Agents.
2026-10-14 10:42:00 -04:00
Lisa Fiander 2254965ef8 docs: update release calendar for v2.38 (#30757)
Updates the release calendar in `docs/reference/releases.md`.

For the `2.38` release: 
* `2.38` becomes Mainline
* `2.37` Stable
* `2.36` Security Support
* `2.35` Not Supported 
* `2.32` drops off. 

 
Latest patch versions are bumped to `v2.34.12`, `v2.35.9`, `v2.36.7`,
`v2.37.4`, and `v2.38.0`, and a `2.39` "Not Released" row is added.
The `2.35` row's link text (`v2.35.6`) is fixed to match its target
(`v2.35.7`, now `v2.35.9`).

Generated with `scripts/update-release-calendar.sh`, then hand-adjusted:

- 2.38 links to its changelog post,
`broader-model-access-and-tighter-governance-controls-in-238`, since
`coder-2-38` returns 404. The longer link widens the table, so every row
is realigned.
- 2.35 keeps `coder-2-35-1`; the script's `coder-2-35` returns 404.
- 2.38's date is the GitHub release publish date (October 06, the first
Tuesday). The script uses the tag commit date (October 01).

The "latest ESR version" link in the ESR section is also updated from
`v2.34.5` to `v2.34.12`.

Note: re-running the script will revert the two link overrides above.

---

_Generated by Coder Agents on behalf of @Lisa-Fiander._
2026-10-14 15:24:26 +01:00
coder[bot] 69fab7de06 chore!: remove the coder_report_task MCP tool (#30742)
Coder Tasks have been removed from coder/coder, so the
`coder_report_task` MCP tool and the status reporting pipeline behind it
no longer do anything useful. This PR removes the tool and the code that
only existed to support it.

### Removed

- `codersdk/toolsdk`: `ToolNameReportTask`, `ReportTaskArgs`,
`ReportTask`, `Deps.report`, `WithTaskReporter`, and the `All` entry,
plus their tests.
- `coderd/mcp`: the remote MCP exclusion for `coder_report_task`.
- `coder exp mcp server`: the task reporter, the AgentAPI screen
watcher, the agent socket connection, and the `coder_report_task` skip
logic. The server now requires an authenticated user client, because
every remaining tool needs one.
- `coder exp mcp configure claude-code`: the
`mcp__coder__coder_report_task` allowed tool, the injected
`coder_report_task` CLAUDE.md prompt, the `report tasks properly`
history line, the default system prompt asking the agent to send task
status updates, and the `CODER_MCP_APP_STATUS_SLUG` /
`CODER_MCP_AI_AGENTAPI_URL` env written to the Claude MCP config.
- `cli/cliutil/queue.go`: only used by the reporter.
- `github.com/coder/agentapi-sdk-go` (and transitive `tmaxmax/go-sse`)
via `go mod tidy`.
- The "task reporting" mention in `docs/ai-coder/mcp-server.md`.

### Breaking: removed `coder exp` flags and env

`coder exp` is experimental. Any scripts that still pass these flags
will now fail with an unknown flag error. Env vars that are no longer
read are ignored.

| Command | Flag | Env |
|---|---|---|
| `coder exp mcp server` | `--app-status-slug` |
`CODER_MCP_APP_STATUS_SLUG` |
| `coder exp mcp server` | `--ai-agentapi-url` |
`CODER_MCP_AI_AGENTAPI_URL` |
| `coder exp mcp server` | `--socket-path` | `CODER_AGENT_SOCKET_PATH`
(still used by `coder agent` and `coder exp sync`) |
| `coder exp mcp configure claude-code` | `--claude-app-status-slug` |
`CODER_MCP_APP_STATUS_SLUG` |
| `coder exp mcp configure claude-code` | `--ai-agentapi-url` |
`CODER_MCP_AI_AGENTAPI_URL` |

`--claude-system-prompt` no longer has a default.

<details>
<summary>Intentionally kept</summary>

- **Workspace app status reporting** (`UpdateAppStatus` on the agent API
and agent socket, `agentsdk.PatchAppStatus` / `ProtoFromPatchAppStatus`,
the deprecated `PATCH /workspaceagents/me/app-status` endpoint): still
served by coderd and the agent and part of versioned protocols. With
this change, nothing in the CLI calls the agent socket `UpdateAppStatus`
client anymore. Removing it would need a separate protocol change.
- **`report_tasks` in
`coderd/templatebuilder/modules/{aider,amazon-q}`**: these catalog
entries mirror the input variables of pinned coder/registry module
versions, and the behavior lives in those modules. Dropping the variable
here would not disable it, because `amazon-q` defaults it to `true`. The
registry modules need a follow-up instead.
- **`UserClientOptional` on toolsdk tools**: other tools still set it,
and remote MCP still uses it.
- No CLI golden files or generated CLI docs changed, because `coder exp`
commands are hidden.

</details>

### Verification

- `go build ./...`
- `go test ./codersdk/toolsdk/... ./coderd/mcp/... ./cli/cliutil/...`
- `go test ./cli -run 'TestExpMcp|TestCommandHelp'`
- `golangci-lint run ./cli/... ./codersdk/toolsdk/... ./coderd/mcp/...`
(0 issues)

---

_Generated by Coder Agents._

Co-authored-by: coder[bot] <137810501+coder[bot]@users.noreply.github.com>
2026-10-14 16:34:56 +05:00
Michael Suchacz fa7cd62c8b feat: send RFC 8707 resource parameter on MCP server OAuth2 flows (#30651)
Coder's MCP OAuth2 client never sent the RFC 8707 `resource` parameter,
which the MCP authorization spec requires on authorization and token
requests. Authorization servers that enforce it cannot be connected:
with Dagster+, discovery and dynamic client registration succeed, then
the authorize request fails with "MCP OAuth requests must include
resource".

MCP server configs get an `oauth2_resource` field (migration 000618,
admin-only in API responses, audited). Coder sends it on the authorize
redirect, the authorization-code exchange, and token refresh. Refresh
now goes through `clientcredentials` with `grant_type=refresh_token`,
because `oauth2.Config` cannot add parameters to refresh requests; it
keeps the same auth-style detection and error types, and adds no
dependency.

Auto-discovery fills the field with the most specific Protected Resource
Metadata `resource` that covers the server URL, stored as advertised. As
in the MCP SDKs, a resource covers URLs on its origin at or under its
path, so `/mcp` covers `/mcp/` but `/mcp/` does not cover `/mcp`. URLs
compare in RFC 3986 normal form (default ports, percent-encodings, dot
segments, and an empty path as `/`), ports ignore leading zeros, IPv6
literals compare by address, and `%2F` stays inside its segment. Unlike
the SDKs, a resource with a query, even an empty one, only covers a
server URL with the same query. When none covers it, Coder uses the
server URL with the scheme and host lowercased and user information and
fragment removed, or sends no resource when that is not a valid resource
indicator. An explicit value in the create request wins.

Manual configurations send no `resource` unless an admin sets one,
because some providers reject it (Microsoft Entra ID v2 fails with
AADSTS901002). Values must be absolute RFC 3986 URIs without a fragment,
user information, or an IPv6 zone identifier.

The resource binds grants like the other OAuth settings: changing it
deletes stored user tokens, and a callback whose config resource changed
after the user started connecting returns 409 before the code is
redeemed. The connect step records the resource in a callback-scoped
cookie for that check.

Discovery only runs when a configuration is created, so existing
auto-discovered configurations, including the Dagster+ one that prompted
this, keep an empty resource until an admin sets the new "Resource URL"
field or re-creates the server.

![MCP server edit form showing the Resource URL field filled by
auto-discovery](https://github.com/user-attachments/assets/319bc8a0-f6e1-4b7d-8878-8e341c94e590)

## Testing

- Go: discovery (most specific match, path and trailing-slash
boundaries, query matching including empty queries, equivalent ports,
IPv6 literals, escapes, and dot segments including escaped ones, the
normalized fallback and an invalid one, explicit override), validation
(URI characters, brackets, IP literals, user information, trimming),
grant deletion on change, clearing on an auth type change, redaction for
members, refresh with and without a resource, the 409 when the resource
changes mid-flow (the authorization server never receives the code), and
a connect and callback flow against an authorization server that rejects
requests without the resource. Each new test was checked to fail when
the behavior it covers is broken, except two malformed IP literal hosts
that Go's URL parser already rejects.
- Vitest: the form round-trips the stored value, and clearing the field
sends `""` on update.
- Remote UAT through Coder Agents
([chat](https://dogfood.cdr.dev/agents/58695d5b-2112-400b-88f7-ab64c678f756))
on a test deployment with loopback MCP and authorization server mocks:
- Round 1 on 2b875068e0: literal verdict FAIL. When the resource
changed between connect and callback, the callback redeemed the code for
the new resource and stored a grant. The 409 binding fixes it.
- Round 2 on 4b54ffb5f9: PASS. The mid-flow change returned 409 with no
token request in every variant (strict and lenient servers, set,
cleared, abandoned flows, parallel configs); auto-discovery, connect,
refresh, validation, and the docs matched. Minor observations: the
binding cookie is an unkeyed digest, so a member who edits their own
HttpOnly cookie can redeem a code with the current resource, which a
fresh connect also gives them; other settings changed mid-flow still
reach the token endpoint, as on main; the 409 popup shows raw JSON; the
UI does not warn that a resource change disconnects users; validation
toasts omit the server's detail.
- Round 3 on the final head 2d6abfac49: PASS. The head moved during the
round, so it ran in four parts, the last on 2d6abfac49. That part
covered the matching rules (queries including empty ones, default and
zero-padded ports, `%2F`, escaped dot segments, trailing slashes, IPv6
literals), the invalid fallback (stored empty, no `resource` sent),
every validation value through the API and the UI, and the discovery,
connect, refresh, and mid-flow 409 flows. The equivalent-encoding cases
last ran live on 5c23fe00dca; unit tests cover them on the final head.
Observation: the path-aware metadata URL is built from the decoded path,
so `/mcp%2Ftenant` fetches metadata for `/mcp/tenant`, as on main.
- `frontend-review` and the eight-role `coder-frontend-review` ran on
the `site/` diff; every role passes after the label, help text, row
layout, API doc wording, and form test fixes. Declined: linking field
descriptions with `aria-describedby`, because the form's shared `Field`
primitive renders every description without one, so it belongs in a
change to all fields.

## Review record

| Review | Commit | Findings | Disposition |
|---|---|---|---|
| [Codex round
1](https://github.com/coder/coder/pull/30651#pullrequestreview-5492085359)
| 4b54ffb5f9 | P2: a resource with another query was treated as
covering the server URL | Reproduced with a failing test, fixed in
bf0879560c, resolved |
| [Codex round
2](https://github.com/coder/coder/pull/30651#pullrequestreview-5492305363)
| bf0879560c | P2: explicit default ports; P2: `%2F` treated as a
segment boundary; P2: `url.Parse` accepts spaces and invalid escapes |
Each reproduced with a failing test, fixed in 16a1d783fa, resolved |
| [Codex round
3](https://github.com/coder/coder/pull/30651#pullrequestreview-5492677517)
| 16a1d783fa | P1: docs wrapped mid-sentence (DOC1); P2: equivalent
percent-encodings compared unequal; P2: brackets accepted outside an IP
literal host | Fixed in 8d617f0528 (the P2s reproduced with failing
tests; the same pass also covers the query, dot segment, and user
information cases), resolved |
| [Codex round
4](https://github.com/coder/coder/pull/30651#pullrequestreview-5493033885)
| 8d617f0528 | P2: the server URL fallback was not validated; P2:
escaped dot segments were compared before decoding | Each reproduced
with a failing test, fixed in 5c23fe00dc, resolved |
| [Codex round
5](https://github.com/coder/coder/pull/30651#pullrequestreview-5493342889)
| 5c23fe00dc | P2: an empty query (`?`) was treated as no query |
Reproduced with a failing test, fixed in 72c019ff5e, resolved |
| [Codex round
6](https://github.com/coder/coder/pull/30651#pullrequestreview-5493524846)
| 72c019ff5e | P2: `/mcp/` covered `/mcp`; P2: equivalent IPv6 literals
compared unequal; P2: malformed IP literals accepted | The first two
reproduced with failing tests. Go 1.26.5 `url.Parse` already rejects the
hosts named in the third, but it accepted an IPv6 zone identifier. All
fixed in ef2df2c4e7, resolved |
| [Codex round
7](https://github.com/coder/coder/pull/30651#pullrequestreview-5493668131)
| ef2df2c4e7 | P2: leading zeros in a port made equal origins differ |
Reproduced with a failing test, fixed in 2d6abfac49, resolved |
| [Codex round
8](https://github.com/coder/coder/pull/30651#issuecomment-6128743972) |
2d6abfac49 | None: "Didn't find any major issues" | Clean verdict on
the current head |

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-13 23:03:08 +02:00
Michael Suchacz adcce66826 feat: load organization skills in chats (#30613)
## Stack

Closes
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. #30609 data model: one migration, queries, RBAC and dbauthz
2. #30610 organization skill API routes and the scope-neutral SDK
3. #30611 sharing ACL routes
4. #30612 settings UI: shared skills table, admin page, member section
5. **#30613** chats: chatd loading, `/` menu, docs (this PR)

## What changes

This PR makes chats use organization skills: chatd adds the skills
shared with the chat owner in the chat's organization to the skill
index, `read_skill` loads them, the `/` menu offers them, and the docs
describe the feature.

**chatd** (`coderd/x/skills`, `coderd/x/chatd`):

- New source `skills.SourceOrganization` (`"org"`).
`MergeSkills(personal, organization, workspace)` sorts by name, then
source. A name in one source keeps its bare alias; a name in more than
one source gets a qualified alias in every source that has it
(`personal/<name>`, `org/<name>`, `workspace/<name>`), so no source
overrides another. `Lookup` returns `ErrSkillAmbiguous` for a bare name
that matches several sources.
- **Authorization (please review closely):** each turn, chatd reads
organization skill metadata and bodies as the chat owner's real RBAC
subject with their roles and groups (`chatOwnerSubject`), never as the
chatd system actor, so per-skill ACLs apply. Disabled skills are
skipped. A skill that is deleted, disabled, or no longer shared by the
time `read_skill` runs is reported as not found. If the owner subject or
the metadata can't be loaded, turn preparation fails with the error, as
main now does for personal skills (#30492), instead of running the turn
without organization skills.
- `read_skill` loads personal and organization bodies through one
`LoadStoredSkillBody` callback. An index description longer than 1,024
runes, the Agent Skills specification limit
(`maxSkillIndexDescriptionRunes`), is cut to 1,023 runes plus an
ellipsis so it stays within the limit; `read_skill` still returns the
full skill.
- Parse and lookup errors keep `%w` last on purpose: with `xerrors`, a
`%w` that isn't last repeats the cause, so main's detail read "skill is
too large: got N bytes, maximum is 65536 bytes: skill is too large".
This stack returns the cause once (ThomasK33 asked about the order in
review).

**`/` menu** (`site/src/pages/AgentsPage`): the chat page fetches the
chat organization's enabled skills (`organizationSkills(...)` from
#30612's queries) next to personal ones. `utils/skillAliases.ts`
(`resolveSkillTriggers`) follows `MergeSkills`: a personal or
organization trigger is bare unless its name is in more than one source,
then it becomes `/personal/<name>` or `/org/<name>`. While any list is
unknown every trigger is qualified, because a qualified alias always
resolves; workspace triggers are always qualified. Built-in `/clear` and
`/compact` stay pending until every skill list is known, and a list with
no data counts as unknown even after an error, so a failed fetch can't
make a built-in run in place of a same-named skill. Disabled skills
never shadow a built-in.

**Docs:** `docs/ai-coder/agents/extending-agents.md` gains two sections,
Organization skills (manage them, control who can use one, find the ones
you can use) and How chats load stored skills (turning a skill on or
off, skills with the same name). The admin page's organization picker
shows only for a user who can view more than one organization's skills.
The member "From your organizations" section shows one organization at a
time with its own picker, starts on the default organization, and has
Export all for the selected organization. The Enabled column is a switch
for editors and a check or X otherwise. The settings table in
`platform-controls/organizations.md` gains rows for organization and
personal skills.

## Commits

The first commit reproduces the reviewed chatd code from the old stack;
the site and docs commits reapply the old layers on #30612's queries,
and the rest are labeled trims or fixes.

- `aa634eec94a` feat(coderd/x): load organization skills in chats.
Reproduction of the old skill sources and chatd layers (old head
`a1047f4986`).
- `97945db4e86` test(coderd/x/skills): make `TestMergeSkills` (6 cases)
and `TestLookup` (8 cases) table-driven; coverage is 100% before and
after, with the same blocks.
- `dde61cc5fe2` test(coderd/x/chatd): drop skill tests duplicated by the
organization skills integration test
`TestOrganizationSkillsFollowChatOwnerAccess`; the covered block set of
the touched code is identical (348 of 506 blocks).
- `aad14b2dd05` feat(site/src/pages/AgentsPage): show organization
skills in the slash menu. The old alias helper and slash menu layers,
applied cleanly on #30612's queries.
- `712e272e140` test(site/src/pages/AgentsPage): trim duplicated slash
menu tests and stories. Deletes `AgentChatPage.test.tsx` (177 lines; its
assertions live in `submitChatTurn.test.ts` and
`ChatMessageInput.test.tsx`), two duplicate `ChatMessageInput` cases,
six of 17 `SkillsTriggerMenu` stories, and one disabled-skill fixture
row from a `ChatMessageInput` story.
- `232535e1011` docs(docs/ai-coder/agents): document organization
skills. From the old docs layer, with the View line updated for #30612's
read-only dialog and Download.
- `62dbbd2dfd3` refactor(site/src/pages/AgentsPage): address frontend
review on the slash menu.
- `7349eac4389` Merge the updated settings-ui layer into chats. Brings
in the #30610 and #30612 fixes; the merge has no changes of its own.
- `0f84a30ec69` Merge the updated settings-ui layer into chats again,
for #30612's read-only View fix; no changes of its own.
- `fb37822f985` fix(coderd/x/chatd/chattool): keep truncated skill index
descriptions within 1,024 runes. The cut now happens at 1,023 runes so
the ellipsis fits; the existing `skill_test.go` assertion now expects
1,023 runes plus the ellipsis.
- `1543666b584` docs(docs/ai-coder/agents): state the 1,023-character
cut before the skill index ellipsis.
- `96f1da47c9a` and `13f03d095ff` merge the updated settings-ui layer
for #30612's cache and Skills link fixes; no changes of their own.
- `b03c14c86de` and `41cc078b85a` merge the updated settings-ui layer;
`b03c14c86de` moves the `AgentChatPage.tsx` and `ChatMessageInput.tsx`
call sites, and their tests and stories, to #30612's split
`organizationSkills(...)` query.
- `1a32d05c9bc`
test(site/src/pages/AgentsPage/components/ChatMessageInput): restore
per-source loading stories for the slash menu.
- `830b0466982` fix(coderd/x/chatd): fail turn preparation when
organization skills cannot load. Main now returns database errors from
turn preparation (#30492); organization skills still logged and dropped
the failure, so a failed read silently hid them from the model. The new
`TestFetchOrganizationSkillMetadataListFailure` covers the returned
error.
- `84c135f8801` and `a6f8f63ad13` merge the updated settings-ui layer,
which brings in main; they resolve `generation_preparer.go` against
main's turn preparation error handling.
- `19b7880840f` merges #30612's member page test change; no changes of
its own.
- `c74d597f3c5` merges #30612's read-only status change; no changes of
its own.
- `f89c232c081` merges #30612's skills test changes; no changes of its
own.
- `17d5b9bfbc5` docs(docs/ai-coder/agents): describe the member skills
organization picker and read-only Enabled status.
- `f97b1710f71` merges the updated settings-ui layer (main at
`e7b76872098`); no changes of its own.

## Size

Production +558/-213 (docs +116/-6), tests +895/-262; total +1453/-475.
This is above the 500-line reviewer-friendly limit on purpose: Mike
asked for 4 to 5 PRs instead of the 21 small ones this stack replaces.

## Replaces

#30593 (skill sources), #30594 (chatd), #30601 (alias helper), #30602
(slash menu), #30604 (docs).

## Validation

- Go: all 21 packages under `coderd/x/skills` and `coderd/x/chatd` pass
on `62dbbd2dfd3`, plus the coverage comparisons above;
`coderd/x/chatd/chattool` passes again on `13f03d095ff` after the
truncation fix.
- Site: `pnpm run lint` and Biome clean; Vitest 102 tests; Storybook
Vitest 49 + 4 tests. `pnpm run lint` reran clean on `13f03d095ff`.
- On `a6f8f63ad13`, this PR's head before the test-only `19b7880840f`
merge: `go test` passes for `coderd/x/skills`,
`coderd/x/chatd/chattool`, and the `coderd/x/chatd` skill tests (`-run
'OrganizationSkill|Skill'`); 38 Vitest files covering skills and the
slash menu pass, 542 tests with 2 skipped.
- Docs: markdownlint 0 findings, Vale 0 findings.
- On `17d5b9bfbc5`: Vale clean, markdownlint and `make pre-commit` pass.
On `f97b1710f71`: `go build`, the `coderd/x/skills` and `chattool`
tests, `pnpm check` and `tsc` pass.
- Remote UAT round 7 through Coder Agents: PASS
([chat](https://dogfood.cdr.dev/agents/3426d4d3-2139-4ae1-8e0c-72ddeff413a8)).
- Full run on `62dbbd2dfd3`, including an in-place upgrade from main
`50c785cc6d7`: personal skills kept their IDs, names, content hashes and
timestamps, came up enabled, and worked in chats (`read_skill`) and the
`/` menu; create, edit, download and delete worked after the upgrade.
The admin page, sharing, the Enabled toggle, the member section, the `/`
menu, chats reading organization skills as the owner, limits, audit,
authorization and scoped keys, and the docs all passed.
- Delta run on `7349eac4389`: an update-only key gets 404 on PATCH with
no content in the response; saving permissions refreshes Updated without
a reload; smoke of the admin page, auditor View and Download, the `/`
menu and `read_skill`.
- Delta run on `0f84a30ec69` for `aaa356f0fd5`: read-only View, as an
org auditor and as a member, shows no Name hint, focuses no field and
starts on Close, and Escape or Close returns focus to the row menu
button; Add skill and Edit still show the hint and focus the import
field, and a saved edit persisted; smoke of the admin page, the `/` menu
organization group and `read_skill`. Screen-reader behavior was not
tested.
- Delta run on `13f03d095ff` for `698dd83946d`, `f82573cd1c2`,
`0e55137de7b` and `fb37822f985`: for an organization admin of org B who
is a plain member of org A, the sidebar Skills link drops `?org=` for
org A on seven AI settings pages and opens org B's skills, keeps `?org=`
for org B, and a typed `/ai/settings/skills?org=` for org A still shows
the permission error. A skill deleted and recreated with the same name
loads a fresh sharing list showing only Everyone, with no stale grant. A
1,500-character description appears in the chat's skill index as 1,023
characters plus an ellipsis, while `read_skill` returns all of it. Smoke
of the admin toggle, the member section, the `/` menu organization group
and `read_skill`.
- Low findings: the read-only View hint and field focus, fixed in
`aaa356f0fd5` and verified by the delta run above. The member section's
always-on disabled Enabled switch (also in the old stack) is replaced by
a read-only status icon in #30612's `63bb42754e3`, which has no UAT run.
Not fixed: `/` shows the `/personal/` prefix while organization skills
fail to load (the unknown-list rule above); the shared Switch
component's disabled styling (unchanged from main). A user who can read
skills in only one organization sees no organization name on the Skills
page, because the picker is hidden for a single organization, as on the
MCP servers page on main.
- Not tested: the workspace skills group (no running agent on the test
deployment), the 100-per-user personal cap, and behavior without a
Premium license.
- Remote UAT round 8 through Coder Agents: PASS on `b03c14c86de` (same
chat). The remote grader marked the unknown `read_skill` item FAIL only
because the prompt asked for the literal phrase "skill not found"; the
result names the skill once and says "not found" once, the same format
as main, so the runner graded it PASS on intent.
- Member page: starts on the default organization, shows one
organization's table with the read-only note once, Export all downloads
only the selected organization's skills, the picker is hidden with one
organization, and an organization without enabled skills isn't listed.
- Personal and admin tables: create, edit, toggle and delete each
refetch the list; reopening the editor shows the new content even with
the detail request delayed; a toggle changes state once, with no
flicker. A skill deleted and recreated with the same name shows only
Everyone in sharing.
- The sidebar Skills link keeps `?org=` only for an organization whose
skills the user can read. A create over 64 KiB returns 400 with the
detail "got 70000 bytes, maximum is 65536 bytes: skill is too large",
the cause once. The `/` menu shows Commands, Personal skills and
Organization skills, and invoking an organization skill loads its body
through `read_skill`.
- New low findings, not fixed: the member page picker's listbox is
labeled "Suggestions" (likely from the shared
`OrganizationAutocomplete`); a typed body over 64 KiB shows only the
size counter and a disabled Create until Import; `/ai/settings?org=`
redirects to the models page without `?org=`. The first and third were
not checked against main.
- `9002dc60382`, `1a32d05c9bc`, `830b0466982`, `ac3e62c83b7`,
`63bb42754e3`, `82b2487ad17`, `17d5b9bfbc5` and the main merges came
after `b03c14c86de`; they have tests but no UAT run.
- Every UAT round ran the migration as `000615_skills`. The heads ship
the same up and down SQL as `000621_skills`, so the upgrade path from
main's 000620 to 000621 has no UAT run.

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-13 17:13:36 +00:00
Michael Suchacz 2c432a12a3 feat: add organization skill sharing ACL routes (#30611)
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. #30609 data model: one migration, queries, RBAC and dbauthz
2. #30610 organization skill API routes and the scope-neutral SDK
3. **#30611** sharing ACL routes (this PR)
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the routes that let admins choose who can read an
organization skill. It reuses the MCP server ACL machinery rather than
adding a second implementation.

Routes under
`/api/experimental/organizations/{organization}/skills/{skillName}`, all
behind `httpmw.ExtractOrganizationSkillParam` with `share`, so a caller
without share gets 404:

- `GET /acl` returns the resolved user and group grants.
- `GET /acl/available` returns the organization's users and groups that
can be granted, with the same `q`, `after_id`, `limit` and `offset`
paging as the MCP endpoint.
- `PATCH /acl` takes a sparse `UpdateOrganizationSkillACLRequest`: only
the listed principals change, `read` grants and `""` removes. It returns
204 and writes a `write` audit entry with the old and new ACL.

**Concurrency (please review closely):** the PATCH transaction first
locks the granted users' `organization_members` rows `FOR KEY SHARE`
(new query `LockOrganizationMembersByUserIDsForShare`, run as system),
then locks the skill row `FOR UPDATE`, then validates the update on the
transaction handle. Member removal takes the same locks in the same
order (its membership row, then the skill rows through the #30609
trigger), so the two can't deadlock, and a removal can't miss a grant
written by a concurrent PATCH. A skill deleted between the middleware
read and the row lock stays a 404.

Grants are users and groups, the same as MCP server configs (Mike's
decision, for parity). Only the `read` role exists; any other role is a
validation error, as are users or groups outside the organization.

Supporting changes:

- `coderd/mcp_acl.go`: the MCP ACL handlers' resolution, candidate
listing and validation move into generic helpers
(`writeOrganizationACLAvailable`, `validateOrganizationACLUpdate`,
`resolveACLUsers`, `resolveACLGroups`) shared by both resources;
`acl.Validate` accepts a named `acl.Role` constraint that now includes
`codersdk.OrganizationSkillRole`.
- `codersdk/skills.go`: `OrganizationSkillRole`, `OrganizationSkillACL`
with its user and group entries, `UpdateOrganizationSkillACLRequest`,
and client methods.
- New sqlc query `UpdateOrganizationSkillACLByID` with its dbauthz
wrapper (requires `share`).

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `b1c85560b69` feat: add organization skill sharing ACL routes.
Reproduction: every file this commit changes equals the reviewed old
`acl-routes` head `80c1c3594e6`; the rest of the tree differs only by
#30609's migration merge and main.
- `b5d2ee265c8` test(coderd): merge duplicate organization skill ACL
route tests (+49/-111). The removed cases repeated
`TestMCPServerConfigACL`, `TestMCPServerConfigACLAvailable` or
`TestRolePermissions`; with the MCP tests included, the covered block
set of `organizationskills_acl.go`, `mcp_acl.go` and
`rbac/acl/updatevalidator.go` is identical before and after. Kept:
`TestOrganizationSkillACL` (`OrgAdminManagesACL`, `ReadersGetNotFound`,
`SparseUpdateChangesReaders` with the audit diff,
`RejectsUnsupportedRole`, `ScopedAPIKeys`),
`TestOrganizationSkillACLConcurrentDelete`, and the lock order tests
`TestOrganizationSkillACLMemberRemoval` (`RemovalBeforeGrant`,
`RemovalAfterGrant`). `OrgAdminManagesACL` now also checks that users
from another organization are not candidates (mutation checked). Sharing
the param extractor with MCP was skipped: it would save about 10 lines
of security-sensitive code.
- `e09c4dba66b` Merge the updated org-api layer into sharing. Brings in
#30610's `ad0a7a37504`; the merge has no changes of its own.
- `1d3817dc639` and `c8c88f84d18` merge the updated #30610 layer,
including main; no changes of their own.
- `c4d22c47990` merges the updated #30610 layer (main at `e7b76872098`);
no changes of its own.

## Size

Production +431/-102, tests +377/-0, generated +918/-0; total
+1726/-102. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30591 (ACL queries), #30592 (ACL routes).

## Validation

- `go build` and `go vet` passed; `make gen` exited 0 with no diff.
- `go test` passed for `coderd` (skill, MCP and ACL tests),
`coderd/database`, `dbauthz`, `migrations`, `gentest`,
`coderd/rbac/...`, `coderd/httpmw`, `coderd/x/skills/...`,
`coderd/x/chatd/...`, and the audit and skill tests in
`enterprise/audit` and `enterprise/coderd`.
- The covered block comparison above, before and after the test merge.
- On `c4d22c47990`: the same checks as #30610's head, plus `go test
./coderd/ -run 'Skill|MCP|ACL'`, pass.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-13 16:43:15 +00:00
Michael Suchacz db7f5a7703 feat: add organization skill API routes (#30610)
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. #30609 data model: one migration, queries, RBAC and dbauthz
2. **#30610** organization skill API routes and the scope-neutral SDK
(this PR)
3. #30611 sharing ACL routes
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the organization skill CRUD routes and makes the skill SDK
types owner-neutral so personal and organization skills share them.

**API contract change (experimental API, personal and organization
skills):** skill list and get responses gain `enabled`, and `PATCH
.../skills/{skillName}` now takes `{content?, enabled?}`, so `content`
is optional and a toggle doesn't resend it. A PATCH with neither field
returns 400; `content`, when present, is validated as before. In the
SDK, `UserSkill`, `UserSkillMetadata`, `CreateUserSkillRequest` and
`UpdateUserSkillRequest` become `Skill`, `SkillMetadata`,
`CreateSkillRequest` and `UpdateSkillRequest` (`codersdk/userskills.go`
moves to `codersdk/skills.go`), and `UpdateSkillRequest.Content` is now
`*string`. The personal client method names are unchanged. The site
changes are the handwritten edits that rename forces (`api.ts`,
`queries/userSkills.ts`, `testHelpers/skills.ts` and three call sites),
with no UI change.

Organization routes under
`/api/experimental/organizations/{organization}/skills`, not gated by an
experiment or license, like the personal ones:

- `GET` lists with the caller's own permissions, so admins, the site
owner and org auditors see every skill and members see only skills
shared with them. `GET /{skillName}` goes through the new
`httpmw.ExtractOrganizationSkillParam` and admits only read, so a
missing skill and a denied one both return 404.
- `POST` checks `create` on the organization before reading the body,
then seeds `group_acl` with the Everyone group (whose ID is the
organization ID) so a new skill reaches every member until an admin
narrows it. The 100-skill cap and a duplicate name return 409.
- `PATCH` admits only callers who can read the skill, because its
response includes the content; `DELETE` admits callers who can read or
delete it. A reader who can't change the skill gets a write-specific 403
from the database wrapper, and everyone else gets 404. PATCH locks the
row as system, updates as the caller in the same transaction, and audits
the locked row only after the transaction commits.
- Audit: `database.AuditableOrganizationSkill` records resource type
`organization_skill` with the organization ID; personal skills keep
`user_skill`.

Personal and organization handlers share one create and update path in
`coderd/userskills.go` (`createSkill`, `updateSkill`, and a
`skillWriteErrors` table per owner and action).

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `49cb2c84276` feat: add organization skill API routes. Reproduction:
every file this commit changes, including the SDK layer's site edits,
equals the reviewed old `write-routes` head `aa597100f28`; the rest of
the tree differs only by #30609's migration merge and main.
- `dc893bc60d6` refactor(coderd): share the skill create and update path
across owners (production +164/-188). It keeps the organization create
check before the body read, the lock as system then update as caller
order, and audit assignment after the transaction. No swagger,
`codersdk` or `typesGenerated.ts` change; `make gen` is clean.
- `f94925425ef` test(coderd): merge duplicate personal and organization
skill tests. `TestSkillsCRUD`, `TestSkillValidationAndConflicts` and
`TestSkillAudit` are table-driven over Personal, OrgAdmin and SiteOwner,
alongside `TestOrganizationSkillAuditsDeniedWrites` and one
`ScopedAPIKeys` subtest; `TestPatchUserSkill` is deleted because none of
its blocks were unique. Coverage of `userskills.go`,
`organizationskills.go` and `httpmw/organizationskillparam.go` is 101 of
117 blocks before and after, the same block set.
- `ad0a7a37504` fix(coderd): require read access to patch an
organization skill. The organization PATCH route now admits only `read`,
because its response carries the skill's content: a key scoped to
`organization_skill:update` without read gets 404, like GET, instead of
200 with the content. Readers without update still get 403, and DELETE
is unchanged. `TestOrganizationSkillAccess/ScopedAPIKeys` asserts the
404, that the response has no content, and that the skill is unchanged;
against the old route it fails with 200.
- `69d00ded0b6` and `f67b79343ec` merge the updated #30609 layer,
including main; `69d00ded0b6` resolves a conflict in the personal skills
page with main. No other changes of their own.
- `18373ffd59e` merges the updated #30609 layer (main at `e7b76872098`)
and reapplies the `AuditableOrganizationSkill` entry in
`enterprise/audit/table.go` alongside main's new
`AuditableChatProjectInstructions` entries.

## Size

Production +838/-308, tests +733/-322, generated +801/-274; total
+2372/-904. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30587 (scope-neutral SDK and personal enabled state), #30588 (read
routes), #30589 (write routes and audit).

## Validation

- The coverage comparison above, before and after the test merge.
- `make gen` leaves no diff after the shared create and update refactor.
- On `18373ffd59e`: `make gen` is clean; build, vet, the `coderd` and
`enterprise/coderd` skill tests, `rbac`, `httpmw`, `dbauthz` and
`enterprise/audit` pass; `pnpm check`, `pnpm lint` and `make pre-commit`
pass.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-13 16:24:45 +00:00
Michael Suchacz b67587c875 feat: add the organization skills data model (#30609)
## Stack

Part of
[CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents).
This stack adds organization skills to Coder Agents: admins publish a
skill once per organization, share it with groups or members, and chats
in that organization load it next to personal and workspace skills. It
replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to
top:

1. **#30609** data model: one migration, queries, RBAC and dbauthz (this
PR)
2. #30610 organization skill API routes and the scope-neutral SDK
3. #30611 sharing ACL routes
4. #30612 settings UI: shared skills table, admin page, member section
5. #30613 chats: chatd loading, `/` menu, docs

## What changes

This PR adds the data model and authorization for organization skills.
Personal skills keep working unchanged: `git diff origin/main --
codersdk site` shows only generated RBAC and API key scope additions
(`apikey_scopes_gen.go`, `rbacresources_gen.go`,
`rbacresourcesGenerated.ts`, the RBAC and scope unions in
`typesGenerated.ts`) and `codersdk.ResourceTypeOrganizationSkill` with
its friendly string. No personal route, SDK type or site component
changes, and `coderd/userskills_test.go` changes only by mechanical
constant renames.

**One migration, `000621_skills`** (please review it closely):

- renames `user_skills` to `skills` with its constraints, index and
triggers, and recreates the cap function and
`delete_deleted_user_resources`, whose PL/pgSQL bodies name the table;
- adds `organization_id` and `project_id` (`ON DELETE CASCADE`),
`enabled` (default true), and `group_acl` / `user_acl` (`jsonb`, default
`{}`), with CHECKs for exactly one owner, ACLs that are JSON objects,
and ACLs that stay empty unless an organization owns the row, plus
partial unique name indexes per owner kind;
- replaces the cap trigger with `enforce_skills_per_owner_limit()`: 100
rows per owner, disabled rows included, locking the owner row `FOR NO
KEY UPDATE` so unrelated foreign key checks are not blocked;
- adds a `BEFORE DELETE` trigger on `organization_members` that removes
a departing member from `user_acl` on that organization's skills, so
rejoining doesn't restore a direct grant;
- adds the `organization_skill` `resource_type` and `api_key_scope` enum
values last; nothing in the migration uses them.

The down migration undoes the three old migrations in reverse order: it
drops organization and project rows and restores `user_skills`, its
names, the cap function and `user_id NOT NULL`.

Authorization: a new RBAC resource `organization_skill` (create, read,
update, delete, share). Owner and org admin get it; site and org
auditors get read; members read only through the skill's ACL, which
applies only to members of its organization. `Skill.RBACObject()`
returns the organization object with both ACLs; project rows stay denied
to everyone. New sqlc queries cover organization insert, get, list
(SQL-filtered through `GetAuthorizedOrganizationSkillMetadata` and a
`regosql` converter), update and delete, with dbauthz wrappers and the
audit table entries. No routes yet.

## Commits

The first commit reproduces the reviewed code from the old stack; each
later commit is a labeled trim or fix.

- `baa3150e3b7` feat: add the organization skills data model.
Reproduction: every non-site file this commit changes equals the
reviewed old `authz` head `1e16b3004c4`, except that the old stack's
migrations 000615, 000616 and 000617 are merged into one migration (then
`000615_skills`, now `000621_skills`) with one fixture
(`testdata/fixtures/000621_skills.up.sql`) and one migration test (now
`testMigration000621Skills`). At that commit, `dump.sql` was
byte-identical to the old head's.
- `1b84e83463a` test(coderd/database): keep only the SQL paths of the
org skill matrix. `TestOrganizationSkillAuthorization` becomes
`TestOrganizationSkillQueries` instead of being deleted, because
coverage showed it is this PR's only run of the
`GetAuthorizedOrganizationSkillMetadata` row scan (80% to 65% without
it) and of the organization update and delete queries (100% to 0%).
Swapping `group_acl` and `user_acl` in the converter makes
`GrantedMember` fail. The removed cases are decided by
`TestRolePermissions`, `TestSkillRBACObjectOrganizationACL` and the
dbauthz method suite.
- `e2931b412e9` test(coderd/database): fold the skill cap cases into
existing coverage. The user case is covered by `TestUserSkillLimit` and
`TestUserSkillLimitConcurrentCreates`; the organization case folds into
`ConcurrentOrganizationInsertsHonorCap`, which now also checks that
disabled rows count and another organization is unaffected (mutation
checked); the project case stays.
- `be62aea9021` test(coderd/rbac): drop
`TestOrganizationSkillReadScope`, covered by `TestExternalScopeNames`
and the generated scope file.
- `0c275ba37de` merges main at `454a2fcc697`, which took 000615 to
000618: it renumbers the migration to 000619 and resolves `dump.sql`,
`check_constraint.go` and the generated API docs. `8f2b4b87ee2` merges
main at `ad85646164e`, which took 000619: it renumbers the migration to
000620.
- `5248d56b64f` merges main at `e7b76872098`, which took 000620
(`000620_audit_chat_project_instructions_resource_type`): it renumbers
the migration, fixture and migration test to `000621_skills` (step
`Migration000621Skills`, version 621), and resolves
`enterprise/audit/table.go` (keeping main's
`AuditableChatProjectInstructions` entries and the `Skill` entry),
`dump.sql` and `models.go` (the `resource_type` enum gets
`chat_project_instructions`, then `organization_skill`) and the
regenerated `schemas.md`. The up and down SQL are unchanged by every
renumbering.

## Size

Production +549/-67, tests +728/-33, generated +881/-314; total
+2158/-414. This is above the 500-line reviewer-friendly limit on
purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this
stack replaces.

## Replaces

#30584 (rename `user_skills` to `skills`), #30585 (skill owners), #30586
(organization skill authorization).

## Validation

- Migration test: up keeps the existing personal row and its ID; down
restores the `user_skills` names, cap function and `NOT NULL`, and drops
organization rows; soft-deleting a user removes their skills after up,
after down, and after re-up.
- `go test` passed on `be62aea9021`, before the main merges, for
`coderd` (skill tests), `coderd/database`, `dbauthz`, `migrations`,
`gentest`, `coderd/rbac/...`, `coderd/x/chatd`, `coderd/x/skills`,
`enterprise/audit` and `enterprise/coderd`; `make lint/check-scopes`
passed; the four personal skills Vitest files pass unchanged.
- On `5248d56b64f`: build, vet, `TestMigrate`, `TestMigrationChain`, the
`migrations`, `database`, `dbauthz`, `gentest`, `rbac` and
`enterprise/audit` packages pass; `make gen` run twice is clean, and
`make pre-commit` passes.
- Remote UAT round 7 through Coder Agents passed on the whole stack; see
#30613's Validation for scope and findings.

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-13 15:51:31 +00:00
97c5260adb feat: add chat project instructions API (#30368)
Adds the experimental API for chat project instructions: `GET`, `PUT`,
and `DELETE
/api/experimental/organizations/{organization}/chats/projects/{project}/instructions`,
behind the `chat-projects` experiment.

- `GET` returns 200 with empty instructions and null
`updated_by`/`updated_at` when nothing is set, so clients don't need a
404 path.
- `PUT` requires update access only (the read-back runs under a system
context, so a custom role with update but not read can save). It
sanitizes the text with `SanitizePromptText`. It rejects blank text with
400, pointing the caller to `DELETE`, and rejects text over the chat
prompt byte limit. It records the caller as `updated_by`. The upsert and
the read-back that returns the editor's profile run in one transaction.
- `DELETE` returns 204, including when nothing is set.
- Users without access to the project get 404, like the other project
routes.
- `PUT` and `DELETE` are audited as a new `chat_project_instructions`
resource (`write` and `delete`), with the project as the resource ID and
its name as the target. The diff tracks only the instruction text.
Saving unchanged text and deleting unset instructions are not audited. A
per-project advisory lock serializes reading the previous value with the
write, so concurrent edits produce accurate diffs. Migration `000615`
adds the enum value.

The codersdk client gains `ChatProjectInstructions`,
`UpdateChatProjectInstructions`, and `DeleteChatProjectInstructions`.

**What to scrutinize:** writes are last-writer-wins with no version
precondition, matching the deployment, user, and organization prompt
settings.

**Generated:** `coderd/apidoc/docs.go`, `coderd/apidoc/swagger.json`,
and `docs/reference/api/schemas.md` come from the Swagger annotations;
`site/src/api/typesGenerated.ts` comes from `codersdk`;
`docs/admin/security/audit-logs.md`, `coderd/database/dump.sql`, and
`coderd/database/models.go` come from the audit table and migration.
Together they are about 400 of this PR's lines.

**Validation:** `make gen` leaves no diff. `go test ./coderd -run
TestChatProject` and `go test ./enterprise/coderd -run
TestChatProjectInstructions` pass. `TestChatProjectInstructionsAudit`
checks the audit entries for create, update, and delete, and that no-op
saves and deletes are not audited. It covers unset GET, create, update,
blank and oversized PUT, delete, access denial, and cascade on project
delete.

---

Stack (merge top to bottom). #30377 through #29583 are f0ssel's split of
the original #29583, and this stack sits on #29583:
- #30377 data layer and project dialog (f0ssel)
- #30378 new-chat form locked to a project (f0ssel)
- #30379 project page route (f0ssel)
- #29583 sidebar folders (f0ssel), the base of this stack
- #30291 composer frame
- #30292 project chat list caches
- #30293 project page header
- #30294 project chats list
- #30367 instructions storage and prompt injection
- #30368 instructions API 👈
- #30369 instructions editor dialog
- #30370 instructions Details panel

---------

Co-authored-by: Garrett Delfosse <delfossegarrett@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 19:15:16 +07:00
Bobby Ho dae7967bd1 feat: persist script resource addresses and dependencies (#30625)
feat(coderd): persist workspace agent script dependencies

Persist Terraform resource addresses and script dependencies supplied by
the provisioner (#30451, #30491), and expose them through the SDK and
REST API.

- Add migration 000618 with `resource_address` and `dependencies`
  columns, empty defaults, and a JSON-array constraint. API responses
  always include the address and omit empty dependency lists.
- Preserve `success` and `completion` requirements, including scripts
  on devcontainer subagents. Legacy scripts and older provisioners
  remain compatible through empty defaults.
- Reject empty prerequisite addresses and unsupported requirements,
  rolling back the entire job. Invalid stored dependencies return HTTP
  500 rather than silently dropping ordering.
- Add persistence, validation, rollback, devcontainer, API, and migration
  coverage; regenerate API docs and TypeScript types.

Unordered templates retain their existing execution behavior.
Dependency lists remain empty until #30556. Agent manifest wiring and
the agent API version bump are deferred to a follow-up.

Refs PLAT-548.
2026-10-13 03:43:55 +00:00
Ehab Younes 2f2169ed19 fix: deduplicate template insights family metrics (#30497)
coderd_insights_applications_usage_seconds summed each family's per-app
minutes, so a user with VS Code and Cursor open in the same minute was
counted as two VS Code minutes. GetTemplateInsightsByTemplate now takes
the registry's app-to-family mapping as jsonb, groups the raw agent
stats by family, and counts each minute once per user and family.

- Keep the metric's four built-in series (Visual Studio Code, JetBrains,
  Web Terminal, SSH) and their labels; only their values change. The
  HELP text now says built-in apps are grouped by family.
- Add AppFamilyName.DisplayName() and remove the duplicate
  TemplateBuiltinAppDisplayName* constants from codersdk. The template
  insights handler returns the same display names.
- Pin how the migration 000596 rollback approximates family minutes
  from per-app rows.

Family values can drop wherever the old per-app sum double-counted
overlapping apps. No migration or storage changes.
2026-10-12 23:58:35 +03:00
Michael Suchacz 41f5caafec fix: fold web searches, answer reasoning, and OpenAI narration into working blocks (#30529) 2026-10-12 22:53:07 +02:00
Atif Ali 8a063ef0d5 docs: add Claude Desktop as a supported client (#30653)
Closes
[DOCS-1198](https://linear.app/codercom/issue/DOCS-1198/document-claude-desktop-as-a-supported-coder-client)

Adds Claude Desktop alongside the other supported clients and IDEs. Once
the Coder CLI is installed and logged in, running workspaces appear in
Claude Desktop.

## Changes

- New page `docs/user-guides/workspace-access/claude-desktop.md`:
prerequisites, setup, troubleshooting.
- New `## Claude Desktop` section in `workspace-access/index.md`.
- Registered the page in `docs/manifest.json`.
- Added Claude Desktop to the IDE list in the glossary.

## Notes

- Setup steps checked against `docs/reference/cli/` and the existing SSH
docs.
- `make fmt/markdown`, `lint/markdown`, `lint/docs-manifest`,
`lint/emdash`, `lint/docs-html` pass.

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-10-12 19:09:46 +00:00
Nick Vigilante f2ddf215dc docs(docs/user-guides/workspace-access): fix broken vscode-coder demo GIF links (#30655)
Closes
[DOCS-1201](https://linear.app/codercom/issue/DOCS-1201/fix-broken-vscode-coder-demo-gif-links-in-workspace-access-docs)

## Summary

coder/vscode-coder#1134 moved `demo.gif` from the repo root into
`media/`, so the VS Code demo GIF embed now returns a 404.
Linkspector flagged it on #30653
([thread](https://github.com/coder/coder/pull/30653#discussion_r4249822055)).

## Changes

- Point the demo GIF embed at `media/demo.gif` in
`docs/user-guides/workspace-access/index.md` and `vscode.md`.

## Testing

- `curl -sIL`: new URL returns 200, old URL returns 404.
- `make lint/markdown` and `make fmt/markdown` pass.

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑‍💻
2026-10-12 14:50:24 -04:00
coder[bot]andAtif Ali 8674e8529e docs: note coder_agent dir un-deprecation in 2.29-2.34 ESR upgrade guide (#30533)
## Summary

Follow-up to
[coder/terraform-provider-coder#549](https://github.com/coder/terraform-provider-coder/pull/549),
which un-deprecated `coder_agent.dir`.

The 2.29-2.34 ESR upgrade guide still says `dir` is deprecated, warns,
and breaks Coder Desktop file sync, and tells admins to set it to
`$HOME`. As planned in #549, this keeps the original row as history and
appends an **Update** to the New State and Action cells:

- Coder Terraform provider 2.20.0 removed the deprecation and warning.
- Coder Desktop file sync works with any `dir` on macOS
[v0.8.4](https://github.com/coder/coder-desktop-macos/releases/tag/v0.8.4)
and Windows
[v0.8.5](https://github.com/coder/coder-desktop-windows/releases/tag/v0.8.5)
(Mutagen v0.18.5,
[coder/mutagen#10](https://github.com/coder/mutagen/pull/10)).

The rest of the diff is `markdown-table-formatter` re-padding the table.
`markdownlint-cli2` passes.

## Merge timing

Opened as a draft. #549 is only in `v2.20.0-pre0` so far; mark ready and
merge once provider 2.20.0 is published to the registry. If the release
number changes, update the version in the row.

Review requested from @aqandrew.

---
Opened by Superblink on behalf of @matifali.

Co-authored-by: coder[bot] <137810501+coder[bot]@users.noreply.github.com>
Co-authored-by: Atif Ali <atif@coder.com>
2026-10-12 23:47:48 +05:00
Denis AfonsoandClaude d7bf081e57 docs: point the 2.29 ESR row at v2.29.21 (#30538)
Updates the latest-patch link for the 2.29 Extended Support Release in
the release calendar to
[v2.29.21](https://github.com/coder/coder/releases/tag/v2.29.21),
released 2026-10-09.

One-line change; no other rows touched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-12 15:57:02 +01:00
Ehab Younes 5b060beeb1 feat: separate connection log methods from app names (#30466)
Connection logs now record how a connection was made
(`connection_method`) separately from which app made it (`app_name`).
Storage, the HTTP API, search filters, and the UI move to the new
fields. Legacy agent reports and the deprecated `type` field keep
working.

- Add `connection_method` (`ssh`, `reconnecting_pty`, `workspace_app`,
  `port_forwarding`, `tunnel`) and optional `app_name` and
  `app_display_name` to `GET /api/v2/connectionlog`. Deprecate `type`
  and make it a plain string in the API and the Go SDK.
- Add `method:` and repeatable `app:` search filters. `type:` keeps its
  old results but can't be combined with the new filters.
- Replace the Type menu with a Method menu, show the app next to the
  method in each row, and warn when a filter uses `type:`.
- Change the Active SSH connections preset to `method:ssh`, so it also
  includes SSH sessions from VS Code and JetBrains apps.
- Generate `codersdk.ConnectionLogMethod` from the database enum with
  `typegen dbenums`.
- Migration 000617 rewrites `connection_logs` under an ACCESS EXCLUSIVE
  lock, which takes about 50 seconds for 10 million rows. `vscode` and
  `jetbrains` rows become `ssh` rows with that app. Rolling back folds
  apps into the old types and loses per-app names.
- Document the new filters and how to replace each `type:` value.

Closes #27412
2026-10-12 15:56:40 +03:00
Thomas Kosiewski f923f4a525 chore!: remove the chat automations experiment (#30412)
Removes the experimental Chat Automations feature (`chat-automations` experiment) from main. This reverts the 16-PR stack that added it and adds two forward migrations that undo its schema and credential changes.

> [!WARNING]
> **Upgrade consequences**
>
> - **Automation data is deleted.** Migration 000615 drops the `chat_automations` table and deletes every queued message an automation delivered. Chats, their messages and ordinary queued messages stay. Messages lose their automation provenance (`automation_id`, `input_id`).
> - **Automation-only credentials are revoked.** Migration 000616 deletes API keys, OAuth2 codes and OAuth2 tokens whose only scopes (or allow-list entries) were `chat_automation:*`. Mixed credentials keep their other scopes. Custom roles lose their `chat_automation` permissions. OAuth2 apps that allowed only `chat_automation` scopes get the whitespace allowlist that grants nothing, as in 000595.
> - **A coordinated restart is required.** Stop all old replicas before the new version runs the migrations. Old replicas read the dropped table and columns, so a rolling deploy is not supported.
> - **Remove `--chat-max-automations-per-owner` before upgrading.** The flag, the YAML key `chat.maxAutomationsPerOwner` and the env var `CODER_CHAT_MAX_AUTOMATIONS_PER_OWNER` are removed. A deployment that still sets the flag or the YAML key will not start (`unknown flag` / `unknown option`). The env var is ignored. This includes dogfood. No release or tag contains the flag.
> - **Down migrations restore the schema only.** 000616 down and 000615 down recreate the 000611 schema with empty tables. They do not restore deleted automations, webhook secrets, provenance, queued deliveries, revoked credentials, stripped permissions or the deleted experiment rule.

## What is removed

- The `chat-automations` experiment and its stored runtime rule (`experiment_rule:chat-automations`).
- The `--chat-max-automations-per-owner` deployment option.
- The `chat_automation` RBAC resource, its member and chatd grants, and the `chat_automation:*` API key scopes.
- The automation sqlc queries, dbauthz wrappers and audit table entries.
- The management routes under `/api/experimental/organizations/{organization}/chat-automations`, and the webhook route `POST /api/experimental/chat-automations/{automation}/events` with its rate limiter.
- The chatd management service, webhook publish, schedule loop, the `manage_automations` tool, and the chatstate admission seam and queue promotion guard that only automations used.
- The Agents Automations page, editor, nav entry, chat labels, the Manage automations toggle and the API client.
- The `archived:any` chat search value that the automations "View chats" dialog added.
- `docs/ai-coder/agents/automations.md`, its manifest entry, the glossary entry and the related rows.

Reverted PRs: #30085, #30096, #30112, #30117, #30127, #30134, #30160, #30166, #30167, #30171, #30187, #30207, #30214, #30217, #30219, #30220.

## What stays, and why

- Migrations 000609, 000610 and 000611, their fixture, and the #30297 lock fix with `migration000609_test.go` stay unchanged. Deployments such as dogfood already ran them.
- New migration **000615** reverses the schema changes of 000609 and 000611 against the current schema. It uses the same short-wait lock-and-retry block as 000609, and it rebuilds `chats_expanded` from main's current definition minus the two automation columns. New migration **000616** follows the 000595 Tasks removal for credentials and recreates `api_key_scope` without the five `chat_automation:*` values. It keeps the `chat_project_memory:*` values from 000612.
- The `chat_automation` value stays in the `resource_type` enum, and `codersdk.ResourceTypeChatAutomation` stays. Old audit log rows stay readable, as with `task` after the Tasks removal.
- The 000615 delete fires the existing queue-version trigger, so `queue_version` moves to `snapshot_version` for each affected chat. `snapshot_version` is not bumped: the coordinated restart restarts every stream loop from an empty state, and the site does not read the version fields.
- `coderd/x/chatd/ARCHITECTURE.md` drops the sections the stack added and gets back its pre-stack wording, merged with the later main edits to the same file.

## Notes for reviewers

- #30379 (chat project page) merged while this PR was in progress. It passed `manageAutomationsEnabled` in `AgentCreatePage.test.tsx` and listed an `automations` route in `AgentsPageLayout.test.tsx`. Later main commits also added automation props in `ConversationTimeline.test.tsx` and `ConversationTimelineWorkingBlocks.stories.tsx`. This PR removes all of them.
- Remaining `automation` matches under `coderd`, `codersdk`, `enterprise`, `site/src` and `docs` are intended:
  - migrations 000609 to 000611, their fixture and `migration000609_test.go`;
  - the new 000615 and 000616 migrations and `migration000615_test.go`;
  - the `chat_automation` resource type in `dump.sql`, `models.go`, `codersdk/audit.go`, the generated API docs, `swagger.json` and `typesGenerated.ts`;
  - unrelated uses of the word "automation" (docs, `chatlabels_test.go`, `ratelimit.go`, `autostop.go`, `subagent_catalog.go`, `WorkspaceSharingSection.tsx`, `AgentChatPage.stories.tsx`).

Remote UAT on an isolated dev deployment passed. It upgraded a populated pre-removal database, then checked chats, queued messages, tokens, the 404 routes, the removed page and nav entry, and the experiments list.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

![Agents sidebar after the upgrade, with no Automations entry](https://github.com/user-attachments/assets/bd446035-7fc8-4ca4-a735-3a4f36380738)
2026-10-11 19:57:49 +02:00
dfa72df9aa docs: remove references to unsupported SAML authentication (#30507)
## Summary

Coder doesn't support SAML, but a few docs pages implied it did.
This PR removes those mentions.

Resolves
[DOCS-1194](https://linear.app/codercom/issue/DOCS-1194/remove-saml-mentions-from-docs-coder-doesnt-support-saml).

## Changes

- `docs/install/index.md` and `docs/install/prepare/index.md`: "OIDC or
SAML application" is now "OIDC application".
- `docs/.style/style-guide/audience-and-scope.md`: the example snippets
no longer mention SAML or link to a `./saml.md` page that doesn't exist.
The hub-page example now lists headless authentication instead, and the
persona "Coder surface" lines say "OIDC" in place of "OIDC/SAML".

<details>
<summary>Evidence that Coder doesn't support SAML</summary>

Checked against `main`:

- No SAML library in `go.mod`, `go.sum`, or `site/package.json`.
- The `login_type` enum in `coderd/database/dump.sql` and
`codersdk.LoginType` only cover `password`, `github`, `oidc`, `token`,
`none`, and `oauth2_provider_app`.
- No SAML handlers, endpoints, or deployment options in `coderd/` or
`enterprise/`.
- The only code mention is a comment in `coderd/userauth.go` about
SAML-to-OIDC bridges sending `email_verified` as a string.

</details>

## Testing

- `pnpm run lint-docs`: 0 errors.
- The pre-commit hook passed.
- `git grep -i saml -- docs` returns nothing.

---

*Generated by Coder Agents on behalf of @nickvigilante.*

---------

Co-authored-by: Ben Potter <me@bpmct.net>
Co-authored-by: Ben Potter <ben@coder.com>
2026-10-11 08:36:17 -07:00
McKayla はな 86ebc72236 chore: remove unused autofill-parameters endpoint and experiment (#30525) 2026-10-09 16:42:41 -06:00
coder[bot] f8e053e385 docs: document VS Code SSH keepalive and reconnection settings (#30501) 2026-10-09 18:43:18 +05:00
Michael Suchacz 782fb30f09 feat: load whole chat turns per history page (#30524)
Closes
[CODAGT-1372](https://linear.app/codercom/issue/CODAGT-1372/load-whole-turns-per-history-page-so-collapsed-working-blocks-fill-in).

With collapsed working blocks, a long agent turn renders as one row, but
chat history pages hold a fixed 50 messages. A 400-step turn took about
eight sequential page loads to fill, and its block showed partial labels
("at least", "or more") until then.

`GET /api/v2/chats/{chat}/messages` now returns `turn_start_id` on
newest-first pages: the ID of the user prompt that starts the turn
containing the page's oldest message. It comes from a new
`GetChatTurnStartID` query on the existing
`idx_chat_messages_user_prompts` index, so there is no migration.
Soft-deleted prompts and model-only user rows never start a turn.

The history query then fills each page back to that prompt with requests
of up to 200 messages, capped at 1000 messages per page, so a page holds
whole turns and a complete block renders without partial labels. Past
the cap, or when a fill request fails or returns no messages, the page
keeps what loaded and ends mid-turn, and the next page continues it, as
before. Because the fill runs inside the page fetch, a chat now waits
for its fill requests (one to five) before it first renders: with an
injected 500 ms per-request delay, a chat whose newest turn hits the cap
appeared after 3.8 s instead of 1.1 s.

## Screenshots

From the dogfood UAT, the same 200-step turn with its next history
request held, so each label shows only what loaded before it:

**Before**, on the base commit `29e876df4da`, after two 50-message
pages: "Worked for at least 1m 35s (48 steps or more)", partly hidden by
the loading indicator.

![Before: partial label for a 200-step
turn](https://github.com/user-attachments/assets/6b4e4abf-4bc6-4476-8ed5-52c39c8eebe6)

**After**, on `186a9b053a0`, after the first page: "Worked for 6m 39s
(200 steps)".

![After: exact label for the same 200-step
turn](https://github.com/user-attachments/assets/22ec1900-1e7b-4c98-87a9-0463e1d852c2)

A 750-step turn, larger than one 1000-message page, is exact once the
next page loads:

![After: 750-step turn,
expanded](https://github.com/user-attachments/assets/f927a848-62b1-4eb7-a548-fbdff61fc9c4)

A malformed fill response keeps the loaded messages and the partial
label instead of showing "Failed to load chat", as `ecdfb27ec29` did:

![Malformed fill response: partial label, no error
screen](https://github.com/user-attachments/assets/6d393df9-15a2-471e-9bb6-71e919aca570)

## Testing

- Go: `TestGetChatMessages_TurnStartID` (pages spanning turns, deleted
prompts, model-only user rows, polling and empty pages) and the dbauthz
suite entry.
- Vitest: fill request parameters, the 1000-message cap, failed,
malformed, and empty fill responses, and servers without
`turn_start_id`.
- Dogfood UAT through Coder Agents: PASS on `186a9b053a0` (round 4):
whole-turn first pages, the 1000-message cap and its continuation, fill
failures, a live turn, and API checks for deleted prompts and model-only
user rows. Round 3 on `ecdfb27ec29` failed: a malformed fill failed the
chat load, and an empty fill reporting `has_more` repeated forever.
`7266f468290` fixes both, with regression tests.

## Review record

- Test audit with mutation checks: the Go test now covers a page
spanning two turns, which catches a lookup keyed on the newest message.
A re-audit of later test changes changed nothing; the one surviving
mutation drops the `!older.has_more` stop, costing one extra request
when the prompt is deleted mid-fill.
- Frontend review (8 roles, 5 rounds): fixed doc, naming, loose-type,
and test findings. Its suggestions to catch only the fill request (DF5)
and drop the empty-page stop (SD4) caused the round 3 failures and are
reverted. Kept: SD1 (`MAX_MESSAGES_PER_REQUEST` is used once, named like
`MESSAGES_PAGE_SIZE`) and round 5 SD4 (`!older.has_more` is the
endpoint's pagination signal). Declined DF6: the `queued_messages`
refetch race predates this change, and a failed refetch fill only
unloads older history that reloads on scroll.
- Codex: no findings on `186a9b053a0`.
- Known: a hung fill delays the first render (no client timeout); fills
are not cancelled when the user leaves; the top of history costs one
extra empty request; injected malformed fill rows break the page as they
do on the first page.

> Xum opened this PR on behalf of @ibetitsmike.
2026-10-09 13:32:39 +02:00
Michael Suchacz 6bae268487 fix: move organization instructions to the Instructions page (#30428)
Moves organization instructions (#30272) from the Coder Agents page to
**AI Settings** > **Coder Agents** > **Instructions**, so every Coder
Agents instruction is managed on one page. The API and stored data are
unchanged.

- **Deployment admins** see a "Deployment instructions" section with the
existing system prompt and plan mode form, then an "Organization
instructions" section. The organization section has an organization
picker when there is more than one organization.
- **Organization admins and auditors** who can read an organization's
chat model configuration get an Instructions entry in the AI settings
sidebar and see only the organization section. Auditors get it
read-only.
- The selected organization is kept in `?org=`, and the sidebar link
carries it over from the other AI settings pages.
- The Coder Agents page goes back to its layout from before #30272. Its
sections and the new page's sections share new `SettingsSection` and
`OrganizationSettingsSection` components.
- Three docs pages point to the new location.

Other behavior changes:

- The deployment section shows a loader while loading and an error alert
when loading or refreshing fails. Before, the page rendered nothing
until both settings loaded.
- The deployment forms no longer have their own accessible names,
because each section is named by its heading.

## Testing

- Vitest for the Instructions page and sidebar link, and stories for the
new states. Breaking each of the 9 main code paths, or removing the
instructions field's accessible name, fails its test.
- The branch merges `main` for #30402, which made the organization
picker a combobox.
- CI passes on `a0cc6a98660`.
- Remote dogfood UAT, [evidence
chat](https://dogfood.cdr.dev/agents/1cbf9da4-9671-4890-ade1-c151a1a69cd7):
**PASS** on `a0d9c3fca46`, 14 scenarios across every role, `?org=`
handling, injected load failures, keyboard use, and a 390 px layout. The
remote agent's FAIL (a double-click on Save sends 2 PUTs) also happens
on the merge base, so it predates this PR. Delta round on `a0cc6a98660`:
**PASS**. When the permission re-check fails, the owner and an
organization admin see the alert above the organization section, and the
unsaved draft stays and saves.
- UAT notes left as is: the fallback for an unreadable `?org=` is
read-only, as on the Coder Agents page; `?org=` matching is
case-sensitive, as on the Models and Spend pages; the old
`/agents/settings/instructions` redirect drops `?org=`; the permission
alert shows the server's error message without saying which check
failed, as on the Models pages.

## Screenshots

From UAT on a test deployment.

| Organization admin | Owner, after a failed refresh (unsaved edit kept)
|
|---|---|
| ![Organization admin sees only the organization
section](https://gist.githubusercontent.com/ibetitsmike/1027eba97c252d6f3e921d2f46debd01/raw/8c6baf5a5b4784cdfecd066fae54af7f4f3c4881/r3-org-admin-instructions.png)
| ![Error alert above the deployment
form](https://gist.githubusercontent.com/ibetitsmike/1027eba97c252d6f3e921d2f46debd01/raw/8c6baf5a5b4784cdfecd066fae54af7f4f3c4881/r3-owner-refresh-error-draft-kept.png)
|
| **Coder Agents page, no instructions card** | **Unavailable `?org=`:
warning and read-only fallback** |
| ![Coder Agents
page](https://gist.githubusercontent.com/ibetitsmike/1027eba97c252d6f3e921d2f46debd01/raw/8c6baf5a5b4784cdfecd066fae54af7f4f3c4881/r3-coder-agents-page.png)
| ![Unavailable organization
warning](https://gist.githubusercontent.com/ibetitsmike/1027eba97c252d6f3e921d2f46debd01/raw/8c6baf5a5b4784cdfecd066fae54af7f4f3c4881/r3-unavailable-org-fallback.png)
|

## Review record

1. `coder-frontend-review` (8 reviewer agents) on `3dd65e828f9`: fixed
in `a0d9c3fca46` (deployment refetch errors were dropped, plus naming,
prop types, test waits, and a single-organization story). Declined:
`SettingsHeader` in `SettingsSection` and merging the sidebar groups
(both change existing layout), and restructuring the moved card (git
would stop detecting the move).
2. `frontend-review` (FE1 to FE10) on `a0d9c3fca46`: every rule passes,
no changes.
3. Codex,
[review](https://github.com/coder/coder/pull/30428#pullrequestreview-5431118231)
on `a0d9c3fca46`: 1 P2, a docs sentence wrote "more than 1" where the
numbers guide spells out "one". Fixed in `0e71b8f16b9`.
4. Codex,
[review](https://github.com/coder/coder/pull/30428#pullrequestreview-5431285875)
on `0e71b8f16b9`: 2 findings, each confirmed by a failing test and fixed
in `a0cc6a98660`. A failed background re-check of organization
permissions showed no alert, unlike the old Coder Agents page and the
Models pages (P2). The page tests found the instructions field by its
value, so removing its accessible name went unnoticed (P1).
5. `coder-frontend-review` (8 reviewer agents) and `frontend-review`
(FE1 to FE10) on `a0cc6a98660`: everything passes, no changes. The round
1 `findByDisplayValue` suggestion is reversed, because FE10 asks for
role and name queries.
6. Codex on `a0cc6a98660`: [no major
issues](https://github.com/coder/coder/pull/30428#issuecomment-6020794170).

> Xum, an AI coding agent, implemented, tested, and opened this PR on
behalf of @ibetitsmike.
2026-10-09 11:14:59 +02:00
Mathias Fredriksson befda9b29f docs: mention chat reasoning_tokens is part of output_tokens (#30500)
Document that reasoning_tokens is included in the output_tokens on
ChatMssageUsage, which is the case for all known providers.

Refs CODAGT-1350
2026-10-09 12:12:08 +03:00
Atif Ali 261269aff0 fix: support path-aware OAuth discovery for remote MCP (#30168)
## Problem

VS Code discovers Coder's MCP endpoint as a path-qualified OAuth
resource, but Coder advertises the deployment root. Accepting MCP-bound
tokens also requires keeping REST-backed tool calls within the
originating MCP resource rather than granting those tokens direct REST
access.

## Fix

- Publish path-aware protected resource metadata and authentication
challenges; keep authorization-server metadata at the root.
- Validate the MCP audience and delegate tool requests through a private
in-process transport that retains identity, scopes, expiry, revocation,
and streaming cancellation.
- Reject unsupported MCP path aliases and validate SDK path components
before URL resolution.
- Add discovery, audience, authorization, endpoint-isolation, and
transport lifecycle regression tests and update integration docs.

## Validation

VS Code completed OAuth and returned the authenticated user through a
real MCP tool. Official MCP SDK 1.30.1 completed discovery,
registration, PKCE, tool execution, and refresh. These live checks
preceded the final path hardening; the hardened paths are covered by
automated regressions.

Affected Go package tests, targeted race tests, backend/SDK lint, and
targeted documentation checks passed during self-review. The exact PR
commit was also checked separately from the uncommitted consent-scope
fix.

> [!NOTE]
> Tokens are MCP-audience-bound, but grants still include `coder:all`;
least-privilege scopes remain a separate requirement
([PLAT-639](https://linear.app/codercom/issue/PLAT-639)).

Preview:
https://coder.com/docs/@fix/mcp-internal-delegation/ai-coder/mcp-server

<details>
<summary>Implementation decisions and review context</summary>

1. Treat `/api/experimental/mcp/http` and its single-trailing-slash form
as supported MCP resource paths; reject other aliases and descendants
before route authentication.
2. Preserve deployment-root discovery and authorization-server metadata
for existing REST integrations.
3. Bind private delegation to the authenticated API-key ID. Revalidate
the original credential and enforce normal RBAC/scopes on every internal
REST request; do not derive delegation from HTTP headers.
4. Keep internal HTTP, streaming, and WebSocket traffic in-process with
no network fallback. Close the transport on outer-request cancellation
and normal completion.
5. Validate workspace owner/name path segments before SDK URL
construction, including tool-level tests that malformed arguments cannot
select a different REST endpoint.
6. Keep compatibility and delegated tool execution together:
discovery-only changes would allow authentication while leaving real MCP
tool calls broken.

</details>

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-10-09 00:58:39 +05:00
Nick Vigilante a8303a8f2b feat!: add output formats to coder schedule start, stop, and extend (#30136)
`coder schedule start`, `stop`, and `extend` printed the updated
schedule as a fixed table with no `-o` or `-c`, while `coder schedule
show` has both.

All four commands now share one formatter with the same row type,
default columns, `-o table|json`, and `-c`, so the output of a change
and of `show` is interchangeable.

**Behavior change:** Adds `-o` and `-c` to the three commands.
The default table output changes slightly: the WORKSPACE column no
longer includes the favorite-star prefix, matching `schedule show`.
Other columns are unchanged.

<details>
<summary>Decisions</summary>

- Previously these commands rendered `WorkspaceListRow`, which prefixes
the workspace name with a favorite icon. Using `scheduleListRow` for
consistency with `schedule show` drops that prefix.

</details>

Closes [CLI-15](https://linear.app/codercom/issue/CLI-15)

_This PR was generated by Coder Agents on behalf of @nickvigilante._
2026-10-08 13:07:17 -04:00
Nick Vigilante 98bcc3afb7 fix!: remove the unused --yes flag from coder autoupdate (#30149)
`coder autoupdate` has registered `-y/--yes` since #10438 but never
prompts, so the flag did nothing.
This PR removes it.

**Breaking change:** `coder autoupdate` no longer accepts `-y/--yes`.
Scripts that pass it now fail with `unknown shorthand flag: 'y'`.
To fix them, drop the flag; it never had an effect.

<details>
<summary>Decisions</summary>

- The first version kept `-y` as a hidden no-op so existing scripts
wouldn't break.
- Reviewers preferred removing it outright as a breaking change, since a
deprecation period would end in the same removal and the hidden flag is
cruft.
- The title uses `fix!:` and the PR carries `release/breaking`, so the
release tooling lists it under breaking changes.
- `cliui.HiddenSkipPromptOption()` landed on `main` through the
organizations create PR and stays there for that command; this PR no
longer touches it.
- The test now pins the new behavior: passing `-y` returns an unknown
flag error.

</details>

Closes [CLI-33](https://linear.app/codercom/issue/CLI-33)

_This PR was generated by Coder Agents on behalf of @nickvigilante._
2026-10-08 11:55:29 -04:00
Andrew G. Dunn c11d60ad8d docs: note the pubsub cluster port between HA replicas (#30290)
HA replicas connect to each other's embedded NATS pubsub on TCP 6222.
The port is hardcoded
([`coderd/x/nats/pubsub.go`](https://github.com/coder/coder/blob/7f3d35353eddcd8a9e573094e5e2531bd2d73659/coderd/x/nats/pubsub.go#L62))
with no flag or environment variable, and since #29283 NATS pubsub is on
by default. The HA page explains `CODER_CLUSTER_HOST` but doesn't name
the port, so a firewall or default-deny NetworkPolicy between `coderd`
nodes blocks it. This adds the port, and what happens without it, next
to `CODER_CLUSTER_HOST`.

Measured on v2.37.3 (`CODER_EXPERIMENTS=nats_pubsub`, the default on
main) with two replicas on GKE under a default-deny NetworkPolicy, port
8080 open between the replicas in both runs. Through a port-forward to
replica B, `PUT /api/v2/workspaces/{id}/extend` publishes a workspace
update in the request path. A watcher on `/api/v2/workspaces/{id}/watch`
through replica A counts the events. The control sends the same request
through A.

6222 blocked:

```text
label=blocked A=coder-699ccb59f8-695bj B=coder-699ccb59f8-w8glp baseline_data_events=1
control: extend via A -> HTTP 409; data events on A: 1 (expect 1)
test: 5x extend via B -> HTTP 409 409 409 409 409; data events on A: 0
coder-699ccb59f8-695bj :6222 established: 0
coder-699ccb59f8-w8glp :6222 established: 0
```

6222 allowed between the replicas (same pods, no restart):

```text
label=allowed A=coder-699ccb59f8-695bj B=coder-699ccb59f8-w8glp baseline_data_events=1
control: extend via A -> HTTP 409; data events on A: 1 (expect 1)
test: 5x extend via B -> HTTP 409 409 409 409 409; data events on A: 5
coder-699ccb59f8-695bj :6222 established: 4
coder-699ccb59f8-w8glp :6222 established: 4
```

The 409s are expected because the workspace is stopped; the handler
publishes the update before it returns
([`coderd/workspaces.go`](https://github.com/coder/coder/blob/3a248167f6e58462a8a8cddba3b49a8ff72a9f80/coderd/workspaces.go#L1711)
at v2.37.3).

Would it also make sense for the chart to declare 6222 as a container
port, or for the port to be configurable? I left both out of this
change.

AI involvement: I used an AI assistant to draft this change, and
verified it with the runs above against a two-replica deployment.
2026-10-07 19:21:29 -04:00
Andrew G. Dunn 020b437ec9 docs: document dropping capabilities for restricted Pod Security (#30271)
Following the suggestion in #22543 to have
`coder.securityContext.capabilities` in `values.yaml` without a default,
this adds it as a commented example, the same way `values.yaml` shows
`env` and `initContainers`, and adds one line to the Kubernetes Security
Reference. Existing deployments don't change on upgrade.

The chart's default security context passes every Pod Security Standards
`restricted` check except capabilities, so a namespace that enforces
`restricted` rejects the pod. Because the example is commented out, the
rendered chart is unchanged:

```console
$ diff main.yaml branch.yaml && echo "renders identical ($(wc -l < branch.yaml) lines)"
renders identical (208 lines)
```

Server-side dry runs of this branch's chart into a namespace labeled
`pod-security.kubernetes.io/enforce=restricted` (GKE, Kubernetes 1.35),
using the pod spec from the rendered Deployment, as is and with the
example uncommented:

```console
$ kubectl create --dry-run=server -n coder -f pod-branch.json
Error from server (Forbidden): error when creating "pod-branch.json": pods "pss-main-branch" is forbidden: violates PodSecurity "restricted:latest": unrestricted capabilities (container "coder" must set securityContext.capabilities.drop=["ALL"])
$ kubectl create --dry-run=server -n coder -f pod-branch-drop.json
pod/pss-main-branch-drop created (server dry run)
```

A v2.37.3 deployment with the value set runs in a `restricted`
namespace, ready with no restarts.

AI involvement: I used an AI assistant to draft this change, and
verified it with the commands above against a running cluster.
2026-10-07 23:18:04 +00:00
dylanhuff-at-coderandNick Vigilante b4d51012da feat: allow template version selection for workspace builds (#30199)
Add named template version selection to `coder start` and `coder stop`,
and independent stop/start selection to `coder update` with
`--stop-template-version` and `--template-version`. Stop still defaults
to the workspace's current version, and update starts with the active
version by default. Explicit selections use the selected version for
parameter preparation and builds, keep server permissions authoritative,
and never silently fall back to the active version.

Classic stop builds retain previous parameter values omitted by the
selected stop version, so a later start can reuse them across separate
commands or an interrupted update. Declared parameters still follow
normal validation, and start builds still discard removed parameters.
Update now returns an error and retry guidance when a start apply fails
after stopping, including unflagged updates that previously returned
success.

Closes #29100


[PLAT-616](https://linear.app/codercom/issue/PLAT-616/cli-allow-specifying-a-template-version-for-stopstart-builds-and-both)

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-10-07 13:17:12 -07:00
Jakub Domeracki b4fb7901e6 docs: clarify that disable-password-auth also applies to owners (#30362)
The `--disable-password-auth` help text says owners can still sign in
with a password "to avoid potential lock out", and a comment in
`coderd/userauth.go` says the same. Neither is true. #6193 removed the
owner bypass on purpose, so the flag blocks password login for everyone.
The recovery advice was also wrong. It named a command that doesn't
exist (`create-admin`), and any admin that `create-admin-user` creates
while the flag is on still can't sign in.

This PR changes docs and comments only:
- Rewrites the flag description to say it applies to owners too and how
to recover access. Regenerated the CLI and config reference docs and the
golden files.
- Fixes the misleading comment in `coderd/userauth.go`.
- Adds the same warning and recovery steps to
`docs/admin/users/password-auth.md`.

> [!NOTE]
> Generated by Coder Agents on behalf of @jdomeracki-coder.
2026-10-07 19:03:46 +02:00
blinkagent[bot]andblink-so[bot] c9680e4f36 docs: correct the CODER_AGENT_BLOCK_FILE_TRANSFER block list (#29705)
## Problem

The FAQ entry _"How can I restrict inbound/outbound file transfers from
Coder workspaces?"_ documents the wrong block list for
`CODER_AGENT_BLOCK_FILE_TRANSFER`.

It currently says the list includes `scp`, `rsync`, `ftp`, and `nc`.

The actual list in
[`agent/agentssh/agentssh.go`](https://github.com/coder/coder/blob/main/agent/agentssh/agentssh.go)
is:

```go
// BlockedFileTransferCommands contains a list of restricted file transfer commands.
var BlockedFileTransferCommands = []string{"nc", "rsync", "scp", "sftp"}
```

So the docs have two errors:

- **`ftp` is documented but is not blocked.** An admin reading this page
could reasonably believe `ftp` is covered when it is not.
- **`sftp` is blocked but is not documented.** This matters
operationally, because SFTP is blanket-blocked at the subsystem level
(`if session.Subsystem() == "sftp"`), which disables anything built on
it.

## Changes

1. Correct the block list to match the source, in the same order as the
slice so the two are easy to diff by eye in future:

```diff
-block list, which includes `scp`, `rsync`, `ftp`, and `nc`.
+block list, which includes `nc`, `rsync`, `scp`, and `sftp`.
```

2. Per review feedback, add a note to **Important Notice** covering what
enabling this actually breaks: SFTP-based tooling, and [Coder Desktop
file
sync](https://coder.com/docs/user-guides/desktop/desktop-connect-sync).

Desktop file sync breaks via `scp` rather than `sftp`. It runs Mutagen
over SSH, and Mutagen's SSH transport installs its remote agent binary
by shelling out to `scp`
([`pkg/agent/transport/ssh/transport.go`](https://github.com/coder/mutagen/blob/v0.18.3/pkg/agent/transport/ssh/transport.go)),
which is on the block list. The note keeps that distinction because an
admin debugging it will see an `scp` failure, not an SFTP one.

## Correction

An earlier revision of this description claimed `coder cp` is also
blocked. **That was wrong — there is no `coder cp` command.** No
`cli/cp.go`, no `docs/reference/cli/cp.md`, no `cp` entry in the CLI
index. I've removed the claim rather than document a command that
doesn't exist. Discussed in the thread below.

## Not included

Linking the FAQ to [Agent
Firewall](https://coder.com/docs/ai-coder/agent-firewall) from the "For
more advanced security needs" line, which currently only says "consider
adopting an endpoint security solution." Happy to add if wanted, but it
felt out of scope for a correctness fix.

Also note I only verified the macOS Desktop client.
`coder-desktop-windows` and `coder-desktop-linux` are very likely the
same Mutagen setup, but I didn't read them, so the note makes no
per-platform claim.

Created on behalf of @bartekgatzcoder.

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-10-07 15:02:55 +00:00
Ehab Younes d56cc3a6c3 docs(docs/support): clarify VS Code support bundle requirements and limits (#30430)
Refs VSC-25, #30118
2026-10-07 11:48:47 +03:00
Ehab Younes fc01bee831 fix: keep new API keys within the caller's scopes and allow list (#30256)
A scoped key holding api_key:create could mint a broader key, e.g. a token scoped to [api_key:create user:read] could mint coder:all.

- New keys must be covered by the caller's scopes and allow list, and inherit them when none are requested
- Requests beyond the caller return 403
- New key expiry is capped at the caller's
- Covers POST /users/{user}/keys/tokens, POST /users/{user}/keys, app auth-redirect, and /oauth2/authorize (invalid_scope on excess grants or a restricted session allow list)
- coder:all sessions, including browser logins, behave as before
- Not addressed: workspace start still mints a coder:all key for the owner
2026-10-07 11:43:19 +03:00
Michael Suchacz e4682343e6 feat: match PR number prefixes in chat search (#30404)
Chat search now matches PR numbers by prefix, so typing `3028` already
finds the chat for PR `30281` instead of showing zero results
mid-typing.

The free-text `search:` branch in `GetChats` switches from `pr_number =
@search::bigint` to `pr_number::text LIKE @search || '%'`, still guarded
by a digits-only regex so the value can never carry LIKE wildcards. The
lookup stays a correlated per-chat EXISTS on the `chat_diff_statuses`
primary key, which leads with `chat_id`, so the cost is the same as
before and no new index is needed. The explicit `pr:` filter stays
exact, and ordering is unchanged (no exact-match ranking) so cursor
pagination is unaffected.

Behavior note: values with leading zeros (`030281`) no longer match PR
`30281`, since the old bigint cast normalized them. PR numbers never
have leading zeros, so this seemed fine.

Closes CODAGT-1342

## Testing

- `TestGetChatsSearch` gains prefix (`4` -> PR 42), no-infix (`2` ->
none), and LIKE-wildcard (`4%` -> none) cases; the prefix case fails on
the old predicate.
- Dogfood UAT through Coder Agents on the branch: searching `3`, `302`,
`3028`, `30281` all surface the PR-linked chat; `0281` and `302810` do
not; `pr:3028` stays exact.

> [!NOTE]
> This PR was created by Xum acting on behalf of @ibetitsmike.
2026-10-06 22:42:56 +02:00
Ian Evans 21c1abe9ad docs(docs/install): reformat to one sentence per line (#30438)
Reformats every Markdown page under `docs/install` to the
[one-sentence-per-line
convention](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line).
Addresses DOCS-668.

This is a source-layout change only: 28 of the 36 pages change, and
rendered HTML is identical for all of them except three wording fixes.
Three pre-existing em dashes sat on reflowed lines, which `lint/emdash`
flags as new, so they're rewritten with commas or a sentence break
(`operate/upgrade/esr-2.24-2.29-upgrade.md`,
`operate/upgrade/best-practices.md`).

Front matter, fenced code, tables, HTML blocks, and headings are
untouched.

`Coder.OneSentencePerLine` is not enabled for `docs/install` in
`.vale.ini`: the 39 remaining findings are all table rows or code, which
the guide puts out of scope, and enabling the rule would break the
zero-baseline doctrine.

<details>
<summary>Implementation and verification notes</summary>

**Approach.** A throwaway script reflowed each paragraph. Bullet items,
numbered entries, and blockquote lines (including `> [!NOTE]` callouts)
are each their own paragraph; extra sentences in a list item continue on
indented lines, matching `docs/.style/content-guidelines.md`. Sentence
breaks are never inserted inside inline code, link text, URLs, or HTML
tags, and abbreviations such as `e.g.` and `etc.` don't count as
sentence ends. Images that started their own source line stay on their
own line. The script is idempotent: a second pass produces no changes.

**Merge with main.** `main` restructured `docs/install` into plan,
prepare, server, validate, and operate sections after this branch was
cut. The merge takes `main`'s tree and re-runs the reflow over every
page now under `docs/install`, so the branch diff against `main` is
reflow only. `releases/index.md` and `releases/feature-stages.md` moved
out of `docs/install` on `main` and are no longer in scope.

**Verification.**

- Rendered every page with `marked` from `main` and from this branch and
compared normalized HTML: identical except the three em-dash rewrites.
- Vale with `Coder.OneSentencePerLine` forced on for `docs/install`: 277
findings on `main`, 39 on this branch, all in table rows or fenced code.
- A broader sweep for mid-line sentence boundaries and for false splits
(lines starting lowercase, lines ending in an abbreviation) found no
prose hits.
- `markdownlint-cli2`, `markdown-table-formatter --check`, `make
lint/emdash`, and `make pre-commit-light` pass.

</details>

---

*Generated by Coder Agents on behalf of @ianjevans.*
2026-10-06 13:31:35 -07:00
Nick Vigilante 44af8a1b56 docs: shorten the add-a-language install script copy and note apt reinstalls (#30376)
The "Add a programming language" guide embedded a full copy of the
install script that had drifted from the shipped Template Builder base
(it used `grep -q` partial matching, not `has_language`). The Final code
tab now shows an abbreviated excerpt (helpers plus the new Ruby branch)
so it can't drift again, and Step 4 and the "How does Coder install the
language you pick?" section use `has_language ruby`.

Also adds a short note in Step 4 that `apt-get` installs Ruby into the
ephemeral container, so it reinstalls on every start, while
home-directory installs persist. The persistent `~/.local` approach from
the ticket is not taught because it never landed on `main` (#28485 was
closed unmerged).

The `has_language` helper is present in the Template Builder base on
`main`. The older example template gets it in #30373. Refs DOCS-713.

Generated by Coder Agents on behalf of @nickvigilante.
2026-10-06 10:12:51 -04:00