Commit Graph
16718 Commits
Author SHA1 Message Date
Michael Suchacz 47345bfc4e fix: adapt agent docs, skills, and Coder Agents prompts for Claude Opus 5.5 (#29817) 2026-09-26 21:39:40 +02:00
Garrett Delfosse b55f721f24 fix: apply user-supplied AWS Bedrock API keys instead of dropping them (#28724)
## Bug

Under `/agents/settings/api-keys`, a personal API key saved for a
Bedrock provider never took effect. AI Gateway forwarded the saved
value, but the Bedrock interceptors re-signed every request with the
deployment's AWS credentials (SigV4), overwriting the `Authorization`
header. The key was silently dropped, so users were unknowingly still
billed to the administrator's AWS account with no way to bring their own
credentials.

## Fix

Apply the user's Bedrock key instead of discarding it. AWS Bedrock API
keys are bearer tokens (`Authorization: Bearer <key>`), so when a
personal key is present AI Gateway now sends it as a bearer token and
skips SigV4 signing. This covers every Bedrock route:

- **InvokeModel** (`/v1/messages`): applies the same wire transform as
the signed path (`/model/{model}/invoke[-with-response-stream]`,
`anthropic_version`, `anthropic-beta` → body, `model`/`stream`
stripping) but sets a bearer `Authorization` header instead of signing.
- **Mantle** (`/v1/messages`, `/v1/responses`, `/v1/chat/completions`):
passthrough with a bearer `Authorization` header instead of signing.

The bearer paths resolve no deployment AWS credentials, so BYOK works
even where the deployment has none. Requests without a personal key keep
the existing SigV4 behavior.

This also reverts the earlier interim guard that hid the key field and
rejected Bedrock key upserts: the field is shown again and the API
accepts the keys, because they now work.

<details>
<summary>Implementation notes</summary>

**Gateway (`aibridge`)**
- `messages.newMessagesService` detects BYOK on a Bedrock interception
and routes it through bearer-token option builders instead of the SigV4
path.
- `withBedrockInvokeModelBYOKOptions` /
`bedrockInvokeModelBearerMiddleware` reimplement the Anthropic SDK's
`bedrock.WithConfig` wire transform without signing, because that helper
couples the transform with SigV4 and would resolve deployment
credentials a BYOK request must not depend on.
- `bedrocksig.BearerMiddleware` is shared by the Messages, Responses,
and chat-completions interceptors for the Mantle passthrough; each
installs it in place of `SignMiddleware` when the credential is BYOK.
- Streaming decoding is unchanged: the Bedrock event-stream decoder is
registered by the SDK package's `init` and selected by response
content-type, independent of `bedrock.WithConfig`.

**coderd / SDK / frontend / docs**
- Removed the interim guard and `supports_user_api_key` capability flag;
restored the API-key field for Bedrock providers.
- Docs describe the Bedrock personal key as an AWS Bedrock API key
forwarded as a bearer token for every model family Bedrock serves.

**Tests**
- Unit: bearer middleware transform + auth for InvokeModel; shared
bearer middleware; option-builder validation.
- Integration: end-to-end through the bridge for InvokeModel, Mantle
Messages, Mantle Responses, and Mantle chat completions, asserting
`Authorization: Bearer <key>`, no `X-Amz-*` headers, correct upstream
path/model, no `X-Api-Key` leak, and that InvokeModel streaming decodes
real AWS binary event-stream frames.
- coderd: Bedrock key upserts succeed.

</details>

Closes
[CODAGT-699](https://linear.app/codercom/issue/CODAGT-699/bedrock-provider-settings-for-byok-only-expose-one-api-key).

---

*This PR was generated by Coder Agents on behalf of @f0ssel.*
2026-09-25 18:15:47 -04:00
TJ 99c42af5fc fix(site/src): stop delete dialog keys and clicks from activating rows (#29868)
Fixes
[DASH-106](https://linear.app/codercom/issue/DASH-106/show-validation-error-for-incorrect-workspace-deletion-confirmation).

In the workspaces list, pressing Enter or Space in the delete
confirmation input took you to the workspace page. Nothing was deleted
and there was no explanation. Review turned up related problems in the
same dialog, which this PR also fixes.

**Root cause:** React sends events from portaled content (dialogs,
menus) up through the component tree to parent components. The delete
dialog is rendered inside a clickable workspace row. The row reacted to
Enter and Space from the dialog's input as if the row itself had been
activated, and it did the same for middle clicks. The actions cell
already stopped normal clicks from reaching the row, but not key events
or middle clicks.

**Changes**

- `useClickable` / `useClickableTableRow`:
  - Enter and Space only activate the row when the row itself has focus.
- Clicks, middle-clicks, and double-clicks from portaled content are
ignored (`isFromPortal`). A middle-click paste (Linux) into the dialog
no longer opens the workspace in a new tab.
- A nested native button still sends its own click to the row unless it
stops click propagation, as the existing row buttons already do.
- New `DeleteConfirmationField` + `useDeleteConfirmation`, shared by
`WorkspaceDeleteDialog` and `DeleteDialog`. They previously duplicated
this logic. The shared field provides:
- Enter with a wrong name shows the error immediately, instead of only
after the input loses focus. Screen readers announce it
(`role="alert"`).
- The typed text is quoted and keeps its whitespace, so a stray space is
visible.
- `WorkspaceDeleteDialog` clears the typed name, "Orphan Resources", and
the error whenever the dialog closes, including after confirm (the
parent closes it then). Before, typing the correct name, cancelling, and
reopening showed an enabled Delete button, so one click deleted the
workspace without retyping.
- `DeleteDialog` (shared) clears the typed name whenever its dialog
closes, including when the parent closes it, as the organization page
does after a failed delete. Before, reopening showed Delete already
enabled. Callers that keep the dialog open after a failed delete
(templates, users) still keep the typed name so the user can retry.
- `WorkspaceOutdatedTooltip`, `ProviderRow`, `ModelRow`: removed key
handlers that only worked around the old row behavior, and corrected
their comments.

**Decisions**

- The mismatch error appears below the input without a reserved slot, so
the controls below move down when it shows (unchanged from `main`, by
design decision).
- Enter with an empty input stays silent on purpose. It doesn't confirm
or navigate, and the disabled Delete button signals that a name is
needed.
- Workspace names can't contain spaces, so a typed space leads to the
mismatch error. The input doesn't block spaces.

**Verification**

- Unit tests:
- Enter and Space from inline and portaled inputs don't activate a
clickable element.
- Clicks and middle-clicks from portaled content don't activate the row.
- Enter with a wrong name marks the input invalid and announces the
error. Editing the name clears it.
  - A matching name confirms on Enter.
- The workspace dialog reopens empty after cancel and after confirm. The
shared dialog reopens empty after its parent closes it, and keeps the
typed name while it stays open for a retry.
  - Each new test fails when the code it covers is removed.
- Stories: new `FilledWrongSubmitted` (error shown while focused).
- Related unit tests and stories pass for every clickable table page and
every `DeleteDialog` caller (workspaces, templates, organizations,
users, Agents).
- Tested by hand by @tracyjohnsonux before the reset, shared-field, and
click-guard changes.

---

_Generated by Coder Agents on behalf of @tracyjohnsonux._
2026-09-25 14:50:24 -07:00
david-fraley 282365b23a feat: report clicks on the workspace build debug action to telemetry (#29853) 2026-09-25 13:59:53 -05:00
Mathias Fredriksson 6f0c4474ee feat(site/src): show agent startup logs in start and create tools (#29550)
feat(site/src): show agent startup logs in start and create tools (#29550)

start_workspace and create_workspace wait for agent startup after the
build, but the row only showed the finished build log. Show the agent
startup log below it, using the same Logs components as the build log.

Closes CODAGT-166
2026-09-25 21:58:54 +03:00
Garrett Delfosse 23cf5fcbe7 ci: remove one-off helm index repair workflow (#29926) 2026-09-25 14:01:02 -04:00
Eric Paulsen aa87166c2f docs: fix step order and values.yaml in Azure App Gateway guide (#29927) 2026-09-25 18:07:17 +01:00
Susana Ferreira 4b3c2b3ca3 docs: remove the User spend page from AI Gateway docs (#29844)
## Description

Remove the **User spend** page from the AI Gateway and spend management
docs, since the page is hidden from the sidebar and marked experimental
for this release. The removed content is commented out with a TODO so it
can be restored once the page leaves experimental.

Related to [internal Slack
thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF).

## Changes

- Comment out the **User spend** page in the dashboard visibility table
and spend details lists in `cost-controls.md` and `spend-management.md`.

> [!NOTE]
> Generated by Coder Agents on behalf of @ssncferreira.
2026-09-25 17:35:03 +01:00
Susana Ferreira fb8b6dc2fb feat: hide the User spend page from the AI settings sidebar (#29843)
## Description

Hide the **User spend** page from the AI settings sidebar for this
release and mark the page as experimental. The page stays reachable at
`/ai/settings/spend`, so nothing else about it is removed.

Related to [internal Slack
thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF).

Screenshot

<img width="1186" height="613" alt="Screenshot 2026-09-25 at 13 44 50"
src="https://github.com/user-attachments/assets/820058d5-1b88-4fe7-8c95-01b1fe2211cb"
/>


## Changes

- Remove the sidebar nav item and the spend access lookup that only fed
it.
- Add an `Experimental` badge next to the page title and a warning alert
explaining that reports may load slowly and the page may change or be
removed.

Docs for the **User spend** page are updated upstack in #29844.

> [!NOTE]
> Generated by Coder Agents on behalf of @ssncferreira.
2026-09-25 17:35:03 +01:00
Susana Ferreira 46ccaf3764 chore: mark organization AI spend users endpoint as experimental (#29842)
## Description

Move `GET /organizations/{organization}/ai/spend/users` under
`/api/experimental` so the per-user spend report is not part of the
stable API for this release. The endpoint behavior is unchanged.

Related to [internal Slack
thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF).

## Changes

- Register the route on the experimental handler and mark it
`@x-apidocgen {"skip": true}`, which removes it from the generated API
reference.
- Move the Go SDK method to `ExperimentalClient` and the frontend method
to `API.experimental`.
- Drop the docs link to the removed API reference section. The link is
commented out with a TODO so it can be restored later.

User-facing docs for the **User spend** page are updated upstack in
#29844.

> [!NOTE]
> Generated by Coder Agents on behalf of @ssncferreira.
2026-09-25 17:35:02 +01:00
Nick Vigilante 9afdea4808 docs(docs): document RPM install on RHEL-family Linux (#29295)
## Summary

Coder ships `.rpm` assets with every release and `install.sh` routes the
RHEL family to `install_rpm()`, but no public page said so. The only
page that named RHEL was the uninstall page. This adds an RPM install
page for the control plane.

New page `docs/install/server/rpm.md`:

- Supported distribution matrix for RHEL 8/9/10, Rocky, AlmaLinux,
CentOS Stream, Amazon Linux, Fedora, and openSUSE, with the
`ID`/`ID_LIKE` detection that makes derivatives work.
- Install tabs for the install script, `dnf install`, and `rpm -U`.
- What the package lays down: `/usr/bin/coder`,
`/etc/coder.d/coder.env`, `coder.service`,
`coder-workspace-proxy.service`, and the unprivileged `coder` user.
- Configure-then-start ordering, because `coder.service` carries
`ConditionFileNotEmpty=/etc/coder.d/coder.env` and won't start against
an empty config.
- SELinux caveat for Docker/Podman inside workspaces on RHEL nodes,
linking the existing guidance instead of duplicating it.
- Iron Bank UBI9-minimal pointer for hardened environments, scoped
correctly as a container image rather than an RPM path.

Supporting edits: manifest entry under "3. Install the control plane"
between OpenShift and Cloud Providers, a row in the platform table on
`install/server/index.md`, and a pointer from `install/cli.md`.

## Placement

The page sits at `docs/install/server/rpm.md`, as a sibling of Docker,
Kubernetes, Rancher, and OpenShift, rather than under community install
methods: RPMs are officially built and shipped, not an unofficial
method. It is a control-plane deployment page, not CLI download content,
so it is out of scope for the CLI-retirement work.

## Verification

Claims on the page were checked against real RHEL-family images, not
just the install script:

| Check | Method | Result |
|-------|--------|--------|
| `ID` and `ID_LIKE` per distribution | `docker run <image> sh -c '.
/etc/os-release; ...'` across UBI 8/9/10, Rocky 9, Alma 9/10, CentOS
Stream 9/10, Amazon Linux 2/2023, Fedora, openSUSE Leap and Tumbleweed |
Every RHEL-family image lists `fedora` in `ID_LIKE`; both openSUSE
variants list `opensuse`. Matches the `distro()` branch in `install.sh`
|
| `dnf install ./coder_*.rpm` | Rocky Linux 9 container | Installs
cleanly |
| Package contents | `rpm -ql coder` | `/usr/bin/coder`,
`/etc/coder.d/coder.env`, `coder.service`,
`coder-workspace-proxy.service` |
| Service account and start condition | Installed unit file | Runs as
`coder:coder`; `ConditionFileNotEmpty=/etc/coder.d/coder.env` |
| Architectures | `.github/workflows/release.yaml` | `amd64`, `armv7`,
`arm64` |

Not verified: `systemctl enable --now coder` against a live database,
since the containers used for verification have no init system. The
`systemctl is-active` output on the page is standard systemd output,
flagged here for the reviewer.

Lint: `make lint/markdown`, `make lint/emdash`, and `make lint/prose`
all clean on the changed files; `pnpm run format-docs` applied.

<details>
<summary>Implementation plan and decision log</summary>

### Style guide application

The first revision of this page was drafted from sibling install pages
rather than from the style guide, and was rewritten against
[`docs/.style/content-guidelines.md`](https://github.com/coder/coder/blob/main/docs/.style/content-guidelines.md)
and the prose style guide. What changed: one sentence per source line,
declared audience and outcome in the opening paragraph, numbered
procedures with one instruction per step and conditions stated first,
`refer to` instead of `see`, `sh` fences instead of `shell`, H3 tab
headings, non-breaking space between number and unit, and `Learn more`
instead of `Next steps`.

### Decisions

- **No version numbers or FIPS certification claims for Iron Bank.** The
tags in `scripts/ironbank/hardening_manifest.yaml` are stale (`0.15.3`);
documenting them would re-create the drift. The page links the registry
and names the UBI9-minimal base only.
- **Iron Bank framed as a container path.** It is a container image, so
the page routes readers to Kubernetes/OpenShift rather than implying it
is an alternative to the RPM.
- **Dropped an unverified SELinux claim.** An earlier draft asserted
that the control plane runs under enforcing mode with no policy changes.
That was not tested, so it is gone. The section now covers only the
workspace container-runtime case, which links to existing verified
guidance.
- **`ID_LIKE` values kept out of the table.** They vary by version (RHEL
8/9 report `fedora`, RHEL 10 reports `centos fedora`), so the table
lists `ID` and the prose states the invariant the install script
actually matches on.
- **Minimal edit to `install/cli.md`.** That file is slated for deletion
in the Install restructure, so it gets a pointer and nothing more.

### Rebase onto the install spine restructure

The install spine restructure landed on `main` while this PR was open
and removed the install-method tabs on `install/index.md` that the first
revision pointed from. The branch was rebased and squashed onto it: the
page moved from `docs/install/rpm.md` to `docs/install/server/rpm.md`,
every relative link was repointed at the new locations
(`../plan/sizing/index.md`, `../prepare/airgap.md`,
`../operate/upgrade.md`, `../operate/uninstall.md`,
`./kubernetes/index.md`), the install script snippet picked up the
standardized `curl -fsSL` flags, and discovery moved from the removed
`install/index.md` tabs to the platform table on
`install/server/index.md`. The prose is otherwise unchanged.

### Follow-ups tracked elsewhere

The install spine has no other bare-host or Linux-package option under
platforms; every other entry is a container platform or a cloud VM. Open
question recorded on the IA proposal: whether this generalizes to a
single "Linux host (system packages)" page covering `.deb` and `.apk`
too.

</details>

---

Linear:
[DOCS-886](https://linear.app/codercom/issue/DOCS-886/document-support-for-running-coder-on-red-hat-linux)

🤖 Generated with Coder Agents on behalf of @nickvigilante.
2026-09-25 11:47:34 -04:00
david-fraley 702b13112d feat: add Debug with Coder Agents action for failed workspace builds (#29811) 2026-09-25 09:52:17 -05:00
Cian Johnston b3e073b7c2 test(coderd/x/chatd): strengthen synthetic key lifecycle coverage (#29885)
Strengthen coverage of existing synthetic Gateway key behavior: check
reuse and renewal on both sides of the renewal margin, preserve key
identity and unrelated fields during renewal, synchronize concurrent
mint callers before they contend for the existing lock, and verify
colliding user-created tokens remain untouched. Uses a mock clock and
joins workers on failure. No production changes or dependency on model
authorization.

Independent extraction from #29846.

Verified locally: `make pre-commit` and five focused synthetic-key
race-test runs passed against unchanged production code. The combined
extraction branch also passed the complete Chatd suite.

Extracted and verified with AI assistance on behalf of @johnstcn.
2026-09-25 15:30:21 +01:00
Nick Vigilante 150d366259 docs: add branch-naming rule to prevent issue-tracker auto-link collisions (#28574) 2026-09-25 08:20:35 -04:00
Nick Vigilante 5e12a74f38 fix: run the test recipe under MAKE_TIMED instead of skipping it (#29849) 2026-09-25 08:16:24 -04:00
Ethan f64ccfb836 feat: add experimental inline MCP servers (#29546)
Closes CODAGT-1131

Fifth PR in the inline MCP servers stack, on top of #29520. A chat owner
can now declare MCP servers by URL and headers on their own chat, and
chatd connects to them every turn alongside the org-configured ones.

They go in a new `inline_mcp_servers` field on `POST /api/v2/chats` and
`POST /api/v2/chats/{chat}/messages`, which replaces the whole set (omit
to keep, `[]` to remove). Root chats only. `GET /api/v2/chats/{chat}`
returns them, with the URL blanked for non-owners and header values
never returned. Subagents only get servers marked `allow_in_subagents`,
a root chat in explore mode gets none, and a root chat in plan mode gets
all of them.

URLs must be `https`, or `http` to an IP literal in
`CODER_MCP_ALLOWED_PRIVATE_CIDRS`. Header values have no minimum length,
so anything under the redactor's 8 byte floor from #29518 is accepted
but not redacted, which the docs call out. Every cap is exported from
`codersdk`.

It's behind the `chat-inline-mcp-servers` experiment, and the
`--disable-chat-caller-supplied-tools` kill switch from #29466 covers it
too. With either off, declaring servers gets a 403 and existing chats
stop connecting to theirs, but `[]` still works so a client can detach.

Load failures show up in the chat debug panel as failed connections, as
do org servers with an invalid config. Docs are hand-written in
`mcp-servers.md`.
2026-09-25 18:51:55 +10:00
Ethan 1c974608b1 feat: rotate, decrypt, and delete encrypted chat_mcp_servers headers (#29520)
Relates to #25381

`chat_mcp_servers.headers_key_id` has a foreign key to
`dbcrypt_keys(active_key_digest)`, but `dbcrypt rotate`, `decrypt` and
`delete` didn't know about the table. `rotate` finishes by revoking
every old key, so an encrypted header row would fail that revoke with an
FK violation, which is the same class of bug as #25381.

This PR adds `chat_mcp_servers` to all three commands. `rotate`
re-encrypts under the new key (and encrypts plaintext rows with no key
ID, like `gitsshkeys`), `decrypt` writes the plaintext back and clears
the key ID, and `delete` removes the encrypted rows outright, like
`user_secrets`, since a server without its headers can't authenticate
anyway. Rows with `{}` headers are never encrypted, so they're left
alone.

The org-level `mcp_server_configs` gap is still tracked at #25381. I've
stacked this on the `mcpclient` PR, though it only depends on the
`chat_mcp_servers` table PR, as `gh stack` is linear.


Part of CODAGT-1131
2026-09-25 18:51:55 +10:00
Ethan 016df8cbab feat(coderd/x/chatd/mcpclient): add hardened connect path for inline MCP servers (#29518)
Third PR in the inline MCP servers stack, on top of
https://github.com/coder/coder/pull/29517. This adds the `mcpclient`
side that chatd will use to talk to servers a chat owner declared by
value on the chat. Nothing in chatd calls the new functions yet.

`mcpclient` now owns its input type. `ConnectAll` and the new
`ConnectInline` both take `[]mcpclient.Server`, and `ServerFromConfig`
converts an org-configured row at the boundary, so a caller never has to
fake a `database.MCPServerConfig` for a server that has no row. The org
path behaves as before with two exceptions: `connectAllWithHooks` no
longer skips disabled servers (the call site in `generation_preparer.go`
filters them), and a `custom_headers` row with malformed JSON or an
unknown auth type used to connect without those headers, whereas now
conversion fails and the caller skips the server with a warning.

Org-configured servers were set up by an admin, so we don't put many
limits on them. Inline ones are supplied by whoever created the chat, so
`ConnectInline` treats the server as untrusted. HTTP response bodies are
capped at 1 MiB, a server can expose at most 64 tools with each
definition under 64 KiB and 256 KiB in total, and tool results are
capped at 256 KiB. If a server blows the tool caps we skip the whole
server rather than hand the model a partial tool set, and an oversized
result comes back to the model as a tool error rather than being
truncated silently. Everything the server sends that we log or hand to
the model (tool names, descriptions, schemas, results, connect errors)
has the values in `Server.SensitiveValues` replaced with `[REDACTED]`;
chatd sets that to the URL and header values. Header names aren't
redacted, as they're public and short enough that redacting them would
rewrite ordinary text. For the same reason the redactor ignores anything
shorter than `MinSensitiveValueBytes` (8), and #29546 rejects header
values that short at the API. The slug is caller-supplied too, so it
also goes through the redactor wherever it lands in a tool name, connect
summary or log field.

`AppendInline` merges the resulting tools into an existing tool list
with the existing names winning, so an inline server can't shadow a
builtin or org-configured tool. Collisions are logged once per server
with the `config_id`.

Lastly, every `tools/call` (for both kinds of server) now carries the
model's tool call ID in `_meta` under `com.coder/tool_call_id`. It's a
correlation ID that's stable across chatd retries of the same call, so a
server can use it to dedupe if it wants to. We make no other idempotency
promise.


Part of CODAGT-1131
2026-09-25 18:51:54 +10:00
Ethan acebdf5b60 feat: add chat_mcp_servers table with encrypted headers (#29517)
This is the second PR in the stack that adds experimental support for
attaching MCP servers to a chat;
https://github.com/coder/coder/pull/29466 is the first. This one is just
the persistence layer, nothing reads from the table yet.

It adds a `chat_mcp_servers` table, unique on `(chat_id, slug)` and
cascading on chat deletion. Each row stores the server URL, a JSON
object of request headers, per-server tool allow and deny lists, and
three flags that later PRs in the stack use to decide when the server
gets connected: `allow_in_plan_mode` (mirroring the existing column on
`mcp_server_configs`), `allow_in_subagents`, and
`forward_coder_headers`. All three default to `false`.

Headers are the sensitive part, so they're encrypted at rest via
`dbcrypt` in the same way `external_auth_links` are: `headers_key_id`
records which key was used, and `NULL` means plaintext. Empty or `{}`
headers are stored as `{}` with no key, so servers that don't need auth
never produce ciphertext. The `dbcrypt` wrappers cover the chat-scoped
reads and writes, plus `GetChatMCPServersByChatOwnerID` and
`UpdateEncryptedChatMCPServerHeaders`, which follow the per-user shape
that `Rotate` and `Decrypt` in `cliutil.go` use. I haven't wired those
two into `coder server dbcrypt rotate` and `decrypt` in this PR.

For authz, reading a chat's servers requires read on the chat, and
upserting or deleting them requires update on the chat. The two
owner-scoped queries above are system-only.


Part of CODAGT-1131
2026-09-25 18:51:54 +10:00
Ethan c1af0793e5 feat: add caller-supplied tools kill switch for chats (#29466)
This is the first PR in a stack that adds experimental support for
attaching MCP servers to a chat when it's created, and then deprecates
`unsafe_dynamic_tools` in favour of them. Both are "caller-supplied
tools", i.e. tools the client hands to coderd at chat creation rather
than tools an admin has configured, so we want a single switch admins
can use to turn all of them off.

This PR adds that switch: `--disable-chat-caller-supplied-tools`
(`CODER_DISABLE_CHAT_CALLER_SUPPLIED_TOOLS`). It follows the existing
`disable-*` deployment flag pattern (`--disable-chat-sharing` etc.), so
there's no new API route and it's independent of any experiment. When
set, `POST /api/v2/chats` returns a `403` if the request includes
`unsafe_dynamic_tools`, and chats that already have dynamic tools run
without them; a call to one gets a tool error result and the model just
continues. Later in the stack, chat-attached MCP servers are gated
behind the same flag.

It's unset by default, so nothing changes unless you opt in.


Part of CODAGT-1131
2026-09-25 18:51:53 +10:00
Lisa Fiander 9700db5b53 chore: update low-risk dependencies (#29860)
## Summary

Updates pinned dependency overrides across three independent pnpm
installs:

| File | Package | From | To |
|------|---------|------|----|
| `package.json` (root) | brace-expansion | 1.1.16 | 1.1.18 |
| `offlinedocs/package.json` | brace-expansion | 1.1.16 | 1.1.18 |
| `scripts/apidocgen/package.json` | form-data | 4.0.4 | 4.0.6 |

All pinned via `pnpm.overrides`; each `pnpm-lock.yaml` is regenerated to
match. There is no `pnpm-workspace.yaml`, so root, `offlinedocs/`, and
`scripts/apidocgen/` are separate installs and each bump is isolated to
its own tooling.

## Testing

Run locally per install:

**Root**
- `pnpm install` — resolves/locks `brace-expansion@1.1.18`; no stale
references
- `pnpm run check-docs` (markdownlint + table formatter, uses js-yaml) —
505 files, 0 errors
- `quicktype` JSON→TS + `biome --version` — pass

**offlinedocs**
- `pnpm install` — resolves/locks `brace-expansion@1.1.18`; no stale
references
- `pnpm run lint:types` / `format:check` / `build` — pass, 453 pages
built

**scripts/apidocgen**
- `pnpm install` — resolves/locks `form-data@4.0.6`; no stale references
- `widdershins --version` + full render of `coderd/apidoc/swagger.json`
(exercises form-data) — rendered successfully

No behavioral changes; dependency version bumps only.
2026-09-25 09:40:45 +01:00
Thomas Kosiewski 2de1f8b111 feat: link promoted chat messages to their queue entry (#29859)
Signed-off-by: Thomas Kosiewski <tk@coder.com>
2026-09-25 09:51:25 +02:00
Michael Suchacz b0b472de9e feat(codersdk/toolsdk): add owner_id to the coder_create_chat MCP tool (#29704) 2026-09-25 09:43:07 +02:00
Michael Suchacz 7c74fa3548 feat: add workspace file upload agent API (#27078)
## What

Adds a dedicated workspace-agent endpoint, `POST
/api/v0/upload-chat-file`, that streams a request body into the chat's
upload directory `~/.coder/chats/<chat-id>/files/<name>`, plus the SDK
plumbing to call it:

- `coderd/x/chatfiles`: upload-name sanitization
(`SanitizeWorkspaceUploadName`), collision suffixes (compound extensions
such as `.tar.gz` stay intact: `archive_2.tar.gz`), and the shared
`~/.coder/chats/<id>/files` path layout.
- `agent/agentfiles`: the HTTP handler. On Linux/macOS the directory
chain is opened with `openat(O_NOFOLLOW)`, so symlinked path components
are rejected. The body streams into a hidden `.<name>.upload-<random>`
temp file and is published under its final name only when complete, via
`linkat` over the `_2`, `_3`, ... collision sequence, so existing files
are never overwritten and a half-written file is never visible under its
final name. Filesystems without hard links fall back to an exclusive
placeholder plus `renameat`. Other platforms use an afero-based fallback
with the same semantics. Stale temp files older than an hour are swept
before each upload, and failures are logged with a structured warning.
- `codersdk/workspacesdk`: `AgentConn.UploadChatFile` + regenerated
`agentconnmock`.

## Why

Coder Agents chat can attach images/text/PDF to prompts, but arbitrary
files (zips, datasets, binaries) have nowhere to land where the agent's
tools can act on them. This is the agent-side foundation; the coderd
route that fronts it is stacked on top.

Design notes:

- There is deliberately no size cap; the resource profile matches
existing SSH/WebSocket proxying, and client cancellation aborts the
stream (a failed write removes the temp file, so no partial files
remain). Because the agent HTTP server uses fixed 20 s read/write
timeouts, the handler pushes both deadlines forward on every received
chunk, so a slow upload only fails after a 20 s stall. If the connection
does not support deadline changes, the agent logs one warning per
request.
- This endpoint is not gated by `CODER_AGENT_BLOCK_FILE_TRANSFER`. That
flag targets SSH-transport file tools (scp/rsync/sftp). Chat uploads are
an agent API capability like `write-file` and `edit-files`, which
already bypass the flag; the interaction is documented in the FAQ.

## How tested

- `go test ./agent/agentfiles ./coderd/x/chatfiles
./codersdk/workspacesdk` (unit + umask/symlink/collision integration
tests).
- UAT on a dogfood-style deployment (2026-09-21): uploads longer than 20
s went from 502 to 201 once the workspace agent was restarted on this
build; a coderd restart alone keeps the old agent running, so the
per-chunk deadline extension needs the agent rolled (older agents get
the 409 "Restart the workspace" from #27079).

Part of CODAGT-211. Stack: agent API (this PR) -> coderd endpoint -> UI.

> This PR was authored by Mux (AI) working on Mike's behalf.
2026-09-25 09:05:51 +02:00
Michael Suchacz 6094c03a90 docs(coderd/x/chatd): remove compaction TODOs from ARCHITECTURE.md (#29870) 2026-09-25 07:01:46 +00:00
Michael Suchacz 37295547b8 feat: add default model picker to Coder Agents settings (#29470) 2026-09-25 08:58:47 +02:00
Thomas Kosiewski 5393f9d5f4 feat: stream advisor reasoning in tool cards (#29742)
Show the advisor’s live reasoning under **Thinking**, separately from
**Advice**, in one tool card with the original question and title. Keep
nested reasoning out of the parent assistant’s reasoning and saved chat
history.

Clear both live channels on retry and remove transient reasoning when
the call finishes. Cover streaming, retry, error, and interrupted-output
behavior with regression tests, and regenerate the SDK and API schemas.

This also changes a shared seam for every tool, not only the advisor:
live output for a tool call that is already saved now completes that
call's card, and the separate live-row card for it is removed.

Remote UAT passed on `a39bbe4c21`: deterministic provider tests covered
streamed reasoning, retry, errors, and refresh; a real-provider run
confirmed advice streaming and card association. The real model did not
emit reasoning. The intermittent, unattributed React console warning is
tracked in #29741.

<details>
<summary>Remote UAT evidence (deterministic provider)</summary>

![One advisor card showing its question, Thinking, and
Advice](https://github.com/user-attachments/assets/edd05bf2-59b7-48c2-a608-2fd5a4fabcc8)

Streaming, completion, and refresh:


https://github.com/user-attachments/assets/dd1f3a24-a365-40c8-a1d9-b78cd17ef4c5

</details>

---

<details>
<summary>📋 Implementation Plan</summary>

# Plan: Stream advisor reasoning in Coder Agents

## Goal and delivery boundary

Show nested advisor reasoning as live **Thinking** in its advisor tool
card. Keep it separate from live **Advice**, normal parent-assistant
reasoning, and the final persisted advisor result.

Deliver one focused PR: optional SDK field, nested publisher, transient
frontend state, existing card rendering, generated API artifacts, and
regression tests. Do not add provider features, persistence, new stream
event types, UI redesigns, or unrelated cleanup.

The implementation already exists and has been reconciled with current
main. The implement-flow implementation phase is an acceptance audit,
not a rewrite. Preserve correct behavior and current architecture.
Change only demonstrated gaps. A no-op implementation result is valid;
do not manufacture an empty commit.

## Current integration points

1. `codersdk/chats.go`: add optional `ReasoningDelta string` with
`json:"reasoning_delta,omitempty" variants:"tool-result?"`. Preserve it
in `StripInternal` alongside other live fields. Register the same
NUL-encoding policy as `ResultDelta` in `chatprompt` so the SDK field
coverage and round-trip tests remain complete. Regenerate SDK types and
API documentation with `make gen`.
2. `coderd/x/chatd/chatadvisor/runner.go`: route assistant text and
reasoning through separate optional callbacks on `RunAdvisorOptions`.
Install the publisher if either callback exists. Preserve empty-delta
and role guards. Use current `GenerateAssistant` and `chatretry.Retry`.
Rename the reset callback to `OnLiveOutputReset` because it clears
advice and reasoning. Keep `extractAdvisorText` text-only and existing
budget/refund behavior.
3. `coderd/x/chatd/chatadvisor/tool.go`: use the current
context-injected `MessagePartPublisherFromContext`; do not reintroduce
the old ToolOptions publishing callbacks or chatd.go wiring. Preserve
the missing-publisher error and the nonempty tool-call-ID guard. Publish
reasoning as role `tool`, part type `tool-result`, tool name `advisor`,
matching `tool_call_id`, and `reasoning_delta`. Use existing
`result_reset` to reset both live channels on retry.
4.
`site/src/pages/AgentsPage/components/ChatConversation/streamState.ts`
and `types.ts`: retain a single transient reasoning string. Append
deltas exactly as plain text, never JSON-parse or trim them during
accumulation. Reasoning makes the tool streaming. An empty
`result_delta` must not swallow a nonempty `reasoning_delta`. Reset
removes the entry. A final result or `is_error` clears reasoning and
streaming state. Pass reasoning through `buildStreamTools` into
`MergedTool`.
5. `MessageBlocks.tsx` and `ChatElements/tools/Tool.tsx`: forward
reasoning at both current Tool instantiation paths and through
AdvisorRenderer. Do not restore the old ConversationTimeline rendering
implementation.
6. `AdvisorTool.tsx`: use current `ToolCall.Root`, `ScrollArea`,
`Response`, and semantic theme tokens. Display Thinking only when
running and trimmed reasoning is nonempty. Display live advice
separately when present. Keep completed advice, empty/loading, limit,
and error behavior unchanged. Reasoning-only running cards must not show
the empty-advice fallback. Do not restore removed MUI dependencies.
7. `messageParsing.ts`, `streamState.ts`, and `ChatPageContent.tsx`:
associate live tool results with matching durable tool calls. Preserve
the invocation's question, intent, and metadata. A durable final result
remains authoritative, including explicit null results. Remove only the
overlaid result and its block from the separate live row; keep unrelated
results and live call/result pairs unchanged. This closes the
durable-call/live-result split found during integration testing.

## Acceptance criteria

1. Nested reasoning reaches the dedicated runner callback and the client
as tool-scoped live output for the same advisor call as advice.
2. Advisor reasoning is not parent assistant reasoning, final advice,
input to the parent's continuation, or persisted chat history.
3. Retry clears stale reasoning and advice before fresh output. Final
success and bare error clear transient reasoning.
4. Raw whitespace and JSON-looking reasoning survive concatenation
unchanged. Empty advice deltas do not hide reasoning.
5. Reasoning-only and reasoning-plus-advice states render in exactly one
existing advisor card per invocation, retaining its question and intent
title when the call is already durable. Completed cards never display
transient thinking, even if handed a stale prop. Other tool and normal
assistant reasoning behavior is unchanged.
6. Generated artifacts match source. Final candidate passes relevant Go
tests, frontend tests, stories, typecheck, lint, and pre-commit checks,
or has explicit verified blockers. Old evidence is not final-candidate
evidence.

## Phases and quality gates

1. Reconcile existing work onto current main while retaining a recovery
snapshot. Remove obsolete workarounds, not current upstream behavior.
Gate: no conflicts, focused diff, preserved original work.
2. Audit regressions at the existing runner, tool publisher, parent-chat
stream, and frontend state boundaries. Add one missing behavior at a
time. Reproduce failures before fixes. Gate: failing tests demonstrate
the defect and pass after the smallest fix.
3. Simplify only within this feature. Use one reasoning string and
existing publishers/components. Gate: tests remain green, generated diff
is scoped, FE1 through FE10 pass.
4. Commit the candidate with repository hooks enabled, then run the
packaged implement-flow audit, validation, remote UAT, and polish
stages. Gate: readyForPr and verified remote evidence for the exact
final candidate. If polish changes HEAD, refresh the UAT evidence for
that SHA.
5. Create a reviewable PR and complete green CI plus bounded Codex
review on its exact head. Get one fresh independent readiness
recommendation. Gate: no unresolved review threads, required evidence
recorded, and a justified readiness decision. Do not merge.

## Regression coverage

- Runner: reasoning and advice callbacks remain separate; final advice
and usage count stay correct. Retain existing retry/refund tests.
- Tool: all reasoning/advice events carry role tool, type tool-result,
advisor name, and the invocation ID. Without an ID, emit no live output.
Retry emits stale reasoning/advice, reset, then fresh reasoning/advice.
- Chatd: extend `TestAdvisorHappyPath_RootChat` with deterministic
`openai-compat` reasoning chunks. Hold the nested response until the
live subscriber captures expected reasoning and advice. Observe the
complete relevant event set, assert no parent-assistant reasoning, and
check continuation and persisted content contain no advisor reasoning.
Extend only the test fixture needed to emit `reasoning_content`; do not
change production adapters.
- Frontend: extend streamState tests for exact accumulation, whitespace,
JSON-looking text, reasoning-only streaming, empty advice delta, reset,
final result, and bare error.
- Durable/live integration: replay a durable assistant tool call
followed by live reasoning and advice results. Assert the durable card
receives both channels and the live row no longer owns the same result
or block. Preserve unrelated IDs and live calls. Clear the overlay on
reset; prefer durable final results, including null. Cover the complete
display path with a real-store ChatPageContent story.
- Visual stories: running reasoning-only, running reasoning-plus-advice,
and completed with stale reasoning. Keep existing limit/error stories.
Stories set up visual states without assertions, following current FE1.

## Validation

Run targeted checks while iterating, then the broader gates:

```sh
umask 022
go test ./coderd/x/chatd/chatadvisor ./coderd/x/chatd ./codersdk -run 'Advisor|ChatMessagePart|ChatStream' -count=1
pnpm -C site exec vitest run --project=unit src/pages/AgentsPage/components/ChatConversation/streamState.test.ts
pnpm -C site exec vitest run --project=storybook src/pages/AgentsPage/components/ChatElements/tools/AdvisorTool.stories.tsx
make gen
make fmt
make test RUN='Advisor|ChatMessagePart|ChatStream'
pnpm -C site lint:types
pnpm -C site check
pnpm -C site lint
make lint
make pre-commit
```

Keep native exit codes and logs. Do not hide a failed check, bypass
hooks, or fix unrelated baseline problems in this PR. Stage intentional
generated/formatting changes before pre-commit's clean-diff checks.
Report exact blockers and risks.

## Remote dogfood UAT

Use the coder-agents-uat skill and an independent critical Coder Agent,
not a local-only substitute. Push only the named feature branch. Test
its exact SHA in an isolated workspace/deployment without changing
shared model credentials or configuration. Use an isolated user, chat,
and model config.

Setup:

1. Read the branch diff and UAT scope. Record the branch and SHA.
2. Start Coder with the repository-supported `./scripts/develop.sh
--port-offset` (or `CODER_DEV_PORT_OFFSET=true`). Do not replace it with
a manual server launch. Record effective API/UI URLs and wait for
readiness.
3. Prefer a deterministic mock OpenAI-compatible provider that emits
advisor reasoning and advice separately, and a retry after stale output.
Use only isolated configuration. Never print or capture secrets.
4. Start a named agent-browser session. Attempt `agent-browser skills
get core`; record the installed version/fallback if unavailable. Record
video before the scenario, then install any stream capture since
recording may recreate browser context.

Scenario:

1. Create a normal advisor-enabled root chat. Do not use Plan Mode:
current product behavior excludes the advisor there.
2. Capture the initial state. Prompt the parent to call advisor.
3. While the tool is running, capture reasoning-only and
reasoning-plus-advice states. Verify exactly one advisor card per
tool-call ID, with its original question and intent title. Verify
Thinking and Advice stay separate inside that card and the parent
thinking area does not receive nested reasoning.
4. Capture the relevant WebSocket event set. Verify role tool, type
tool-result, advisor name, matching tool-call ID, and reasoning_delta.
An advisor-filtered subset is insufficient to prove absence of parent
reasoning.
5. Let the advisor finish. Verify final advice remains, Thinking
disappears, and refresh does not restore transient reasoning.
6. Exercise retry with the deterministic provider if feasible. Verify
stale reasoning/advice clears before fresh output. If not exercised,
record the omission and remaining test evidence; do not claim it was
dogfooded.
7. Capture console errors before and after. Inspect the screenshots and
semantic video frames, not only successful media decoding.

Required evidence: exact tested SHA; remote chat URL; setup command and
effective URLs; non-secret provider/model names;
before/thinking/thinking-plus-advice/completed screenshots; a short
streaming video; complete relevant stream evidence; refresh and retry
observations; console results; explicit omissions; and owned-resource
cleanup receipts. Keep evidence under `.mux-uat/round-<n>/`, excluded
from source commits. When publishing evidence to GitHub, use native `gh
--attach`, not cookie-based uploads or gh-image.

Cleanup: stop only owned develop/provider processes and named browser
sessions. Do not use unscoped process sweeps, shared database resets, or
`agent-browser close --all`.

</details>

---
_Generated with [`xum`](https://github.com/coder/xum) • Model:
`coder:openai/gpt-6-astra` • Thinking: `xhigh`_

---------

Signed-off-by: Thomas Kosiewski <tk@coder.com>
2026-09-25 07:58:22 +02:00
c931c1a4ef fix(site): apply design feedback to the workspace filter combobox (#29111)
Design review follow-ups for the unified workspace search and filter
(`FilterCombobox`) on `/workspaces`, continuing #29080.

**Search box**
- Filter toggle shows a dotted `ListFilterActiveIcon` while at least one
chip is applied; it renders 2px larger than the plain icon so both read
as the same size.
- Chips render the `key:` prefix in content-secondary and the value in
content-primary, at 14px with 8px left padding.
- Attributes chips display as `attribute:outdated` (etc.) instead of
`outdated:true`; the category key is now `attribute` with `attributes`
kept as a typed alias. The emitted query is unchanged.
- The trailing text input sizes to its content (`field-sizing: content`)
and matches chip height, so an empty input no longer forces a second row
and the box no longer changes height when the first chip is added.

**Dropdown**
- Categories are ordered Owner, Status, Attributes, Template,
Organization.
- Each category row ends with either the labels of its applied chips
plus a check mark, or a sample of its options (templates and
organizations come from the deployment; Owner shows a fixed `me`).
Applied values are content-secondary, the sample is muted; both 12px.
- Rows are 34px with 8px horizontal padding, a 24px icon slot (18px
lucide icons, 24px avatars), 14px regular text. List padding is 8px;
group headers get 16px above except the first.
- Attributes uses `TagIcon`; Organization keeps `Building2Icon`.
- Result rows inherit the row colour so label and icon highlight
together; the workspace result subtitle (and the unused
`SearchResult.subtitle` field) is removed.

**Table**
- Pagination summary is prefixed with `Filtered:` while a query is set;
with zero filtered results it reads `No workspaces match your search.`
- Filtered empty state uses the same sentence and adds an outline `Clear
all` button that resets the query.

Stories cover the new states (active icon, wrapped chips, attribute
chips, category previews and applied values, filtered summary, empty
state, Clear all). `chipDisplay` and `categoryPreview` have unit tests.

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

- "Filter active" for the toggle icon means at least one committed chip;
free text alone does not switch it.
- The supplied SVG for the active icon was redrawn on lucide's 24px grid
with `currentColor` and stroke 2 so it matches `ListFilterIcon` in
weight and theming; its shortened top line carries less visual mass,
hence the 20px render.
- Row spec asked for 34px rows and 8px padding with a 24px icon slot; 24
+ 2*8 = 40, so rows use 8px horizontal / 5px vertical padding to hit
34px.
- Chips use `text-sm` with `leading-4` so they stay 28px tall and the
box height and first-row icon alignment are unchanged.
- Chips are now two spans, so story assertions use a `chip(token)`
matcher on the chip element's full text instead of
`getByText("owner:me")`.
- The `field-sizing` input relies on browser support that is now in
Chrome, Safari, and Firefox 152; `size={1}` keeps the fallback intrinsic
width small elsewhere.
- Category previews reuse the empty-query option lookup
(`filterComboboxOptions(key, getOptions, "")`), so entering a category
hits the react-query cache. `FilterCategory.hint` is a fixed override of
the sample; `FilterOption.appliedLabel` lets `owner:me` read as `me`
rather than `admin (you)`.
- The helper text uses `text-content-disabled` because the theme defines
no `content-tertiary` token (the 18 existing `text-content-tertiary`
usages under `AgentsPage` generate no CSS).
- Free text is still emitted live (debounced) while browsing the
dropdown; the backend treats bare terms as workspace-name substrings, so
typing `admin` does not match owner `admin`. Left unchanged here; a
backend change would be a separate PR.

</details>

---

This PR was generated by Coder Agents on behalf of @tracyjohnsonux.

---------

Co-authored-by: Jake Howell <jacob@coder.com>
Co-authored-by: Jake Howell <jake@hwll.me>
2026-09-24 22:49:41 +00:00
Bobby Ho b70702d50d docs: split OAuth2 provider page (#29778)
Split the OAuth2 provider documentation into seven focused pages.

- Update navigation and inbound links, preserving compatibility anchors for moved headings.
- Correct `DELETE /oauth2/tokens` documentation: it revokes only the calling user's tokens and codes, not every user's for the application.
- Clarify client authentication and app creation, mention PKCE, and update callback UI references.
- Remove contributor-only instructions and the feature-specific example from feature-stage docs; restore release and upgrade guidance in `security.md`.
- Standardize formatting and verify internal anchors. Markdown and em-dash linting pass.

Refs PLAT-659.
2026-09-24 13:42:59 -07:00
Nick Vigilante 3d30e201b5 docs: move contributor guides out of the published docs into the repo (#29751)
## Merge order

Merge first; then republish the docs; then coder/coder.com#1100 (the
redirects).

## Summary

The nine pages under `docs/about/contributing/` are for people working
in this repository, not for Coder users or administrators, so they leave
the published documentation.
The repository becomes their canonical home.
Until now the root `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` were
two-line stubs that only linked to the docs site, so contributors on
GitHub were bounced out to read them.

A companion PR in `coder/coder.com` adds redirects from every retired
`/docs/about/contributing/*` URL to the new GitHub location.
It must merge only after this PR has merged and the docs have
republished.

## Changes

| Old path | New path |
| -- | -- |
| `docs/about/contributing/CONTRIBUTING.md` | `CONTRIBUTING.md`
(replaces the stub) |
| `docs/about/contributing/CODE_OF_CONDUCT.md` | `CODE_OF_CONDUCT.md`
(replaces the stub) |
| `docs/about/contributing/SECURITY.md` | deleted; the root
`SECURITY.md` already holds the policy |
| `docs/about/contributing/AI_CONTRIBUTING.md` |
`contributing/AI_CONTRIBUTING.md` |
| `docs/about/contributing/backend.md` | `contributing/backend.md` |
| `docs/about/contributing/frontend.md` | `contributing/frontend.md` |
| `docs/about/contributing/modules.md` | `contributing/modules.md` |
| `docs/about/contributing/templates.md` | `contributing/templates.md` |
| `docs/about/contributing/documentation.md` |
`contributing/documentation.md` (see note below) |

For every moved file: the docs front matter is stripped and its `title`
becomes the H1, relative links are rewritten for the new depth
(`../../../foo` becomes `./foo` at the root and `../foo` under
`contributing/`; the two links into `docs/admin/` become
`../docs/admin/...`), and the docs-only `<div class="tabs">` wrapper in
`CONTRIBUTING.md` is removed.
`CONTRIBUTING.md` gains a short intro that links the code of conduct,
the security policy and the area guides, since GitHub only auto-surfaces
the root files.

`docs/manifest.json` loses the About → Contributing group and
`docs/images/icons/contributing.svg`, which only that group used.

Inbound references updated:

- `README.md`: contribution guide link now points at `CONTRIBUTING.md`
on GitHub.
- `docs/tutorials/example-guide.md` and
`docs/install/releases/feature-stages.md`: link to
`contributing/documentation.md` on GitHub, since a docs page cannot link
to a repo-only file.
- `docs/.style/style-guide/README.md`: the "Relationship to" section
names the new location.
- `scripts/docshtmlcheck/main.go`: both the package comment and the
user-facing error string name `contributing/documentation.md`.
- `scripts/docshtmlcheck/README.md`: relative link to the new location.
- `coderd/database/migrations/migrate_test.go`: `t.Log` link now points
at `contributing/backend.md#database-fixtures-for-testing-migrations`.
- `.github/pull_request_template.md`: AI contribution guidelines link.
- `.github/workflows/contrib.yaml`: commit-message guidelines link in
the PR title check.
- `.github/workflows/test-docs-preview-mapper.sh`: the mapper test case
that used `docs/about/contributing/CONTRIBUTING.md` now uses
`docs/admin/security/audit-logs.md`.
-
`.claude/docs/{ARCHITECTURE,PR_STYLE_GUIDE,WORKFLOWS,DOCS_STYLE_GUIDE}.md`:
links to `CONTRIBUTING.md`.

`git grep about/contributing` is empty after this change.
`CODEOWNERS` had no entry for the old paths.

Note on `documentation.md`: it is docs-authoring guidance and is parked
in `contributing/` for now.
Folding it into `docs/.style/` is tracked separately and is deliberately
not attempted here.

## Testing

- `go run ./scripts/docshtmlcheck` over `docs/`, and again over
`contributing/`, `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`: clean.
- `go vet ./scripts/docshtmlcheck/...` and `go test
./scripts/docshtmlcheck/...`: 47 tests pass.
- `go vet ./coderd/database/migrations/...`: clean. `go test` for that
package fails to link on this machine (`tailscale.com/tstime/mono:
invalid reference to runtime.nanotime1`) identically on unmodified
`main`, so it is a local toolchain issue and not exercised here; the
change is a string in a `t.Log`.
- `pnpm check-docs` (markdownlint-cli2 and markdown-table-formatter over
`docs/`, `.claude/docs/`, root `*.md`): 495 files, 0 errors. The same
two tools over `contributing/*.md`: 0 errors.
- Every relative link in the eight moved files resolves to an existing
path (scripted check).
- `bash .github/workflows/test-docs-preview-mapper.sh`: the changed
`assert_maps_to` case passes; the six `resolve_ref`/`pages_for_image`
failures it reports are identical on unmodified `main` on macOS.

Linear: [DOCS-975](https://linear.app/codercom/issue/DOCS-975)

---

🤖 Built with AI assistance.
2026-09-24 19:42:18 +00:00
Nick Vigilante d7b6528d7e docs: cap the config reference TOC and drop the Dangerous emoji (#29857)
## Merge order

Standalone; no dependency on the other DOCS-977 PR (task-list
checkboxes).

## Summary

Tracy and Ian flagged the mixed checkbox/emoji styling in the docs
(Slack thread linked from DOCS-977), including the `⚠️ Dangerous`
heading that `scripts/configdocgen` generates from
`codersdk.DeploymentValues`.
The generated configuration reference also has around 130 `h3` headings,
which makes its "On this page" list unreadable.

This PR changes only the generator, `scripts/configdocgen`, and
regenerates `docs/admin/setup/configuration-reference.md` from it.

## Design or Fix

- Emit `toc_depth: 2` frontmatter at the top of the generated page,
before the `<!-- DO NOT EDIT -->` comment.
docs-engine's sync (`packages/docs-build/src/sync.ts`) reads a page's
own frontmatter before stripping it, so this caps the on-page TOC at h2
without any docs-engine change.
- Strip any leading emoji or symbol from generated section headings
(`stripLeadingSymbol`), so the Dangerous heading reads "Dangerous"
instead of "⚠️ Dangerous".
`sectionRank`'s "Dangerous last" ordering still keys off the raw serpent
group name, so ordering is unaffected.
- Render a GitHub `[!CAUTION]` alert directly under the Dangerous
heading, using the group's own codersdk description when it has one,
otherwise a short fallback ("These options can break your deployment or
weaken its security...").
The `⚠️ Dangerous` group name in `codersdk/deployment.go` is unchanged,
because the CLI and other output use it.

## Testing

- `go test ./scripts/configdocgen/...` — 45 passed (7 new/updated cases:
`TestStripLeadingSymbol`, `TestRenderDangerousWithDescription`, and
updated `TestRenderPipeline` assertions for the stripped heading, the
Caution alert, and its position between the heading and the first
option).
- `go vet ./scripts/configdocgen/...` and `gofmt -l
scripts/configdocgen/*.go` — clean.
- `make docs/admin/setup/configuration-reference.md` — regenerated the
page (never hand-edited); this also runs `markdownlint-cli2 --fix` and
`markdown-table-formatter` as part of the make target, both clean.
- `go run ./scripts/docshtmlcheck` — clean.
- Verified with a small Node script against docs-engine's built
`parseFrontmatter`/`extractTitle` (from
`packages/docs-transforms/dist/transform.js`, at the commit that
introduced `toc_depth` support) that a page shaped like the regenerated
one — `toc_depth: 2` frontmatter followed by the `<!-- DO NOT EDIT -->`
comment and then the `# Configuration reference` H1 — parses `toc_depth:
2` and the title correctly.

## QA

Confirmed via the docs-engine sync parser directly (see Testing) that
`toc_depth: 2` is picked up correctly from this file shape.
I did not spin up docs-engine's dev server against this worktree: my
local docs-engine checkout is behind `origin/main` by several commits
including the one that added `toc_depth` support, so a faithful local
preview would first need a docs-engine rebuild against `origin/main`.
Given the direct parser verification above already confirms the
mechanism, I judged the full dev-server rebuild too heavy for the
marginal confidence gained and skipped it.

Expected rendering, based on the diff and docs-engine's documented
`toc_depth` behavior:

- The "On this page" TOC lists only h2 sections (General, Dangerous, and
the rest), not the ~130 option h3s.
- The Dangerous section renders as a plain "Dangerous" heading, followed
immediately by a Caution callout, with no emoji.

## Upstream

No. This is Coder product documentation generation (`codersdk`-driven),
not a Fumadocs engine change.

Linear:
[DOCS-977](https://linear.app/codercom/issue/DOCS-977/docs-replace-emoji-checkboxes-and-emoji-headings-with-one-icon-style)

---
🤖 Built with AI assistance.
2026-09-24 15:21:48 -04:00
dylanhuff-at-coder b5ce79b9e0 fix(coderd): validate GCP instance token audience (#29765)
Google instance identity authentication accepted tokens issued for any
audience. A Google-signed token for a registered VM but intended for
another service could therefore be exchanged for a Coder agent token.

Require `aud=coder` before the exchange. The standard GCP agent already
requests this audience. Custom clients requesting another audience will
receive 401 and need to update. Add coverage for foreign-audience
rejection and the returned agent token.

Refs
https://linear.app/codercom/issue/PLAT-655/fixcoderdworkspaceresourceauth-validate-audience-on-gcp-instance
2026-09-24 11:41:32 -07:00
Nick Vigilante 99a3425333 fix: advertise install.sh with curl -fsSL everywhere (#29801)
## Summary

The install one-liner is advertised as `curl -L` in most docs pages, the
README, and the CLI's default version-mismatch hint, while `install.sh`
itself and the deployment-local hint use `curl -fsSL`.
Without `-f`, curl writes an HTTP error body to stdout, and the
one-liner pipes that error page into `sh`.
This PR standardizes every `install.sh` invocation on `-fsSL` so a
failed download fails closed.

## Changes

- Docs: `install/cli.md`, `install/operate/upgrade.md` (twice),
`get-started/index.md`, `start/local-deploy.md`,
`install/operate/provisioners/index.md`,
`admin/templates/managing-templates/change-management.md` (twice),
`user-guides/workspace-access/zed.md`, and `README.md`.
- CLI: `defaultUpgradeMessage` in `cli/root.go` now prints `curl -fsSL`,
matching the deployment-local branch in the same function.
- `codersdk/deployment.go`: the `--cli-upgrade-message` description now
says `curl -fsSL`; the server help goldens, `server-config.yaml.golden`,
`docs/reference/cli/server.md`, and
`docs/admin/setup/configuration-reference.md` are regenerated to match.
- `install.sh`: the "To run" header comment now matches the script's own
usage text.
- Style guide: a new "Commands that pipe a download into a shell" rule
in `docs/.style/style-guide/formatting.md`, and the tabs example uses
`-fsSL`.

The coder.com download page already builds its command from `-fsSL` in
coder/coder.com#1093, and coder.com `main` has no other `install.sh`
one-liners outside test fixtures, so no coder.com change is needed.
DatoCMS content and a release verification page are not in this PR.

`main` since moved the upgrade and provisioner pages under
`docs/install/operate/` and removed the install one-liner from
`docs/install/index.md` in #29304, so that page no longer appears in
this diff.

## Testing

- `TZ=UTC go test ./cli
-run='Test(CommandHelp|ServerYAML|ErrorExamples|.*Golden)' -update` and
`go test ./enterprise/cli -run=TestEnterpriseCommandHelp -update` pass
and produce the committed golden diffs.
- `go test ./cli -run 'Test.*Version|TestWrapTransport'` passes,
including `Test_wrapTransportWithVersionCheck`.
- `go run ./scripts/configdocgen` output contains the new `curl -fsSL`
description.
- `markdownlint-cli2` on the edited style guide page reports 0 errors.
- `git grep` finds no remaining `curl -L …install.sh` outside the style
guide's **Don't** example.
- After merging `main`: `make pre-commit` passes, and `make test`, `make
test-js`, and `make site/out/index.html` pass.

Linear:
https://linear.app/codercom/issue/DOCS-964/standardize-installsh-curl-flags-on-fssl-across-docs-codercom-and-the

---
🤖 Built with AI assistance.
2026-09-24 18:23:54 +00:00
Andrew Aquino 6d490f076f feat(site/src/pages/WorkspacesPage): open link context menu when right clicking workspace name (#29813)
closes DASH-101

This PR changes `WorkspacesRow`'s workspace name from a `span` into a
`Link` (which renders an `a`), enabling right-clicking to open the
browser's context menu to perform link-specific actions like opening in
a new tab or copying the URL.

<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/1555449b-70cf-4b97-b279-bf43d541d8ba"
/>

The user who opened the issue is requesting that the row renders an
anchor element. However, the entire table row cannot be turned into an
anchor, since it contains other interactive elements, including other
anchors. Anchors cannot be nested according to the [`<a>`
spec](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element).

Within `WorkspacesRow`, we already support opening a workspace in a new
tab by clicking the row with the middle mouse button. Adding event
handlers to non-interactive HTML elements like `tr` is not an a11y best
practice, but it's a workable solution considering the interactive
descendant elements contained in each row.
2026-09-24 11:22:05 -07:00
Nick Vigilante d5a6047879 docs: restructure Install into the five phase deployment spine (#29304)
Restructures the Install section into the five-phase deployment spine,
so the reading order matches the order a deployment actually happens:
**plan, prepare, install, validate, operate.** Today the first thing a
reader sees is a shell command, and architecture and sizing sit
downstream in Administration, after the point where they would have been
useful.

Resolves [DOCS-869](https://linear.app/codercom/issue/DOCS-869). Part of
[DOCS-685](https://linear.app/codercom/issue/DOCS-685) and
[DOCS-738](https://linear.app/codercom/issue/DOCS-738).

> [!IMPORTANT]
> **Stacked on [#28960](https://github.com/coder/coder/pull/28960)**
(DOCS-871, terminology). Base is that branch, not `main`. Retarget to
`main` after it merges.
>
> **Paired with coder/coder.com
[#1077](https://github.com/coder/coder.com/pull/1077)**, which must
merge **first**. Without it, every inbound link to a moved page 404s in
the gap.

## Deliberately mechanical

No prose changes. The only edits inside moved pages are relative link
and image path repairs, so the diff reads as renames. That is the point:
this is the highest link-breakage change in the project, and it should
be reviewable as such.

The prose work is [DOCS-868](https://linear.app/codercom/issue/DOCS-868)
(phase overview, architecture rewrite, sizing split, actor table) and
[DOCS-872](https://linear.app/codercom/issue/DOCS-872) (new pages).

## The new spine

```text
Install and deploy Coder            /install
├── Coder CLI                                   [unchanged, retired by DOCS-870]
├── 1. Plan your deployment
│   ├── Architecture and components             [from admin/infrastructure]
│   └── Coder Validated Architecture            [from admin/infrastructure]
│       └── 1k / 2k / 3k / 10k users
├── 2. Prepare prerequisites
│   ├── Licensing                               [from admin/licensing]
│   ├── Air-gapped deployments                  [from install/airgap]
│   └── Mirror images and registries            [from install/registry-mirror-artifactory]
├── 3. Install the control plane
│   ├── Docker / Kubernetes / Rancher / OpenShift
│   ├── Cloud marketplace and VM images
│   └── Unofficial install methods
├── 4. Validate your deployment
│   └── Scale testing                           [from admin/infrastructure]
│       ├── Scale test utility
│       └── Scaling best practices
└── 5. Operate and maintain
    ├── External provisioners                   [from admin/provisioners]
    ├── Upgrading (+ best practices, ESR guides)
    └── Uninstall
```

Leaving Install: release channels become `reference/releases`, feature
stages become `reference/feature-stages`.

`docs/admin/infrastructure/` is gone entirely, which is what DOCS-738
recommended.

## Numbers

- 31 pages moved, all as `git mv` renames.
- 1 page deleted: `admin/infrastructure/index.md`, whose content was a
one-line section blurb.
- 5 new placeholder index pages, one per phase, each a sentence of
orientation plus `<children></children>`. The nav schema requires a path
on every entry, so a phase cannot exist without one.
- 265 relative links and asset paths repaired across 57 files.
- `docs/manifest.json` restructured. Entry count goes 460 to 464: plus 5
stubs, minus the deleted Infrastructure entry.

## Reviewer attention, please

**The redirects PR repairs 19 existing redirects, not just adds new
ones.** This was the surprise. `redirects.json` already had entries
whose *destinations* pointed at pages this PR moves, so they would have
started redirecting to 404s. Examples:
`/docs/architecture/architecture`, `/docs/admin/architectures`,
`/docs/scaling/scale-testing`, `/docs/licensing`, `/docs/enterprise`,
`/docs/install/offline`, `/docs/platforms`, `/docs/install/1-click`,
`/docs/admin/upgrade`, `/docs/install/cloud/ec2`, and both
`feature-stages` aliases. All 19 are fixed in the paired PR.

**This PR touches `scripts/`, so it is not docs-only.** Two release
tools write to paths that moved and would have broken silently at
release time:

- `scripts/update-release-calendar.sh`: `DOCS_FILE` now points at
`docs/reference/releases.md`.
- `scripts/releaser/docs.go`: `releasesFile`, and also `kubernetesFile`
and `rancherFile`, which pointed at `docs/install/kubernetes.md` and
`docs/install/rancher.md`.

<details>
<summary>Deliberate scope decisions</summary>

- **Self-managed vs cloud grouping is flattened.** The reconciled IA
nested platform pages under a "Self-managed platforms" parent. That
would need two more placeholder index pages for groups with no content
yet, so the platform pages sit directly under Phase 3 and the grouping
lands with the DOCS-868 prose.
- **Release-notes URLs left alone.** `scripts/releaser/release.go` and
`scripts/release/generate_release_notes.sh` embed
`https://coder.com/docs/install/releases` and `/docs/install/upgrade` in
release-note templates. The redirects cover them, and changing the
strings would require updating Go test fixtures in
`scripts/release/main_internal_test.go`. Better as its own change.
- **In-product doc links left alone.** Several `site/src` pages link to
`coder.com/docs/admin/provisioners` and similar. Those are absolute
URLs, so the redirects cover them. Updating them is a frontend change
that would pull frontend review into a docs restructure.
- **`admin/security/audit-logs.md` line 237** is hand-written prose
below the generated table, and its `../licensing/index.md` link had to
move with the licensing page. Verified `make gen` does not revert it.
- **`reference/feature-stages.md`** has generated blocks whose relative
links changed depth with the move. The generator named in its own marker
comment (`scripts/release/docs_update_feature_stages.sh`) no longer
exists in the repo, so those links were repaired by hand and the file is
effectively hand-maintained. Worth its own issue.
- **`install/cli.md` keeps its nav slot** here. DOCS-870 retires it.

</details>

## Verification

| Check | Result |
|---|---|
| Broken relative link scan | 0 in `install/`, `admin/`, `reference/`.
21 remain, all pre-existing illustrative examples in
`docs/.style/style-guide/**` and one malformed URL in `docs/README.md` |
| `make gen` | clean, manifest not clobbered, phase structure intact |
| `make lint/markdown` | pass, 508 files, 0 errors |
| `make lint/emdash` | pass |
| `make lint/docs-html` | pass |
| `make lint/prose` | pass, 1 intentional demo error, no new findings |
| `make pre-commit` | pass, including `lint/go`, `lint/ts`,
`lint/shellcheck`, and a slim build |
| Manifest audit | every path resolves to a file on disk; entry-by-entry
diff shows only the expected moves |

Generated with Coder Agents on behalf of @nickvigilante.


<details>
<summary>CI note: doc-check failure is infrastructure, not this
PR</summary>

`Analyze PR for Documentation Updates Needed` fails before it reviews
anything: the Coder account behind `agents-chat-action` returns `User is
not active (status = "suspended")`. It isn't a required check.
`check-docs` (linkspector) and every other check pass on `58ed9e3e4b`.

_CI note added by Coder Agents on behalf of @nickvigilante._
</details>
2026-09-24 13:51:38 -04:00
Nick Vigilante eb893f536d docs: move section page to index.md (#29858) 2026-09-24 13:13:27 -04:00
david-fraley 6f22956063 docs(docs): label MCP Server page early access (#29864) 2026-09-24 11:59:38 -05:00
Nick Vigilante dd3963a408 ci(.github/workflows): stop doc-check workspaces after each review (#29851)
doc-check creates one `doc-check-pr-<N>` workspace per PR and never
stops or deletes it. On docfood.cdr.dev, 54 of them ran at once, and the
host's load average reached about 2900, mostly from processes blocked on
I/O.

This stops the review workspace once the chat reaches a terminal status,
starts it again before the next review, and deletes it when the PR
merges. A PR closed without merging keeps its workspace, because stale
PRs get closed and reopened and the review needs its context back. Runs
for the same PR share a concurrency group, so one run cannot stop or
delete the workspace while another is reviewing in it.

The workspace lookup also now matches the name exactly. The `name:`
filter matches substrings (`coderd/database/queries/workspaces.sql`), so
`doc-check-pr-12` also matched `doc-check-pr-123`.

Depends on #29849, which fixes the pre-push hook crash that blocked
pushing this branch. Retarget to `main` after it merges.

Refs
[DOCS-1007](https://linear.app/codercom/issue/DOCS-1007/doc-check-stop-review-workspace-after-each-run-and-delete-it-on-pr),
CODAGT-1025

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

### Choices

- **Stop only on a terminal chat status** (`waiting`, `completed`,
`error`). When the 40-minute wait times out, the chat is still working
in the workspace, so the step leaves it running.
- **Start in the workflow, not the model.** The next run finds the
workspace stopped. The workflow starts it through the REST API and waits
up to 3 minutes, rather than relying on the agent to call
`start_workspace`. The job timeout goes from 45 to 50 minutes to make
room. A failed start only warns, so the agent's existing recovery path
still applies.
- **Delete on merge only.** Per review feedback, `closed` without
`merged` keeps the workspace. Workspaces for PRs that close and never
reopen will pile up (stopped, then dormant) until a sweep removes them.
- **Serialize per PR** with `cancel-in-progress: false`. Canceling a job
does not cancel the Coder chat, so cancellation would not stop the
review it interrupts.

### Follow-up

Replace per-PR workspaces with one persistent doc-check workspace and a
git worktree per PR, pinned through the action's `workspace-id` input.

### Verification

- `actionlint` and `zizmor --persona=regular` pass.
- The exact-name jq filter picks the right workspace from sample
responses, including an empty or null `workspaces` field.
- Not exercised end to end against docfood.

</details>

---

🤖 Generated by Coder Agents on behalf of @nickvigilante.
2026-09-24 16:50:21 +00:00
Cian Johnston 9a4cb3aebd refactor(aibridge/intercept): inject actor headers in middleware (#29839)
Move actor-header injection into the shared upstream-header middleware
for Messages, Chat Completions, and Responses. Read the authenticated
actor from the request context and remove the duplicated SDK-option
injection from blocking and streaming paths, completing the TODO from
@ssncferreira.

Preserve the existing header names and forwarding toggle. This is the
first PR in the actor-header stack: #29839 → #29840 (email forwarding) →
#29812 (configurable names).

Refs https://linear.app/codercom/issue/AIGOV-601

> 🤖 Generated by AI with human input.
2026-09-24 17:20:40 +01:00
陈志谦 442b08fee5 docs: drop duplicated 'the the' in scaletest flag help and OIDC docs (#29107)
Two doubled-word typos:

- `cli/exp_scaletest.go`: the `--connect-url` flag description shown by
`coder exp scaletest --help` read "inside **the the** workspace over
WireGuard"
- `docs/admin/users/oidc-auth/index.md`: "as **the the** username"

Docs/help text only.
2026-09-24 16:19:53 +00:00
Michael Suchacz 77763b5aa7 chore: own AgentsPage via the agents-frontend team (#29703)
Replaces the solo `@DanielleMaywood` ownership of
`site/src/pages/AgentsPage/` with the new `@coder/agents-frontend` team
(`@DanielleMaywood`, `@jakehwll`, `@jaaydenh`).

`coderd/schedule/autostop.go` (co-owned with `@deansheather`) is
intentionally left unchanged since it's not frontend code.

---
_Generated by Coder Agents on behalf of @ibetitsmike._
2026-09-24 17:16:42 +01:00
Bobby Ho c95a87cea7 feat: warn before narrowing a self-registered OAuth2 app's scope allowlist (#29777)
- Warn rather than block when admins narrow a self-registered OAuth2 app's scope allowlist. Clients requesting all advertised scopes may receive `invalid_scope` on new authorizations; existing tokens retain their scopes.
- Expose `dynamically_registered` in API responses and display registration type on the app page.
- Show no warning for widening or clearing allowlists, or for admin-created apps.
- Update scope and `invalid_scope` troubleshooting docs and remove the outdated note that the UI cannot set allowlists.

Closes PLAT-664.
2026-09-24 08:03:32 -07:00
Spike Curtis 9c0c3948c9 feat: narrow ssh and bash tool client.Workspace calls with include_related (#29542)
Part of the lite `codersdk.Workspace` work
([GRU-82](https://linear.app/codercom/issue/GRU-82),
[RFC](https://app.notion.com/p/coderhq/Lite-Workspace-API-Requests-3aad579be5928060b5e7cc65c539717f)).
Stacked on #29541.

Narrows the two production `client.Workspace` (get-by-ID) call sites
that read only a subset of the returned workspace.

- **`cli/ssh.go`** (`notifyCondition`) reads `TTLMillis` and
`LatestBuild.Deadline`. `TTLMillis` is computed server-side from the
template (`AllowUserAutostop`/`DefaultTTL`), so this requests `template`
and `latest_build` (the deadline is on the build itself; no job,
resources, or template version needed).
- **`codersdk/toolsdk/bash.go`** (`findWorkspaceAndAgent`) refetches
after autostart only to locate the first agent, so it requests
`latest_build.resources.agents`. Callers read only the agent plus the
top-level `Name`/`OwnerName`.

The other production by-ID callers were left on the default (full)
selection because they need the whole object: `support/support.go`
serializes the workspace into the support bundle,
`codersdk/toolsdk/chatgpt.go` JSON-marshals it for the model, and
`codersdk.ResolveWorkspace` is a generic resolver whose callers expect
everything. CLI paths that use `WorkspaceByOwnerAndName` are not touched
because that endpoint does not parse `include_related` yet.

### Testing

- `TestWorkspaceBash` and `TestWorkspaceBashTimeout` pass; the
autostart-refresh branch has no dedicated test, so its selection was
verified by tracing the fields read from the returned workspace and
agent.
- `cli` and `codersdk/toolsdk` build/vet/lint clean; the SSH deadline
notifier has no dedicated test, so its selection was verified the same
way (and by confirming the server derives `TTLMillis` from the
template).

---

*Generated by Coder Agents on behalf of @spikecurtis.*
2026-09-24 16:34:08 +02:00
Ben Potter 4def4b480a docs(docs/ai-coder/agents/platform-controls): rename sandboxing guide to network isolation (#29847)
Renames the guide added in #29698 from "Sandboxing" to "Network
isolation" in both places it appears: the `docs/manifest.json` entry and
the `agent-isolation.md` heading.

> Generated by Coder Agents on behalf of @bpmct.
2026-09-24 13:55:50 +00:00
Mathias Fredriksson 646270a62a fix(site/src/pages/AgentsPage): render stop_workspace like start_workspace (#29549)
`stop_workspace` had no renderer and used the generic tool row. The
backend already saves the stop build ID on the chat binding, so the
`start_workspace` renderer handles stop with its own labels and icon.

The build log polling fallback only accepted `pending` and `starting`,
so a `stopping` build was never streamed when the binding had not
arrived. It now uses `ACTIVE_BUILD_STATUSES`.
2026-09-24 16:14:36 +03:00
Ehab Younes bacb4fc6ed feat: expose per-app session counts (#29351)
Track individual applications across deployment statistics, Prometheus, telemetry, and the dashboard instead of exposing only fixed family totals. Preserve existing fields and gauges so current consumers can migrate without breaking.

- Add per-app counts with normalized identifiers and registry-backed display names, families, and bundled icons. Unrecognized apps retain their identifiers.
- Limit each statistics report to 64 distinct app names, combining excess names into an explicit overflow bucket.
- Group dashboard connections by family, including an Other category, with alphabetical per-app tooltips and distinct loading and empty states.
- Export app-keyed Prometheus counts separately from current family metadata, allowing queries to enrich historical counts without rewriting stored samples.
- Document family queries with unknown fallback, deployment isolation, and replica handling, alongside collection behavior and migration guidance.
- Include per-app counts in telemetry, update API schemas and documentation, and add regression coverage across collection, metrics, and dashboard behavior.

Closes #27411
2026-09-24 15:12:28 +03:00
deafad29cc chore: refresh AI model price book (#29835)
## Price book changes

22 models added, 5 models removed, 21 models changed.

<details>
<summary>Added</summary>

- bedrock/global.moonshotai.kimi-k3
- bedrock/global.openai.gpt-6-luna
- bedrock/global.openai.gpt-6-sol
- bedrock/openai.gpt-6-luna
- bedrock/openai.gpt-6-sol
- bedrock/us.moonshotai.kimi-k3
- bedrock/us.openai.gpt-6-luna
- bedrock/us.openai.gpt-6-sol
- copilot/claude-opus-5.5
- copilot/gpt-6-luna
- copilot/gpt-6-sol
- openrouter/aion-labs/aion-3.5
- openrouter/aion-labs/aion-3.5-mini
- openrouter/cohere/command-a-plus
- openrouter/fireworks/ember-1
- openrouter/qwen/qwen3.8-max-prime
- openrouter/stealth/space-bunny-alpha
- openrouter/upstage/solar-mini4
- openrouter/z-ai/glm-5.3-prime
- vercel/alibaba/qwen3.8-max-prime
- vercel/google/gemini-3.8-flash-lite-tts
- vercel/google/gemini-3.8-flash-tts
</details>

<details>
<summary>Removed</summary>

- openrouter/inclusionai/ling-3.0-flash-vl:free
- openrouter/mistralai/devstral-2512
- openrouter/nex-agi/nex-n2.5-mini
- openrouter/nex-agi/nex-n2.5-pro
- vercel/inclusionai/ling-3.0-flash-vl-free
</details>

<details>
<summary>Changed</summary>

- openrouter/deepseek/deepseek-v4-flash
- openrouter/deepseek/deepseek-v4-flash-0731
- openrouter/deepseek/deepseek-v4-pro
- openrouter/deepseek/deepseek-v4-pro-0813
- openrouter/deepseek/deepseek-v4.1-flash
- openrouter/minimax/minimax-m2
- openrouter/moonshotai/kimi-k2.7-code
- openrouter/nvidia/nemotron-3.5-lightning
- openrouter/qwen/qwen3-30b-a3b-instruct-2507
- openrouter/qwen/qwen3-next-80b-a3b-instruct
- openrouter/tencent/hy3
- openrouter/z-ai/glm-5.3
- openrouter/z-ai/glm-5.3-flashx
- openrouter/~deepseek/deepseek-flash-latest
- openrouter/~deepseek/deepseek-pro-latest
- openrouter/~deepseek/deepseek-v4-flash-latest
- openrouter/~moonshotai/kimi-latest
- openrouter/~z-ai/glm-flash-latest
- openrouter/~z-ai/glm-latest
- vercel/inclusionai/ling-3.0-flash-vl
- vercel/openai/gpt-oss-120b
</details>

## Review notes

Regenerated by `make gen/aibridge-prices` from the live
[models.dev](https://models.dev) catalog. Both artifacts come from one
snapshot, so they ship together:

- `coderd/aibridge/prices/data/prices.json`
- `site/src/modules/aiModels/knownModels/knownModelsGenerated.json`

These are customer-visible cost numbers taken from upstream data, so
this PR is never merged automatically. The summary above lists what
moved; check the diff for exact figures before approving.

Opened automatically by the [aigateway-prices-refresh
workflow](https://github.com/coder/coder/actions/runs/35979133021).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cian Johnston <cian@coder.com>
2026-09-24 10:48:28 +01:00
blinkagent[bot]andblink-so[bot] 59adebc28d fix(site/src/pages/AgentsPage): stop remembering the last model in the new chat composer (#29802)
## Problem

The new chat composer on `/agents` restored the last model that was
actually sent (`localStorage["agents.last-model-config-id"]`, written on
every send and on chat creation). Bumping to a more expensive model for
one tricky problem silently carried that model into every subsequent new
chat, which makes spend unpredictable.

## Change

New chat composer only. Model precedence becomes:

```
user click > personal root override (model) > personal root override (chat_default, resolved) > organization default > first available
```

The `last-used` step is removed, along with the `localStorage` key that
fed it. The key was written in `AgentCreatePage` and `submitChatTurn`,
but `AgentCreateForm` was its only reader, so the writes are removed as
dead code.

**The composer inside an existing chat is unchanged.** It resolves its
model from the chat record (`chats.last_model_config_id`) via
`AgentChatPage`, never from `localStorage`, so switching models
mid-conversation still sticks for that conversation.

## Stories

- `LastUsedModelFallbackWithoutRootOverride` ->
`OrganizationDefaultModelWithoutRootOverride`, now asserting the
organization default is selected and submitted.
- `DelayedAuthorizationPreservesForeignPersistedModel` ->
`DelayedAuthorizationResolvesPermittedOrganization`, with the obsolete
seeding dropped.

## Validation

- `pnpm exec tsc -p . --noEmit`
- `pnpm exec vitest run
src/pages/AgentsPage/components/ChatConversation/submitChatTurn.test.ts`
(14 passed)
- `pnpm exec biome check`

Storybook interaction tests were not runnable in this environment (no
browser runner); CI covers them.

Requested by @ibetitsmike.

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-09-24 11:09:05 +02:00
Jaayden Halko 82691e66a1 feat(site): add section switcher to agents sidebar header (#29829)
closes CODAGT-1179

<img width="314" height="274" alt="Screenshot 2026-09-24 at 17 10 55"
src="https://github.com/user-attachments/assets/c5f510db-324d-405a-8eca-9ad45abf43e6"
/>


Adds a dropdown to the right of the product logo in the agents sidebar
header with **Workspaces**, **Templates**, and **Agents** entries that
navigate to the respective pages. The current section (Agents) is marked
with a check.

The menu items are real links (`DropdownMenuItem asChild` + `Link`, the
same pattern as the Admin settings menu) so middle-click and cmd-click
open in a new tab and Radix roving focus keeps them keyboard reachable.
Navigation is covered in `ChatsSidebar.test.tsx` and the open state by
the `SectionSwitcherMenu` story.

<details>
<summary>Implementation notes</summary>

- The switcher lives in a new `chats/SectionSwitcher.tsx` next to
`UserSidebarFooter.tsx` rather than inline, since `ChatsPanel.tsx` is
already over 600 lines.
- `DropdownMenuRadioItem` would give `menuitemradio` semantics for free,
but its wrapper renders the indicator as a sibling of `children`, so it
cannot be used with `asChild` around a `Link`. Plain `DropdownMenuItem`
items with a manual `CheckIcon` and `aria-current="page"` were used
instead to keep the items as anchors.
- The checked item is hardcoded to Agents because this sidebar only
renders under `/agents`.
- The logo's existing link to `/workspaces` and the desktop-only
(`hidden sm:flex`) header are unchanged.

</details>

---

Generated by Coder Agents on behalf of @jaaydenh.
2026-09-24 15:34:51 +07:00
Lisa Fiander 2fcbe1957e chore: update low-risk dependencies (#29789)
## Summary

Updates two pinned dependency overrides in the root `package.json`:

| Package | From | To |
|---------|------|----|
| brace-expansion | 1.1.12 | 1.1.16 |
| js-yaml | 4.1.1 | 4.3.2 |

Pinned via the `pnpm.overrides` block; `pnpm-lock.yaml` is regenerated
to match.
These overrides affect the root tooling install only (docs/codegen
tooling); `site/` and `offlinedocs/` have their own lockfiles and are
unaffected.

## Testing

Run locally at the repo root:

- `pnpm install` — resolves/locks both; lockfile has no references to
old versions
- `pnpm run check-docs` (markdownlint + table formatter, uses js-yaml) —
504 files, 0 errors
- `quicktype` version + functional JSON→TS run (depends on js-yaml; used
in `make gen`) — pass
- `biome` / `markdown-table-formatter` load — pass

No behavioral changes; dependency version bumps only.
2026-09-24 09:11:29 +01:00