This allows a Coder Agents chat to detach from its linked workspace
without deleting or changing the workspace, so a different workspace can
be linked later. It adds detach controls wherever the linked workspace
appears, including the workspace pill menu, fallback workspace badges,
and the workspace picker. The workspace selection state now updates
consistently across desktop and mobile.
Running workspace:
<img width="453" height="296" alt="image"
src="https://github.com/user-attachments/assets/ac5197a7-f0f4-4123-bbea-d3ddaca7a3e4"
/>
Stopped workspace:
<img width="389" height="203" alt="image"
src="https://github.com/user-attachments/assets/f5a8a90c-4bb0-405a-ade3-791146687b2d"
/>
Closes CODAGT-510
After the chat agent creates a workspace via the `create_workspace`
tool, opening the composer `+` menu and clicking "Attach workspace"
could show "No workspaces found" until a full page refresh, even though
the workspace pill already rendered the linked workspace correctly.
The picker was sourced only from the `owner:me` workspace list query,
whose cache could be stale right after `create_workspace` completed. The
fix derives the picker options at render time from both the owner
workspace list and the linked workspace already fetched by ID for the
pill, prepending or replacing the linked workspace only when the current
user owns it. This keeps the picker consistent with the pill without
broadening visibility beyond `owner:me` or invalidating workspace lists
on chat link updates.
Relates to CODAGT-510
The Flake Check workflow runs `make test` through the `test-go-pg`
action, which invokes `gotestsum`, but the workflow never installs it.
The mise refactor (#25727) deleted the `setup-go` action that previously
installed `gotestsum` implicitly, and added explicit `mise install ...
go:gotest.tools/gotestsum` steps to every other Go test job. The flake
check's `Install Go mise tools` step only listed `whichtests`, so the
check fails with `gotestsum: command not found` whenever it selects
changed tests to run.
Add `go:gotest.tools/gotestsum` to the flake check's install step,
matching the other `test-go-pg` jobs in `ci.yaml` and
`nightly-gauntlet.yaml`.
Refs #25727🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
Fixes all 9 Windows CI test failures caused by the mise CI refactor
(`fe257666d7`, PR #25727).
### Root cause
`jdx/mise-action` exports `Path` (Windows convention) via `GITHUB_ENV`.
Bash on Windows maintains its own `PATH`. When Go's `os.Environ()`
returns both, `cmd.exe` subprocesses non-deterministically pick the
MSYS-translated `PATH` (forward slashes), causing Windows executables
(`printf`, `powershell.exe`, `cmd.exe`) to be unresolvable.
These failures only appeared on `main` (where `-count=1` forces real
test execution) and were masked on PRs by Go test cache.
### Fixes applied
**CI (`setup-mise` action)**:
- Write both `Path` and `PATH` to `GITHUB_ENV` with Git usr/bin
prepended
**Code (`cli/root.go`)**:
- Add `appendAndDedupEnv` helper that deduplicates case-insensitive env
vars on Windows, preferring native Windows paths (backslashes) over MSYS
paths
**Code (`cli/configssh_windows.go`)**:
- Use absolute paths for `powershell.exe` and `cmd.exe` in the SSH
config `Match exec` escape function, avoiding PATH resolution entirely
**Tests**:
- Switch `--header-command` tests from `printf` to `echo` (cmd.exe
builtin) for reliable cross-platform execution
- Add env dedup in `Test_sshConfigMatchExecEscape` for subprocess PATH
consistency
Fixescoder/internal#1556, coder/internal#1558, coder/internal#1559
> 🤖 Generated by Coder agent, will be reviewed by @mafredri. 🏂🏻
Document the automatic key failover feature for AI Gateway, which allows
configuring multiple centralized API keys per provider instance (OpenAI
and Anthropic only).
## Changes
- **`docs/ai-coder/ai-gateway/providers.md`**: Add "Key failover"
section covering supported providers, configuration via the API (max 5
keys), and failover behavior (auth errors permanently disable a key
until restart/reload, exhausted pool returns `429` or `502`).
- **`docs/ai-coder/ai-gateway/auth.md`**: Add note in BYOK section
clarifying that key failover is skipped when a user-supplied credential
is present.
> [!NOTE]
> Generated by Coder Agents (by @ssncferreira)
PowerShell's echo aliases to Write-Output, which rejects -e as
an ambiguous parameter and exits 1. Use plain echo with spaces
instead. Remove the Windows t.Skip and TestMain exception.
TestMain untested-tools check now only fails on full-suite runs.
Filtered runs (e.g. -run TestTools) warn instead.
Closes CODAGT-518
The agents UI showed "Response startup is taking longer than expected"
after a 15s grace period while waiting on the LLM provider. The message
implied a problem was about to occur, but it does not actually lead to a
timeout. The typical underlying cause is provider slowness rather than a
client-side issue, so the warning is alarmist and unhelpful.
Drop the delayed message and its timer entirely. The `starting` phase
now keeps showing the shimmering "Thinking..." indicator until the first
stream chunk arrives. Also remove the now-dead `startingResetKey` /
`chatID` plumbing that only existed to remount the placeholder and reset
the delayed-message timer when switching chats.
Closes CODAGT-536
I ran into the `SettingsViewResets` Storybook flake twice on my branch.
The story reopens Agents settings immediately after clicking `Back to
Agents`, but the helper was synchronously checking for the desktop
`Settings` link before React Router had finished rendering `/agents`; on
desktop it could then fall through to the mobile-only `More options`
menu and fail.
Use `findByRole` for the desktop `Settings` link so the helper waits for
the accessible sidebar link before clicking it, matching the existing
Storybook interaction pattern used elsewhere in Agents stories.
Adds a new **Provider Configuration** reference page (`providers.md`) covering:
- The migration from environment-variable-based provider config to database-backed management introduced in v2.34, including the one-time seeding behavior and deprecation of `CODER_AI_GATEWAY_PROVIDER_<N>_*` and related flags
- All supported provider types (`openai`, `anthropic`, `bedrock`, `copilot`, `azure`, `google`, `openrouter`, `vercel`, `openai-compat`) with setup notes for each
- Provider lifecycle statuses (`enabled`, `disabled`, `error`) and their effect on request handling
- Reload behavior and how configuration changes apply without restarting `coderd`
- Bring Your Own Key (BYOK) and failure mode reference table
Updates **Setup** (`setup.md`) to replace the environment-variable-based provider configuration instructions with dashboard-driven steps (Add provider form, provider list, edit/disable flow), referencing the new `providers.md` page for deeper detail. Screenshots of the provider list, add, and edit forms are included.
Adds a **Provider metrics** section to **Monitoring** (`monitoring.md`) documenting the `coder_aibridged_*` and `coder_aibridgeproxyd_*` Prometheus metrics for provider status and reload timestamps, along with two suggested PromQL alert queries.
Retry Coder Agents workspace creation once with a generated random
suffix when the requested workspace name already exists. This preserves
structured errors for other conflicts and avoids surfacing avoidable
name collisions.
Closes CODAGT-386
Coder runs all migrations in a single transaction (`pgTxnDriver`).
Postgres forbids using an enum value added by `ALTER TYPE ... ADD VALUE`
within the same transaction that added it. Migration `000499` widened
`ai_provider_type` with `ADD VALUE`, and `000504` casts existing
`chat_providers` rows to that enum in the same transaction. On
deployments with a legacy provider using one of the new values (for
example `openai-compat`), the batch failed with `unsafe use of new
value` and the server could not start.
Recreate the type (create a new enum, alter the column, drop and rename)
instead of using `ADD VALUE`, matching the existing precedent in
`000144_user_status_dormant`. A freshly created enum's values are usable
immediately in the same transaction, so the cast in `000504` succeeds.
The resulting schema is identical, so `make gen` produces no `dump.sql`
diff and databases that already applied these migrations see no drift.
Added a regression test that seeds an `openai-compat` provider and
applies `000499` through `000504` in a single transaction, reproducing
the production path. The per-step `Stepper` used by the other migration
tests commits each migration separately and cannot surface this class of
bug.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: Danny Kopping <danny@coder.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot is the only AI provider type that could not be added through the `/ai/settings` UI. The aibridge runtime and the env-var seeding path already supported it, but the runtime CRUD API rejected `type=copilot` and the UI omitted it entirely. The root cause is that Copilot's auth model (a per-request GitHub OAuth token, with no pre-shared key) does not fit the credential-centric add-provider flow that every other provider uses.
## Backend
Allow `type=copilot` in `CreateAIProviderRequest.Validate()`, and reject `api_keys` for Copilot on both create (validation) and update (handler sentinel), mirroring the existing Bedrock guards. Copilot carries no stored credential.
## Frontend
Add Copilot to the provider type picker (with the `github-copilot.svg` icon) and give the form a credential-free branch: name, display name, and a free-text endpoint defaulting to `https://api.business.githubcopilot.com`, with copy explaining that authentication happens via the user's GitHub token at request time. Copilot maps to the distinct `copilot` wire type rather than collapsing to `openai`, and the edit flow recovers it correctly.
The endpoint stays required with a business-tier default; users on the individual or enterprise endpoints edit the field.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Use testing.Testing() inside createTransport to automatically
clone http.DefaultTransport when running in tests. In production,
DefaultTransport is used as-is (efficient connection pooling).
This fixes the CloseIdleConnections flake class: httptest.Server.Close()
calls http.DefaultTransport.CloseIdleConnections(), which disrupts
any MCP client sharing that transport. The testing.Testing() check
means every MCP transport created during tests gets isolation
automatically, with no caller changes needed.
Closescoder/internal#1016
Closes PLAT-291
- Add the "AI Governance Add-On" label across all pages
- Use a generic `coder.example.com` URL across examples
- Fix a few typos
- Remove mentions of command access as a feature of AI Gov
Fixes DOCS-262
<!--
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.
-->
---------
Co-authored-by: Danny Kopping <danny@coder.com>
Several relative links in the docs pointed at pages that no longer exist
or rendered incorrectly on coder.com.
Fixes:
- `start/first-template.md`: IDE links repointed from the removed
`../ides.md` / `../ides/web-ides.md` to their current homes under
`user-guides/workspace-access/`.
- `tutorials/example-guide.md`: contributing link repointed to
`../about/contributing/documentation.md`.
- `about/contributing/backend.md`: the `migrations/testdata/fixtures`
and `full_dumps` references (and the `000024_example.up.sql` example)
used relative paths that escape `docs/` and render as bogus
`/docs/coderd/...` routes on the site. Normalized to the canonical
`github.com/coder/coder/(blob|tree)/main/...` form already used by ~120
other source links in the docs.
- Normalized extensionless directory links (`ai-coder/ai-gateway`,
`user-guides/workspace-access`, `install`) to their `/index.md` targets
for consistency with the rest of the docs.
This class of bug is invisible to the local doc checks (`make
lint/markdown` / `pnpm check-docs` only run markdownlint + table
formatting); only CI's Linkspector job validates link targets. Found via
a relative-link audit while investigating the docs preview on #25816.
Source-link version-awareness (so older docs versions don't all point at
`main`) is tracked separately in DOCS-268 and will be handled in the
coder.com render layer.
Linear: DOCS-278
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Execute tool failures that only return an `error` field, such as
stopped-workspace connection failures, were rendered as a generic failed
command without showing the backend detail.
Normalize execute results into transcript blocks so shell output and
tool errors both render in the *expanded* command transcript, and add
Storybook coverage for connection errors plus output-with-error cases.
<img width="832" height="482" alt="image"
src="https://github.com/user-attachments/assets/50b04b9a-b153-48e5-ab5e-6c2fa000f21e"
/>
edit: i've dropped the red on the danger icon, though it was
pre-existing. no point alerting the user to an error the model will
handle.
Closes CODAGT-530
The PausedDuringWaitForReady and WaitsForWorkingAppState tests flaked
because the quartz resetTrap was released immediately after catching
ticker.Reset (line 174), allowing client.TaskByID (line 175) to race
with the subsequent DB mutation (pauseTask / PatchAppStatus).
Fix: keep the resetTrap open across both poll iterations. On the first
poll, release the trap so the goroutine sees the initial state and
continues. On the second poll, hold the goroutine frozen at
ticker.Reset while mutating state. Then release; client.TaskByID
deterministically sees the mutated state. No race because the
goroutine cannot execute client.TaskByID while trapped.
Closes CODAGT-482
Two additions to the compaction summary prompt:
1. Error specificity: the "errors encountered" bullet now instructs the
model to keep error notes specific (name the file, the error, the
fix) and not generalize from a specific failure to a blanket
tool-avoidance rule. This addresses the doctrine crystallization
pattern where a single tool failure gets promoted to a standing
"avoid tool X" rule that persists across compactions and model swaps.
2. Reproducibility: a new closing sentence instructs the model to
reference reproducible content by path, command, or URL rather than
inlining it. Content without a stable reproducer is still preserved
inline with a brief summary. This targets summary bloat from
inlined code blocks (worst case: 34k chars, 76 code blocks
reproducing repo content verbatim).
Refs CODAGT-331
The `check-docs` job has been failing on every PR touching `docs/**`
since 2026-05-29. `umbrelladocs/action-linkspector` runs linkspector
under puppeteer, which expects an exact Chrome build (e.g.
`148.0.7778.97`) in `/home/runner/.cache/puppeteer`. When that build
isn't present on the hosted runner, linkspector crashes with `Could not
find Chrome` and reviewdog then fails parsing the empty rdjson output
with `proto: syntax error`.
The pinned `v1.4.1` of the action was installing linkspector `0.4.7`,
whose puppeteer requires `148.0.7778.97`; that build is no longer in the
runner cache. Upstream `v1.5.2` upgrades linkspector to `0.5.3` and adds
Chromium fallback logic, but on `ubuntu-22.04` x86_64 none of its new
code paths fire (the AppArmor branch is gated on `lsb_release -rs ==
"24.04"`, the system-Chromium branch on aarch64 or missing 24.04
sysctl), so the bump alone leaves the same Chrome error in place.
This PR:
- Bumps the action to `v1.5.2` (linkspector `0.5.3`).
- Sets `PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome` on the action
step. The hosted `ubuntu-22.04` image ships Google Chrome at that path.
`v1.5.2`'s `script.sh` short-circuits Chromium setup when this env is
set, so puppeteer skips the cache lookup and uses the runner binary
directly.
End-to-end verified by temporarily perturbing `docs/**` on this branch
so the workflow's `pull_request` trigger would fire:
https://github.com/coder/coder/actions/runs/26732938434. `check-docs`
ran linkspector against `docs/**` for ~2m30s and exited 0, with no
`Could not find Chrome` or reviewdog parse errors in the log. That
perturbation has been removed from the branch.
Refs UmbrellaDocs/action-linkspector#62,
UmbrellaDocs/action-linkspector#61
Fixes a race where concurrent notification dispatch goroutines could
overwrite `coderd_notifications_pending_updates` with an older
buffer-length snapshot. Pending update snapshots now serialize count
evaluation with the gauge write, and inhibited dispatch results refresh
the metric when buffered.
Fixes minor spacing issues in the agents sidebar.
## Changes
- Reduce gap between New Agent / Search nav items from `gap-1` (0.25rem)
to `gap-[0.15rem]`
- Change Chats header top spacing from `mt-4` (margin-top 1rem) to
`pt-6` (padding-top 1.5rem)
- Remove `pt-5` padding-top from the scroll content groups container
(Today, Yesterday, etc.)
- Add `pr-1` (0.25rem padding-right) to the unread indicator circle
> Generated by Coder Agents on behalf of @tracyjohnsonux
The lifecycle executor did not handle unique-violation errors from
InsertWorkspaceBuild. When a concurrent actor (API handler, another
lifecycle executor, or prebuilds reconciler) inserts a workspace build
with the same build number, PostgreSQL returns a unique constraint
violation on workspace_builds_workspace_id_build_number_key. The
lifecycle executor treated this as a hard error, logging it and storing
it in stats.Errors.
The per-workspace advisory lock (pg_try_advisory_xact_lock) prevents
two lifecycle executors from racing, but does not protect against
races with the CreateWorkspaceBuild API handler or the prebuilds
reconciler, which use different (or no) locking.
Catch the specific unique-violation error after InTx returns (where
the transaction is already rolled back) and clear it. The concurrent
actor's build takes effect; the lifecycle executor treats the
workspace as a no-op for this tick.
Closescoder/internal#455
Closes PLAT-290
Implements https://linear.app/codercom/issue/AIGOV-285
Follow the structure established in
https://github.com/coder/coder/pull/25203
## Summary
Adds the `user_ai_budget_overrides` table and CRUD API at
`/api/v2/users/{user}/ai/budget`. An override sets a custom per-user
spend cap that supersedes group-budget resolution, attributing spend to
a specific group.
## Schema
```sql
CREATE TABLE user_ai_budget_overrides (
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
spend_limit_micros BIGINT NOT NULL CHECK (spend_limit_micros >= 0),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
## Membership lifecycle
The membership invariant — a user must be a member of the attributed
group, including when that group is "Everyone" — would naturally be
expressed as a composite FK on `(user_id, group_id) →
group_members_expanded(user_id, group_id)`. PostgreSQL doesn't allow
foreign keys to reference views, so enforcement is split across two
mechanisms:
- **Write-time check.** A CHECK constraint on the table
(`user_ai_budget_overrides_must_be_group_member`) calls a `STABLE`
function `is_group_member(user_id, group_id)` that queries
`group_members_expanded`. The view surfaces both regular group
memberships and the implicit "Everyone" group memberships from
`organization_members`. Any INSERT or UPDATE that violates the predicate
is rejected with a Postgres `check_violation`, which the handler maps to
a 400. `is_group_member` is defined as a general predicate, reusable by
any future table that needs the same check.
- **Cascade on removal.** Two `BEFORE DELETE` triggers handle membership
loss:
- `trigger_delete_user_ai_budget_overrides_on_group_member_delete` on
`group_members` — covers regular group removals (admin action, OIDC
sync).
- `trigger_delete_user_ai_budget_overrides_on_org_member_delete` on
`organization_members` — covers the "Everyone" group, whose membership
lives in `organization_members`.
The single-column FKs on `users(id)` and `groups(id)` remain to cascade
on user or group deletion (those paths don't pass through
`group_members`).
## Authorization
The dbauthz layer gates each operation against the `User` and (for
writes) `Group` resources:
| Operation | User resource | Group resource |
|-----------|----------------|----------------|
| `GET` | `ActionRead` | — |
| `PUT` | `ActionUpdate` | `ActionUpdate` |
| `DELETE` | `ActionUpdate` | `ActionUpdate` |
For `DELETE`, the dbauthz layer fetches the existing override first to
learn the attributed `group_id`, then runs both checks.
### Role matrix
| Role | GET | PUT | DELETE |
|--------------|-----|-----|--------|
| Owner | ✅ | ✅ | ✅ |
| UserAdmin | ✅ | ✅ | ✅ |
| OrgAdmin | ✅ | ❌ | ❌ |
| OrgUserAdmin | ✅ | ❌ | ❌ |
Internal discussion:
https://codercom.slack.com/archives/C096PFVBZKN/p1779392747885359
## Audit logs
Audit logs will be addressed in a follow-up PR.
Previously, `SeedAIProvidersFromEnv` only hashed provider-level fields,
so env var key changes were silently ignored once a provider already
existed in the database.
Include bearer keys and Bedrock credentials in the canonical drift hash,
and cover multi-key, multi-provider cases so restarts now fail loudly
when the configured credentials no longer match what is stored.
When changing a key, you'll now see this in the server startup logs:
```
2026-05-29 12:29:02.674 [info] api: Encountered an error running "coder server", see "coder server --help" for more information
2026-05-29 12:29:02.674 [info] api: error: create coder API:
2026-05-29 12:29:02.674 [info] api: github.com/coder/coder/v2/cli.(*RootCmd).Server.func2
2026-05-29 12:29:02.674 [info] api: /home/coder/coder/cli/server.go:1015
2026-05-29 12:29:02.674 [info] api: - seed ai providers from env:
2026-05-29 12:29:02.674 [info] api: github.com/coder/coder/v2/enterprise/cli.(*RootCmd).Server.func1
2026-05-29 12:29:02.674 [info] api: /home/coder/coder/enterprise/cli/server.go:187
2026-05-29 12:29:02.674 [info] api: - execute transaction:
2026-05-29 12:29:02.674 [info] api: github.com/coder/coder/v2/coderd/database.(*sqlQuerier).runTx
2026-05-29 12:29:02.674 [info] api: /home/coder/coder/coderd/database/db.go:212
---> 2026-05-29 12:29:02.674 [info] api: - AI provider "vercel" already exists in the database and differs from the current environment configuration; update the provider through the API or remove the CODER_AIBRIDGE_* env vars to stop seeding it:
2026-05-29 12:29:02.674 [info] api: github.com/coder/coder/v2/coderd.SeedAIProvidersFromEnv.func1
2026-05-29 12:29:02.674 [info] api: /home/coder/coder/coderd/ai_providers_migrate.go:139
2026-05-29 12:29:02.674 [info] api: slogjson: failed to write entry: io: read/write on closed pipe
2026-05-29 12:29:02.700 [info] dlv: Stop reason: exited
2026-05-29 12:29:02.825 [info] site: ELIFECYCLE Command failed.
error: running command "develop": server did not become ready in 1m0s:
main.waitForHealthy
/home/coder/coder/scripts/develop/main.go:877
- context canceled
```
_This PR was generated with Coder Agents._
Builds on top of https://github.com/coder/coder/pull/25794
Adds a new `provider_disabled` error classification in `chatd` with the
corresponding plumbing to classify it as non-retryable. Also adds a
story for how this particular error kind is displayed in the UI.
Update the coder/tailscale fork to include the fix for goroutine leaks
in measureHTTPLatency. The function creates an http.Transport per DERP
probe for a single HTTP request but did not disable keep-alives,
causing readLoop/writeLoop goroutines to persist after the function
returns. These were detected by goleak in support/TestRun.
The fork fix sets DisableKeepAlives: true on the transport.
Closes PLAT-289
## Problem
Centralized requests recorded *the first available key from the pool at
`CreateInterceptor` time* as `credential_hint`, so the interception
could be persisted in the database with a hint that didn't match the key
that actually served the request. The fix consists in storing, at
end-of-interception, the hint of the key that succeeded, or the last
attempted key if all keys are unavailable.
## Changes
- Add `Key.Hint()` and update `credential_hint` on every failover
attempt so it reflects the actually-used key.
- Stop pre-populating `credential_hint` at `CreateInterceptor`.
Centralized starts empty and is updated by the key failover loop.
- Persist the final hint via `RecordInterceptionEnded`; SQL updates
`credential_hint` only when `credential_kind = 'centralized'` so BYOK
keeps its start-time value.
- Log the actually-used hint on interception end/failure; start log uses
a `<keypool-pending>` placeholder for centralized.
> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by
@ssncferreira
RFC: [Bridge ↔ Boundaries Correlation
RFC](https://www.notion.so/coderhq/Gateway-and-Firewall-Correlation-RFC-31ad579be592803aa8b3d48348ccdde9)
Register a dedicated `boundary_log` RBAC resource type with `create`,
`read`, and `delete` actions, replacing the placeholder
`rbac.ResourceAuditLog` and `rbac.ResourceSystem` references previously
used in the dbauthz layer.
Create is granted at user-level so workspace agents can only write logs
owned by their workspace owner, preventing cross-workspace log
fabrication. Delete is restricted to `DBPurge` only; no human role
(including owner) can delete boundary logs.
| Subject | Create (own) | Create (other) | Read (all) | Delete |
|---|---|---|---|---|
| Workspace agent | yes | no | no | no |
| Owner (site admin) | yes (via member) | no | yes | no |
| Auditor | no | no | yes | no |
| DBPurge | no | no | no | yes |
### Changes
- **RBAC policy & resource definition**: add `boundary_log` to
`policy.go` and generate `ResourceBoundaryLog` object, scope constants,
and codersdk/TypeScript types.
- **dbauthz authorization**: replace all
`ResourceAuditLog`/`ResourceSystem` placeholders with
`ResourceBoundaryLog`. `InsertBoundaryLog` and `InsertBoundarySession`
derive the workspace owner from the agent and authorize with
`.WithOwner()` for user-scoped create.
- **Role assignments:**
- **Owner (site):** read only. Excluded from `allPermsExcept` wildcard;
create is inherited from member at user-level.
- **Member (user-level):** create. User-scoped so agents can only write
logs they own.
- **Auditor (site):** read.
- `boundary_log` is excluded from org-admin, org-member, and
org-service-account `allPermsExcept` calls for consistency with
`ResourceBoundaryUsage`.
- **System subjects:**
- **DB Purge** (`SubjectTypeDBPurge`): delete. The only subject that can
remove boundary logs.
- **Workspace agent scope**: `ResourceBoundaryLog` with wildcard ID in
the agent scope allow-list (necessary for creation since no pre-existing
ID exists). User-level role scoping prevents deployment-wide access.
- **DB migration** (`000510_boundary_log_scopes`): add `boundary_log:*`,
`boundary_log:create`, `boundary_log:delete`, `boundary_log:read` enum
values to `api_key_scope`.
- **Test coverage**: `BoundaryLogCreate` (user-scoped, only matching
owner succeeds), `BoundaryLogDelete` (all human roles denied),
`BoundaryLogRead` (owner + auditor). dbauthz mock tests set up workspace
agent lookups for owner derivation.
- **Generated docs**: update OpenAPI specs, API reference docs, and
frontend type definitions.
---------
Co-authored-by: Muhammad Danish <mdanishkhdev@gmail.com>
Co-authored-by: Coder Agents <coder-agents-review[bot]@users.noreply.github.com>
Error messages in agent chat now expose the actual error detail
instead of hiding it entirely. Also captures API response detail
for generic errors that previously dropped it.
PausedDuringWaitForReady used the real clock, so the 5s poll in
waitForTaskIdle could race with an in-flight stop build. The SQL
view (tasks_with_status) returns "unknown" for stop builds with
job_status != "succeeded" because the build_status CASE has no
branch for (stop, pending) or (stop, running). On macOS CI, where
the provisioner is slower, the poll fires during this transient
window and hits the TaskStatusUnknown case instead of
TaskStatusPaused, failing with "task entered unknown state" rather
than the expected "was paused".
Convert to the same quartz mock clock pattern that PR #25648
applied to WaitsForWorkingAppState: inject a mock clock via
NewWithClock, trap ticker creation and reset, then advance time
deterministically so the poll fires after the stop build completes.
Closes CODAGT-482
_Disclosure: created with Coder Agents._
When providers are disabled, we should serve a sentinel error so the
requesting client (Claude Code, Coder Agents, etc) is informed. Coder
Agents can also conditionalize its display to show a helpful error
message.
---------
Signed-off-by: Danny Kopping <danny@coder.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the inline security advisory table and the standalone advisory
file (`0001_user_apikeys_invalidation.md`). The advisories section now
directs readers to [GitHub Security
Advisories](https://github.com/coder/coder/security/advisories).
> Generated by Coder Agents on behalf of @jdomeracki-coder
Adds a database migration that reconciles existing stale chat MCP server
IDs, then installs a `BEFORE DELETE` trigger on `mcp_server_configs` to
remove the deleted ID from `chats.mcp_server_ids`. This keeps chat
continuation from failing with `400 One or more MCP server IDs are
invalid` after an MCP server config is deleted.
This matches the existing repo precedent in
`coderd/database/migrations/000241_delete_user_roles.up.sql`, where
deleting a custom role cleans `organization_members.roles`, a similarly
structured array of references that cannot be protected by a normal
foreign key.
Closes CODAGT-505
Updates the description text on the Agent Settings > Models page
(`/agents/settings/models`).
**Before:** "Choose which models from your configured providers are
available for users to select. You can set a default and adjust context
limits."
**After:** "Choose which models from your configured providers are
available for Coder Agents. Set a default and adjust context limits."
> Generated by Coder Agents on behalf of @tracyjohnsonux