Skip to content

feat!: add organization-scoped coderd_agents_default_model - #423

Merged
ethanndickson merged 12 commits into
org-chat-models/agents-modelfrom
org-chat-models/default-model
Aug 31, 2026
Merged

feat!: add organization-scoped coderd_agents_default_model#423
ethanndickson merged 12 commits into
org-chat-models/agents-modelfrom
org-chat-models/default-model

Conversation

@ethanndickson

@ethanndickson ethanndickson commented Aug 25, 2026

Copy link
Copy Markdown
Member

Stacked on #422.

Coder 2.37 makes the default chat model per-organization rather than deployment-global: each organization has its own default, the first model created in an organization is automatically promoted, and existing configurations are migrated to the default organization. The experimental coderd_default_agents_model resource modeled one global selection and no longer matches the server.

This PR replaces it with coderd_agents_default_model:

  • Renames the resource from coderd_default_agents_model to coderd_agents_default_model, grouping it with coderd_agents_model.
  • Requires an explicit organization_id; changing it forces replacement.
  • Uses the organization UUID as the resource id, since each organization has one default.
  • Create and update mark the selected model as default through the organization-scoped /api/v2 endpoint.
  • Read lists the organization's models and resolves its current default.
  • Missing or inaccessible organizations and unsupported Coder versions produce actionable diagnostics.
  • Delete remains an intentional no-op because Coder requires a default while models exist and provides no unset-default API.

Breaking change and migration

coderd_default_agents_model is removed and replaced by coderd_agents_default_model. The new resource implements ResourceWithMoveState, allowing existing state to migrate declaratively:

moved {
  from = coderd_default_agents_model.this
  to   = coderd_agents_default_model.this
}

resource "coderd_agents_default_model" "this" {
  organization_id = var.organization_id
  model_id        = coderd_agents_model.default.id
}

The legacy deployment-wide selection is assigned to the provider's default organization during the move. The configured organization_id should therefore identify that same organization.

Also folds in the coderd_agents_mcp_server import ID change (originally #427): <organization-name>/<slug> instead of <organization-id>/<id> (the organization component also accepts a UUID). Slugs are unique per organization, but the get-by-ID endpoint only accepts UUIDs, so import resolves the slug from the organization's server list.

The resource requires Coder v2.37.0 or later. Its import ID is the organization name (a UUID is also accepted); model_id is resolved during read.

Disclosure: Xum (AI agent) authored this PR on @ethanndickson's behalf.

Closes CODAGT-973

@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 6638443 to 98d5bc3 Compare August 25, 2026 10:08
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 98d5bc3 to c5fbf17 Compare August 25, 2026 10:16
@ethanndickson ethanndickson changed the title feat!: make coderd_default_agents_model per-organization DNM: feat!: make coderd_default_agents_model per-organization Aug 25, 2026
@ethanndickson
ethanndickson marked this pull request as ready for review August 25, 2026 10:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5fbf17cc5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/provider/agents_default_model_resource.go Outdated
Comment thread internal/provider/agents_default_model_resource.go Outdated
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch 2 times, most recently from 92f104e to a0e3b26 Compare August 25, 2026 12:38
@linear-code

linear-code Bot commented Aug 25, 2026

Copy link
Copy Markdown

CODAGT-973

@ethanndickson ethanndickson changed the title DNM: feat!: make coderd_default_agents_model per-organization DNM: feat!: add organization-scoped coderd_agents_default_model Aug 25, 2026
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from ab939e9 to c918c14 Compare August 25, 2026 14:47
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c918c1495d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/provider/agents_default_model_resource.go Outdated
Comment thread integration/agents-model-test/main.tf
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch 2 times, most recently from 2d02b85 to f152fdd Compare August 25, 2026 15:59

Copy link
Copy Markdown
Member Author

@codex review

matifali added a commit that referenced this pull request Aug 25, 2026
Add per-resource tfplugindocs templates (templates/resources/<name>.md.tmpl,
templates/data-sources/<name>.md.tmpl) that set a subcategory
front-matter field per resource/data source, so the Terraform Registry
sidebar groups coderd_* pages into Agents, AI Governance, Deployment,
Identity & Access Management, and Templates instead of listing them flat.

The templates are copies of tfplugindocs' default resource template,
minus the HasImportIDConfig/HasImportIdentityConfig branches: no
resource ships import-by-string-id.tf or import-by-identity.tf example
files, so those branches were always-false dead code. Data-source
templates drop the import section entirely.

Stacked on org-chat-models/default-model (#423): templates cover the
renamed coderd_agents_default_model and this base's
coderd_chat_system_prompt; when the stack rebases past #425, rename
templates/resources/chat_system_prompt.md.tmpl to
agents_system_prompt.md.tmpl.

Regenerated docs/ with make gen; only the subcategory line changed per
file.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f152fdd55d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/provider/agents_default_model_resource.go Outdated

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f3b9705ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/provider/agents_default_model_resource.go Outdated
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 1f3b970 to 78daa14 Compare August 25, 2026 16:44
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 78daa14 to efee9c8 Compare August 25, 2026 17:13

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19eaf12e25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

organizationID := state.OrganizationID.ValueUUID()
configs, err := r.experimentalClient().ChatModels(ctx, organizationID)
if err != nil {
if isHTTPNotFound(err) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat Coder's 400 not-found response as deletion

When the collection lookup for an externally deleted or inaccessible organization returns Coder's known 400 "must be an existing uuid or username" response, isHTTPNotFound rejects it because it recognizes only status 404. Refresh then emits an error and retains the resource in state instead of allowing Terraform to recreate it. Use the shared isNotFound helper here so both server not-found representations follow the deletion path.

AGENTS.md reference: AGENTS.md:L73-L73

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 49d64a31ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


func (r *AgentsDefaultModelResource) agentsDefaultModelDiag(ctx context.Context, action string, organizationID, modelID uuid.UUID, err error) diag.Diagnostics {
var diags diag.Diagnostics
if !isHTTPNotFound(err) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle alternate not-found responses during apply

When Create or Update targets an organization that Coder reports with its known 400 "must be an existing uuid or username" response, this check bypasses all model/organization probing and emits only a generic client error; the same problem occurs if a 404 PATCH is followed by that 400 from the collection or organization probe. Fresh evidence beyond the previously fixed Read path is that agentsDefaultModelDiag still uses the narrower isHTTPNotFound in all three checks, so use the shared isNotFound helper here as well to preserve the actionable missing-resource diagnosis.

AGENTS.md reference: AGENTS.md:L73-L73

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 957e9a128c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 957e9a1 to bd9c46b Compare August 27, 2026 10:53
matifali added a commit that referenced this pull request Aug 27, 2026
Add per-resource tfplugindocs templates (templates/resources/<name>.md.tmpl,
templates/data-sources/<name>.md.tmpl) that set a subcategory
front-matter field per resource/data source, so the Terraform Registry
sidebar groups coderd_* pages into Agents, AI Governance, Deployment,
Identity & Access Management, and Templates instead of listing them flat.

The templates are copies of tfplugindocs' default resource template,
minus the HasImportIDConfig/HasImportIdentityConfig branches: no
resource ships import-by-string-id.tf or import-by-identity.tf example
files, so those branches were always-false dead code. Data-source
templates drop the import section entirely.

Stacked on org-chat-models/default-model (#423), which now includes the
renamed coderd_agents_default_model and coderd_agents_system_prompt.

Regenerated docs/ with make gen; only the subcategory line changed per
file.
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch 2 times, most recently from 4d08c53 to 7154760 Compare August 27, 2026 11:36
ethanndickson pushed a commit that referenced this pull request Aug 27, 2026
Add per-resource tfplugindocs templates (templates/resources/<name>.md.tmpl,
templates/data-sources/<name>.md.tmpl) that set a subcategory
front-matter field per resource/data source, so the Terraform Registry
sidebar groups coderd_* pages into Agents, AI Governance, Deployment,
Identity & Access Management, and Templates instead of listing them flat.

The templates are copies of tfplugindocs' default resource template,
minus the HasImportIDConfig/HasImportIdentityConfig branches: no
resource ships import-by-string-id.tf or import-by-identity.tf example
files, so those branches were always-false dead code. Data-source
templates drop the import section entirely.

Stacked on org-chat-models/default-model (#423), which now includes the
renamed coderd_agents_default_model and coderd_agents_system_prompt.

Regenerated docs/ with make gen; only the subcategory line changed per
file.

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 14390bf5c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ethanndickson pushed a commit that referenced this pull request Aug 27, 2026
Add per-resource tfplugindocs templates (templates/resources/<name>.md.tmpl,
templates/data-sources/<name>.md.tmpl) that set a subcategory
front-matter field per resource/data source, so the Terraform Registry
sidebar groups coderd_* pages into Agents, AI Governance, Deployment,
Identity & Access Management, and Templates instead of listing them flat.

The templates are copies of tfplugindocs' default resource template,
minus the HasImportIDConfig/HasImportIdentityConfig branches: no
resource ships import-by-string-id.tf or import-by-identity.tf example
files, so those branches were always-false dead code. Data-source
templates drop the import section entirely.

Stacked on org-chat-models/default-model (#423), which now includes the
renamed coderd_agents_default_model and coderd_agents_system_prompt.

Regenerated docs/ with make gen; only the subcategory line changed per
file.
@ethanndickson
ethanndickson force-pushed the org-chat-models/default-model branch from 14390bf to d54038a Compare August 27, 2026 12:37
@ethanndickson

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T09:21:05.585737Z d54038a Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: d54038a92c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ethanndickson
ethanndickson merged commit 93527ae into main Aug 31, 2026
26 checks passed
@ethanndickson
ethanndickson deleted the org-chat-models/default-model branch August 31, 2026 10:19
ethanndickson added a commit that referenced this pull request Aug 31, 2026
Bumps `github.com/coder/coder/v2` to
`v2.34.0-rc.0.0.20260827091847-26b9c8764f91`, containing the promoted
organization-scoped chat model APIs.

Coder 2.37 scopes chat models to organizations and serves the chat API
under `/api/v2`. The old unscoped model-config API and
`codersdk.ChatModelConfig` surface were replaced by organization-scoped
chat models under `/api/v2/organizations/{organization}/chats/models`,
and coder/coder#28632 removed the legacy unscoped
`/api/experimental/chats/models` route entirely. This PR adapts
`coderd_agents_model` and `coderd_agents_system_prompt` to the stable
`/api/v2` API, with no experimental-route fallbacks.

## Breaking changes

`coderd_agents_model` and `coderd_agents_system_prompt` now require
Coder v2.37.0 or later. Against an older server, plans and applies fail
with a diagnostic naming the promoted endpoint and minimum version.
Downgrade the provider if you need compatibility with older Coder
releases.

`coderd_agents_model` gains an `organization_id` attribute. It is
optional and defaults to the provider's default organization, where
upstream migrated pre-2.37 chat models:

```hcl
resource "coderd_agents_model" "sonnet" {
  organization_id = coderd_organization.eng.id
  # ...
}
```

Changing a configured `organization_id` forces replacement because
models cannot move between organizations.

The import ID format changes from the model UUID to
`<organization-name>/<model-id>` (the organization component also
accepts a UUID):

```shell
terraform import coderd_agents_model.sonnet my-org/4c766bb0-0b48-4b55-9d7c-3f7c0116e78a
```

State written by earlier provider releases has no `organization_id`, and
the compatibility route that could have recovered it was removed
upstream. To upgrade, set `organization_id` in config and apply: the
provider adopts the model in place (an update, not a replace), verifies
the value against the organization-scoped API, and records it in state.
Until then, refresh warns and skips, and updates or destroys fail with
instructions.

## What changed

- CRUD uses the promoted organization-scoped `/api/v2` endpoints; `Read`
uses GET-by-ID instead of scanning the organization list.
- `organization_id` is mapped from server responses and composite
imports; legacy state without it is adopted in place from the configured
value on the next apply.
- An end-to-end test upgrades real pre-organization state (written by a
schema without `organization_id`) and asserts adoption plans as an
in-place update.
- Endpoint 404s produce actionable diagnostics that distinguish
unsupported Coder versions from missing or inaccessible organizations.
- The existing create-conflict retry remains in place.
- Acceptance tests probe for the promoted endpoints (chat models and
system prompt) and skip when the target deployment predates them,
because `ghcr.io/coder/coder:latest` and development builds can lag the
promotion.
- Container logs are dumped from a cleanup-safe context so failed
integration tests keep their logs.
- `coderd_default_agents_model` is mechanically adapted to the promoted
SDK surface; #423 replaces it with the organization-scoped
`coderd_agents_default_model` resource.

<details>
<summary>Stack plan</summary>

1. Scope `coderd_agents_model` to organizations and bump the Coder SDK
(this PR).
2. Replace `coderd_default_agents_model` with
`coderd_agents_default_model` in #423.

</details>

> Disclosure: Xum (AI agent) authored this PR on @ethanndickson's
behalf.

Relates to CODAGT-973
ethanndickson added a commit that referenced this pull request Aug 31, 2026
## Problem

All `coderd_*` resources and data sources render on the Terraform
Registry with an empty `subcategory`, so the sidebar lists every
resource/data source flat with no grouping.

## Fix

Add per-resource doc templates under
`templates/resources/<name>.md.tmpl` and
`templates/data-sources/<name>.md.tmpl` (the [tfplugindocs conventional
paths](https://github.com/hashicorp/terraform-plugin-docs#conventional-paths),
matching the pattern used by hashicorp/aws, azurerm, google). Each is a
copy of tfplugindocs' default template with a hardcoded `subcategory`,
grouping pages into:

- **Agents** — `agents_mcp_server`, `agents_model`,
`agents_system_prompt`, `agents_default_model`
- **AI Governance** — `ai_provider`
- **Deployment** — `license`, `oauth2_provider_settings`,
`provisioner_key`, `workspace_proxy`
- **Identity & Access Management** — `organization`,
`organization_group_sync`, `organization_sync_settings`, `group`, `user`
- **Templates** — `template`

The templates also drop the
`HasImportIDConfig`/`HasImportIdentityConfig` branches from
tfplugindocs' default template: no resource in this repo ships
`import-by-string-id.tf`/`import-by-identity.tf` example files, so those
branches were always-false dead code. Resource templates keep a single
`HasImport` (`terraform import`) section; data-source templates have no
import section (data sources are never imported).

Regenerated `docs/` with `make gen`; the diff against the base branch is
exactly the `subcategory` line per file (19 files), nothing else
changed.

## Stacking

Stacked on #423 (which stacks on #422). Covers the stack's org-scoped
`coderd_agents_default_model` rename (subcategory: Agents); the base
already includes the #425 `agents_system_prompt` rename.

## Note for future resources

With per-resource templates, a new resource/data source added without a
matching `templates/` file falls back to tfplugindocs' embedded default
(`subcategory: ""`) and renders uncategorized at the top of the sidebar.
Copy a sibling template and set the right subcategory when adding one.

## Testing

- `make build`, `make fmt`, and `make gen` (idempotent, no drift) are
all clean.
- `tfplugindocs validate --provider-name coderd` passes.
- `make lint` has 15 pre-existing `usetesting` findings, unchanged from
the base (verified via `git stash`); unrelated to this change.

---------

Co-authored-by: Ethan Dickson <ethan@coder.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants