Commit Graph
15896 Commits
Author SHA1 Message Date
Atif Ali 7268cada94 docs: remove JetBrains Fleet references (#28301)
## Summary

The `jetbrains-fleet` module was removed from
[registry.coder.com](https://registry.coder.com) and `coder/registry`,
but the docs still pointed users at Fleet and at the now-dead module
page.

## Changes

- Removed `docs/user-guides/workspace-access/jetbrains/fleet.md` and its
screenshot
- Removed the Fleet entry from `docs/manifest.json`
- Dropped Fleet from the supported IDE lists in `jetbrains/index.md` and
`workspace-access/index.md`
- Glossary: replaced the Fleet link with Toolbox
- Contributing guide: replaced the dead `jetbrains-fleet` registry link
with `jetbrains`

## Validation

- No remaining Fleet references in `docs/` (the only match left is
Tailscale's "global fleet of DERP relays")
- `docs/manifest.json` parses, `pnpm run lint-docs` reports 0 errors

Preview:
https://coder.com/docs/@docs-remove-jetbrains-fleet/user-guides/workspace-access/jetbrains

> [!NOTE]
> `site/static/icon/fleet.svg` and its entry in
`site/src/theme/icons.json` are intentionally left in place. Removing
the icon would break existing templates that reference that path.
> The deleted page will 404 until a redirect is added in the website
repo.

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑‍💻
2026-08-19 20:35:57 +05:00
Jake Howell 46c0dba1e9 fix: standardize EmptyState typography (#27720) 2026-08-19 22:01:58 +07:00
Nick Vigilante 71b5bc398f docs: fix broken callout on the AI Gateway Monitoring page (#28303)
The callout on this page is broken, as flagged by Atif. This PR moves
the callout out of the `<details>` block to avoid the broken formatting.

Fixes DOCS-679

<!--

If you have used AI to produce some or all of this PR, please ensure you
have read our [AI Contribution
guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING)
before submitting.

-->
2026-08-19 10:51:35 -04:00
Nick Vigilante fc6d6babfa docs: add markdown_url front matter so the About page links to /docs.md (#28281)
The docs About page renders at `/docs/about`, but its Markdown source is
the docs root `README.md`, whose Markdown twin is `/docs.md`. The
path-derived mapping (`/docs/about` -> `/docs/about.md`) points the
"Copy page / view as Markdown" affordance and the sitewide
`rel="alternate"` link at a URL that 404s for this page.

Add a `markdown_url: /docs.md` front-matter override to
`docs/README.md`. It is inert for rendering and for `/docs.md` itself
(the body still begins at `# About`); it only populates the front matter
the docs site reads to advertise the correct Markdown alternate.

Reader side: coder/coder.com#1013 (DOCS-638). Neither change breaks
without the other, so they can merge in either order.

Refs DOCS-678

> This PR was created with AI assistance (Coder Agents).
2026-08-19 10:37:43 -04:00
Hugo Dutka c2bb62446d fix(coderd): remove per-chat system prompt limit (#28294)
Per-chat system prompts longer than 10,000 characters are rejected
during chat creation.

Remove that validation so chat creation accepts longer system prompts
within the existing request-body limit.
2026-08-19 16:36:41 +02:00
Nick Vigilante 31e95f7096 docs: fix prebuilt-workspaces example syntax and defaults (#28088) 2026-08-19 09:56:15 -04:00
Ben Potter 8a7e8d9d5b refactor: move chat prompt sanitization into codersdk (#28283)
Exports `SanitizePromptText` (and its helpers) from `codersdk` instead
of `coderd/x/chatd`, so API consumers can sanitize prompt text exactly
the way the server stores it.

## Why

coder/terraform-provider-coderd#412 adds a `coderd_chat_system_prompt`
resource whose `system_prompt` attribute compares values by their
sanitized forms (otherwise the trailing newline from
`file("system-prompt.md")` is perpetual drift, since the server stores
the sanitized value). That currently requires a mirrored copy of the
sanitizer in the provider, which can silently rot. Per review there
([discussion](https://github.com/coder/terraform-provider-coderd/pull/412#discussion_r3801110795)),
the sanitizer should be exported from `codersdk` and imported instead.

## What

- `coderd/x/chatd/sanitize.go` → `codersdk/promptsanitize.go` (pure
move; package + doc-comment note about why it lives in codersdk)
- `coderd/x/chatd/sanitize_test.go` → `codersdk/promptsanitize_test.go`
- Callsites updated (`exp_chats.go`, `chatd.go`, `subagent.go`,
`context_prompt.go`); no wrapper left behind, single source of truth
- No behavior change

> Generated by Coder Agents on behalf of @bpmct
2026-08-19 08:51:25 -05:00
Matt Vollmer ddf2d33665 docs: update Tallyman Agent Time reporting (#28275)
Moves Coder Agents usage reporting into the Licensing & Usage page and
updates the documentation to describe Agent Time and the
`hb_agent_runtime_v1` Tallyman payload.

Removes the superseded Usage Data Reporting page and its manifest entry,
and removes the obsolete AI Governance link to that page.

PR generated with Coder Agents
2026-08-19 09:51:07 -04:00
TJ 97cb722fb8 fix: show no budget instead of unlimited for empty group AI budget (#27993)
An empty per-member AI budget on the group settings page previously
displayed "unlimited budget" with a "Members in this group have no
spending cap." alert. Unlimited spend only applies when the everyone
group is the sole group, so this messaging was misleading everywhere
else.

## Changes

- Empty budget now shows "This group has **no budget** set. View docs"
with no info alert. "View docs" links to [Effective group
resolution](https://coder.com/docs/ai-coder/ai-gateway/cost-controls#effective-group-resolution)
using the versioned `docs()` helper.
- Removed the "Members in this group have no spending cap." alert
entirely.
- Input placeholder changed from `unlimited` to `no budget`.
- Updated the `AIBudgetUncapped` story expectations to match.

## Unchanged

- Entering an explicit `$0` still shows the "A $0 limit disables AI
access for this group." alert, as before.
- Saving with an empty field still sends `null` to the budget API;
backend semantics are untouched.

Story tests pass: `pnpm test:storybook
src/pages/GroupsPage/GroupSettingsPageView.stories.tsx` (7/7).

---

*This PR was generated by Coder Agents on behalf of @tracyjohnsonux.*
2026-08-19 06:15:06 -07:00
Cian Johnston da99941099 feat(site): add shared DateTimeRangeFilter component (#28255)
A text-expression datetime range picker with From/To inputs accepting
`now`, a clock time (current day), a date (midnight), or a date with a
clock time. Invalid text gets inline errors, underspecified expressions
resolve on blur, and out-of-order boundaries clamp against the other
one. The trigger derives a concise label ("Last 24 hours", "Apr 10",
"Aug 11 - Today", "Apr 17 - 19").

Placed in `site/src/components/DateTimeRangeFilter/` so other pages can
reuse it. Expression parsing and trigger-label derivation live in
`timeRange.ts` next to the component; both are generic over `Date`
pairs. Depends on #28254 for the shared `filterQuery` serialization
helpers.

Part of
[AIGOV-580](https://linear.app/codercom/issue/AIGOV-580/ai-gateway-sessions-page-takes-5-10-seconds-to-load)

---
_Generated by Coder Agents on behalf of @johnstcn._$

---

**Stack:** #28254 (filterQuery fix) \u2192 #28255 (component) \u2192
#28256 (sessions page)
2026-08-19 13:47:06 +01:00
Paweł Banaszewski 63641b98c8 fix: treat a missing serve endpoint as a fatal dial error (#27864)
Adds 404 as a terminal error for establishing DRPC connection.

A standalone AI Gateway pointed at a coderd that does not expose
`/api/v2/ai-gateway/serve` gets a 404, which the connect loop classified
as transient and retried forever. Redialing cannot fix a missing
endpoint.
404 now is treated as terminal handshake failure. `--url` is expected to
point directly at coderd, so a 404 from an intermediary is not
distinguished.

Refs https://linear.app/codercom/issue/AIGOV-320/write-connection-tests

---

Generated with Coder Agents.
2026-08-19 13:19:20 +02:00
Danielle Maywood 8405bbb26c feat(site): show best-effort model pricing on the model form (#28290) 2026-08-19 11:45:30 +01:00
Atif Ali 34e95c46bf docs: note JetBrains client attribution in AI Gateway (#28296)
Noticed while testing Junie that JetBrains AI Assistant sends
`User-Agent: ktor-client`, the stock Ktor default, so AI Gateway records
these sessions as `Unknown`. Admins who enable Gateway for governance
won't see their JetBrains attributed in the sessions view or the
`client` filter.

Documents the behavior on the JetBrains client page. Nothing to fix on
our side, matching `ktor-client` would misattribute any other Ktor-based
application.
2026-08-19 15:32:23 +05:00
Paweł Banaszewski a441b03d70 feat: add yaml config option to standalone AI gateway (#28258)
`coder ai-gateway start` now accepts a `--config` / `-c` flag (and
`CODER_CONFIG_PATH`) to load configuration from a YAML file.
2026-08-19 10:07:22 +00:00
Ethan 059546e92a ci: skip oversized flake-check selections (#28293)
Skip the targeted Go flake check when a change selects more than 100
tests, and update `whichtests` to the version that supports this limit.

Large selections usually come from broad or mechanical changes rather
than a narrowly introduced flaky behavior. Repeating hundreds of tests
substantially increases runtime and runner resource usage while
providing less focused signal; regular CI still exercises the affected
test suite across its normal jobs and repetitions.
2026-08-19 09:21:44 +00:00
Jim 1fbd029754 fix(provisioner/terraform): sync version constants with the shipped binary (#27871)
`provisioner/terraform/install.go` still pins `TerraformVersion` to
1.14.5 and `maxTerraformVersion` to 1.14.9, but the shipped binary has
been Terraform 1.15.5 since v2.35.0. `scripts/Dockerfile.base`,
`install.sh`, `mise.toml`, `mise.lock`, and `flake.nix` all track
1.15.5; only the Go constants were left behind, which makes the `NOTE:
Keep this in sync with ...` comments on those constants false.

Two user-visible effects on the same release:

- Provisioner daemons that have a system Terraform log `installed
terraform version newer than expected, you may experience bugs
installed_version=1.15.5 max_version=1.14.9` on every startup. The check
at
[`provisioner/terraform/serve.go#L122-L126`](https://github.com/coder/coder/blob/79723db2d23b6b941e405a8d3c2200206e7e4cb4/provisioner/terraform/serve.go#L122-L126)
is warn-only, so the 1.15.5 binary is used anyway and the warning is
pure noise.
- Hosts *without* a system Terraform fall through to `Install()` at
[`serve.go#L105`](https://github.com/coder/coder/blob/79723db2d23b6b941e405a8d3c2200206e7e4cb4/provisioner/terraform/serve.go#L105),
which downloads `TerraformVersion`. So the same Coder version provisions
with 1.15.5 in some environments and 1.14.5 in others.

This sets `TerraformVersion` to 1.15.5 and `maxTerraformVersion` to
1.15.9, keeping the existing `.9` convention that auto-allows patch
releases. `minTerraformVersion` is unchanged. No other file needed
updating; everything else already tracks 1.15.5.

This is a consistency fix, not a CVE remediation.

The divergence was already identified as [CRF-2 in the review of
#27183](https://github.com/coder/coder/pull/27183#pullrequestreview-4685322854)
(`provisioner/terraform/install.go:25`), which noted that leaving the
constants behind means "a maintainer who trusts it could 'resync'
install.sh/Dockerfile.base back to 1.14.5". That PR was closed for
unrelated reasons; this change addresses only the drift.

Refs #27183
2026-08-19 08:35:25 +01:00
Matt Vollmer ddcffd8248 docs: remove inaccurate Agent Firewall filesystem protection claim (#28286) 2026-08-19 06:44:34 +02:00
Bobby Ho 663f41ffa9 feat: derive OAuth2 client type from token_endpoint_auth_method (#28043)
Adds an OAuth2 client type (public vs confidential, RFC 7591 §2) derived
from the requested auth method instead of hardcoded confidential. The
type is stored and guarded here, but no endpoint enforces on it yet;
public behavior at the token endpoint follows in the next PR in the
stack.

- Client type is derived once and reused by both registration and
redirect URI validation, so they can't disagree
- IsPublic() fails closed: an unrecognized or missing value reads as
confidential
- RFC 7592 update (PUT) now rejects moving a client between public and
confidential (400) instead of silently flipping it when the auth method
is omitted
- Discovery still doesn't advertise "none"; follows once the token
endpoint honors it

### Behavior by client shape

`client_type` is derived from `token_endpoint_auth_method` at POST and
pinned at PUT. RFC 7592 GET/PUT authenticate with the registration
access token, not the client secret, so neither endpoint reads a secret.

| Registered with | Stored `client_type` / method | GET reports | PUT
that flips the method |

|------------------------------------|---------------------------------------|-----------------------|-----------------------------------------|
| omitted, or `client_secret_basic` | `confidential` /
`client_secret_basic` | `client_secret_basic` | `none` → 400
`invalid_client_metadata` |
| `none` (new) | `public` / `none` | `none` | `client_secret_*` → 400
`invalid_client_metadata` |
| `none` (before this PR) | `confidential` / `none` | `none` | either →
200, type stays `confidential` |

- PUT still replaces every other RFC 7591 field. `client_type` is the
only pinned one; the method may move within a type
(`client_secret_basic` ↔ `client_secret_post`).
- Row 3 is the only shape where the two columns disagree. The guard
fires only on a method change that crosses the type line, so those
clients keep managing themselves instead of being locked out of their
own configuration endpoint.
- The token endpoint does not consult `client_type` yet, so every client
still authenticates with a secret and registration still issues one.

Split out of #27873, second in the stack (on top of #28041).
Refs
https://linear.app/codercom/issue/ENG-3029/oauth2-support-public-client
2026-08-18 21:12:44 -07:00
Jake Howell 4d13bef74d feat(site): add Install Coder Desktop item to UserDropdown (#28244)
> 🤖 This PR was modified by Coder Agents on behalf of Jake Howell.

Resolves
[DEVEX-722](https://linear.app/codercom/issue/DEVEX-722/add-install-coder-desktop-button-to-userdropdown).

Adds an **Install Coder Desktop** item to `UserDropdown`, sitting
directly above the existing **Install CLI** option. Because
`UserDropdownContent` is shared, it appears in both the navbar dropdown
and the agents-page sidebar footer.

### Screenshots

macOS/Windows shots are captured with `navigator.platform` overridden
accordingly; the Linux shot is the real workspace platform, where the
Coder Desktop item is hidden. Install Coder Desktop uses a monitor
glyph, and Install CLI now uses a terminal glyph (it was a monitor on
`main`).

| `main` (before) | This PR · macOS/Windows | This PR · Linux / iPad OS
|
| --- | --- | --- |
| ![UserDropdown on
main](https://raw.githubusercontent.com/coder/coder/jakehwll/devex-722-assets/.github/assets/devex-722-userdropdown-main.png)
| ![UserDropdown with Install Coder
Desktop](https://raw.githubusercontent.com/coder/coder/jakehwll/devex-722-assets/.github/assets/devex-722-userdropdown-new.png)
| ![UserDropdown on Linux without the Desktop
item](https://raw.githubusercontent.com/coder/coder/jakehwll/devex-722-assets/.github/assets/devex-722-userdropdown-linux.png)
|

### Behaviour
- **Platform-gated visibility:** shown only on macOS and Windows (the
platforms Coder Desktop ships for), hidden on Linux/other. The Linux
client
([coder/coder-desktop-linux](https://github.com/coder/coder-desktop-linux))
is experimental and not advertised yet, so it stays hidden there.
- **Links to the docs** (`https://coder.com/docs/user-guides/desktop`)
rather than a single install method. The docs page is the canonical hub
covering Homebrew, WinGet, manual release downloads, and source, and it
stays current without frontend changes. The `coder-desktop-*` repo
READMEs don't enumerate install methods; they defer to these same docs.
- **No installed-detection:** consistent with the Install CLI item, we
don't try to detect whether Coder Desktop is already present.

### Changes
- `site/src/utils/platform.ts`: add `isWindows()` and
`supportsCoderDesktop()`.
- `UserDropdownContent.tsx`: render the platform-gated item
(`MonitorIcon`) and switch Install CLI to `TerminalIcon`.
- Unit tests for the platform helpers and Storybook coverage for the
dropdown item (present + correct href on macOS/Windows, absent on
Linux/iPadOS).


Implementation plan & decision log

**Ticket open questions and decisions**

1. *Shown to all users or only supported platforms?* Only supported
platforms (macOS, Windows); hidden elsewhere. The Linux client is
experimental and not advertised yet, so hiding it there is intentional.
2. *Where should it link?* The Coder Desktop docs page. Users install
via many methods (brew, winget, releases, source); the docs are the
single hub that lists them all and are maintained in-repo. The GitHub
release pages / repo READMEs only cover downloads and defer back to the
docs.
3. *Hide when already installed?* No. There is no reliable browser-side
way to detect a native app install, and it mirrors how Install CLI
behaves.

**Implementation**
- Extend `site/src/utils/platform.ts` with `isWindows()` and
`supportsCoderDesktop()` (reusing the existing `isMac()`).
- In `UserDropdownContent.tsx`, conditionally render an `Install Coder
Desktop` `DropdownMenuItem` (external link, `MonitorIcon`, opens in a
new tab) above `Install CLI` when `supportsCoderDesktop()` is true.
- Tests: `platform.test.ts` (OS detection via `vi.stubGlobal`) and
`UserDropdown.stories.tsx` (visibility + href per platform, mocking
platform detection with `spyOn`).



Left as a **draft** pending review, let me know when you'd like it
opened.
2026-08-19 09:11:07 +07:00
McKayla はな 60722bb653 fix: link workspaces empty state to template builder (#28280) 2026-08-18 18:30:28 -06:00
Andrew Aquino 71e95a3611 feat(coderd/tracing): correlate request logs and spans by client_session_id (#27671)
## What

Adds `client_session_id` correlation to coderd's HTTP request handling,
per the
[Connection log collection and correlation
RFC](https://www.notion.so/coderhq/Connection-log-collection-and-correlation-36ed579be5928025a56cd11fe58661fb).

Clients attach a per-session correlation ID to every API request via W3C
baggage using the `client_session_id` key. This change makes coderd's
tracing
middleware read that baggage member and:

- add `client_session_id` to the **per-request log context** so all logs
for a
request (and the handlers it calls) can be correlated by a single ID,
and
- set `client_session_id` as a **span attribute** when tracing is
enabled.

Per RFC requirement 6.1, the value is added to the log context **even
when
tracing is disabled** (the middleware previously returned early when no
tracer
provider was configured, so baggage was never read). The
`client_session_id` is
validated as a 32-character hexadecimal string (a 16-byte value, per RFC
requirement 1) to guard against logging arbitrary client-controlled
baggage
values.

## Scope

This is `DEVEX-659` and is intentionally limited to the coderd tracing
middleware. It is the first piece of a stack: the web terminal client
change
(`DEVEX-663`) that generates and sends the `client_session_id` will be
stacked on top
of this PR. No client currently sends `client_session_id` baggage, so
this change is
a no-op until the client work lands.

## Testing

- `coderd/tracing`: new unit tests cover `validSessionID`, baggage
extraction
  (`sessionIDFromHeaders`), and the middleware end to end, asserting
`client_session_id` lands on the log context with tracing enabled
**and** disabled,
  is exposed as a span attribute when tracing is enabled, and that
  absent/malformed baggage is ignored.
- Existing `Test_Middleware` route-matching behavior is unchanged.

<details>
<summary>Design notes / decision log</summary>

- **Where the value is read:** the existing `tracing.Middleware` runs
high in
the coderd middleware stack (`coderd/coderd.go`), before request-id and
request-logger middleware, and already matches the `/api`, `/api/**`,
app
proxy, and external-auth routes. Reading baggage here means the
`client_session_id`
is on the context before the request logger and handlers run, so it
flows
into all downstream `slog` calls that use the request context. This
mirrors
  the existing `request_id` pattern in `httpmw.AttachRequestID`
  (`slog.With(ctx, ...)` + span attribute).
- **Works when tracing is off:** the middleware now gates only on the
route
matcher, extracts baggage and adds `client_session_id` to the log
context for all
matched routes, and only then branches on whether a tracer is
configured.
When a tracer is present, `client_session_id` is additionally set as a
span
  attribute.
- **Explicit baggage propagator:** extraction uses
`propagation.Baggage{}`
directly rather than the global text map propagator, so it does not
depend
on the global propagator being configured (also makes it deterministic
in
  tests).
- **Validation:** only a 32-char hex string is accepted (lower or upper
case).
Malformed values are dropped rather than logged, preventing
log/attribute
  pollution from arbitrary client-supplied baggage.
- **Out of scope for this PR (tracked elsewhere):** client
generation/sending
of `client_session_id` (`DEVEX-663`, web terminal), the equivalent
agent-side
middleware (RFC 6.2), `connection_logs.client_session_id` (RFC 12), and
additional
  connection state-change logging (RFC 7-13).

</details>

---

_Opened by Coder Agents on behalf of @aqandrew._
2026-08-18 17:28:36 -07:00
Jon Ayers 821d91fabd fix: log tailnet tunnel authorization decisions (#27819) 2026-08-18 18:21:50 -05:00
TJ b3f05a23fc feat(site/src/pages/AgentsPage): surface subagents in the chat sidebar (#28234)
## What

Makes subagents more discoverable in the agent chat sidebar, without
disturbing the existing status icon or layout.

- **Parent chat rows show a subagent count** with a bot icon (e.g. `3
🤖`) at the start of the metadata line, next to the diff stats. Only
shown when a chat has subagents; uses lucide `BotIcon`, the same icon
this codebase already uses to denote agents. Passive indicator (the
leading status icon, timestamp, and kebab are untouched).
- **The chat actions menu gains a "Show subagents (N)" / "Hide
subagents" toggle**, grouped directly under "Rename chat" in both the
kebab (⋮) and the right-click context menu. It expands/collapses the
row's subagents and is only rendered when the chat has subagents.

Expansion still uses the existing sidebar expand state, so the hover
chevron, the menu toggle, and the count all stay in sync.

## Notes / decisions

- Subagent children are capped at depth 1, so the count and toggle only
appear on parent chats.
- The menu toggle lives in the shared `ChatActionsMenuItems`, so it
appears in both the kebab and the right-click menu; the top-bar kebab
intentionally does not pass the props, so it stays hidden there.
- The on-row `N 🤖` indicator is currently passive (clicking the row
opens the chat as before). Can be made a click-to-expand control if
wanted.

## Testing

Validated in Storybook (`ChatsSidebar` stories) with 0 TypeScript
errors. Added a `SubagentsMenuToggle` story with a `play` function
asserting the label swaps between "Show subagents (3)" and "Hide
subagents" and that children expand. Existing `ChatsSidebar.test.tsx`
does not assert menu contents and is unaffected.

---

*This PR was generated by Coder Agents on behalf of @tracyjohnsonux.*
2026-08-18 13:25:42 -07:00
Danielle Maywood 72a6c8ae72 fix(site): stop the new-turn scroll snap on agent chat (#28213) 2026-08-18 21:01:43 +01:00
Bobby Ho 166d92ba73 fix: bound request body size on JSON API endpoints (#28168)
## Summary

`httpapi.Read` decoded request bodies with no size limit, so a single
request could allocate memory without bound. This adds a 4 MiB default
ceiling, leaves the endpoints that legitimately need more explicitly
exempted, and counts the rejections so a limit set too tight is visible.

This is the first of three PRs split out of #28048, covering the
endpoints that answer in `codersdk.Response` shape. The OAuth2 decode
paths (RFC 6749, RFC 7591) and the SCIM ones (RFC 7644) answer in their
own error shapes and follow in separate PRs, along with the lint rule
that pins the invariant.

Closes PLAT-463. Remediates SEC-416 (CWE-770, CVSS 7.5) and SEC-392.

## Problem

`httpapi.Read` calls `json.NewDecoder(r.Body).Decode(value)` with no
ceiling, and no middleware in the chain bounds body size. The exposure
is pre-authentication: login, OTP, and first-user creation all read a
body before any authorization decision is reached. The existing rate
limiter bounds request *rate*, which is orthogonal to the memory a
single admitted request may consume.

## Fix

`Read` is split into `Read` and `ReadLimit`. `ReadLimit` wraps `r.Body`
in an `http.MaxBytesReader` and keeps the existing decode and validate
logic; `Read` delegates to it with a new `DefaultMaxRequestBodyBytes` of
4 MiB, which covers the 124 remaining non-test callers at a single site.

`http.MaxBytesReader` composes as tightest-wins, so the handlers that
pre-wrapped their own bodies pass their limit to `ReadLimit` rather than
wrapping, and each keeps its previous ceiling byte for byte. That
matters most for the bulk secrets import at `8 * MaxSecretsFileBytes`:
an unconditional wrap inside `Read` would have silently halved it to the
default. `TestImportUserSecretsBodyLargerThanDefaultLimit` is the
regression guard for that specific failure, and
`TestMaxBytesReaderNesting` pins the composition behavior the whole
requirement rests on.

Every rejection site calls `httpapi.RecordRequestBodyLimit`, which names
the limit that tripped on the request's existing log line and marks the
request so `coderd_api_requests_too_large_total{reason="request_body"}`
counts body rejections apart from the 413s coderd answers for other
causes, such as agent log storage overflow. A limit set too tight for a
legitimate payload therefore surfaces without waiting for a user report.

The limit is a constant rather than a deployment option: an operator
raising it to unblock something would reopen the vulnerability as
configuration, where a security scan will not find it. A legitimate 413
is answered with a targeted `ReadLimit` on that endpoint.

## Behavior change

`POST /api/v2/files` now answers 413 rather than 400 when a request body
exceeds `HTTPFileMaxBytes`. It installed that bound already but reported
the rejection as a read failure, which leaked the stdlib `http: request
body too large` string through `Detail` and kept the largest limit in
the tree off the metric. The separate 413 for an oversized expanded
archive is unchanged.

The task log snapshot endpoint now answers 413 rather than 400 when its
64 KiB cap is exceeded. Routing it through `ReadLimit` also changes its
decode-failure message from "Failed to decode request payload." to
"Request body must be valid JSON.", which is what every other endpoint
answers. Its tests are updated to match both.

`coderd_api_requests_too_large_total` is new, so there is no existing
query to migrate. It counts the 413s coderd answers, labeled `method`,
`path`, and `reason`. `reason="request_body"` is a rejection by one of
the limits above; `reason="other"` is a 413 that has nothing to do with
body size, such as agent log storage overflow.

## Reading this

The commits are ordered to be read in sequence. Commits 1 and 2 are the
security fix; commits 3 to 5 are the observability consequences, and
commit 3 is the one that touches dashboards. Commit 7 documents the
limit on the REST API reference index. Commits 6 and 8 add and revert an
exhaustive `@Failure 413` annotation pass, which buried the fix under
its regenerated swagger, and cancel out.
2026-08-18 12:54:45 -07:00
Matt VollmerandNick Vigilante 5f6eeda588 docs: add Licensing & Usage page and reorder agents manifest (#28263)
Adds a new Licensing & Usage page under `docs/ai-coder/agents/` covering
the difference between Community and AI Premium licenses, how Agent Time
is measured, and what happens when concurrency or usage limits are
reached.

Reorders the Coder Agents section in `docs/manifest.json` to the
following sequence: Getting Started, Architecture, Platform Controls,
Extending Agents, Models, Tools, Chat Sharing, Search Syntax, Licensing
& Usage, Tasks to Chats API Migration.

---

PR generated with Coder Agents

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-18 15:19:26 -04:00
Mathias FredrikssonandMichael Suchacz d3f08b1983 feat: audit chat system instructions changes (#27668)
Adds an audit record for administrative events on the deployment-wide
chat instruction settings (system prompt, the include-default toggle,
and the plan-mode instructions), per CODAGT-719 and operator decision
D5. Each endpoint records under a stable identity: resource type
`chat_instruction_settings`, a fixed resource ID and a human-readable
target ("System prompt", "Plan mode instructions"), so two changes to
one setting share an ID and history-by-setting works. A real change
exports a Write entry with the old-to-new text visible; a
value-identical PUT still upserts and still returns 204 but records
nothing.

Attempts are recorded, not only transitions. Identity is assigned before
the authorization check, so a denied PUT exports a 403 row with an empty
diff (no request content reaches it), a validation failure exports a 400
row, and a write failure exports a 500 row, each with an empty diff; an
operator can tell "nothing changed" from "something changed and capture
degraded" by the status code.

The write path stays authoritative. The advisory lock and, on plan-mode,
the transaction exist only to serve change-detection; if any of that
machinery fails (lock, begin, commit, rollback), the handler runs main's
idempotent write path directly and derives the response from it, so a
member-visible failure of audit-only infrastructure can never replace
main's successful response. Accepted consequence: when the lock cannot
be taken, two concurrent identical writes can produce two rows instead
of one. That is audit degradation, which is allowed; changing a member's
response is not. Write failures keep the exact response the endpoint
produced before this wiring (transaction error for the system prompt,
which was always transactional; the raw write error for plan mode, which
was not), and the full transaction error is logged so rollback failures
cannot vanish.

<details>
<summary>CODAGT-66 plan entry: S1 (verbatim)</summary>

**S1 `feat: audit chat system instructions changes`** (CODAGT-719; base:
main)

- Struct: `database.ChatSystemPromptSettings{ID uuid.UUID; SystemPrompt
string; IncludeDefaultSystemPrompt bool; PlanModeInstructions string}`
in `coderd/database/types.go` (ticket-sketched shape; one struct, both
endpoints).
- Registration: union entry (diff.go), table.go entry (`id`
ActionIgnore, other three ActionTrack), `AuditActionMap` Write-only;
four request.go cases (`ResourceTarget` "", `ResourceID` from struct,
`ResourceType` new enum value `chat_system_prompt_settings`,
`ResourceRequiresOrgID` false with the "Artificial ID / deployment
singleton" comment convention).
- Migration: `ALTER TYPE resource_type ADD VALUE IF NOT EXISTS
'chat_system_prompt_settings';` comment-only no-op down (000558 shape);
number picked at push per the numbering constraint.
- codersdk: constant + prose `FriendlyString` ("chat system prompt
settings"); `TestAuditDBEnumsCovered` forces both. `coderd/audit.go`
presentation switches: rely on safe defaults (no link, generic
description); no FE changes (filter label falls back to capitalized
value; acceptable per precedent).
- Wiring `putChatSystemPrompt` and `putChatPlanModeInstructions`:
InitRequest with Action Write; artificial `ID: uuid.New()` on `New` only
when a change is detected; no-op suppression by leaving both aReq sides
unset (nil resource IDs skip the log, request.go skip rule); the write
path itself stays byte-identical (upserts still run unconditionally).
- `putChatSystemPrompt` (writes two keys conditionally in one existing
tx): inside that tx, read the pair via `GetChatSystemPromptConfig` for
`Old`, perform the conditional writes exactly as today, then RE-READ the
pair for `New`. The re-read is load-bearing:
`include_default_system_prompt` is computed from the toggle row AND the
prompt, so a prompt-only write can flip the effective value without the
request carrying the pointer. `PlanModeInstructions` stays zero on both
sides.
- `putChatPlanModeInstructions` (no tx exists today): wrap its
read-upsert in `InTx` (behavior-preserving: same single write);
`Old`/`New` populate only `PlanModeInstructions`; the two system-prompt
fields stay zero on both sides; no cross-key reads.
- Change detection compares the populated payload fields only (never the
artificial ID).
- Tests: handler-level coderdtest with `audit.NewMock()` asserting Write
entry on change and NO entry on a value-identical PUT, for both
endpoints (this also exercises `ResourceRequiresOrgID` end to end); the
fallback-flip case (no explicit include-default row, nonempty prompt set
to empty, effective boolean flips: entry emitted with the boolean diff);
diff assertions (old->new prompt text tracked, not secret) in
`enterprise/audit/diff_internal_test.go`; `TestAuditableResources`
passes by construction.
- Bookkeeping at PR open: correct CODAGT-719's no-op premise ("matches
the existing 204-on-unchanged behavior" does not exist on main;
suppression is new, write path unchanged).
- Review focus: Old capture and the New re-read inside the tx (three of
four existing singletons never set Old; do not copy them; and the
computed include-default value makes a naive New construction wrong);
the skip-on-no-op mechanism; prompt text deliberately visible in diffs.

</details>

Note: the plan excerpt above predates operator decision D5 (2026-07-30),
which this PR implements: the resource type is
`chat_instruction_settings` (not `chat_system_prompt_settings`), each
setting carries a stable ID and a display-name target (not a per-write
artificial ID and an empty target), no-op suppression runs through
`InitRequestWithCancel` (not the nil-ID skip), and attempts (denied,
failed, capture-degraded) record rows with real statuses and empty
diffs. Ticket bookkeeping for CODAGT-719 was corrected on Linear at
kickoff: the ticket's "matches the existing 204-on-unchanged behavior"
premise does not exist on main; suppression is new, and the write path
is unchanged.

> 🤖 This PR was created with the help of Coder Agents, and _will be_
reviewed by a human. 🏂🏻

---------

Co-authored-by: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com>
2026-08-18 20:03:06 +02:00
Michael Suchacz ba5717dc67 fix(site/src/pages/AgentsPage): disallow queued message edits (#28265)
Closes CODAGT-230.

Selecting "Edit queued message" in Agent Chat did not stop the queued
message from sending: edit mode was purely client-side state, so at turn
end the backend promoted the queued message and sent it anyway, leaving
the UI stuck in a stale "Editing queued message" state with the send
button showing "Save".

This removes queued-message editing entirely instead of adding backend
locking. Queued messages can still be promoted ("Send now") and deleted
("Remove from queue"); editing already-sent history messages is
unchanged.

## Changes

- Remove the Edit pencil from queued message rows
(`QueuedMessagesList`), the "Editing queued message" banner and "Save"
button label (`AgentChatInput`), and the queue-edit state, handlers, and
prop plumbing (`AgentChatPage`, `AgentChatPageView`, `ChatPageContent`).
- Remove the queued-edit save flow that deleted the original queued row
and re-queued a new message, plus the now-unused `rawText`/`fileBlocks`
fields of `getQueuedMessageInfo`.
- Drop the redundant `isEditingHistoryMessage` prop on `ChatPageInput`,
which had become identical to `isEditing`, and stop discarding the
delete/promote promises so `QueuedMessagesList` busy state works again.
- Replace the queued-edit stories and tests with an `ActionsExcludeEdit`
regression story asserting queued rows expose "Send now" and "Remove
from queue" but no "Edit" button.

## Testing

- `pnpm -C site check`, `pnpm -C site lint:types`.
- Unit: `AgentChatPage.test.ts`, `QueuedMessagesList.test.ts` (92
tests). Storybook: all four touched story files (102 tests). A
pre-existing unhandled xterm error in `AgentChatPageView.stories.tsx`
reproduces identically at the merge base.
- Remote dogfood UAT passed on a dev.coder.com workspace with a real
model: no edit affordance on queued rows, queued delete and turn-end
promotion still work, history-message editing and Escape behavior
unaffected.

> Mux acted on behalf of Mike for this pull request.
2026-08-18 19:34:40 +02:00
Michael Suchacz affeeaf9c8 feat: extend agent chat MCP tools for remote UAT evidence loops (#28233)
Extends the Agent-chat MCP tools so an unattended UAT evidence loop can
fetch artifacts, monitor long runs, and find prior runs without burning
model context.

## Backend

- New `chat_files_token` crypto key feature (migration 000571) with
rotator support and a dedicated signing keycache on coderd.
- `POST /api/experimental/chats/files/{file}/download-url`
(authenticated) mints a short-lived (5 min) signed URL and returns it
with `sha256`, `size_bytes`, `name`, `mime_type`, and `expires_at`.
- `GET /api/experimental/chats/files/{file}/download?token=` (no session
token) redeems the signed URL: verifies the JWS, requires the token's
`file_id` to match the path, and re-checks the minting user's RBAC
access live at redemption. Clients can `curl -o` artifacts with zero
credentials in the URL consumer.
- `ChatFileMetadata` gains `size_bytes` (via `octet_length`, no bytes
fetched).

## MCP tools (`codersdk/toolsdk`)

- `coder_download_chat_file`: by `file_id` or `chat_id`+`file_name`;
returns the signed URL plus checksum and size instead of base64.
- `coder_await_chat`: blocks (bounded `wait_secs`, 1-120) until a chat
leaves `running`/`interrupting`, using the existing watch stream with
subscribe-before-read.
- `coder_list_chats`: label, query, and limit filtering; chat
projections now include labels.
- `coder_get_chat_messages`: `after_id` forward cursor with
`next_after_id` (exact incremental reads), plus per-message `files`
metadata so artifact-bearing messages are identifiable.
- `coder_get_chat`: file listings now include `size_bytes` and
`created_at`.
- `coder_list_templates`: exposes `agents_allowed` for pre-flight
checks.

## Testing

- coderd: mint/redeem happy path with an unauthenticated client,
expired/tampered/file-mismatched tokens, auth still required on the
plain file endpoint, non-owner mint rejection.
- toolsdk: harness + integration coverage for all new/changed tools,
including signed-URL redemption with checksum verification,
forward-cursor exactness, await transition/timeout paths, and label
filtering.
- Remote dogfood UAT (dev.coder.com Coder Agent) passed all six
acceptance scenarios end to end over both MCP transports.

Note: `go test ./codersdk/toolsdk/` has a pre-existing goleak flake on
main (leaked `agentssh` non-PTY session goroutines from SSH exec tests;
reproduced 3/3 on clean `b4971bc49f1`). It is unrelated to this diff.

> Mux acted on Mike's behalf to create this PR.

<!-- mux-attribution: model=claude-sonnet-4-6 thinking=high -->
2026-08-18 19:15:30 +02:00
Michael Suchacz 7724ee281a feat: defer MCP tool schemas behind a find_tools search (#28225)
## Summary

When the `mcp-tool-search` experiment is enabled, chatd stops inlining
connected MCP tool schemas into every generation. It instead exposes a
built-in `find_tools` tool whose description carries a compact catalog
of the deferred tools, and only ships full JSON schemas for tools the
model has activated by searching or by calling them directly.

Closes [CODAGT-760](https://linear.app/coder/issue/CODAGT-760).

## Problem

Tool-heavy agent configurations (GitHub, Linear, Notion, and dev-tooling
MCP servers) inline over 100k tokens of tool schema definitions into
every generation. Initial uncached requests reached ~216k tokens with
time-to-first-token close to nine minutes, while the model typically
invokes only a handful of tools per turn.

## How it works

- `decideMCPToolSearch` defers external and workspace `.mcp.json` MCP
tools whenever the experiment is enabled. Native, dynamic, provider,
skill, and transport tools are never deferred.
- `find_tools` embeds a server-grouped catalog in its tool description
(degrading to names-only, then counts-only, then a constant-size summary
past a context-scaled size cap) and scores keyword matches across tool
names, descriptions, parameter schemas, and server metadata. Queries can
scope to one server with a `server:` prefix, and exact `names` arguments
always activate.
- Activation state is ephemeral: it is re-derived each generation from
surviving chat history (`find_tools` results and direct calls to
deferred tools), so activations naturally lapse when compaction
summarizes them away. Aggregate activated schema weight is capped at 10%
of the context window, shedding the least recently activated schemas
first; `find_tools` shares that budget across parallel calls in one
step. No new persistence.
- Deferred tools stay registered for execution, so the model can call a
cataloged tool directly without searching first; the schema is activated
for subsequent steps.
- Fail-open: the experiment being disabled, an empty candidate set, or
an MCP tool named `find_tools` all disable deferral, leaving today's
behavior byte-identical on the wire.
- Prometheus counters/histograms track `find_tools` calls, matches,
activations, and deferred token weight.
- The conversation timeline renders `find_tools` calls with a collapsed
search summary and expandable match list, falling back to the generic
renderer on malformed payloads.

## Validation

- Unit tests for the catalog, matcher, experiment-gated decision, and
activation derivation; end-to-end chatd generation tests covering
search-then-call, direct-call activation, experiment-off wire parity,
compaction lapse, and subagent tool gating.
- Storybook interaction tests for the timeline rendering and
malformed-payload fallback.
- Remote dogfood UAT on dev.coder.com passed: deferral with a real MCP
server and Anthropic model, direct calls without prior search,
activation persistence across turns, experiment-off parity, and clean
UI/console.

> Disclosure: Mux (AI agent) authored this PR on Mike's behalf.
2026-08-18 19:12:47 +02:00
J. Scott Miller 62f4afbb60 perf(coderd): build the workspace build fan-out maps once per batch (#28074)
`convertWorkspaceBuild` rebuilt seven maps from the caller's global
slices on every call and rescanned the provisioner daemon rows to filter
by job ID. `convertWorkspaceBuilds` calls it once per build with
identical slices, so map construction cost `O(builds x rows)` where
`O(rows)` suffices — quadratic in the number of workspaces on `GET
/api/v2/workspaces`.

The maps move into a `workspaceBuildIndex` built once per batch, keyed
exactly as before and now including daemons by job ID.
`convertWorkspaceBuild` takes the index instead of eight slices. Its
parent already hoisted `workspaceByID`, `jobByID`, and
`templateVersionByID` out of the same loop; this makes the rest
consistent.

Agents are sorted while the index is built, so a resource read by
several builds is sorted once rather than once per build. Same
comparator over the same rows, so the order is unchanged;
`TestConvertWorkspaceBuildsAgentOrder` covers it.

`BenchmarkConvertWorkspaceBuilds`, 5 resources x 2 agents x 4 apps per
build:

| builds | ns/op | B/op | allocs/op |
| --- | --- | --- | --- |
| 1 | 48.3k -> 48.1k | 121k -> 125k | 342 -> 359 |
| 25 | 12.7M -> 1.34M | 38.0MB -> 3.2MB | 69,621 -> 8,347 |
| 100 | 186M -> 5.67M | 596MB -> 13.0MB | 1,024,941 -> 33,080 |

Single-build conversion is a wash (one extra struct allocation); the
quadratic term is gone.

Addresses the map-allocation half of PLAT-386 / #27205. Bounding the
page size is separate (#28040) and does not remove this cost: at 100
workspaces per page it is still 100 passes over every resource, agent,
app, script, log source, status, and daemon row in the page.

---

Created with Coder Agents on behalf of @jscottmiller.
2026-08-18 11:33:01 -05:00
Nick Vigilante 27e3d0fb00 Change all windsurf.com links to devin.ai links (#28270)
This avoids the redirects from our docs to Devin's docs.

<!--

If you have used AI to produce some or all of this PR, please ensure you
have read our [AI Contribution
guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING)
before submitting.

-->
2026-08-18 16:18:17 +00:00
Cian Johnston 962366ffc6 fix(site): quote colon-containing values in filter serialization (#28254)
`stringifyFilter` in the shared `Filter` component only quoted values
containing spaces. Filter values like RFC 3339 timestamps
(`2026-08-16T20:42:00Z`) contain colons but no spaces, so when any
filter was edited and the whole query re-serialized, the timestamp went
out unquoted and the backend `searchTerms` parser rejected it (`Query
element ... can only contain 1 ':'`).

Quote values containing colons as well; they were never valid unquoted
because the backend parser already rejects them. Extract
`parseFilterQuery`/`stringifyFilter` into `filterQuery.ts` with unit
tests, including a round-trip of quoted timestamps.

Part of
[AIGOV-580](https://linear.app/codercom/issue/AIGOV-580/ai-gateway-sessions-page-takes-5-10-seconds-to-load)

---
_Generated by Coder Agents on behalf of @johnstcn._$

---

**Stack:** #28254 (filterQuery fix) \u2192 #28255 (component) \u2192
#28256 (sessions page)
2026-08-18 17:01:42 +01:00
Nick Vigilante 0db25caad6 docs(docs/.style/style-guide): fix self-violations found by audit (#27855)
Builds on #27849 and #27852 (both merged).

Runs every style guide page through the guide's own rules, including the
STE-derived rules from #27852, and fixes the violations in the guide's
prose and **Do** examples. **Don't** examples keep their intentional
violations. Three parallel audit passes produced roughly 120 findings;
this PR applies the accepted ones.

Objective defects fixed: an unbalanced quotation mark on the audience
page, a stale "in this PR" reference in the README, a `console` **Do**
example whose command and output had been collapsed onto one line,
inline `> [!NOTE]` markers that GitHub renders as literal text instead
of callouts, "a `onClick`", and two stale Vale rule references. Two
**Do** examples modeled banned or wrong prose: the audience page's
example contained the exact `*Audience: ...*` metadata line the same
page bans, and a word-choice example had Coder running its own login
command.

Rule-adherence fixes: US-quotation comma/period placement throughout,
banned idioms and figurative language ("wall of commas", "silently
rots", "when in doubt", "stretch goal", "bleeding-edge", the Churchill
"put up with" example), simplicity words and vague qualifiers ("easy",
"straightforward", "typically", "almost always", "often"), directional
"above", framing paragraphs under bare headings, run-in bold leads split
to one sentence per source line, prose semicolons split into sentences,
6-item prose enumerations reduced, and end-of-page "Related" sections
renamed to **Learn more** per the guide's own heading rule.

**One policy call for docs-team review**: the digits-everywhere rule now
scopes out numbers that describe language itself ("a contraction joins
exactly two words") and `one` as a determiner or pronoun. The
alternative was rewriting every determiner as a digit ("give each
paragraph 1 topic"), which makes the prose worse. With the scoped rule,
the remaining real counts were converted to digits.

Deliberately not changed: "lands"/"land" as release vocabulary,
attributed claims inside the Latin-abbreviations `` block,
persona-sketch color on the audience page (writer-facing planning
vocabulary), and the "What's a workspace" heading example.

Linear: DOCS-650

---

> This PR was created with AI assistance (Coder Agents).
2026-08-18 11:14:07 -04:00
Michael Suchacz 5af08a1a09 fix(site): repair the locally-run storybook vitest suite (#28261) 2026-08-18 17:07:39 +02:00
Michael Suchacz 119f2b1dd9 feat: limit concurrent chat agents with pooled admission (#27902)
Limits concurrent chat generation on capped deployments to 5 root chats
and 10 delegated subagent chats. The pools are deployment-wide and
independent, so delegated work can continue while root capacity is full.

The default caps live in AGPL code. Enterprise contributes only a
licensing unlock, so unlicensed deployments stay capped and cannot fail
open. Licensed deployments are uncapped while Agent Hours usage stays
below an explicit hard limit. Deployments without a hard limit remain
uncapped, and reaching the Agent Hours allocation only triggers
warnings.

Admission happens before a worker takes chat ownership. Capped
deployments serialize admission across replicas with a
transaction-scoped advisory lock and derive active and queued state from
current ownership plus fresh runner heartbeats, rather than persisted
queue markers or per-replica state. The acquisition query returns a
bounded, pool-interleaved candidate set instead of ranking the whole
backlog; a migration replaces the acquisition index with a pool-aware
one. Refused chats stay running but unowned, and interrupt requests
bypass admission so users can stop queued or over-cap chats.

The single-chat API derives `queued_for_capacity` from live pool state;
list endpoints do not report it. The UI polls that value every 5 seconds
while a chat is running and shows a callout when the chat is waiting for
capacity.

Updates the administrator documentation and deployment-wide Prometheus
gauges for active and queued agents. Replica-level values must be
aggregated with `max`, not `sum`.

> Mux updated this PR on Mike's behalf.
2026-08-18 16:55:43 +02:00
TJ cb0a9ebbbf fix(site/src/pages/AgentsPage): remove sidebar nav bottom divider (#28239)
## What

Removes the horizontal divider line that appears directly under the
**Search** item in the Agents chats sidebar.

The line was the `border-b border-border-default` on the sidebar `<nav>`
that wraps the **New chat** and **Search** items. Since Search is the
last item in that nav, the border rendered as a stray line beneath it.

## Change

`site/src/pages/AgentsPage/components/ChatsSidebar/chats/ChatsPanel.tsx`

```diff
-className="hidden border-b border-border-default px-2 py-1.5 sm:flex sm:flex-col sm:gap-0.5"
+className="hidden px-2 py-1.5 sm:flex sm:flex-col sm:gap-0.5"
```

The bottom border is dropped entirely. Note: this was a Tailwind border,
not MUI.

---

*This PR was generated by Coder Agents on behalf of @tracyjohnsonux.*
2026-08-18 14:39:37 +00:00
TJ 16ae996b93 fix(site/src/pages/AgentsPage/components): clean up agents composer borders and normalize dropdown pills (#28230)
Audit pass on the Agents chat composer: borders, the history-edit
divider, and making the model selector and workspace pill visually
consistent with each other and the left chat-list chevron.

## Borders

1. **Remove the composer outline** — drop `border
border-border-default/80` from the `chat-composer` container in
`AgentChatInput.tsx`. Focus ring, drag-over ring, history-edit warning
shadow, rounded corners, background, and `shadow-sm` are unchanged.
2. **Match the skeleton** — drop the same border from
`ChatInputSkeleton` in `AgentsSkeletons.tsx` so the loading placeholder
stays consistent with the loaded composer.
3. **Neutral history-edit divider** — the divider under the "Editing
will delete all subsequent messages..." warning header used
`border-border-warning/50` (a harsh, light gold line in dark mode).
Switched to `border-border-default/70`, matching the sibling "editing
queued message" divider. The warning text/icon keep `content-warning`.

## Model selector <-> workspace pill consistency

The model selector (`ModelSelector.tsx`) and workspace pill
(`WorkspacePill.tsx`) rendered inconsistently. Normalized both, using
the left `ChatSectionHeader` chevron (`size-3.5`) as the reference:

4. **Chevron size** — model was `size-icon-sm` (18px) and forced to 24px
by the shared `Button` `cva` (`[&>svg]:size-icon-lg`); workspace was
`size-3` (12px). Both now render `size-3.5` (14px). The model override
uses the repo's `[&>svg]:!size-3.5 [&>svg]:p-0` convention since the
`Button` variant otherwise wins on specificity.
5. **Chevron color** — removed `opacity-60` from the workspace chevron
so both are full-opacity `content-secondary` (and
`hover:content-primary`).
6. **Chevron rotation** — the model chevron snapped instead of animating
because the Button's `[&>svg]:transition-colors` overrode the icon's
`transition-transform`. Switched to `[&>svg]:transition` (covers
transform and color) so it rotates smoothly like the workspace/sidebar
chevrons.
7. **Pill shape + fill + height** — gave the model selector
`bg-surface-secondary` (hover `bg-surface-tertiary`) and `rounded-full`
to match the workspace pill, and replaced the fixed `h-8` with the
pill's height mechanism (`h-7` mobile, `h-auto` + `py-0.5` at desktop).

## Notes

- The composer borders pre-existed in the markup; they became more
visually apparent after the recent MUI/Emotion removal (#27821) changed
the global baseline/theming layer.
- Out of scope: `DiffViewer/CommentableDiffViewer.tsx` uses the same
`border border-border-default/80` pattern for the "Add a comment" box on
diffs. Separate surface, left unchanged.

---

> This PR was generated by Coder Agents on behalf of @tracyjohnsonux.
2026-08-18 07:21:08 -07:00
Jake Howell a3a0079bd2 fix(site): stop redundant RBAC paywall error toast on Groups page (#28249)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Fixes coder/coder#23898 / coder/coder#23898.

## Problem

On a deployment without a Premium license, opening **Admin → Deployment
settings → Groups** shows the Premium paywall *and* a redundant error
toast in the bottom-right reading "Template RBAC is a Premium feature.
Contact sales!".

## Root cause

`GroupsPage.tsx` fired the paginated `groupsByOrganization` query
unconditionally. Groups are gated behind the `template_rbac` (Premium)
entitlement, so the request returned `403` ("Template RBAC is a Premium
feature"), which a `useEffect` surfaced via `toast.error`. Meanwhile
`GroupsPageView` already renders `PaywallPremium` when `groupsEnabled`
is false, hence the duplicate messaging. The AI Governance page doesn't
fire an entitlement-gated request, so it only shows the paywall.

There's a second subtlety that made the bug load-path dependent:
`selectFeatureVisibility` returns `{}` when unlicensed, so
`template_rbac` is `undefined`, not `false`. React Query treats
`enabled: undefined` as enabled, so a naive `enabled: groupsEnabled &&
...` gate still fired the request on a fresh full page load (where
entitlements were briefly in flight). Client-side navigation happened to
have entitlements cached as `false`, so it looked fixed there but
reproduced on hard reload.

## Fix

Gate the groups query with `enabled: Boolean(groupsEnabled &&
organization)`. The `Boolean()` coercion is load-bearing: it turns the
`undefined` entitlement into a real `false` so the request is genuinely
skipped rather than defaulting to enabled. When the entitlement is
missing there is no request, no error, and the paywall remains the
single source of truth. Legitimate load failures (when the feature *is*
entitled) still toast as before.

<details><summary>Investigation notes</summary>

* `site/src/pages/GroupsPage/GroupsPage.tsx` — `groupsQuery` ran
regardless of entitlement; the `groupsQuery.error` effect calls
`toast.error`.
* `site/src/pages/GroupsPage/GroupsPageView.tsx` — renders
`PaywallPremium` when `!groupsEnabled`, independent of the query.
* `site/src/modules/dashboard/entitlements.ts` — `getFeatureVisibility`
returns `{}` when `!hasLicense`, so feature flags are `undefined` (not
`false`) on unlicensed deployments.
* `usePaginatedQuery` forwards `enabled` to the underlying `useQuery`,
and its prefetch / invalid-page effects are no-ops while the query is
disabled.
* Backend source of the message: `enterprise/coderd/templates.go`.

</details>

## Testing

Verified end-to-end on a local unlicensed `scripts/develop.sh`
deployment (the exact repro condition):

* Confirmed `GET /api/v2/organizations/coder/paginated-groups` returns
`403 "Template RBAC is a Premium feature. Contact sales!"` — the toast's
text.
* **Before fix:** hard reload of `/deployment/groups` shows the error
toast bottom-right alongside the paywall.
* **After fix:** 3 consecutive hard reloads, no toast at any point
(including the \~3s mark where it previously fired); paywall still
renders correctly.
* `pnpm --dir site lint:types` passes.

Before/after screenshots are attached in the PR thread / chat.
2026-08-18 14:14:30 +00:00
Paweł Banaszewski 0a34a37314 test(enterprise/cli): add standalone AI Gateway tests against a live coderd (#27863)
Stacked on #27860.

Adds four connection tests that run the real `ai-gateway start` against
`coderdenttest` and assert only what an operator or LLM client can
observe. A `chaosProxy` between the gateway and coderd simulates outages
by answering 503 and closing the connections it accepted, the latter
because the DRPC websocket is hijacked and so out of reach of
`httptest.Server`.

- `RevokedKey`: revoking an in-use key closes the session, and the 401
on redial terminates the command.
- `ReconnectAfterDisconnect`: LLM traffic and interception recording
resume after a coderd outage, with no intervention.
- `RequestWhileDisconnected`: a request arriving while disconnected is
parked until the connection returns, not failed. The pre-flight DRPC
calls block with the caller's context as the only bound, which is
intentional: a caller willing to wait is served on reconnect, and
`/readyz` has already withdrawn the replica. The RFC's "fails with 503
if pre-flight DRPC calls cannot complete" does not describe this and
needs correcting.
- `InFlightRequestSurvivesDisconnect`: a stream whose first chunk
already reached the caller completes after the DRPC connection drops.

No production code is changed.

Refs https://linear.app/codercom/issue/AIGOV-320/write-connection-tests

---

Generated with Coder Agents.
2026-08-18 14:03:41 +00:00
Jaayden Halko 995d7fe31b feat: add per-license Products section with Coder Agents price gates (#28051)
<img width="1100" height="312" alt="Screenshot 2026-08-17 at 3 43 51 PM"
src="https://github.com/user-attachments/assets/30d21467-93ec-4880-a430-ccd4b494b8f5"
/>


Each license card now always expands to a **Products** section: a Coder
Workspaces box showing active seat usage, and, on Premium licenses, a
Coder Agents box driven by the `agent_runtime_hours_*` license claims
and the merged `agent_runtime_hours` entitlement. The card header gains
a **Type** column (`Trial`/`Standard`), and the left header label now
shows the feature set only (`Premium`/`Enterprise`).

The Coder Agents box renders five states: no allocation (dashed purple
upgrade CTA), unlimited allocation (`-1` sentinel), normal usage,
allocation exceeded (red border and red "Agent hours exceeded" status;
concurrent chats stay Unlimited), and hard limit exceeded (red "Hard
limit exceeded" status; concurrent chats capped at 5, mirroring the
backend's `maxConcurrentRootAgents`, which is not exposed via the API).
Usage and overage indicators only render on the license whose allocation
matches the merged entitlement and which is currently effective,
following the existing AI Governance winning-license pattern via a
generalized `isLicenseApplicableForFeatureUsage` helper; AI Governance
add-on behavior is unchanged.

Stacked on #27985 (base branch `runtime-hours-entitlements`); do not
merge before it.

Notes for review:

- #27985 now grandfathers claim-less Premium licenses into a zero-hour
`agent_runtime_hours` allocation, so the merged entitlement (disabled,
`limit: 0`) and its measured `actual` are always present for Premium
deployments. The upgrade card's "Agent hours used" row therefore renders
universally; the `Premium` story pins that state.


- Agent hours usage now renders with exactly one decimal (e.g.
`16,264.3`, `42.0`), derived from #27985's new `actual_ms` field and
floored to tenths with integer math. The same floored value drives the
exceeded checks, so the displayed number and the red state flip at the
same instant; a fraction past the allocation now trips "Agent hours
exceeded" (`20,000.1 > 20,000`), pinned by the
`PremiumWithAgentHoursExceededByFraction` story. The allocation
denominator stays whole (it comes from the whole-hour license claim).
2026-08-18 20:07:28 +07:00
david-fraley 6dfba5c567 test(site/src/modules/workspaces): cover version picker stacking (#28154) 2026-08-18 07:52:55 -05:00
Danielle Maywood 9590e9586e fix(site/src/pages/AgentsPage): stop gating chat stream parts on client status (#28207) 2026-08-18 12:51:36 +01:00
Danielle Maywood 14e3ae33cf fix(site/src/pages/AgentsPage): treat interrupting chats as busy in the composer (#28209) 2026-08-18 12:51:29 +01:00
dependabot[bot] 522ef09517 chore: bump github.com/stretchr/testify from 1.11.1 to 1.12.0 (#28259)
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify)
from 1.11.1 to 1.12.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/stretchr/testify/releases">github.com/stretchr/testify's
releases</a>.</em></p>
<blockquote>
<h2>v1.12.0</h2>
<h2>What's Changed</h2>
<h3>Functional Changes</h3>
<ul>
<li>assert: make *AssertionFunc types just aliases by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1563">stretchr/testify#1563</a></li>
</ul>
<h3>Fixes</h3>
<ul>
<li>mock: avoid panic when expected type is nil in Arguments.Diff by <a
href="https://github.com/mutaiib"><code>@​mutaiib</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1775">stretchr/testify#1775</a></li>
<li>mock: revert to pre-v1.11.0 argument matching behavior for mutating
stringers by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1786">stretchr/testify#1786</a></li>
<li>suite: validate method signatures and continue execution for valid
tests by <a
href="https://github.com/vyas-git"><code>@​vyas-git</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1665">stretchr/testify#1665</a></li>
<li>assert.PanicsWithError: report error message by <a
href="https://github.com/olivergondza"><code>@​olivergondza</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1400">stretchr/testify#1400</a></li>
<li>assert: IsIncreasing et al can return false w/out failing by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1787">stretchr/testify#1787</a></li>
<li>add type to error message of assert.Same by <a
href="https://github.com/egawata"><code>@​egawata</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1792">stretchr/testify#1792</a></li>
<li>mock.AssertExpectationsForObjects fix panic with wrong testObject
type. by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1795">stretchr/testify#1795</a></li>
<li>assert: truncate very long objects in test failure messages by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1646">stretchr/testify#1646</a></li>
<li>assert: fix NotSubset error messages using %#v instead of %q (fixes
<a
href="https://redirect.github.com/stretchr/testify/issues/1800">#1800</a>)
by <a href="https://github.com/nghiack7"><code>@​nghiack7</code></a> in
<a
href="https://redirect.github.com/stretchr/testify/pull/1888">stretchr/testify#1888</a></li>
<li>suite: prevent panic when SetupTest skips with HandleStats by <a
href="https://github.com/blackwell-systems"><code>@​blackwell-systems</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1877">stretchr/testify#1877</a></li>
</ul>
<h3>Documentation, Build &amp; CI</h3>
<ul>
<li>CI: test also with Go 1.23 by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1783">stretchr/testify#1783</a></li>
<li>Vendor unmaintained github.com/pmezard/go-difflib by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1708">stretchr/testify#1708</a></li>
<li>Promote ccoVeille to maintainer by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1784">stretchr/testify#1784</a></li>
<li>build(deps): bump actions/setup-go from 5 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/stretchr/testify/pull/1790">stretchr/testify#1790</a></li>
<li>assert.YAMLEq: Document mutlidoc behavior by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1791">stretchr/testify#1791</a></li>
<li>_codegen: copy dependency github.com/ernesto-jimenez/gogen/imports
by <a href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1782">stretchr/testify#1782</a></li>
<li>doc: remove ineffective inline code blocks by <a
href="https://github.com/brackendawson"><code>@​brackendawson</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1714">stretchr/testify#1714</a></li>
<li>Tag generated assertions as non-generated in new .gitattributes by
<a href="https://github.com/ubunatic"><code>@​ubunatic</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1815">stretchr/testify#1815</a></li>
<li>chore: vendor go-spew from <a
href="https://github.com/davecgh/go-spew">https://github.com/davecgh/go-spew</a>
by <a href="https://github.com/ccoVeille"><code>@​ccoVeille</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1827">stretchr/testify#1827</a></li>
<li>require: fix godoc generation for assertions returning a bool by <a
href="https://github.com/Baxromumarov"><code>@​Baxromumarov</code></a>
in <a
href="https://redirect.github.com/stretchr/testify/pull/1850">stretchr/testify#1850</a></li>
<li>docs(require): correct example usage to use assert.CollectT
(require.CollectT does not exist) by <a
href="https://github.com/a2not"><code>@​a2not</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1821">stretchr/testify#1821</a></li>
<li>docs: Fix EventuallyWithTf documentation with proper placement of
formatting arguments by <a
href="https://github.com/a2not"><code>@​a2not</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1842">stretchr/testify#1842</a></li>
<li>EMERITUS.md: add <a
href="https://github.com/tylerb"><code>@​tylerb</code></a> by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1812">stretchr/testify#1812</a></li>
<li>CI: test also with Go 1.24 by <a
href="https://github.com/alexandear"><code>@​alexandear</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1856">stretchr/testify#1856</a></li>
<li>deps: bump objx to v0.5.3 and remove dependency cycle issue by <a
href="https://github.com/ccoVeille"><code>@​ccoVeille</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1823">stretchr/testify#1823</a></li>
<li>CI: upgrade GitHub Actions and pin hashes by <a
href="https://github.com/SuperQ"><code>@​SuperQ</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1883">stretchr/testify#1883</a></li>
<li>CI: add _readme-gofmt tool to reformat Go code in README by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1889">stretchr/testify#1889</a></li>
<li>CI: add check of GitHub Action pinned hashes against tag by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1885">stretchr/testify#1885</a></li>
<li>_codegen: modernize by <a
href="https://github.com/dolmen"><code>@​dolmen</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1890">stretchr/testify#1890</a></li>
<li>build(deps): bump actions/checkout from 6.0.2 to 6.0.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/stretchr/testify/pull/1906">stretchr/testify#1906</a></li>
<li>mock: Mock.Return does not exist anymore by <a
href="https://github.com/Kentzo"><code>@​Kentzo</code></a> in <a
href="https://redirect.github.com/stretchr/testify/pull/1905">stretchr/testify#1905</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/mutaiib"><code>@​mutaiib</code></a> made
their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1775">stretchr/testify#1775</a></li>
<li><a href="https://github.com/vyas-git"><code>@​vyas-git</code></a>
made their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1665">stretchr/testify#1665</a></li>
<li><a
href="https://github.com/olivergondza"><code>@​olivergondza</code></a>
made their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1400">stretchr/testify#1400</a></li>
<li><a href="https://github.com/egawata"><code>@​egawata</code></a> made
their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1792">stretchr/testify#1792</a></li>
<li><a href="https://github.com/ubunatic"><code>@​ubunatic</code></a>
made their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1815">stretchr/testify#1815</a></li>
<li><a
href="https://github.com/Baxromumarov"><code>@​Baxromumarov</code></a>
made their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1850">stretchr/testify#1850</a></li>
<li><a href="https://github.com/a2not"><code>@​a2not</code></a> made
their first contribution in <a
href="https://redirect.github.com/stretchr/testify/pull/1821">stretchr/testify#1821</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/stretchr/testify/commit/001eb7946baf451879253643e4ce4b38eaa0d4a7"><code>001eb79</code></a>
Merge pull request <a
href="https://redirect.github.com/stretchr/testify/issues/1905">#1905</a>
from Kentzo/patch-1</li>
<li><a
href="https://github.com/stretchr/testify/commit/ad40f384b10b10d2bbac85354c80eab5abed0a45"><code>ad40f38</code></a>
Merge pull request <a
href="https://redirect.github.com/stretchr/testify/issues/1906">#1906</a>
from stretchr/dependabot/github_actions/actions/chec...</li>
<li><a
href="https://github.com/stretchr/testify/commit/3bae01746b7ef55bd50252b8c7fe5a41b7bf0fcc"><code>3bae017</code></a>
build(deps): bump actions/checkout from 6.0.2 to 6.0.3</li>
<li><a
href="https://github.com/stretchr/testify/commit/f8c01f33a3747928ede4174ad1b718698fc352e7"><code>f8c01f3</code></a>
mock: Mock.Return does not exist anymore</li>
<li><a
href="https://github.com/stretchr/testify/commit/12f8b5612e125f337c4589e198771e5f8970f160"><code>12f8b56</code></a>
Merge pull request <a
href="https://redirect.github.com/stretchr/testify/issues/1563">#1563</a>
from stretchr/make-AssertionFunc-types-aliases</li>
<li><a
href="https://github.com/stretchr/testify/commit/a11649e4279ae45a978a29285d46c347c351e382"><code>a11649e</code></a>
assert: make *AssertionFunc type just aliases</li>
<li><a
href="https://github.com/stretchr/testify/commit/dc20f419863ab083f472a7af1215cc3c049e8ecd"><code>dc20f41</code></a>
Merge pull request <a
href="https://redirect.github.com/stretchr/testify/issues/1890">#1890</a>
from stretchr/dolmen/codegen-modernize</li>
<li><a
href="https://github.com/stretchr/testify/commit/098f8d75b344a22ada8a305282530785e81f8ea2"><code>098f8d7</code></a>
_codegen: use strings.Builder</li>
<li><a
href="https://github.com/stretchr/testify/commit/d2699bed69a45be5ac63448f017ce0c9e2d103d3"><code>d2699be</code></a>
_codegen: modernize</li>
<li><a
href="https://github.com/stretchr/testify/commit/a463c8caf3411b7d36b87204f997c17ef573675d"><code>a463c8c</code></a>
Merge pull request <a
href="https://redirect.github.com/stretchr/testify/issues/1885">#1885</a>
from stretchr/dolmen/ci-check-ghactions-hashes</li>
<li>Additional commits viewable in <a
href="https://github.com/stretchr/testify/compare/v1.11.1...v1.12.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/stretchr/testify&package-manager=go_modules&previous-version=1.11.1&new-version=1.12.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-18 11:17:49 +00:00
Atif Ali 062c0fdd3b docs: rebrand Windsurf doc page to Devin Desktop (#28205)
## Summary

Cognition (maker of Devin) rebranded the Windsurf Editor as Devin
Desktop on June 2, 2026, after acquiring it from Codeium in July 2025.
Our docs still referred to the editor as Windsurf and linked to a dead
`codeium.com` domain.

## Changes

- Renamed `docs/user-guides/workspace-access/windsurf.md` to
`devin-desktop.md`, rewritten to lead with Devin Desktop branding, note
the Codeium -> Windsurf -> Devin Desktop history, and use current links
(`windsurf.com`, `docs.windsurf.com`) instead of dead `codeium.com`
ones.
- Updated `docs/manifest.json` and
`docs/user-guides/workspace-access/index.md` to reference the new page.
- Updated remaining Windsurf mentions to Devin Desktop in
`docs/ai-coder/ide-agents.md`, `docs/ai-coder/index.md`,
`docs/reference/glossary.md`, and
`docs/ai-coder/ai-gateway/clients/index.md`.
- Added `windsurf.com`/`devin.ai` to `.github/.linkspector.yml` ignore
patterns; both rate-limit repeated automated requests with 429s (same
class of issue as the `codeium.com`/`marketplace.visualstudio.com` fix
in #28203).
- Switched every module reference from `windsurf` to the new
`devin-desktop` registry module (`docs/about/contributing/modules.md`,
the three `get-started/customize-your-template/*.md` Terraform
tutorials, and the main doc page's module link), since the new module
actually renders `display_name = "Devin Desktop"` / `slug =
"devin-desktop"` in the UI (the old `windsurf` module hardcodes
"Windsurf Editor").

<details>
<summary>Scope notes / sequencing</summary>

The `devin-desktop` module referenced here is being added in
[coder/registry#1050](https://github.com/coder/registry/pull/1050) (not
yet merged/released). That PR is itself gated on
[coder/coder#28214](https://github.com/coder/coder/pull/28214)
(whitelisting the `devin:` URI scheme) shipping in a released Coder
version first. This docs PR can merge independently, the module link
will 404 until #1050 is released, same as any
docs-ahead-of-registry-release sequencing.

The Terraform code samples now show `module "devin-desktop"` because
that module's `display_name`/`slug` are properly parameterized (unlike
`windsurf`, which hardcodes "Windsurf Editor"/`windsurf` regardless of
what's passed in), so the docs stay accurate to the rendered UI.

</details>

## Validation

- `make lint` (docs lint, markdownlint, repo checks) passes.
- Manually verified the new outbound links (`docs.windsurf.com`) return
200; `windsurf.com`/`devin.ai` are rate-limited (429) from this
environment too, hence the added ignore patterns.

Stacked on #28203 (targets that branch so the diff here stays scoped to
the rebrand; will retarget to `main` once #28203 merges).

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-08-18 15:17:02 +05:00
Jake Howell a749cf521f refactor(site): tidy secrets list layout (#27917)
Tighten the user secrets settings page layout.

Move the enable toggle into a leading column, truncate long
descriptions, promote Add secret and docs into the settings header
actions, and drop the redundant Refresh control now that mutations
already invalidate the secrets query.

| Old | New |
| --- | --- |
| <img width="2936" height="1810" alt="SECRETS_PAGE_OLD"
src="https://github.com/user-attachments/assets/e7d18953-9207-4ea1-874e-054de85a0098"
/> | <img width="2936" height="1810" alt="SECRETS_PAGE_NEW"
src="https://github.com/user-attachments/assets/221e9ab5-3be8-4b3a-80d1-89489b61a008"
/> |
2026-08-18 16:55:27 +07:00
Susana Ferreira db3566c1a3 chore: correct AI Gateway metric provider label and cardinality notes (#28220)
The cardinality notes in `aibridge/metrics/metrics.go` assume the
`provider` label takes one of three values, and two for the key pool
metrics. That was accurate when the notes were written: `provider` is
the provider instance name, and the name defaulted to one of the three
provider types aibridge supports. Instances can now be given their own
names, so the label takes any configured name and the series counts
scale with the number of configured providers rather than being capped
at a fixed number.

The monitoring docs are also updated to make clear that `provider` is
the provider instance name.

Comments and documentation only, no behaviour change.

Follow-up to #28210.
2026-08-18 09:47:00 +00:00
Cian Johnston 6079c514ee fix: follow-up fixes for conditional VCS requests (#27711)
Follow-ups from #27627 

- Memoizes `Config.Git()` with a mutex so the provider's ETag response
cache survives across calls. Only successful construction is cached;
errors are retried.
- Moves the HTTP client onto `Config.HTTPClient`, wired through
`ConvertConfig`, so `Git()` no longer takes a per-call argument that
would be silently ignored after memoization.
- `newGitHub` and `newGitLab` now return `(Provider, error)`,
eliminating the typed-nil-interface class in `gitprovider.New` rather
than the single instance.
- Gates the 304 branch on a `haveCached` flag instead of a nil body
check.
- Only caches bodies that decode successfully, preventing poisoned
entries.
- Keys the response cache on the full token digest rather than a
truncated prefix.
- Tests added: `TestConfigGitMemoizesProvider`,
`TestConfigGitRetriesOnConstructorError`,
`TestGitLabConstructorErrorReturnsNilInterface`,
`TestResponseCacheStore`,
`TestConditionalRequestReuse/MalformedResponseNotCached`;
`TestConvertYAML/CustomScopesAndEndpoint` now asserts
`Config.HTTPClient` wiring.

Follow-ups tracked in #28139, #28140, #28141, #28142.

> 🤖 Generated by Coder Agents on behalf of @johnstcn.
2026-08-18 09:00:20 +01:00
Atif Ali b674d40d39 ci: ignore flaky codeium.com and marketplace.visualstudio.com links (#28203)
## Problem

The docs link-check job (linkspector) started failing on two external
links that aren't actually broken, they're being rate-limited/blocked by
the target sites when hit from GitHub runner IPs:

- `https://codeium.com/windsurf` -> 429
- `https://marketplace.visualstudio.com/vscode` -> 503

## Fix

Add both domains to `ignorePatterns` in `.github/.linkspector.yml`,
matching the existing pattern already used for other real sites that
block the linkspector action / GitHub runner IPs
(`code.visualstudio.com`, `npmjs.com`, `merriam-webster.com`, etc.).

## Validation

Validated the updated YAML parses correctly and ran `make lint` locally
(docs lint, markdownlint, and repo checks all pass).

Follow-up: a separate PR will rebrand the Windsurf docs to Devin Desktop
(Codeium -> Windsurf -> Devin Desktop), since codeium.com is stale
branding, not just a flaky link.

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-08-18 12:32:56 +05:00