Commit Graph
2801 Commits
Author SHA1 Message Date
Nick Vigilante 827c11f43a docs: update Coder Agents admin navigation to AI Settings (#28572)
## Summary

Fixes stale admin navigation on the three Coder Agents platform-controls
pages not covered by #28482: the retention pages pointed at tabs that do
not exist ("Behavior", the old Agents settings "Lifecycle" tab), and
template optimization pointed at the removed **Agents** > **Settings** >
**Manage Agents** navigation.

Breadcrumbs follow the **Admin settings** > **AI** > **Coder Agents**
convention established by #28482.

## Changes

- `docs/ai-coder/agents/platform-controls/chat-retention.md`: replace
the nonexistent **Behavior** tab with **Admin settings** > **AI** >
**Coder Agents** > **Lifecycle**.
- `docs/ai-coder/agents/platform-controls/chat-debug-retention.md`: same
page, same convention, aligned with chat-retention.md.
- `docs/ai-coder/agents/platform-controls/template-optimization.md`:
replace **Agents** > **Settings** > **Manage Agents** > **Templates**
with **Admin settings** > **AI** > **Coder Agents** > **Templates**.

## Scope note

The first revision also fixed `models.md`, `advisor.md`,
`chat-debug-logging.md`, and `platform-controls/index.md`. Those pages
are covered by #28482 with the same corrections, so this PR reverted
them to avoid conflicting edits and adopted that PR's breadcrumb
convention instead.

Linear: DOCS-715 https://linear.app/codercom/issue/DOCS-715

<details><summary>Analysis evidence</summary>

- `site/src/router.tsx` (~735-780):
`/ai/settings/{lifecycle,templates,coder-agents}` are the live routes;
`/agents/settings/{admin pages}` (~833-890) are `Navigate`-only
redirects.
- No "Behavior" tab exists in any router revision;
`RetentionPeriodSettings` and `DebugRetentionSettings` both render in
`LifecyclePageView.tsx`.
- Breadcrumb convention **Admin settings** > **AI** verified against
`AdminSettings.tsx` / `AISettingsSidebarView.tsx` in #28482.

</details>

Generated by Coder Agents on behalf of @nickvigilante.
2026-08-25 12:49:27 -04:00
Marcin Tojek 31a976b288 chore(docs): update release docs for v2.35.6 (#28577)
Automated docs update for v2.35.6 release.

Created by `releasetui`.
2026-08-25 18:33:58 +02:00
Ethan 409049d1d8 docs: document org-scoped admin configuration for agents (#28482)
## Summary

Documents the organization scoping of Coder Agents admin configuration,
and corrects the navigation paths, access wording, and default-model
instructions that no longer matched the product. Documentation only, no
product code changes.

Follows #28473, which moved the organization model overrides into an
**Organization settings** section on **Admin settings > AI > Coder
Agents**. #28473 is merged, so this targets `main`.

Closes CODAGT-715

## Changes

- **New page**
`docs/ai-coder/agents/platform-controls/organizations.md`, registered in
`docs/manifest.json`. Covers the deployment/organization scope split,
what an upgrade changes, how an organization without models or MCP
servers behaves, who configures each scope, and how model and MCP server
sharing works.
- **`models.md`**: models are organization-scoped while providers and
their credentials stay deployment-wide. Each organization has one
default model, and the first model added becomes it. Documents the
**Default** badge and the **Set as Coder Agents default model** form
option in place of the star action that no longer exists, and points
model overrides at **Organization settings**.
- **`getting-started.md`**: replaces the Owner-only claim with the
actual access model, adds an organization selection step, and uses the
**Add model** label.
- **`platform-controls/index.md`**: separates deployment-wide controls
from organization-scoped controls, documents personal model overrides
alongside the model configuration section rather than as an enforcement
caveat, and adds `--agents-allowed` plus the `agents-allowed:` search
filter.
- **`platform-controls/advisor.md`** and
**`platform-controls/virtual-desktop.md`**: the Advisor and Virtual
desktop settings are cards in the **Deployment settings** section of the
**Coder Agents** page, not sidebar entries. **Providers** is a sidebar
item, not a tab.
- **`platform-controls/mcp-servers.md`**: slug uniqueness is per
organization, the **Add server** label is correct, and the page is no
longer described as admin-only.
- **`architecture.md`**, **`index.md`**,
**`tasks-to-chats-migration.md`**: organization scope corrections and
organization-scoped model routes.
- Breadcrumbs standardized to **Admin settings > AI > ...**, verified
against `AdminSettings.tsx` and `AISettingsSidebarView.tsx`.

<details>
<summary>Review follow-ups</summary>

The first revision leaked implementation detail into user-facing pages
and contained several claims that did not match the UI. The follow-up
commit removed and corrected the following.

Removed as implementation detail:

- The `chat_model_config` RBAC resource, its actions, and the token
scopes.
- The `available`, `unavailable_reason`, and `unsupported_providers`
response fields, along with the `missing_api_key`, `fetch_failed`, and
`user_api_key_required` values.
- Role and permission tables, ACL storage mechanics, audit internals,
and JSON error bodies on the new organizations page.
- Migration mechanics with no effect on what a user does.

Corrected against the product:

- The star action does not exist. The list shows a **Default** badge and
the add/edit form offers **Set as Coder Agents default model**
(`ModelRow.tsx`, `ModelFormFields.tsx`).
- The first model added to an organization becomes its default
automatically (`coderd/exp_chats.go`). An organization without a stored
default does not fail every chat, so that claim is gone.
- Advisor and Virtual desktop are cards under **Deployment settings**
(`CoderAgentsPageView.tsx`).
- The MCP servers page does not require deployment configuration edit
permission (`AISettingsSidebarView.tsx`).
- Button labels: **Add model** and **Add server**.
- The organization query parameter is `org`, confirmed by
`modelOrganizationSearchParam`.

Left alone deliberately: pre-existing defects outside the introduced
text, including the `/api/v2/chats` route prefixes, create-chat examples
missing `organization_id`, and the pre-existing MCP permissions table.

</details>

## Testing

- `pnpm run format-docs` and `pnpm run lint-docs` pass.
- `make lint/emdash` passes. No emdash or endash added.
- `grep -rn "Defaults & overrides" docs/` returns nothing.
- Every navigation path, button label, and access claim checked against
the corresponding file under `site/src/pages/AISettingsPage/` and
`site/src/modules/management/`.

---

This pull request was generated by Coder Agents on behalf of
@ethanndickson.
2026-08-25 17:24:39 +01:00
TJ c07bde80c4 fix: use medium badges and shorter shared key label on agent API keys page (#28557)
On `/agents/settings/api-keys`, bumps the provider key status badge and
the enabled model badges from `sm`/`xs` to the medium (`md`) size, and
shortens the status label "Using shared key" to "Shared key". Updates
the matching Storybook assertion and the status indicator name in
`docs/ai-coder/agents/models.md`.

Verified with `tsc` and the page's Storybook tests (15 passing).

---

*Created by Coder Agents on behalf of @tracyjohnsonux.*
2026-08-25 16:16:59 +00:00
Matt Vollmer 79856ebd15 docs: reference Coder Agents instead of Coder Tasks in style guide (#28539)
## Summary

Updates the Caitlin the Citizen Developer persona in the style guide to
reference Coder Agents instead of the deprecated Coder Tasks product.

### Changes

* `docs/.style/style-guide/audience-and-scope.md`: replaced both "Coder
Tasks" mentions with "Coder Agents" in the Caitlin persona description
and Coder surface list.

<details><summary>Context</summary>

Coder Tasks is deprecated as of v2.34 and replaced by Coder Agents. This
change keeps the internal style guide's persona reference aligned with
current product naming.

</details>

---

This PR was drafted by a Coder Agent on behalf of Matt.
2026-08-25 10:03:25 -04:00
Garrett Delfosse 7cf24b1a37 docs(docs/ai-coder/agents): document the chat search: full-text filter (#28474)
Documents the `search:` full-text filter in
`docs/ai-coder/agents/chat-search-syntax.md` and drafts the release
notes copy for chat history search.

Describes `main` plus #28319, which must merge first: stemming and
stopword removal apply to message content only; titles and PR titles
keep `simple` whole-word matching. All claims verified against the
implementation. Two statements in CODAGT-727 were inaccurate and are
documented as the code behaves:

- A value that tokenizes to no searchable words returns an **empty
list**, not HTTP 400
(`TestListChats_Search/NoSearchableWordsReturnsEmpty`). HTTP 400 covers
only an empty `search:` value, unsupported keys, bare terms, or
combining `search:` with `title:`, `pr_title:`, or `pr:`
(`coderd/searchquery/search.go`).
- Results are **paginated** with the standard chat list cursor (default
50), not a bounded non-paginated set (`GetChats`, `listChats`). Ordering
is pinned first, then most recently updated.

Also verified: message bodies are indexed by the dbpurge sweep
(10-minute tick, up to 5 x 10,000 rows, newest first) while titles and
PR titles are searchable immediately; numeric values match exact PR
numbers; `title:`, `pr_title:`, and `repo:` retain `ILIKE` semantics.

`pnpm run format-docs` and `pnpm run lint-docs` pass.

Closes
[CODAGT-727](https://linear.app/codercom/issue/CODAGT-727/chat-search-documentation-and-release-notes)

<details>
<summary>Release notes draft</summary>

### Chat history search

You can now search your chat history by what was said, not just by
title. The chat list `q` parameter accepts a new `search:` filter that
performs full-text search across chat titles, pull request titles, PR
numbers, and message content, for example `?q=search:"kubernetes
restart"`. Matching is case-insensitive and supports quoted phrases,
`OR`, and `-` negation. Message content additionally matches English
word stems (`refactor` finds a message containing `refactoring`).
`search:` cannot be combined with the `title:`, `pr_title:`, or `pr:`
filters; the existing substring filters are unchanged.

**Upgrading with existing chat history:** the message search index is
populated by a background job (every 10 minutes, up to 50,000 messages
per run, newest first). Upgrades are not blocked, and chat reads and
writes are unaffected while the index fills. Older messages appear in
search results progressively; messages indexed before the stemming
upgrade match exact word forms until re-indexed. Titles and PR titles
are searchable immediately.

</details>

---

🤖 This PR was generated by Coder Agents on behalf of @f0ssel.
2026-08-25 09:09:10 -04:00
Garrett Delfosse 378ac91b49 fix: stem chat search terms with the english text search config (#28319)
Chat message search used the `simple` text search config, which folds
case but does no stemming, so `refactor` did not match messages
containing `refactoring`. Message bodies now index and query with the
`english` config, which stems both sides. Titles, PR titles, and all
other filters are unchanged.

Migration `000585` adds a `chat_messages.search_tsv_config` enum column
recording which config produced each stored vector and stamps existing
vectors `'simple'` (a column-only update; vectors and indexes are
untouched, since rewriting `search_tsv` would block message writes on
large tables). The dbpurge sweep gains a bounded
`ReindexStaleChatMessagesSearchTsv` pass that rewrites stale vectors
newest first and stops for the process lifetime once drained. Until a
row is rewritten, `GetChats` matches it with the config that produced
it, so pre-migration exact-form searches keep working during the drain.
Vectors written by old binaries mid rolling upgrade cannot stamp the
config, stay pending, and self-heal on the next upgraded sweep.
Steady-state DB load is unchanged.

The down migration resets `english` vectors to `NULL` so the parent
version's existing sweep rewrites them with `simple`.

Closes
[CODAGT-867](https://linear.app/codercom/issue/CODAGT-867/backend-search-improvements-to-handle-partial-matches)

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

- **`english` stemming over prefix matching.** On a 300k-row corpus a
stemmed lookup is a single GIN entry-tree probe, while `term:*` prefix
matching unions posting lists of every lexeme sharing the prefix (up to
a full scan for short prefixes), is asymmetric, and loses the
`websearch_to_tsquery` phrase/OR/negation UX. `pg_trgm` rejected as a
heavier index with different semantics.
- **Scope to message bodies only** (review). Titles and PR titles keep
their `simple` FTS expressions and indexes, identical to main.
- **Config-versioned queue over migration-time reset** (review). An
unqualified `UPDATE ... SET search_tsv = NULL` rewrites every indexed
row in the migration transaction, and an old replica could backfill
reset rows with `simple` vectors that permanently leave the `search_tsv
IS NULL` queue. The config column makes staleness explicit and both
problems disappear.
- **Enum over `text`** (review) for the config column.
- **Trade-offs.** English stopwords are dropped from message search
(stopword-only queries match no messages); stemming is English-specific;
titles do not stem; prefix matching remains out of scope.

</details>

---

🤖 This PR was generated by Coder Agents on behalf of @f0ssel.
2026-08-25 09:08:52 -04:00
Garrett Delfosse eedc0ece47 fix: avoid 500 when generating chat title from rename dialog and remove unused endpoint (#28306) 2026-08-25 06:52:45 -04:00
Jon Ayers 26de6140fb feat: add flag to disable workspace agent context sync (#28522) 2026-08-24 19:58:30 -05:00
Michael Suchacz b6d7653231 fix: apply MCP server selection when editing a chat message (#28471)
## Problem

Editing a user message in an Agent chat silently dropped the MCP server
selection. The composer renders the MCP picker in edit mode and toggles
update local client state, so the picker displayed the new selection,
but the edit request omitted `mcp_server_ids` at every layer (frontend
request builder, `codersdk.EditChatMessageRequest`, the `PATCH
/chats/{chat}/messages/{message}` handler, and `chatd.EditMessage`). The
chat's persisted selection never changed and the regenerated turn ran
without the newly enabled MCP tools. Two dogfood users hit this within
hours; there is no error anywhere and the UI shows the opposite of the
server state.

## Changes

- `codersdk`: add `MCPServerIDs *[]uuid.UUID` to
`EditChatMessageRequest`, mirroring `CreateChatMessageRequest` (nil
preserves the current selection).
- `chatd`: extract the send path's MCP update block into one shared
`applyRequestedMCPServerIDs` helper (explore-subagent snapshot
immutability guard plus Force On enforcement, Cure53 CDM-02-010) and
call it from both `SendMessage` and `EditMessage`, so enforcement cannot
drift between the two paths.
- `coderd`: extract the send handler's request validation (dedupe,
enabled-in-organization check, persisted-ID exemption) into
`normalizeRequestedChatMCPServerIDs` and wire it into the edit handler,
which now threads the selection into `EditMessageOptions`.
- Frontend: the edit request now includes `mcp_server_ids:
[...effectiveMCPServerIds]`, exactly like the send path, making the
picker's displayed state real.
- `make gen` artifacts (swagger, API docs, `typesGenerated.ts`).

## Tests

Each layer is covered and was proven with independent red toggles
(removing one layer's wiring fails only that layer's tests):

- chatd (`TestEditMessage_MCPServerIDs`): edit applies a provided
selection, nil preserves it, an emptied list cannot remove a `force_on`
server, and explore subagent chats keep the spawn-time snapshot.
- API (`TestPatchChatMessage/MCPServerIDsApplied`,
`MCPServerIDsInvalidRejected`): persistence via the endpoint, omission
preserves, unknown IDs get the same 400 as the send path.
- Storybook (`EditAppliesMCPServerSelection`): toggling a server on
during an edit puts it in the edit request payload.

Note: the `AgentChatPage.stories.tsx` story "Queued For Capacity After
Polling" fails locally on current main as well (verified against the
main baseline with this branch's changes reverted); it is unrelated to
this diff.

Remote dogfood UAT ran on the exact head and passed, including proof
that the regenerated turn actually gains the newly enabled MCP server's
tools.

> 🤖 Xum acted on Mike's (@ibetitsmike) behalf. • Model:
`anthropic:claude-fable-5`
<!-- xum-attribution: model=anthropic:claude-fable-5 -->
2026-08-24 17:39:52 +02:00
J. Scott Miller 76962273d8 feat: add coder organizations edit for default member roles (#28227)
`default_org_member_roles` was only settable through Terraform or a raw
`PATCH /api/v2/organizations/{organization}`. This adds a CLI
equivalent.

```console
coder organizations edit --org acme --default-org-member-roles organization-workspace-access,organization-template-admin
coder organizations edit --org acme --default-org-member-roles ""   # grant no roles
```

- The flag replaces the organization's current list rather than adding
to it. It accepts a comma-separated list, may be repeated, and
de-duplicates. An empty value removes every role.
- Removing a role prompts for confirmation, listing the roles being
removed, unless `-y` is passed. Adding roles applies without a prompt.
- The resulting set is printed, so no follow-up command is needed to
confirm what was applied.
- The organization is chosen with `-O/--org` or `$CODER_ORGANIZATION`,
and is implicit when the caller belongs to exactly one organization.

The org update endpoint is behind `FeatureMultipleOrganizations`, so the
command is enterprise/premium only. Non-built-in roles are rejected by
the server, and `dbauthz` already prevents a caller from setting a
default they could not assign to a member individually.

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

## Shape

`codersdk.UpdateOrganizationRequest.DefaultOrgMemberRoles *[]string` and
the enterprise `patchOrganization` handler already existed; only the CLI
was missing, and nothing in `cli/` called `UpdateOrganization` at all.
No server or SDK changes are needed.

`organizations edit` follows the partial-update pattern of `coder groups
edit`: check `ParsedFlags().Changed(...)`, populate only the fields the
user set, and leave the rest nil so the handler preserves them. Passing
no flags is an error.

Two earlier shapes were tried and dropped:

- **A `default-org-member-roles` entry in the `organizations settings`
registry.** Every sibling entry unmarshals an SDK type that maps 1:1 to
a dedicated endpoint; this field has no such endpoint. Reusing
`UpdateOrganizationRequest` for the piped JSON meant a stray `name`
field could rename the org, and the documented `show > file`, edit, `set
< file` workflow failed on the default organization, whose name is
reserved.
- **A `--default-org-member-roles` flag on `organizations create`.**
`create` cannot set display name, description, or icon either, so a
roles-only flag there is asymmetric. It would also require
`CreateOrganizationRequest` to grow the field plus server-side
validation.

## Known sharp edge

`serpent.StringArray` resets its slice when any flag value is empty, so
`--default-org-member-roles a --default-org-member-roles ""` clears the
list rather than keeping `a`. This is pinned by a test and called out in
a code comment. The confirmation prompt catches it interactively; a
script passing `-y` would not. A custom flag value that ignores empty
occurrences was prototyped and reverted as more machinery than the
behavior warranted.

## Validation

Manually verified against a local dev deployment with a premium license:
setting, adding, clearing, prompt accepted and declined, duplicate and
whitespace handling, invalid role rejection, and a plain member being
denied. Confirmed with `/authcheck` that a member loses workspace-create
access when the roles are cleared and regains it when restored, and that
the change is recorded in the audit log.

## Follow-ups worth considering

- `--name`, `--display-name`, `--description`, and `--icon` on
`organizations edit`; all already exist on `UpdateOrganizationRequest`.
Rename deserves its own discussion.
- Setting the defaults to `organization-admin` makes every member an org
admin, including the ability to edit the org further, and those users
still render as plain members in member listings. Reachable today via
the API, UI, and Terraform; a warning on privileged roles would help.
- `dbauthz.InsertOrganization` has no `canAssignRoles` check, unlike
`UpdateOrganization`. Harmless while the only caller passes the
deployment default constant.
- `docs/admin/users/organizations.md` still points users at the
dashboard or a raw `PATCH`.
</details>

---

Created by Coder Agents on behalf of @jscottmiller.
2026-08-24 09:41:21 -05:00
Ben PotterandNick Vigilante 3bdd395faa docs(docs/admin/templates/extending-templates): clarify coder_env merge_strategy does not include host environment (#28466)
`merge_strategy` on `coder_env` only combines values across `coder_env`
resources targeting the same name. It does not know about the value
already set by the workspace's image or host, such as the base `PATH`. A
user hit this in #27501: appending to `PATH` with three `coder_env`
resources replaced the host's `PATH` entirely, since none of them
referenced the existing value.

Clarify this in the docs, and update the `PATH` example to show
referencing `$PATH` in one of the resources so the host's original value
is kept.

Refs #27501

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

- `coderd/provisionerdserver/provisionerdserver.go` builds the merged
env starting from an empty map (`MergeExtraEnvs`), only combining
`coder_env` resources with each other.
- `agent/agent.go`'s `updateCommandEnv` applies the result with
`os.ExpandEnv(v)`, which expands `$VARNAME` against the agent's real
process environment.
- Confirmed with a standalone repro that `value =
"$PATH:/usr/local/cuda/bin"` preserves the host's real `PATH` and
appends the extra directory, and that this composes correctly across
multiple `coder_env` resources with `merge_strategy = "append"` as long
as one of them references `$PATH`.
- A companion PR updates the `terraform-provider-coder` schema
description and example that feed the registry docs:
https://github.com/coder/terraform-provider-coder (branch
`bpmct/docs-env-merge-host`).

</details>

---
*Opened by Coder Agents on behalf of @bpmct.*

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-24 07:55:23 -05:00
Cian Johnston 042421694f fix: surface duplicate AI provider hostname as warning, not error (#28208)
Two live `ai_providers` rows can share the same `base_url` hostname.
This is an intended configuration (AIGOV-97): the direct routing path
(`/api/v2/ai-gateway/{name}/...`) routes by provider name and fully
supports it. Only the MITM proxy path (`aibridgeproxyd`) cannot
disambiguate, because its `nameByHost` map is 1:1.

`classifyProviderRow` marked the second provider as
`ProviderStatusError`, which surfaced as a misleading log warning and a
`status=error` Prometheus label. The provider is not actually broken; it
is fully routable via the direct path. The error was only visible in
server logs and Prometheus, not in the API or UI.

This change:

- Extracts `BaseURLHostname` into `coderd/aibridged` and eliminates
three duplicate implementations (proxy classifier, chatprovider, and the
API layer now uses it for status checks).
- Downgrades the proxy classifier from `ProviderStatusError` to a new
`ProviderStatusProxyExcluded` status. The provider is not broken; it is
just not reachable via the MITM proxy path.
- Adds `Status *AIProviderStatus` to `codersdk.AIProvider` with
`Warnings []string`, matching the `WorkspaceProxy` precedent.
- Populates warnings on create, update, GET, and list when a provider's
hostname collides with another enabled provider.
- Adds an integration test proving that a duplicate provider is routable
via the direct path but not via the proxy path.

Refs AIGOV-596

Generated by Coder Agents



https://github.com/user-attachments/assets/bf323837-5121-4d1b-ab19-593f1d32374e
2026-08-24 13:27:22 +01:00
earapo13andNick Vigilante defd5d48a1 docs: clarify that Coder server should run on a separate machine (#27468)
Closes
[DOCS-600](https://linear.app/codercom/issue/DOCS-600/make-it-clear-in-the-quickstart-that-you-should-install-the-coder).

The Quickstart guide has readers install and run `coder server` on the
same machine they're working from, without calling out that this is only
for a quick trial. Coder's actual value comes from remote development,
so hosting the Coder server on a separate machine has a lot more power
than running it locally.

This adds two notes to `docs/get-started/index.md`:
- In **Prerequisites**, explaining that this quickstart runs the server
locally for convenience, but a real deployment should host it on a
separate machine, and linking to the
[Install](https://coder.com/docs/install) page.
- In **Step 2: Install and start Coder**, a shorter reminder right
before the install commands.

----

Created using Coder Agents 🤖

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-24 08:27:00 -04:00
df6a33ad37 docs: fix broken extending-templates examples (dynamic-parameters, docker-in-workspaces) (#28100)
## Summary

Fixes broken examples on the `extending-templates` pages surfaced by the
DOCS-637 runtime drift sweep, and completes the dangling `external-auth`
reference. Verified against `main` and the CLI source (`coder templates
init --id`, `coder templates push`).

## Changes

| Page | Fix |
|------|-----|
| `dynamic-parameters.md` | The **Dynamic Validation** snippet
referenced an undefined `show_cpu_cores` through a stray `count =
data.coder_parameter.show_cpu_cores.value ? 1 : 0` line copied from the
earlier Hide/Show Options example. Standalone copy failed `terraform
validate`. Removed the `count` line (and its misleading "Only show this
parameter" comment) so the snippet is self-contained. The valid
occurrence in the Hide/Show example (where `show_cpu_cores` is defined)
is untouched. |
| `docker-in-workspaces.md` | The rootless Podman step used `echo
"kubernetes-with-podman" \| coder templates init`, but
`kubernetes-with-podman` isn't a built-in starter id, so the command
scaffolds nothing. Step 4 now starts from the built-in `kubernetes`
starter (`coder templates init --id kubernetes`) and shows the minimal
Podman delta inline: the maintained `codercom/example-podman:ubuntu`
base image, the `container.apparmor.security.beta.kubernetes.io/dev =
unconfined` pod annotation, and a `github.com/fuse` device limit. The
starter already runs as UID/GID 1000 with `run_as_non_root`, which
rootless Podman needs. Also switches the deprecated `coder templates
create` to `coder templates push`. Follow-up from review: swapped
`ghcr.io/coder/podman` for the maintained
`codercom/example-podman:ubuntu` image and linked its source, added a
note that the AppArmor annotation is deprecated on Kubernetes 1.30+
(`securityContext.appArmorProfile`), and added an EKS Auto Mode caveat
to the Bottlerocket section. |
| `external-auth.md` | The **External Auth Providers** sentence
dead-ended at "...in the Coder Control Plane. See" with no link.
Completed it with a link to the admin External Authentication page
(`../../external-auth/index.md`), the target chosen in review. |

## Dependency

The `docker-in-workspaces.md` example now references
`codercom/example-podman:ubuntu`, published by coder/images#339. That PR
is approved but should merge (and publish the image to Docker Hub)
before this PR merges, so the docs don't point at an image that doesn't
exist yet.

Linear: https://linear.app/codercom/issue/DOCS-645

> This PR was created with AI assistance (Coder Agents).

---------

Co-authored-by: Ben Potter <me@bpmct.net>
Co-authored-by: Ben Potter <ben@coder.com>
2026-08-24 08:24:26 -04:00
Atif Ali 54d4ae9aca fix: detect Xum client in aibridge after Mux rename (#28448) 2026-08-24 16:20:57 +05:00
Ethan c275327fb7 feat: audit operational agent settings (#28369)
Depends on #28394.

Audit changes to seven operational agent settings through a typed
`chat_operational_settings` resource. Each handler serializes baseline
capture and mutation with a per-setting advisory lock, keeps both
operations in one transaction, and records field-specific diffs.

Effective no-op requests now skip both the database upsert and the
success audit, including absent rows whose effective value is already
the default. The change also retains the allowlisted raw `site_configs`
query, updates generated audit and API surfaces, adds failure and
concurrency coverage, and reuses the existing AuditPage resource-filter
story pattern.

Relates to CODAGT-720.
2026-08-24 11:53:47 +01:00
Michael SuchaczandEthan Dickson 0ef331fcd0 feat!: scope chat model override settings to organizations (#28442)
Moves chat model override settings from deployment scope to organization
scope, following the org-scoping of chat model configs in #28440.

Depends on #28440 (based on
`ethan/chat-models-availability-consolidation`).

Remote dogfood UAT passed on this change, including multi-organization
scenarios on a licensed deployment with real models.

## Problem

Chat model configs are now owned by organizations, but the override
settings that reference them stayed deployment-wide: admin
subagent/title/compaction overrides in `site_configs`, personal
overrides in `user_configs`, and the advisor model embedded in the
advisor runtime JSON. A single deployment-level override can only point
at one organization's model config, so overrides effectively worked for
the default organization only, and title generation had to soften its
hard-failure contract to tolerate unusable overrides.

## Fix

Admin overrides (general, explore, title generation, compaction,
advisor) and personal overrides (root, general, explore) become
organization-scoped rows in two new typed tables,
`chat_organization_model_overrides` and `chat_user_model_overrides`.
Composite foreign keys on `(organization_id, model_config_id)` make
cross-organization model references unrepresentable. The migration
deletes the legacy serialized `site_configs`/`user_configs` override
keys instead of migrating them; admins and users re-select models in the
new organization-scoped settings.

New endpoints live under
`/api/experimental/organizations/{organization}/chats/model-overrides`
(admin defaults) and
`/api/experimental/organizations/{organization}/members/{user}/chats/model-overrides`
(personal overrides); the legacy deployment-level routes are removed.
chatd resolves overrides via the chat's organization, restoring the
hard-failure contract for configured-but-unusable title generation
overrides. The deployment-level `AllowUsers` switch and advisor runtime
limits stay deployment-scoped.

The Coder Agents settings UI gains a per-organization "Defaults &
overrides" page under AI Settings > Models, and the personal overrides
page gains an organization selector for users in multiple organizations.
Advisor telemetry now reports per-organization override rows.

**BREAKING CHANGE**: Existing deployment-level overrides are dropped,
not migrated. Every organization starts with no overrides after upgrade,
and model selections must be re-applied in the new settings. The legacy
deployment-level override endpoints are removed.

Closes https://linear.app/coder/issue/CODAGT-872

> [!NOTE]
> Xum (AI agent) authored this PR on behalf of @ibetitsmike.

<!-- xum-attribution: model=claude-opus-4-6 thinking=high -->

---------

Co-authored-by: Ethan Dickson <ethan@coder.com>
2026-08-24 11:20:26 +01:00
Ethan 3809314b31 refactor!: consolidate chat model availability (#28440)
## Summary

Consolidate chat model management and runtime availability into a single
organization model collection contract. The organization model response
now includes provider availability, unavailable reasons, and
unsupported-provider details, so callers no longer need a separate
availability request.

Depends on #28439.

## Problem

The organization-scoped API exposes two overlapping representations of
the same chat models:

```text
GET /api/experimental/organizations/{organization}/chats/models
GET /api/experimental/organizations/{organization}/chats/models/available
```

The collection route returns organization-owned model configurations and
redacted provider descriptors. The availability route returns a second
catalog-oriented response with provider availability and synthetic
catalog entries. Callers must fetch, reconcile, and cache both responses
even though they describe the same effective set of models.

This creates duplicated server logic and separate SDK, OpenAPI, and
frontend types. It can also produce inconsistent client state when one
request succeeds while the other fails or when the two responses are
refreshed at different times.

## Fix

Return all model-management and runtime-availability information from
the organization model collection route:

```text
GET /api/experimental/organizations/{organization}/chats/models
```

`OrganizationChatModelsResponse` continues to return the caller-readable
organization model configurations and redacted provider descriptors.
Provider descriptors now also include:

- `available`
- `unavailable_reason`

The response additionally includes `unsupported_providers`, allowing
clients to explain configurations that the Agents harness cannot use.

Frontend model settings, agent creation, existing chat recovery, and
model override surfaces now consume this single collection query. This
keeps model ownership, caller visibility, provider availability, and
unsupported-provider guidance in one cache entry and one authorization
path.

The default-organization compatibility route remains available:

```text
GET /api/experimental/chats/models
```

It now returns the same consolidated `OrganizationChatModelsResponse`
contract instead of the former availability response.

## Breaking change

This removes the separate organization model availability endpoint:

```text
GET /api/experimental/organizations/{organization}/chats/models/available
```

Clients using that endpoint must migrate to:

```text
GET /api/experimental/organizations/{organization}/chats/models
```

This PR also removes the corresponding public experimental client and
schema surface:

- `ExperimentalClient.ChatModelAvailability`
- `ChatModelAvailabilityResponse`
- `ChatModelProvider`
- `ChatModelCatalogEntry`
- The generated OpenAPI schema and frontend API/query types for the
availability endpoint

Callers must use `ExperimentalClient.ChatModels` and
`OrganizationChatModelsResponse` instead. Availability is now reported
on each `ChatModelProviderDescriptor`, and unsupported providers are
returned in `OrganizationChatModelsResponse.UnsupportedProviders`.

The default-organization compatibility route retains its URL, but its
response schema changes from `ChatModelAvailabilityResponse` to
`OrganizationChatModelsResponse`. Direct HTTP clients and generated
clients that decode the previous response type must be updated even if
they do not use the removed organization-scoped `/available` route.
2026-08-24 11:20:26 +01:00
Ethan a53c6e6366 feat: audit chat model config changes (#28439)
Adds audit logging for chat model config creates, updates, deletes, ACL
changes, and automatic default-model transitions. Audit records use the
config display name or ID as the target and are emitted only after
successful transactions.

Depends on #27960.
2026-08-24 11:20:26 +01:00
Ethan 75ad45109d feat: use organization-scoped chat models (#27960)
Move chat model settings to
`/ai/settings/organizations/:organization/models`, add an organization
switcher, and redirect legacy settings paths. The pages use organization
permissions for read, create, update, and delete controls. They use
redacted provider descriptors.

Agent creation loads models for the selected organization. Existing
chats load models for the chat organization. Chat views warn about
unavailable historical models, select a usable local recovery model, and
disable generation when none exists. Settings that aggregate
organizations retain successful results when one request fails.

Depends on #27959

_This pull request description was generated by Coder Agents._
2026-08-24 11:20:25 +01:00
Ethan aefc761fcf feat!: enforce organization scope for chat models (#27959)
## Summary

Move chat model management and runtime availability to
organization-scoped API routes. The API now identifies the organization
in every model-management operation, applies chat model RBAC and ACLs
within that organization, and returns only models the caller can use
there.

Depends on #27958.

## Problem

Chat model configurations now belong to organizations, but the existing
experimental management and discovery APIs are deployment-shaped. Their
routes do not identify an organization, SDK methods do not accept an
organization ID, and item operations address a model configuration by ID
alone.

That contract cannot safely expose organization-owned model
configurations. It also does not provide the organization-specific
provider information, authorization behavior, ACL management, or
recovery guidance needed by the settings and chat clients later in the
stack.

## Fix

Add organization-scoped chat model endpoints under:

```text
/api/experimental/organizations/{organization}/chats/models
```

The new API provides:

- Organization-scoped model listing and creation.
- Model get, update, and delete operations scoped by both organization
and model ID.
- Model ACL read and update operations.
- Organization-scoped runtime availability and provider status.
- Redacted provider descriptors for model-management clients.
- Chat model RBAC and row ACL enforcement for writes, runtime discovery,
and Chatd model selection.
- Recovery guidance when a chat's organization has no usable local
model.

Historical chats can retain a model reference owned by another
organization, but runtime selection uses an authorized local default
when one is available. Foreign, inaccessible, disabled, and otherwise
unusable models are not exposed as usable selections for the
organization.

The existing collection and availability routes remain as
default-organization compatibility endpoints in this layer:

```text
GET  /api/experimental/chats/model-configs
POST /api/experimental/chats/model-configs
GET  /api/experimental/chats/models
```

These compatibility routes do not provide access to models in
non-default organizations. The previous unscoped item update and delete
routes are removed because item operations must include the owning
organization.

## Breaking change

This changes the experimental HTTP API and Go SDK contracts for chat
model management.

Clients must migrate model-management and availability requests to the
organization-scoped routes and provide an organization identifier. In
the Go SDK, the following methods now require an organization ID:

- `ChatModelAvailability`
- `ChatModels`
- `CreateChatModel`
- `UpdateChatModel`
- `DeleteChatModel`

`ChatModels` also changes its return value from `[]ChatModel` to
`OrganizationChatModelsResponse`, which includes the organization models
and the redacted provider descriptors required by management clients.
New item and ACL methods likewise require both the organization ID and
model ID.

The default-organization compatibility routes reduce the immediate
impact for collection and availability callers, but they do not preserve
the previous item API or SDK method signatures. Generated clients and
direct consumers of the experimental API must be updated before adopting
this change.

_This pull request description was generated by Coder Agents._
2026-08-24 11:20:25 +01:00
Ethan 9bd8899359 refactor: clarify chat model resource names (#27958)
Rename the admin-managed SDK resource from `ChatModelConfig` to
`ChatModel`. Rename catalog entries from `ChatModel` to
`ChatModelCatalogEntry` and replace `ChatModelsResponse` with
`ChatModelAvailabilityResponse`.

API routes and JSON fields do not change. Experimental SDK and OpenAPI
schema names do change.

Depends on #27957

_This pull request description was generated by Coder Agents._
2026-08-24 09:43:45 +00:00
Ethan cbe24a3da5 feat: add chat model config RBAC resource (#27957)
Add the `chat_model_config` RBAC resource, actions, and API key scopes.
This layer includes the scope migration and generated API types. Model
list queries apply token scopes, SQL authorization filters, and row
ACLs.

Write and default-management handlers keep deployment configuration
authorization until the next API layer replaces it.

Depends on #27956

_This pull request description was generated by Coder Agents._
2026-08-24 09:43:45 +00:00
Paweł BanaszewskiandNick Vigilante 4ce8e8ed56 docs: address AI Gateway documentation review feedback (#28309)
Applies the review feedback from #27794. Prose only.

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-23 19:42:48 +00:00
david-fraley cb52f5339d feat: show a premium paywall on the external auth settings page (#28435) 2026-08-21 11:45:38 -05:00
david-fraley a2afb458c5 feat: add premium paywall conversion telemetry (#28425)
**TLDR:** When someone using free Coder taps a "Start trial for free"
button, we now write down which page they tapped it on, and whether they
went on to actually start the trial. That tells us which locked features
make people want Premium.

## Brief summary

- Records two things: the button being clicked, and a trial actually
being started.
- Each click gets a random ID that travels with the person to the trial
form, so we can tell who finished from who walked away.
- Records a short label for the page (like `appearance` or `audit_log`),
never the web address, so no customer names are collected.

#28226 added the trial form and has since merged, so this now targets
`main`.

## Description

Today the "Start trial for free" button just moves you to the Premium
page and nothing is recorded, so there is no way to know which feature
convinced someone.

This adds two events:

| Event | Happens when |
|---|---|
| `cta_click` | Someone clicks "Start trial for free" |
| `trial_signup` | A trial licence is actually issued |

The click generates a random ID. It rides along to the trial form and
gets saved on the signup, so a click and a signup can be matched up
later. Clicks with no matching signup are the people who gave up. Trials
started without a paywall (for example straight from the sidebar) are
labelled `direct`, so "no label" never gets confused with "broken".

A few small choices worth knowing:

- The ID is kept in browser session storage, not in the web address, so
the URL stays clean. It expires after 30 minutes.
- The trial signup event is recorded by the server, not the browser, so
nobody can fake a signup.
- The browser cannot say which kind of event it is sending. It can only
report a click; the server labels it.
- Only people allowed to start a trial are counted. The server rejects
the rest, which matters because a few paywalls show their button to
everyone.
- Nothing is recorded at all when telemetry is turned off.

There is deliberately no "paywall was shown" event. Every admin page
visit would report one, which is a lot of noise for little insight.

Every paywall in the [Premium Copy
Updates](https://www.notion.so/coderhq/Premium-Copy-Updates-3c1d579be59280a59557cabd54fd8a1f)
table has a label. The rows that do not are badges and alerts with no
button to click.

## Proof

Ran a local Coder with no licence and clicked the paywall button on the
Appearance page.

What the browser sent, and the reply:

```json
POST /api/v2/deployment/premium-funnel-events  ->  204 No Content
{"id":"92d96afa-f975-4789-b8a7-b1fd19d4df85","source":"appearance","variant":"premium"}
```

What the browser saved for the trial form, same ID:

```json
{"id":"92d96afa-f975-4789-b8a7-b1fd19d4df85","source":"appearance","createdAt":1787268520857}
```

The click then landed on the Premium page with the trial form.
Screenshots of the network panel, the saved value, and the Premium page
are attached below. The form itself was not submitted, since that would
contact the real licence server.

## Testing

- Backend tests: a click is recorded with the server's own label, an
unknown page label is refused, and a normal member is refused.
- Storybook tests: button clicked and ID saved on all three paywall
styles, plus the case where the viewer only sees guidance text and has
nothing to click.
- Unit tests for the saved ID: expiry, bad data, unknown page label, and
the `direct` fallback.
- `make gen` is clean, and lint, types, and formatting pass.

Two stories fail on `main` today and fail the same way here:
`ExternalAuthSettingsPageView > Page` and `PremiumPageView > No
License`. Neither file is touched by this branch; both were verified
failing on `main` with this branch checked out elsewhere.

## Follow-up

coder/coder-telemetry-server#45 saves these events for reporting. It
merges after this one.

<details>
<summary>Plan and decisions</summary>

**Goal:** find out which Premium paywall drives trial signups, and tell
abandons apart from completions.

**Options considered and dropped:**

1. Put `?from=appearance` in the URL. Rejected: messy for users.
2. Use router state. Rejected: lost if the page is refreshed.
3. Let the browser report the signup. Rejected: it could be faked or
lost during the redirect.
4. Work out the page from the URL. Rejected: URLs contain organization
and template names.
5. Report every paywall impression. Rejected: one event per admin page
visit is noise, and the click is the signal.
6. Separate event types and tables. Rejected: makes the matching query
harder for no gain.

**Event shape:**

```go
type PremiumFunnelEvent struct {
	ID            uuid.UUID // event ID; for a click this is also the matching ID
	EventType     string    // cta_click | trial_signup, set by the server
	Source        string    // appearance, audit_log, ..., direct
	Variant       string    // which paywall design was shown
	AttributionID uuid.UUID // the click this signup came from
	UserID        uuid.UUID
	CreatedAt     time.Time
}
```

**Where the code lives:** nothing under `components/` imports from
`modules/`, so the paywall components stay presentational and only gain
an `onCTAClick` prop. New wrappers in `modules/paywall/` own the
reporting, one per paywall style, each taking a fixed `source`.

**Self-review:** the `frontend-review` skill caught that reading
permissions inside the wrapper forced an auth context into
presentational page views, which broke their stories. Every call site
already passes `canViewPremium={permissions.viewAllLicenses}` and the
button only renders when that is true, so the wrapper no longer reads
permissions and the server stays the gate. It also flagged one
unattributed paywall on the Security page, now wired up as
`browser_only`.

</details>

> Generated with [Coder Agents](https://coder.com/agents) on behalf of
@david-fraley
2026-08-21 10:31:01 -04:00
Samuel VolinandMatt Vollmer f44a3b59d7 feat: Premium Page CTA updates and form handling (#28226)
* Premium page has form for signing up for a trial
* Input validation and normalization for trial form fields
* api endpoint definition to make this processes seamless 
* license page updates to access `?success=true` queryparam and confetti

<img width="1512" height="833" alt="Screenshot 2026-08-17 at 10 08
41 PM"
src="https://github.com/user-attachments/assets/1766e724-c63a-4da9-b2bd-a98e6b66cc9b"
/>

<img width="1510" height="874" alt="Aug-17-2026 22-12-38"
src="https://github.com/user-attachments/assets/3a2a0f35-1176-4290-aa0d-b3f7d66c15d6"
/>


```mermaid
sequenceDiagram
    autonumber
    actor Owner
    participant UI as UI<br/>TrialRequestForm + PremiumPage
    participant API as API<br/>api.ts + coderd middleware
    participant Coderd as Coderd<br/>postTrialLicense + trialer
    participant Licensor as Licensor<br/>v2-licensor + Postgres + pubsub + cache

    Note over UI: mutation.status = "idle"

    Owner->>UI: fills 10 fields, checks acknowledgement
    UI->>UI: Yup validate, strip "acknowledged", submit
    UI->>API: POST /api/v2/licenses/trial<br/>cookie + X-CSRF-TOKEN
    Note over UI: mutation.status = "pending"

    API->>API: verify CSRF, apiRateLimiter,<br/>apiKeyMiddleware sets actor
    API->>Coderd: dispatch

    Coderd->>Coderd: audit.InitRequest, authorize license:create,<br/>httpapi.Read validates, HasLicense is false
    Coderd->>Licensor: POST trial request<br/>deployment_id unspoofable, 10s deadline
    Licensor-->>Coderd: 200, raw signed JWT

    Coderd->>Coderd: ParseClaimsIgnoreNbf, uuid.Parse
    Coderd->>Licensor: InsertLicense, updateEntitlements,<br/>publish PubsubEventLicense, commit audit log
    Licensor-->>Coderd: database.License
    Coderd-->>API: 201 codersdk.License
    API-->>UI: 201 codersdk.License

    Note over UI: mutation.status = "success"
    UI->>Licensor: invalidate entitlements + licenses keys
    UI->>Owner: navigate /deployment/premium?success=true
    Note over Owner: confetti fires on the success param
```

---------

Co-authored-by: Matt Vollmer <matthewjvollmer@outlook.com>
2026-08-21 09:54:54 -04:00
Bobby Ho 6348c83142 feat: register public clients without a secret (#28046)
Third in the stack, split out of #27873. This is where dynamic client
registration first produces a public client.

- A registration requesting token_endpoint_auth_method `none` issues no
secret and persists the client_type derived in #28043. The response
omits client_secret entirely, per RFC 7591 §3.2.1.
- Discovery still advertises only the two secret-based methods. `none`
is withheld until the token endpoint honors it, so a conforming client
is not told to attempt an exchange that would be rejected.
- The app and its secret are written in one transaction. They were two
independent inserts, so a failed second one left a committed app that
could never authenticate while still holding a registration access
token. Pre-existing, but a public client's missing secret row makes the
orphaned case unspottable by inspection.
- registration_client_uri uses url.JoinPath, fixing a trailing-slash
access URL producing //oauth2/clients/{id}.
- Docs state both limits above, so the page does not describe a flow
that returns 400 until #28047 lands.

A client registered here cannot obtain a token yet; #28047 adds that.
Dynamic client registration is off by default, so none of this is
user-visible until then.

Refs
https://linear.app/codercom/issue/ENG-3029/oauth2-support-public-client
2026-08-20 12:49:47 -07:00
Nick Vigilante c6deadbc6c docs: fix broken .style/ link and lift details block out of list item [DOCS-661] (#28180)
## What

Two small docs fixes, split out of the offlinedocs Fumadocs migration
(#27390) so that PR stays a focused tooling change and these land on
their own review track.

- `docs/about/contributing/documentation.md`: the Vale style-guide link
pointed at `docs/.style/style-guide/`, which is excluded from the
published docs corpus, so the relative link 404s on the live site.
Repointed to an absolute github.com URL.
- `docs/ai-coder/ai-gateway/monitoring.md`: lifted the "Possible client
values" `<details>` block out of the list item so it renders as a
top-level accordion, and restored a dropped blockquote continuation
marker (`>`).

## Why

Both are genuine docs bugs on their own:

- The `.style/` link is broken on the live site today, because that
directory is intentionally excluded from the published corpus.
- The `<details>` nested inside a list item renders inconsistently;
lifting it to a sibling block is portable across renderers.

They are also prerequisites for the offlinedocs Fumadocs migration,
whose stricter build-time sync hard-fails on unmapped inter-doc links
and only converts a `<details>` to an accordion when it is a list
sibling. Landing them here first lets the migration PR drop these two
files on its next rebase.

## Validation

- `make fmt/markdown` and `make lint/markdown`: clean (via
pre-commit-light).
- Docs-only change; no CI or build config touched.

> This PR was created with AI assistance (Coder Agents).
2026-08-20 19:09:46 +00:00
Susana Ferreira d989ae36cd docs: clarify who can set AI model prices and how they are keyed (#28401)
The docs named the `ai_model_price:update` permission but never said
which role holds it, and nothing anywhere explained that a price is
keyed by provider type and model, so every configured provider of that
type shares it. This names the Owner role, documents the keying and why
`openai-compat` cannot be priced, and repeats both in the CLI's
`--provider` descriptions and `update` help.

> [!NOTE]
> Initially generated by Claude Opus 5, modified and reviewed by
@ssncferreira
2026-08-20 17:35:30 +01:00
Jake Howell d3b3aeaabc docs: refresh workspace-management screenshots with current UI (#28356)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

Refreshes the six stale screenshots on the
[Workspaces](https://coder.com/docs/user-guides/workspace-management)
page (`docs/user-guides/workspace-management.md`) with the current Coder
UI, recreating equivalent dummy data (matching template and workspace
names) so the images stay recognizable.

Linear: DOCS-55

## Updated images

| Image | Section |
|-------|---------|
| `creating-workspace-ui.png` | Creating workspaces |
| `workspace-update.png` | Updating workspaces |
| `workspace-automatic-updates.png` | Automatic updates |
| `user-guides/workspace-bulk-actions.png` | Bulk operations |
| `schedule.png` | Starting and stopping |
| `templates/template-variables.png` | Repairing workspaces |

Prose is unchanged; this is a screenshot-only refresh.

## Notes / limitations

The originals came from production-like deployments with
AWS/Azure/Kubernetes templates, multiple users, and aged data. These
were reproduced on a local `scripts/develop.sh` (Docker) instance, so:

- Template/workspace names, states (Running/Stopped/Failed), the
"Selected 3 of 5" bulk selection,
`use_kubeconfig=True`/`namespace=default`, and the auto-update =
`Always` setting all match.
- Instance-derived values cannot match: "used by" counts show `0
developers`, build times show `Unknown`, the connection-latency pill has
no value, and the workspace name field is disabled by the template.

<details>
<summary>How these were produced (decision log)</summary>

Followed the `dogfood` skill:

1. Started a local instance with `./scripts/develop.sh`
(`v2.36.0-devel`, matching the docs version).
2. Created Docker-backed templates named to match the originals:
`data-warehouse`, `analytics`, `api-services`, `frontend-web`,
`pod-share-jupyter`, `aws-linux-ephemeral`, `azure-aks-pod`, plus
`kubernetes2` ("Develop in Kubernetes"). The JetBrains module was
dropped from the Docker template to avoid a plan-time error;
`kubernetes2` uses a Coder-only variant declaring the real `namespace`
and `use_kubeconfig` variables so it imports with `use_kubeconfig=true`.
3. Created workspaces: `admin/my-frontend` (outdated → update available,
with a schedule), `admin/dev` (auto-update = Always), and
`kirby/{data-science, aws-large, azure-space, ephem-demo (Failed), kirbs
(Stopped)}`.
4. Captured each page with a headless Playwright script, hiding dev-only
chrome (the sticky deployment banner, the navbar `::before` hazard
stripe, and the `-devel` version chip) and cropping settings pages to
the form. Images are 2x for crispness.
5. Each screenshot was visually verified against the original for
content parity.
</details>
2026-08-20 23:26:20 +07:00
Susana Ferreira d58788cb23 fix: clarify AI model price configuration (#28372)
## Description

Model prices displayed in the Agents model form are read-only because
they are managed by AI Gateway. Add guidance and a link to the model
price configuration documentation, and rename the related documentation
subsection to **Configure model prices**.

> [!NOTE]
> Generated with Coder Agents by @ssncferreira.
2026-08-20 12:55:51 +00:00
Susana Ferreira 50ecd6959f feat: add a source filter to the AI model price list (#28329)
## Description

With prices from the price book and prices set through the API both in the table, `list` showed only the price in effect and gave no way to tell where it came from. There was also no way to see the price book's entry for a model that had been overridden, since the listing resolves to the custom price.

This adds a `source` column to the output and a `--source` filter for narrowing to one source, or to every row with `all`.

Note: `--source` selects rows rather than models. A model carrying both a price book price and a custom one appears under either value, so the two filtered listings do not sum to the unfiltered one. `--source all` reports both rows at once.

## Changes

- Add `Source` to `codersdk.AIModelPrice` and `AIModelPricesFilter`, and map it in `db2sdk`, which previously dropped it.
- Filter `GetAIModelPrices` by source before resolution, so the price book's row for an overridden model stays reachable.
- Accept `all` as a source, which reports every price a model holds instead of resolving to one.
- Accept a `source` query parameter on the list endpoint, rejected with a 400 when outside the enum.
- Add `--source` to the list command and a `source` column to its output.
- Document the column and the filter, and lead the price section with `coder exp ai-model-prices list`.
- Distinguish a deployment's default prices from the price book that ships with each release.

Closes https://linear.app/codercom/issue/AIGOV-593

> [!NOTE]
> Initially generated by Claude Opus 5, modified and reviewed by @ssncferreira
2026-08-20 11:56:58 +01:00
Susana Ferreira 19d1ee9fc8 feat: support custom prices for models in the price book (#28328)
## Description

The experimental CLI could only price models the price book does not cover, so an operator with a negotiated rate for a model Coder already prices had no way to record it. The restriction existed because a single row served both the price book and prices set through the API, and the startup seeder would overwrite an override on the next restart.

Each source now keeps its own row (https://github.com/coder/coder/pull/28204), so that no longer applies. This removes the restriction: a price set through the CLI takes effect over the price book for any model, and the book stays underneath it.

## Changes

- Remove the validation that rejected models the price book covers.
- Delete `prices.IsDefaultPriced` and the index behind it, which existed only for that check.
- Generalize the `coder exp ai-model-prices update` help.
- Document that a custom price overrides the price book and does not follow its updates.
- Rework the spend approximation callout around what a custom price can and cannot correct.

Closes https://linear.app/codercom/issue/AIGOV-594

> [!NOTE]
> Initially generated by Claude Opus 5, modified and reviewed by @ssncferreira
2026-08-20 11:46:38 +01:00
Michael Suchacz 2f996d765a feat: remove task management MCP tools (#28354)
Removes the six task-management tools from the MCP tool surface in
`codersdk/toolsdk`:

- `coder_create_task`
- `coder_delete_task`
- `coder_list_tasks`
- `coder_get_task_status`
- `coder_send_task_input`
- `coder_get_task_logs`

Both the coderd-hosted MCP server (`coderd/mcp`) and the CLI `coder exp
mcp server` derive their tool list from `toolsdk.All`, so removing the
registry entries removes the tools from both servers with no server-side
changes.

The MCP server documentation (`docs/ai-coder/mcp-server.md`) is updated
to drop the task-management entry from the tool overview.

## What stays

- `coder_report_task` is intentionally kept: it is the agent-side
status-reporting mechanism (`WithTaskReporter`), already excluded from
the hosted MCP server, and required by `coder exp mcp server`, Claude
Code configuration, and scaletest.
- The `codersdk` Task SDK methods (`CreateTask`, `DeleteTask`, `Tasks`,
`TaskLogs`, etc.) and the Tasks feature (CLI, UI, API) are untouched;
this PR only removes MCP tool registration.
- The task-only `taskIDDescription` helper is deleted; `userDescription`
stays (used by `coder_create_workspace`).

The code change is deletion-only: 970 removed lines across `toolsdk.go`
and its test file, no added behavior.

## Validation

- `go build ./...`, `go test ./coderd/mcp/`, and targeted
`golangci-lint` pass. `go test ./codersdk/toolsdk/` passes all tests;
the package-level goleak failure (agentssh goroutines) reproduces
identically on unmodified `main` and is unrelated to this diff.
- `pnpm run lint-docs` passes on the docs change.
- Remote dogfood UAT ran against the toolsdk change and passed:
`tools/list` on both the hosted MCP endpoint and `coder exp mcp server`
confirms the six tools are absent and the remaining surface is intact
(34 hosted tools; CLI adds `search`/`fetch`), a `tools/call` of
`coder_get_authenticated_user` succeeds, and calling a removed tool
returns `-32602 unknown tool`. `coder_report_task` still registers in
the CLI server when `CODER_MCP_APP_STATUS_SLUG` is set.
- The failing `Pixel / Review` commit status is unrelated: this PR
contains no `site/` changes, and the same status fails on the last 8
`main` commits including this PR's merge base (`676b9bb06bf`).

> Mux acted on Mike's behalf to create this pull request.
2026-08-20 12:07:30 +02:00
Marcin Tojek 2529a54cfc chore(docs): update release docs for v2.36.1 (#28357)
Automated docs update for v2.36.1 release.

Created by `releasetui`.
2026-08-20 10:01:27 +02:00
Michael Suchacz 24b83dc727 feat: add organization picker to MCP server settings pages (#28150)
Adds an organization picker to the MCP server settings pages so
multi-org deployments can manage every organization's MCP servers
through the UI, not just the default organization's. Closes CODAGT-714
(scoped to MCP servers only; model configs stay deployment-wide until
CODAGT-709 lands).

## Stack Context

Top of the CODAGT-711/717/712/806 stack: MCP server configs are
org-scoped with RBAC, audit logging, per-config ACLs, and owner-scoped
user tokens. This layer makes the admin UI org-aware, resolving the
"default org only" limitation documented in the bottom PR.

## Summary

- The MCP servers list and add pages resolve the working organization
from an `org` search param (falling back to the default org), and render
an organization picker built on the existing `OrganizationAutocomplete`.
The picker only appears when more than one organization is visible, so
single-org deployments see no change.
- Selecting an organization rewrites the search param, refetches the
list for that org, and threads through to the add page so creation posts
to the selected organization.
- The update page now loads the server by ID (new organization-scoped
`GET /api/experimental/organizations/{organization}/mcp-servers/{id}`
frontend binding) instead of listing the default org and searching
client-side, so servers from any organization can be edited. Post-save
navigation returns to the owning organization's list via the server's
`organization_id`.
- Removes the now-unused `getDefaultOrganizationId` helper.
- Review hardening: organization display labels are disambiguated with
the unique org name when effective display names collide (picker
options, trigger text, and accessible name). Access is no longer
restricted to deployment admins: the pages, sidebar item, and nav entry
accept org-scoped `mcp_server_config` permissions, the picker lists only
organizations the user can view, content and affordances (add, edit,
delete) are gated on the selected organization's permissions, and
deployment admins keep full access everywhere.

## Testing

Storybook interaction stories cover: picker hidden with one org,
switching orgs refetches and swaps list contents, add posting to the
URL-selected org, add posting after an in-form org switch (asserting
typed form state survives the switch), and update loading by ID.
Red-green verified by breaking the search-param resolution and observing
the new stories fail.

> Mux acted on Mike's behalf for this PR.
2026-08-19 19:46:23 +00:00
david-fraley 8203b2ebaf feat!: hide Coder Tasks behind the enable-ai-tasks flag (#28008) 2026-08-19 14:46:10 -05:00
Michael Suchacz 7ca7c30f40 feat: add group and user ACLs to MCP server configs (#27944)
Adds group and user ACLs to org-scoped MCP server configs so
organizations can restrict specific MCP servers to subsets of members,
mirroring the template ACL pattern.

## Summary

- Migration adds `group_acl`/`user_acl` JSONB columns (nested `{"<id>":
{"permissions": [...]}}` shape) and seeds every existing config with its
organization's Everyone group read entry (the Everyone group ID equals
the org ID), so member access is unchanged by default. Creation seeds
the same entry.
- The blanket org-member read grant from the base PR is replaced by ACL
evaluation: Rego requires org membership for every ACL grant, and
`GetAuthorizedMCPServerConfigs` compiles ACL-aware SQL filters.
- New `ActionShare` (org admins) gates `GET|PATCH
/api/experimental/organizations/{organization}/mcp-servers/{mcpserverconfig}/acl`
(nested under the organization like the rest of the config surface).
PATCH validates principals against the config's organization, merges
sparse updates under a row lock, stamps `updated_by`/`updated_at`, and
is audited as a Write with `Old` captured before authorization. A config
deleted concurrently between the middleware fetch and the locked
re-fetch is concealed as 404, matching the update and delete handlers.
ACL columns are tracked in the audit table.
- ACL management is available in all editions (no enterprise
entitlement), documented in the MCP servers page. Revoking an ACL does
not retro-strip already-selected configs from existing chats; new
selection is blocked at chat create.
- Force On respects the ACL: the forced set is loaded as the chat owner,
so a `force_on` server whose ACL denies the owner never attaches at
create, send, or generation time.
- No rolling-upgrade machinery: upgrades run in scheduled maintenance
downtime, so the migration only backfills existing rows; the API sets
the Everyone read grant explicitly on every insert.

Stacked on #27943. Part of the MCP org-separation stack.

Closes https://linear.app/codercom/issue/CODAGT-712

UAT: verified on a dogfood instance with two members and a custom group:
Everyone-seed default visibility, group grant with Everyone removal
(non-member loses list/fetch/selection), foreign-principal rejection,
non-admin share denial (audited 403 / concealed 404), user_acl restore,
and audited ACL diffs.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->
2026-08-19 19:25:18 +00:00
Michael Suchacz 299e72ad30 feat: audit MCP server config changes (#27943)
Adds enterprise audit logging for MCP server config create, update, and
delete, with strict secret redaction. MCP configs hold credentials
(OAuth2 client secrets, API keys, custom headers), so admin changes to
them need an audit trail.

## Summary

- `enterprise/audit/table.go` gains an `MCPServerConfig` entry
enumerating every column: `oauth2_client_secret`, `api_key_value`, and
`custom_headers` are `ActionSecret` (never appear in diffs); dbcrypt
`*_key_id` bookkeeping, IDs, and timestamps are ignored; the remaining
config fields, including the endpoint URL fields, are tracked so
auditors can see which endpoints a config points at.
- Type registration in `coderd/audit` (diff, request, resource target
with org attribution), `codersdk/audit.go`, and a `resource_type` enum
migration.
- Handlers wire `audit.InitRequest`: create records `New`; update and
delete record `Old` from the param middleware before the
write-authorization check, so a readable-but-not-writable caller
produces an audited 403 while read-denied callers stay concealed as
unaudited 404s.
- Tests: create/update/delete audit entries, write-denied and
delete-denied 403 auditing, cross-org concealment producing zero
entries, and a serializer-level regression test proving none of the
three secret classes can reach a serialized diff.
- Review round: MCP config audit entries link to
`/ai/settings/mcp-servers/{id}`, audit table comments are trimmed per
review, and a fault-injection test pins that a config row surviving a
failed post-discovery credential update still gets its creation audit
entry.

Stacked on #27942 (org-scoped MCP configs). Part of the MCP
org-separation stack.

Closes https://linear.app/codercom/issue/CODAGT-717

UAT: verified on a trial-licensed dogfood instance: audit entries for
the full CRUD lifecycle with correct actor/org/target, redacted secrets
in the update and OAuth2 create diffs, and a full plaintext scan of the
audit dump finding zero secret leaks.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->
2026-08-19 19:11:52 +00:00
Michael Suchacz f7a0de7a11 fix: harden org-scoped MCP config chat gating, updates, and visibility (#28065)
Hardens the org-scoped MCP server config surface from #27942 with fixes
and regression pins that are independent of the core cutover:

- Keep chats sendable after a selected MCP server is disabled (persisted
selections are exempt from message-time rejection).
- Keep cached MCP selections usable after a background refetch error
(gate the composer on missing data, not `isSuccess`).
- Merge PATCH updates onto the current row so unset fields are not
clobbered.
- Give auditors the full management view of MCP configs their audit logs
reference (site and org auditor roles).
- Regression pins: frozen OAuth2 callback path, cross-org concealment
for item routes, OAuth callback token binding, and disconnect responses
indistinguishable from nonexistent config IDs.
- Storybook: semantic textbox queries in MCP loading stories; docs note
that the MCP settings page needs deployment access.

## Stack context

Part of the MCP org-separation stack (CODAGT-711 org scope -> apidocs ->
hardening -> CODAGT-717 audit -> CODAGT-712 ACLs -> CODAGT-806 token
RBAC). Split out of #27942 to keep the core cutover reviewable; each
change here builds on the org-scoped routes and chat gating introduced
below it.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->
2026-08-19 18:50:31 +00:00
TJ dd43574990 refactor: remove AI add-on badge, seat column, and add-on wording leftovers (#28004)
Removes all "AI add-on" labeling from the UI, plus two leftover "AI
Governance add-on" wording items from the licensing repackaging (AI
Governance is now included with Premium).

- Remove the **AI add-on** badge from the group settings AI budget
section and the AI Governance add-on card on the Licenses page.
- Remove the **AI add-on** column (check icon showing AI seat
consumption) from the Users and Organization Members tables, along with
its help popover, the `AISeatCell` component, and the
`shouldShowAISeatColumn` entitlement helper.
- Update related Storybook stories.
- Drop "add-on" from the AI cost control route comments in
`enterprise/coderd/coderd.go` and the `coder exp ai-model-prices`
prerequisite in `docs/ai-coder/ai-gateway/cost-controls.md` (leftovers
not covered by #28075/#28077/#28268).

The `has_ai_seat` API field is left intact.

<details>
<summary>Removal scope</summary>

Badge usages removed:

- `site/src/pages/GroupsPage/GroupSettingsPageView.tsx`
-
`site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceAddOnCard.tsx`

AI seat column plumbing removed:

- `site/src/pages/UsersPage/UsersTable.tsx` and `UsersPage.tsx`
- `site/src/pages/OrganizationSettingsPage/OrganizationMembersTable.tsx`
and `OrganizationMembersPage.tsx`
- `site/src/modules/users/AISeatCell.tsx` (deleted)
- `AiAddonHelpPopover` in `site/src/modules/users/UserHelpPopovers.tsx`
- `shouldShowAISeatColumn` in
`site/src/modules/dashboard/entitlements.ts`

Add-on wording leftovers:

- `enterprise/coderd/coderd.go`: 7 route comments (comments only, no
behavior change)
- `docs/ai-coder/ai-gateway/cost-controls.md`: model prices CLI
prerequisite

</details>

---

🤖 This pull request was generated by Coder Agents on behalf of
@tracyjohnsonux.
2026-08-19 11:43:27 -07:00
Michael Suchacz f2bc9ab1f5 docs: complete swagger annotations for organization-scoped MCP routes (#28064)
Adds the missing swagger annotations for the eight organization-scoped
MCP server config routes introduced in #27942 and checks in the
regenerated API artifacts (`coderd/apidoc`, `docs/reference/api`). No
behavior changes: 58 hand-written annotation lines, the rest is
generated output.

## Stack context

Part of the MCP org-separation stack (CODAGT-711 org scope -> apidocs ->
hardening -> CODAGT-717 audit -> CODAGT-712 ACLs -> CODAGT-806 token
RBAC). Split out of #27942 to keep the core cutover reviewable; these
routes live under `/api/experimental`, where main already ships several
MCP handlers without annotations, so the base PR is consistent with
existing precedent until this lands.

Closes nothing on its own; documentation completion for CODAGT-711.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->
2026-08-19 18:36:25 +00:00
Michael SuchaczandMathias Fredriksson 443e3b9b80 feat!: org-scope MCP server configs with RBAC (#27942)
Moves `mcp_server_configs` from deployment scope to organization scope
so each organization fully controls the MCP servers its members can use
with Coder Agents.

## Summary

- Migration: adds `organization_id` (NOT NULL, FK) and keeps existing
rows as the default organization's originals with credentials intact.
Other organizations start with no MCP servers and configure their own;
nothing is copied across organizations. Chats outside the default
organization keep any now-cross-organization `mcp_server_ids` entries;
the runtime already ignores IDs that do not resolve in the chat's
organization, so no data rewrite is needed. Slug uniqueness becomes
`(organization_id, slug)`.
- RBAC: new org-scoped `ResourceMCPServerConfig` with regosql converter
and `GetAuthorizedMCPServerConfigs`; org admins get in-org CRUD, org
members get read (replaced by ACL evaluation in the follow-up ACL PR in
this stack).
- API: all config routes nest under the organization, matching
templates: `POST|GET
/api/experimental/organizations/{organization}/mcp-servers` and
`GET|PATCH|DELETE .../mcp-servers/{mcpserverconfig}` (plus
`oauth2/connect`), resolved by a read-only param middleware that
conceals read-denied and cross-organization access as 404. Two routes
stay on the frozen `/api/experimental/mcp/servers/{mcpServer}` block:
the OAuth2 callback (the redirect URI baked into existing AS-side client
registrations) and `oauth2/disconnect`, which must remain reachable by
users removed from the organization so they can still revoke their token
grant.
- Chat runtime: selection validation and generation resolve configs
strictly by IDs, enabled state, and the chat's organization in SQL;
requested duplicates are normalized; invalid or cross-org IDs are
rejected with the precise ID list. IDs already persisted on a chat are
exempt from message-time rejection so disabling a selected server never
blocks sends; generation skips servers that are no longer usable.
- Frontend: API layer and admin settings pages target the new endpoints.
The admin page manages the default organization's servers; the org
picker is tracked separately (CODAGT-714).

- Security hardening from review: OAuth user grants are additionally
bound to `oauth2_revocation_url` (changing it invalidates grants, and a
racing OAuth callback gets 409 instead of recreating a grant).
Stack-wide SSRF protection for MCP config-directed traffic was split
into its own PR at the top of this stack (#28242) to keep this diff
reviewable; this PR keeps main's existing discovery IP-range guard.
OAuth2 auto-discovery now completes before the config row is inserted: a
failed discovery persists nothing, and there is no provisional row that
concurrent updates could race against.

Two follow-up PRs in this stack were split out to keep this diff
reviewable: #28064 completes the swagger annotations for the moved
routes (main already ships these experimental MCP handlers unannotated),
and #28065 carries hardening fixes and regression pins on top of the
cutover.

- Force On enforcement (landed on main mid-review) is org-scoped: the
forced set is read per chat organization
(`GetForcedMCPServerConfigsByOrganization`), so another organization's
`force_on` server never attaches to a chat.

## Breaking changes (experimental API)

The MCP server config endpoints move from the deployment-scoped
`/api/experimental/mcp/servers` block to organization-nested paths:
`POST|GET /api/experimental/organizations/{organization}/mcp-servers`
and `GET|PATCH|DELETE
/api/experimental/organizations/{organization}/mcp-servers/{mcpserverconfig}`
(plus `oauth2/connect`). The old paths are removed, so API consumers
must supply an organization. Two routes intentionally stay on the frozen
`/api/experimental/mcp/servers/{mcpServer}` block: the OAuth2 callback
(its redirect URI is baked into existing AS-side client registrations)
and `oauth2/disconnect` (must remain reachable by users removed from the
organization). These endpoints are under `/api/experimental`, so no
deprecation window is provided.

## Rolling upgrades

During a rolling deploy, an old replica creating an MCP config can fail
the new `NOT NULL organization_id` constraint until it is upgraded
(reads are unaffected: old binaries' generated queries select their own
column lists). This matches the repo's existing precedent for additive
NOT NULL migrations (000562) and affects only the admin config-create
path in the upgrade window.

Upgrades are expected to run in scheduled maintenance downtime with the
database locked during migration, so the migration ships no
rolling-upgrade compatibility machinery. The down migration deletes
organization-created configs (their chat references are cleaned by the
000510 delete trigger) and restores deployment-wide slug uniqueness.

Part of the MCP org-separation stack (CODAGT-711 -> CODAGT-717 audit ->
CODAGT-712 ACLs -> CODAGT-806 token RBAC).

Closes https://linear.app/codercom/issue/CODAGT-711

UAT: validated end to end on a two-org dogfood deployment, including a
real pre-migration to post-migration upgrade, cross-org isolation
(404s), same-slug-two-orgs, chat selection gating, and a live MCP tool
call through the org-scoped generation path. The migration was later
revised to keep existing rows in the default organization only (no
per-organization copies); that revision is covered by the migration test
suite.

> Mux (AI agent) authored this PR on Mike's behalf.

<!-- mux-attribution: model=claude-fable-5 thinking=high -->

---------

Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
2026-08-19 18:04:13 +00:00
Atif Ali 7ff1278ab3 feat: track Junie as an AI Gateway client (#28266)
## Problem

Junie CLI works with AI Gateway, but every Junie session is recorded as
`Unknown`. Junie sends `User-Agent: Junie:SNAPSHOT` (observed directly
from the CLI), which `GuessClient` does not match, so usage, spend, and
audit views cannot attribute Junie traffic. There were also no docs for
pointing Junie at AI Gateway.

## Fix

- Detect the observed `junie:` user-agent prefix and add the `Junie`
client value.
- Add the Junie icon so sessions render with a logo instead of the
fallback question mark.
- Add a Junie client page and list it in the compatibility table.
- Add `Roo Code` and `Charm Crush` to the documented `client` filter
values. Both were already implemented but missing from the list.

## Supported configurations

| Provider  | API type          | Endpoint                 |
|-----------|-------------------|--------------------------|
| OpenAI    | `OpenAIResponses` | `/openai/v1/responses`   |
| Anthropic | `Anthropic`       | `/anthropic/v1/messages` |

BYOK works on both through `extraHeaders` with
`X-Coder-AI-Governance-Token`.

Preview:
https://coder.com/docs/@matifali-junie-ai-gateway-client/ai-coder/ai-gateway/clients/junie

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑‍💻
2026-08-19 21:13:49 +05:00
Nick Vigilante e003014ff8 docs: remove space in GitHub-style callout markers [DOCS-680] (#28305)
## What

Normalize the one GitHub-style callout marker that had a space after `!`
to the canonical tight form.

- `docs/user-guides/workspace-access/jetbrains/gateway.md`: `> [!
WARNING]` -> `> [!WARNING]`

A full-corpus scan confirmed this was the only spaced marker.

## Why

GitHub alerts, the hosted docs (coder.com), and the offlinedocs Fumadocs
renderer all require the tight `> [!WARNING]` form. The spaced form
rendered as literal `[! WARNING]` text instead of a styled alert, so
this is a genuine rendering fix on GitHub and coder.com, not an
offline-pipeline accommodation.

Surfaced by the offlinedocs Fumadocs migration review (CRF-60 on
#27390). Tracked separately from the mixed-case uppercasing fix
(DOCS-681), per request.

Linear:
[DOCS-680](https://linear.app/codercom/issue/DOCS-680/remove-the-space-after-in-github-style-callout-markers-across-docs)

> This PR was created with AI assistance (Coder Agents).
2026-08-19 11:48:52 -04:00
Nick Vigilante 2ee6f459b2 docs: uppercase mixed-case GitHub-style callout markers [DOCS-681] (#28304)
## What

Uppercase the mixed-case GitHub-style callout markers in the docs corpus
to the canonical all-caps form.

- `docs/install/rancher.md`: `> [!Important]` -> `> [!IMPORTANT]`
- `docs/user-guides/shared-workspaces.md`: `> [!Important]` -> `>
[!IMPORTANT]`
- `docs/user-guides/workspace-access/index.md`: `> [!Note]` -> `>
[!NOTE]`

A full-corpus scan confirmed these were the only mixed-case markers.

## Why

GitHub alerts, the hosted docs (coder.com), and the offlinedocs Fumadocs
renderer all require all-caps alert types (`[!NOTE]`, `[!IMPORTANT]`,
and so on). The mixed-case form rendered as literal text instead of a
styled alert (on some pages directly next to a correctly-rendered
all-caps alert), so this is a genuine rendering fix on GitHub and
coder.com, not an offline-pipeline accommodation.

Surfaced by the offlinedocs Fumadocs migration review (CRF-60 on
#27390). Tracked separately from the space-after-`!` fix (DOCS-680), per
request.

Linear:
[DOCS-681](https://linear.app/codercom/issue/DOCS-681/uppercase-mixed-case-github-style-callout-markers-across-docs)

> This PR was created with AI assistance (Coder Agents).
2026-08-19 11:48:32 -04:00
Cian Johnston 023f61626d feat: default AI Gateway sessions list to a 24h time range (#28256)
The AI Gateway sessions list page takes 5-13 seconds to load because
`ListAIBridgeSessions` scans all `aibridge_interceptions` rows (~1M on
dogfood) when no time filter is set. This PR defaults the list to the
last 24 hours of sessions, reducing the scan by roughly two orders of
magnitude without any backend or migration changes: the
`started_after`/`started_before` filters already exist end-to-end in
SQL, searchquery, and the API.

The default range is held in component state (not the URL) and merged
into every query payload including prefetches, so the unbounded query
never runs on page load. A time range filter in the filter bar lets
users override the window explicitly, which doubles as a forensic tool.
Picking a range writes quoted RFC 3339 timestamps into the existing
filter query. There are no presets and no unbounded "all time" mode, so
the fast path is the only path. Existing "All sessions"/"My sessions"
presets reset the filter query, which resets the time window to the
default 24 hours; that is intentional.

Also makes the five filter triggers a uniform width and left-aligns the
new picker so the search input keeps room on wide viewports.

Depends on #28255 (the DateTimeRangeFilter component) and #28254
(filterQuery serialization).


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 16:42:43 +01:00
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