Skip to content

feat(coderd_chat_system_prompt): manage the deployment-wide chat system prompt - #412

Open
bpmct wants to merge 6 commits into
mainfrom
bpmct/chat-system-prompt-resource
Open

feat(coderd_chat_system_prompt): manage the deployment-wide chat system prompt#412
bpmct wants to merge 6 commits into
mainfrom
bpmct/chat-system-prompt-resource

Conversation

@bpmct

@bpmct bpmct commented Aug 18, 2026

Copy link
Copy Markdown
Member

Closes #411

Adds coderd_chat_system_prompt, a singleton resource for the deployment-wide Coder Agents system prompt (Settings → Instructions). Replaces the CI curl workaround used in coder/dogfood#400.

resource "coderd_chat_system_prompt" "this" {
  system_prompt                  = file("${path.module}/system-prompt.md")
  include_default_system_prompt = true
}

Status

Design

  • Coder sanitizes stored prompts, so system_prompt compares values by sanitized form (codersdk.SanitizePromptText). A trailing newline from file(...) never drifts; real edits still diff.
  • Singleton like coderd_oauth2_provider_settings: one idempotent PUT, destroy resets deployment defaults, import adopts the live value, plan-time warnings before a first apply overwrites out-of-band values.
  • Plan-time 128 KiB length validation.
  • A 404 reports that the endpoint is unavailable and explains both likely causes: Coder older than v2.32.0 or insufficient site-wide permissions.

Stack

Depends on #414. The SDK export used by this resource is provided by the bottom stack layer, #413.

  1. chore!: bump coder/coder SDK and remove model cost settings #413 — bump the Coder SDK and remove obsolete model cost settings
  2. feat(coderd_template): expose agents_allowed #414 — expose agents_allowed on templates
  3. feat(coderd_chat_system_prompt): manage the deployment-wide chat system prompt #412 — manage the deployment-wide chat system prompt

Testing

  • Real-Coder acceptance tests (integration.StartCoder): lifecycle no-drift with a deliberately messy prompt (CRLF, zero-width space, blank-line run, trailing newline), import convergence, destroy reset.
  • Fake-coderd tests for request-level assertions (import issues no PUT, unavailable-endpoint diagnostic) plus unit tests for semantic equality, the validator, and the ModifyPlan advisories.
  • Build, formatting, generated docs, lint, and provider unit tests pass locally on the restacked branch.

Generated by Coder Agents on behalf of @bpmct

@ethanndickson
ethanndickson self-requested a review August 18, 2026 04:23
Comment thread internal/provider/chat_system_prompt_sanitize.go Outdated
Comment thread internal/provider/chat_system_prompt_resource.go Outdated
@bpmct
bpmct requested a review from ethanndickson August 18, 2026 22:59
@bpmct
bpmct marked this pull request as draft August 18, 2026 23:15
bpmct added a commit to coder/coder that referenced this pull request Aug 19, 2026
Exports `SanitizePromptText` (and its helpers) from `codersdk` instead
of `coderd/x/chatd`, so API consumers can sanitize prompt text exactly
the way the server stores it.

## Why

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

## What

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

> Generated by Coder Agents on behalf of @bpmct
@bpmct
bpmct marked this pull request as ready for review August 19, 2026 15:55
@ethanndickson
ethanndickson force-pushed the bpmct/chat-system-prompt-resource branch from 70d90e3 to 7ec9e36 Compare August 19, 2026 15:55
@ethanndickson
ethanndickson changed the base branch from main to codagt-716/agents-allowed August 19, 2026 15:55
@bpmct

bpmct commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

@ethanndickson ready for another review :)

@ethanndickson
ethanndickson force-pushed the bpmct/chat-system-prompt-resource branch from 3f5358a to 5f97a0a Compare August 20, 2026 10:08
Base automatically changed from codagt-716/agents-allowed to main August 20, 2026 10:16
ethanndickson added a commit that referenced this pull request Aug 20, 2026
Bumps `github.com/coder/coder/v2` from the previously pinned main commit
(`fbac602456c9`, 2026-07-28) to a newer `main` commit (`8a7e8d9d5b31`,
2026-08-19).

Resulting module version: `v2.34.0-rc.0.0.20260819135125-8a7e8d9d5b31`

## Breaking change

This SDK bump removes pricing fields from
`coderd_agents_model.model_config`. The following settings are no longer
supported and must be removed:

```hcl
model_config = jsonencode({
  cost = {
    input_price_per_million_tokens  = "3"
    output_price_per_million_tokens = "15"
  }
})
```

The four legacy top-level pricing settings are also removed:

- `input_price_per_million_tokens`
- `output_price_per_million_tokens`
- `cache_read_price_per_million_tokens`
- `cache_write_price_per_million_tokens`

The provider validates `model_config` against its pinned SDK.
Configurations with these pricing settings will fail at plan time.
Remove these settings before you upgrade the provider. Coder now gets
cost data from AI Gateway.

The example and generated documentation remove `model_config.cost`.

## Compatibility

This SDK bump does not set a new minimum Coder version for the
`coderd_template` resource. The follow-up #414 adds the optional
`agents_allowed` attribute. Explicit use of that attribute requires
Coder v2.37.0 or later.

## Release context

This change requires a provider release that is marked as breaking. The
release notes must include the `model_config` pricing migration. The
breaking change applies to `coderd_agents_model`.

This is the prerequisite layer for #414 and also includes the exported
`codersdk.SanitizePromptText` used by #412.

Refs
https://linear.app/codercom/issue/CODAGT-716/expose-agents-allowed-in-the-coderd-terraform-provider

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

1. Update the Coder SDK and remove obsolete chat model cost
configuration.
2. Add `agents_allowed` to the `coderd_template` resource and data
source in #414.

3. Add the deployment-wide chat system prompt resource in #412.

</details>

_Opened by Coder Agents on behalf of @ethanndickson._
ethanndickson added a commit that referenced this pull request Aug 20, 2026
Expose the per-template `agents_allowed` flag through the
`coderd_template` resource and data source. Terraform can now create,
update, and read whether Coder Agents can use a template.

The change does not set a new minimum Coder version for existing
`coderd_template` configurations. If the configuration omits
`agents_allowed`, the provider does not send the field during create.
Older Coder servers omit the field in responses, so the provider reads
it as `false`, consistent with other versioned template attributes.

The PR author accepts these compatibility limits:

- Explicit `agents_allowed` configuration requires Coder v2.37.0 or
later. An older server will ignore the unsupported field and cause an
inconsistent-result apply error.
- The template data source reports `false` for `agents_allowed` on older
servers because the API response omits the field.
- A saved plan created before a Coder v2.37.0 upgrade can carry the
synthetic `false` into an unrelated template update after the upgrade.
This only disables Coder Agent access for that template. It does not
affect ordinary workspaces or damage the template. Users can restore
access by setting `agents_allowed = true` in a fresh plan.

Users must create a fresh Terraform plan with refresh enabled after
upgrading Coder to v2.37.0. They must not apply a saved pre-upgrade plan
after the upgrade.

Acceptance coverage runs only when the Coder image reports v2.37.0 or
later.

Depends on #413.

Closes
https://linear.app/codercom/issue/CODAGT-716/expose-agents-allowed-in-the-coderd-terraform-provider

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

1. Update the Coder SDK and remove obsolete chat model cost
configuration in #413.
2. Add `agents_allowed` to the resource and data source, including
generated documentation and version-gated acceptance coverage.

3. Add the deployment-wide chat system prompt resource in #412.

</details>

This PR was generated by Coder Agents.
@ethanndickson
ethanndickson force-pushed the bpmct/chat-system-prompt-resource branch from 5f97a0a to 98e2a4b Compare August 20, 2026 10:16
bpmct and others added 6 commits August 20, 2026 16:17
…em prompt

Adds a singleton resource for the Coder Agents chat system prompt
(Settings -> Instructions), backed by the experimental
/api/experimental/chats/config/system-prompt endpoint via
ExperimentalClient.GetChatSystemPrompt/UpdateChatSystemPrompt.

Coder sanitizes the stored prompt (invisible-char stripping, CRLF
normalization, blank-line collapsing, trimming), so system_prompt is a
custom string type whose semantic equality compares sanitized forms.
The everyday case this absorbs is the trailing newline from
file("system-prompt.md"); real edits still diff. The sanitizer is a
straight port of chatd.SanitizePromptText, and divergence fails loud
(a visible diff) rather than silent.

Follows the coderd_oauth2_provider_settings singleton pattern: shared
PUT for create/update, destroy resets the never-configured defaults
(empty prompt, include_default_system_prompt = true), import adopts
the live value without writing, a plan-time warning fires when a first
apply would overwrite a non-empty out-of-band prompt, and a 404 maps
to an actionable version hint (the endpoint shipped in Coder v2.32.0).
Prompt length is validated at plan time against coderd's 128 KiB cap.

Closes #411
- Gate the fake-server TestAcc tests on TF_ACC with testAccPreCheck,
  matching every other TestAcc in the repo.
- Rewrite the length-validator test as a direct ValidateString unit
  test; ungated Test* functions here do not spin up the Terraform CLI.
- Add real-Coder acceptance tests via integration.StartCoder, the
  dominant pattern for resources the stock coder image serves (the
  fake-only approach is justified for oauth2_provider_settings because
  its endpoint needs unreleased Coder; that does not apply here). The
  no-drift test is the live proof the sanitizer port matches the
  server: the prompt carries CRLF, a zero-width space, a blank-line
  run, and a trailing newline, and the re-plan must be empty. The
  import test pins both convergence behaviors: a byte-matching config
  plans clean immediately; a config differing only by sanitization
  applies one normalization update and then converges.
- Document the one-time post-import normalization update and the
  trimspace(file(...)) escape hatch in the resource description.

No license required: the endpoint has no entitlement check, so
UseLicense would only cause needless skips on fork PRs.
…ystem_prompt

Per review, the create-time overwrite advisory now also fires when the
first apply would change include_default_system_prompt away from the
deployment's live value, not just when it would overwrite a non-empty
prompt. Covered by a direct ModifyPlan table test in the
oauth2_provider_settings style.

Also leaves a TODO on the mirrored sanitizer pointing at
coder/coder#28283, which exports it as codersdk.SanitizePromptText;
once the pinned coder/coder includes that commit the local copy goes
away.
Deletes the mirrored sanitizer now that coder/coder#28283 exports it
from codersdk and the pinned dependency includes it. Semantic equality,
the plan-time length validator, and the create-time overwrite advisory
all call the codersdk function directly, so the provider and server can
no longer drift.

The local parity unit test goes with it (the function's tests moved to
codersdk upstream); the real-Coder no-drift acceptance test remains the
end-to-end guard that the pinned SDK's sanitizer matches the deployed
server.
@ethanndickson
ethanndickson force-pushed the bpmct/chat-system-prompt-resource branch from 98e2a4b to ea9bca8 Compare August 20, 2026 15:17

@ethanndickson ethanndickson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

💯

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.

Add a resource for the deployment-wide chat system prompt

2 participants