mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
callum/chatd-local-first-acquire
3115
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9eba637584 |
docs(docs/ai-coder/agents): reformat to one sentence per line (#30700)
Reformats the Coder Agents docs under `docs/ai-coder/agents` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 59 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (21 files changed, 870 insertions(+), 1294 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
7aef110ca2 |
feat: add workspace secrets table, queries, and RBAC (#30248)
Adds the database table, queries, and permissions for workspace secrets: secrets set on a workspace build and delivered to the agent, never to Terraform. Each secret belongs to one workspace build. A new build copies the previous build's secrets, then the old copies lose their values but stay as history. |
||
|
|
c6a47c4428 |
docs: replace references to the retired Enterprise license tier (#30853)
## Summary Coder has only Community and Premium license tiers, but several docs pages, CLI help strings, and SDK field comments still called features "Enterprise" or "enterprise-only". This PR changes them to say Premium and regenerates the reference docs built from those strings. Resolves [DOCS-1298](https://linear.app/codercom/issue/DOCS-1298/remove-references-to-the-retired-enterprise-license-tier). ## Changes - `docs/admin/users/quotas.md`: Replace "scoped to Groups in Enterprise and organizations in Premium" with a correct sentence. Quotas are Premium, allowances are set on groups, and each user's budget is calculated separately in each organization (per `GetQuotaAllowanceForUser`). - `docs/user-guides/workspace-lifecycle.md`: Replace "Enterprise" with Premium, and correct the quotas sentence to match the quotas page. - `docs/ai-coder/agents/platform-controls/mcp-servers.md`: Replace "enterprise entitlement" with Premium license. - `cli/templatecreate.go`, `cli/templateedit.go`: Update `--require-active-version`, `--allow-user-autostart`, and `--allow-user-autostop` help text. Point the `--require-active-version` help at the renamed `#template-update-policies` section, because the old `#require-automatic-updates-enterprise` anchor is broken. Make the errors for these flags tier-neutral. - `enterprise/cli/features.go`: `coder features` now says "List license features and entitlements", and its AGPL error no longer names a tier. - `codersdk/templates.go`, `codersdk/organizations.go`: Update field comments that feed the API reference and TypeScript types. - `docs/reference/glossary.md`: The Premium entry now says "paid license tier" instead of "paid enterprise tier". - `docs/.style/style-guide/voice-and-tone.md`: The example sentence now says "Premium licensing". - Regenerated: CLI golden files, `docs/reference/cli/`, `docs/manifest.json`, `docs/manifest/generated/cli.json`, `docs/reference/api/`, `coderd/apidoc/`, and `site/src/api/typesGenerated.ts`. ## Testing - `go test ./cli -run 'TestCommandHelp|TestCliTemplateCreate'` and `go test ./enterprise/cli -run 'TestEnterpriseCommandHelp|TestTemplateCreate|TestTemplateEdit|TestFeaturesList'` pass. - The pre-commit hook passed, including `make gen`, `fmt`, `lint/go`, `lint/ts`, `lint/markdown`, and a slim build. <details> <summary>Decisions and out-of-scope items</summary> ### Decisions - **Premium wording and legacy Enterprise licenses:** Coder still accepts existing Enterprise licenses, and `FeatureSetEnterprise` includes the features labeled Premium here. Docs and help text say "Premium" because that is the tier sold today, and about 25 other docs pages already use "Premium feature". Error strings are tier-neutral, so they're accurate for every license holder. - **Glossary and style guide:** The issue marked these as borderline. Both were one-word changes, so I made them. ### Not changed - `docs/reference/api/enterprise.md` keeps the "Enterprise" sidebar title. It comes from the swagger tag on the `enterprise/` Go package, so renaming it is a larger change. - Other "Enterprise" references the review flagged as out of scope: the `coder server --help` option group, quiet hours SDK comments, internal `coderd` comments, and the dashboard's "Enterprise" badge on the require-active-version option. - No docs page says that legacy Enterprise licenses are still valid. - Uses that don't refer to the license tier: GitHub Enterprise, Red Hat Enterprise Linux, "enterprise environments", and `enterprise/` package paths. </details> --- _This PR was generated by Coder Agents on behalf of @nickvigilante._ |
||
|
|
4ae1b7bd28 |
docs(docs/user-guides): fix tab block class typo on the remote desktops page (#30862)
## Summary The VNC section of the Remote desktops page opened its nested tab block with `<div class="tab">` instead of `<div class="tabs">`. The new docs site converts only `class="tabs"` blocks into tabs, so **Coder Desktop** and **CLI** rendered as `<h4>` headings directly under the `## VNC` heading. The outer tab's **Desktop Client** label isn't a heading, so the page skipped from h2 to h4, and axe reports `heading-order`. This was the only occurrence of the typo in `docs/`. ## QA | Page | Production | Expected after merge | | --- | --- | --- | | Remote desktops, VNC section | [beta-docs @main](https://coder.com/beta-docs/@main/user-guides/workspace-access/remote-desktops/#vnc) | **Coder Desktop** and **CLI** render as tabs inside **Desktop Client**, with no h4 headings | The default version on beta-docs (v2.37.4) has the same typo, so the fix shows there only after the next release. A docs-engine change that warns on `class="tab"` at build time is tracked separately. Linear: [DOCS-1306](https://linear.app/codercom/issue/DOCS-1306/fix-div-classtab-typo-that-leaves-stray-h4-headings-on-remote-desktops) --- 🤖 Built with AI assistance. |
||
|
|
0dc36786de |
docs(docs/.style): add compliance-claims wording rule to the style guide (DOCS-1256) (#30778)
Adds a "Describe what Coder does, not compliance outcomes" rule to the
docs style guide's word-choice page, so writers and reviewers have one
place for compliance-claim wording.
- The rule says to describe Coder's controls, not the reader's
compliance status, and to back every certification, audit, validation,
or authorization claim with a current artifact.
- A Do/Don't table covers SOC 2, ISO/IEC 27001, FIPS 140-3, FedRAMP and
DoD Impact Levels, DISA STIG, Iron Bank, CMMC, HIPAA, GDPR, DORA, and
the AI Act, with the reason behind each entry.
- The style guide README coverage counts move from 79 to 80 rules (Word
choice: 17 rules, 10 planned), and the Vale README lists the planned
`Coder.ComplianceClaims` rule.
Resolves DOCS-1256.
<details>
<summary>Decision log</summary>
- **Self-contained phrasing.** The approved phrasing comes from an
internal assessment that can't be linked from public docs, so the rule
states each term directly instead of pointing to it.
- **Facts checked before writing:**
- The AICPA issues no SOC 2 certificate; a CPA firm issues an
attestation report.
- ISO doesn't certify; a certification body certifies a management
system within a scope.
- CMVP validates modules under a certificate number; FIPS 140-2
certificates moved to the Historical list in September 2026.
- FedRAMP authorizes cloud service offerings, which a self-hosted
deployment isn't.
- CMMC certifies organizations; HIPAA has no certification program.
- **Scope limits:** protocol conformance ("specification-compliant OIDC
provider") and sentences where the reader is the subject stay allowed,
so the planned lint rule doesn't flag them.
- **Enforcement:** the footer marks `Coder.ComplianceClaims` as planned.
The Vale rule itself is separate work.
- Checks: `make lint/style-claims`, `markdownlint-cli2`, `vale`,
`check_emdash.sh`, and the pre-commit hook pass locally.
</details>
<details>
<summary>CI note: Storybook failure is unrelated</summary>
The `Storybook` job failed when the Pixel snapshot service marked its
build as failed (31 snapshots awaiting review). This PR changes only
Markdown under `docs/.style/` and touches no `site/` code or stories.
</details>
---
_Generated by Coder Agents on behalf of @nickvigilante._
|
||
|
|
1f61a290e7 |
docs(docs/ai-coder): reformat AI Gateway client and Agent Firewall docs to one sentence per line (#30702)
Reformats the AI Gateway client and proxy docs, the Agent Firewall docs, and the top-level pages under `docs/ai-coder` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 1 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (27 files changed, 414 insertions(+), 513 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
c58ac71ca3 |
docs(docs/tutorials): reformat to one sentence per line (#30703)
Reformats the tutorials under `docs/tutorials` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 9 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. The two reverse proxy tutorials also write `*.coder.example.com` in backticks instead of escaping the asterisk, which the formatter would otherwise drop. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (19 files changed, 656 insertions(+), 1265 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
603dd420d1 |
feat: add ServerTailnet logs and metrics for unreachable agents (#30133)
Add default-level metrics and warn-level diagnostics to investigate ServerTailnet reachability failures causing agent-specific 502s, without restarting coderd or enabling debug logging. - Enrich request logs and PTY/chatd warnings with agent ID, failure reason, wait duration, coordinator state, WireGuard handshake and byte counts, and DERP regions. - Add metrics for unreachable attempts by reason, reachability latency, embedded DERP connections, and offline app/terminal requests. - Distinguish reachability failures from subsequent TCP dial failures, cap reverse proxy dials at one minute, and exclude expected chatd readiness polls and superseded-agent dials from unreachable counts. - Report missing handshakes as zero time instead of 1970, also fixing `coder ping`. Part of PLAT-680, a sub-issue of PLAT-360. |
||
|
|
c647260901 |
docs(docs/ai-coder/ai-gateway): reformat to one sentence per line (#30701)
Reformats the AI Gateway docs directly under `docs/ai-coder/ai-gateway` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 4 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (10 files changed, 395 insertions(+), 570 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
1872b183ee |
docs(docs/admin): reformat setup and integrations docs to one sentence per line (#30704)
Reformats the setup and integrations docs under `docs/admin/setup` and `docs/admin/integrations` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 1 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (25 files changed, 380 insertions(+), 572 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
ed6a8441dc |
docs(docs/user-guides): reformat to one sentence per line (#30705)
Reformats the user guides under `docs/user-guides` to one sentence per line, as the [docs style guide](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line) requires. Hard-wrapped paragraphs are unwrapped and lines holding several sentences are split, so a later edit to one sentence shows up as a one-line diff. Apart from the exception below, only whitespace inside paragraphs and list items changes, and the rendered pages are the same. Comparing the changed files against `main` word for word, ignoring whitespace and blockquote `>` markers, finds differences only on the reworded lines. `git diff --word-diff` is easier to read than the line diff. 7 lines that already contained an em or en dash were reworded by hand, because `lint/emdash` treats every reflowed line as newly added. Each uses a parenthetical, a separate sentence, or a colon after a lead-in. Dashes on lines the reflow did not touch are left alone. Applied with an in-progress formatter, limited to pages listed in `docs/manifest.json` and excluding generated reference docs. This is one of a batch of PRs that split the docs by area (29 files changed, 715 insertions(+), 1068 deletions(-)). --- 🤖 Built with AI assistance. |
||
|
|
935e076210 |
docs: delete unlisted pages and their screenshots (#30758)
Deletes seven docs files and 10 screenshots that are not in the docs manifest and are superseded or empty: - `docs/about/why-coder.md`: a TODO stub. The one link to it, a "Do" example in the style guide, now names its source in plain text. - `docs/tutorials/example-guide.md`: a contributor template with no inbound links. Its guidance is recorded in DOCS-1207 for a tutorial section in `contributing/documentation.md`, which is still to write. - `docs/start/first-template.md` and six step 6 screenshots in `docs/images/templates/`. Content is cataloged in DOCS-1209 for the Templates landing page. - `docs/start/first-workspace.md` and three screenshots in `docs/images/start/`. Content is cataloged in DOCS-1208 for the Workspaces landing page. - `docs/start/local-deploy.md` and `docs/images/start/setup-page.png`. Redundant with `get-started/` and `install/cli.md`. The deleted files stay recoverable at `adcce66826`. This replaces #30710, #30711, #30712, #30713 and #30714, which are closed in favor of this PR. Linear: DOCS-1205, DOCS-1206, DOCS-1207, DOCS-1211, DOCS-1212. Related: DOCS-1208, DOCS-1209. I ran `lint/docs-html`, `lint/docs-manifest`, `lint/docs-redirects` and `lint/emdash` locally. > Generated by Coder Agents on behalf of @nickvigilante. |
||
|
|
c856d5fb22 |
feat: accept template version IDs in --template-version (#30563)
Follow-up to #30199. `--template-version` on `coder create`, `start`, `stop`, and `update` (plus `--stop-template-version` on `update`) now takes a template version ID as well as a name. Passing a version UUID used to 404 with a pretty unhelpful `get template version by name` error. `resolveTemplateVersionID` still looks up by name first, so a version that happens to be named like a UUID resolves the same way it did before. If that 404s and the input parses as a UUID, it falls back to fetching the version by ID. Either way the version has to belong to the selected template. That check matters most for `create`, which only sends the version ID and lets the server derive the template from it, so without it `coder create --template foo --template-version <id of a bar version>` would quietly create a `bar` workspace. The name is now path-escaped before the lookup. Previously something like `../../../templateversions/<id>` could reach other API routes through the name lookup and skip the template check entirely. Not-found errors now read `template version "x" not found for template "foo"` instead of the raw SDK error, so anything matching on the old text will need updating. Flag help and the generated CLI docs say "name or ID" now. |
||
|
|
2b9fad8bba |
feat: add chat project sharing database layer (#30479)
Database and authorization layer for chat project sharing (experiment `chat-projects`), part 1 of 2. #30439 adds the API on top of it. Nothing here changes behavior: projects start with empty ACLs, no endpoint writes them yet, and deleting a project still detaches its chats. Project deletion is in #30683. - **Schema:** migration `000621` adds `user_acl` and `group_acl` jsonb columns to `chat_projects`, typed as `ChatACL` like chats, with GIN indexes. It also adds the `chat_project:share` API key scope. - **Queries:** - `GetChatProjectsOwnedOrSharedWithUserID`: owned projects plus projects with an ACL entry for the user directly, through a group, or through the Everyone group (whose ID is the organization ID). Entries count only for members of the project's organization. Keys match regardless of actions, so dbauthz filters the rows. - `IsChatProjectAccessibleByUserID`: whether a user owns a project or holds a `read` or `*` grant on it, for code running under a system subject. With sharing disabled, dbauthz answers owner-only. - `GetChatProjectByIDForUpdate`: lets the ACL update read, modify, and write in one transaction. - `UpdateChatProjectACLByID`. - **RBAC:** - New `share` action on `chat_project`. dbauthz requires it to update the ACL. - `ChatProject.RBACObject` attaches the project ACL. Memory objects get a derived ACL: project `read` grants memory read, and `read` with `update` grants memory create and delete. Wildcard grants count. Read sharees change memories through their chats' agents, which #30439 gates. Project instructions authorize through the same object, so a `read` grant reads them and an `update` grant edits them. - `--disable-chat-sharing` also covers projects: ACLs are ignored, the ACL update is rejected, and roles deny `chat_project:share`. The help text and chat sharing docs say so. - **Audit:** `user_acl` and `group_acl` changes are tracked. - **Tests:** - Querier tests run the access queries both raw and through dbauthz (owner, direct user, group, Everyone, wildcard grants, a member of another org, grants without read). - RBAC object and memory ACL tests, with an authorizer check, in both sharing modes. - dbauthz cases including the disabled guards, and the `chat_project:share` negation in the roles test. The generated TypeScript changes only add the new scope value. > Generated by Coder Agents. |
||
|
|
2254965ef8 |
docs: update release calendar for v2.38 (#30757)
Updates the release calendar in `docs/reference/releases.md`. For the `2.38` release: * `2.38` becomes Mainline * `2.37` Stable * `2.36` Security Support * `2.35` Not Supported * `2.32` drops off. Latest patch versions are bumped to `v2.34.12`, `v2.35.9`, `v2.36.7`, `v2.37.4`, and `v2.38.0`, and a `2.39` "Not Released" row is added. The `2.35` row's link text (`v2.35.6`) is fixed to match its target (`v2.35.7`, now `v2.35.9`). Generated with `scripts/update-release-calendar.sh`, then hand-adjusted: - 2.38 links to its changelog post, `broader-model-access-and-tighter-governance-controls-in-238`, since `coder-2-38` returns 404. The longer link widens the table, so every row is realigned. - 2.35 keeps `coder-2-35-1`; the script's `coder-2-35` returns 404. - 2.38's date is the GitHub release publish date (October 06, the first Tuesday). The script uses the tag commit date (October 01). The "latest ESR version" link in the ESR section is also updated from `v2.34.5` to `v2.34.12`. Note: re-running the script will revert the two link overrides above. --- _Generated by Coder Agents on behalf of @Lisa-Fiander._ |
||
|
|
69fab7de06 |
chore!: remove the coder_report_task MCP tool (#30742)
Coder Tasks have been removed from coder/coder, so the
`coder_report_task` MCP tool and the status reporting pipeline behind it
no longer do anything useful. This PR removes the tool and the code that
only existed to support it.
### Removed
- `codersdk/toolsdk`: `ToolNameReportTask`, `ReportTaskArgs`,
`ReportTask`, `Deps.report`, `WithTaskReporter`, and the `All` entry,
plus their tests.
- `coderd/mcp`: the remote MCP exclusion for `coder_report_task`.
- `coder exp mcp server`: the task reporter, the AgentAPI screen
watcher, the agent socket connection, and the `coder_report_task` skip
logic. The server now requires an authenticated user client, because
every remaining tool needs one.
- `coder exp mcp configure claude-code`: the
`mcp__coder__coder_report_task` allowed tool, the injected
`coder_report_task` CLAUDE.md prompt, the `report tasks properly`
history line, the default system prompt asking the agent to send task
status updates, and the `CODER_MCP_APP_STATUS_SLUG` /
`CODER_MCP_AI_AGENTAPI_URL` env written to the Claude MCP config.
- `cli/cliutil/queue.go`: only used by the reporter.
- `github.com/coder/agentapi-sdk-go` (and transitive `tmaxmax/go-sse`)
via `go mod tidy`.
- The "task reporting" mention in `docs/ai-coder/mcp-server.md`.
### Breaking: removed `coder exp` flags and env
`coder exp` is experimental. Any scripts that still pass these flags
will now fail with an unknown flag error. Env vars that are no longer
read are ignored.
| Command | Flag | Env |
|---|---|---|
| `coder exp mcp server` | `--app-status-slug` |
`CODER_MCP_APP_STATUS_SLUG` |
| `coder exp mcp server` | `--ai-agentapi-url` |
`CODER_MCP_AI_AGENTAPI_URL` |
| `coder exp mcp server` | `--socket-path` | `CODER_AGENT_SOCKET_PATH`
(still used by `coder agent` and `coder exp sync`) |
| `coder exp mcp configure claude-code` | `--claude-app-status-slug` |
`CODER_MCP_APP_STATUS_SLUG` |
| `coder exp mcp configure claude-code` | `--ai-agentapi-url` |
`CODER_MCP_AI_AGENTAPI_URL` |
`--claude-system-prompt` no longer has a default.
<details>
<summary>Intentionally kept</summary>
- **Workspace app status reporting** (`UpdateAppStatus` on the agent API
and agent socket, `agentsdk.PatchAppStatus` / `ProtoFromPatchAppStatus`,
the deprecated `PATCH /workspaceagents/me/app-status` endpoint): still
served by coderd and the agent and part of versioned protocols. With
this change, nothing in the CLI calls the agent socket `UpdateAppStatus`
client anymore. Removing it would need a separate protocol change.
- **`report_tasks` in
`coderd/templatebuilder/modules/{aider,amazon-q}`**: these catalog
entries mirror the input variables of pinned coder/registry module
versions, and the behavior lives in those modules. Dropping the variable
here would not disable it, because `amazon-q` defaults it to `true`. The
registry modules need a follow-up instead.
- **`UserClientOptional` on toolsdk tools**: other tools still set it,
and remote MCP still uses it.
- No CLI golden files or generated CLI docs changed, because `coder exp`
commands are hidden.
</details>
### Verification
- `go build ./...`
- `go test ./codersdk/toolsdk/... ./coderd/mcp/... ./cli/cliutil/...`
- `go test ./cli -run 'TestExpMcp|TestCommandHelp'`
- `golangci-lint run ./cli/... ./codersdk/toolsdk/... ./coderd/mcp/...`
(0 issues)
---
_Generated by Coder Agents._
Co-authored-by: coder[bot] <137810501+coder[bot]@users.noreply.github.com>
|
||
|
|
fa7cd62c8b |
feat: send RFC 8707 resource parameter on MCP server OAuth2 flows (#30651)
Coder's MCP OAuth2 client never sent the RFC 8707 `resource` parameter, which the MCP authorization spec requires on authorization and token requests. Authorization servers that enforce it cannot be connected: with Dagster+, discovery and dynamic client registration succeed, then the authorize request fails with "MCP OAuth requests must include resource". MCP server configs get an `oauth2_resource` field (migration 000618, admin-only in API responses, audited). Coder sends it on the authorize redirect, the authorization-code exchange, and token refresh. Refresh now goes through `clientcredentials` with `grant_type=refresh_token`, because `oauth2.Config` cannot add parameters to refresh requests; it keeps the same auth-style detection and error types, and adds no dependency. Auto-discovery fills the field with the most specific Protected Resource Metadata `resource` that covers the server URL, stored as advertised. As in the MCP SDKs, a resource covers URLs on its origin at or under its path, so `/mcp` covers `/mcp/` but `/mcp/` does not cover `/mcp`. URLs compare in RFC 3986 normal form (default ports, percent-encodings, dot segments, and an empty path as `/`), ports ignore leading zeros, IPv6 literals compare by address, and `%2F` stays inside its segment. Unlike the SDKs, a resource with a query, even an empty one, only covers a server URL with the same query. When none covers it, Coder uses the server URL with the scheme and host lowercased and user information and fragment removed, or sends no resource when that is not a valid resource indicator. An explicit value in the create request wins. Manual configurations send no `resource` unless an admin sets one, because some providers reject it (Microsoft Entra ID v2 fails with AADSTS901002). Values must be absolute RFC 3986 URIs without a fragment, user information, or an IPv6 zone identifier. The resource binds grants like the other OAuth settings: changing it deletes stored user tokens, and a callback whose config resource changed after the user started connecting returns 409 before the code is redeemed. The connect step records the resource in a callback-scoped cookie for that check. Discovery only runs when a configuration is created, so existing auto-discovered configurations, including the Dagster+ one that prompted this, keep an empty resource until an admin sets the new "Resource URL" field or re-creates the server.  ## Testing - Go: discovery (most specific match, path and trailing-slash boundaries, query matching including empty queries, equivalent ports, IPv6 literals, escapes, and dot segments including escaped ones, the normalized fallback and an invalid one, explicit override), validation (URI characters, brackets, IP literals, user information, trimming), grant deletion on change, clearing on an auth type change, redaction for members, refresh with and without a resource, the 409 when the resource changes mid-flow (the authorization server never receives the code), and a connect and callback flow against an authorization server that rejects requests without the resource. Each new test was checked to fail when the behavior it covers is broken, except two malformed IP literal hosts that Go's URL parser already rejects. - Vitest: the form round-trips the stored value, and clearing the field sends `""` on update. - Remote UAT through Coder Agents ([chat](https://dogfood.cdr.dev/agents/58695d5b-2112-400b-88f7-ab64c678f756)) on a test deployment with loopback MCP and authorization server mocks: - Round 1 on |
||
|
|
adcce66826 |
feat: load organization skills in chats (#30613)
## Stack Closes [CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents). This stack adds organization skills to Coder Agents: admins publish a skill once per organization, share it with groups or members, and chats in that organization load it next to personal and workspace skills. It replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to top: 1. #30609 data model: one migration, queries, RBAC and dbauthz 2. #30610 organization skill API routes and the scope-neutral SDK 3. #30611 sharing ACL routes 4. #30612 settings UI: shared skills table, admin page, member section 5. **#30613** chats: chatd loading, `/` menu, docs (this PR) ## What changes This PR makes chats use organization skills: chatd adds the skills shared with the chat owner in the chat's organization to the skill index, `read_skill` loads them, the `/` menu offers them, and the docs describe the feature. **chatd** (`coderd/x/skills`, `coderd/x/chatd`): - New source `skills.SourceOrganization` (`"org"`). `MergeSkills(personal, organization, workspace)` sorts by name, then source. A name in one source keeps its bare alias; a name in more than one source gets a qualified alias in every source that has it (`personal/<name>`, `org/<name>`, `workspace/<name>`), so no source overrides another. `Lookup` returns `ErrSkillAmbiguous` for a bare name that matches several sources. - **Authorization (please review closely):** each turn, chatd reads organization skill metadata and bodies as the chat owner's real RBAC subject with their roles and groups (`chatOwnerSubject`), never as the chatd system actor, so per-skill ACLs apply. Disabled skills are skipped. A skill that is deleted, disabled, or no longer shared by the time `read_skill` runs is reported as not found. If the owner subject or the metadata can't be loaded, turn preparation fails with the error, as main now does for personal skills (#30492), instead of running the turn without organization skills. - `read_skill` loads personal and organization bodies through one `LoadStoredSkillBody` callback. An index description longer than 1,024 runes, the Agent Skills specification limit (`maxSkillIndexDescriptionRunes`), is cut to 1,023 runes plus an ellipsis so it stays within the limit; `read_skill` still returns the full skill. - Parse and lookup errors keep `%w` last on purpose: with `xerrors`, a `%w` that isn't last repeats the cause, so main's detail read "skill is too large: got N bytes, maximum is 65536 bytes: skill is too large". This stack returns the cause once (ThomasK33 asked about the order in review). **`/` menu** (`site/src/pages/AgentsPage`): the chat page fetches the chat organization's enabled skills (`organizationSkills(...)` from #30612's queries) next to personal ones. `utils/skillAliases.ts` (`resolveSkillTriggers`) follows `MergeSkills`: a personal or organization trigger is bare unless its name is in more than one source, then it becomes `/personal/<name>` or `/org/<name>`. While any list is unknown every trigger is qualified, because a qualified alias always resolves; workspace triggers are always qualified. Built-in `/clear` and `/compact` stay pending until every skill list is known, and a list with no data counts as unknown even after an error, so a failed fetch can't make a built-in run in place of a same-named skill. Disabled skills never shadow a built-in. **Docs:** `docs/ai-coder/agents/extending-agents.md` gains two sections, Organization skills (manage them, control who can use one, find the ones you can use) and How chats load stored skills (turning a skill on or off, skills with the same name). The admin page's organization picker shows only for a user who can view more than one organization's skills. The member "From your organizations" section shows one organization at a time with its own picker, starts on the default organization, and has Export all for the selected organization. The Enabled column is a switch for editors and a check or X otherwise. The settings table in `platform-controls/organizations.md` gains rows for organization and personal skills. ## Commits The first commit reproduces the reviewed chatd code from the old stack; the site and docs commits reapply the old layers on #30612's queries, and the rest are labeled trims or fixes. - `aa634eec94a` feat(coderd/x): load organization skills in chats. Reproduction of the old skill sources and chatd layers (old head `a1047f4986`). - `97945db4e86` test(coderd/x/skills): make `TestMergeSkills` (6 cases) and `TestLookup` (8 cases) table-driven; coverage is 100% before and after, with the same blocks. - `dde61cc5fe2` test(coderd/x/chatd): drop skill tests duplicated by the organization skills integration test `TestOrganizationSkillsFollowChatOwnerAccess`; the covered block set of the touched code is identical (348 of 506 blocks). - `aad14b2dd05` feat(site/src/pages/AgentsPage): show organization skills in the slash menu. The old alias helper and slash menu layers, applied cleanly on #30612's queries. - `712e272e140` test(site/src/pages/AgentsPage): trim duplicated slash menu tests and stories. Deletes `AgentChatPage.test.tsx` (177 lines; its assertions live in `submitChatTurn.test.ts` and `ChatMessageInput.test.tsx`), two duplicate `ChatMessageInput` cases, six of 17 `SkillsTriggerMenu` stories, and one disabled-skill fixture row from a `ChatMessageInput` story. - `232535e1011` docs(docs/ai-coder/agents): document organization skills. From the old docs layer, with the View line updated for #30612's read-only dialog and Download. - `62dbbd2dfd3` refactor(site/src/pages/AgentsPage): address frontend review on the slash menu. - `7349eac4389` Merge the updated settings-ui layer into chats. Brings in the #30610 and #30612 fixes; the merge has no changes of its own. - `0f84a30ec69` Merge the updated settings-ui layer into chats again, for #30612's read-only View fix; no changes of its own. - `fb37822f985` fix(coderd/x/chatd/chattool): keep truncated skill index descriptions within 1,024 runes. The cut now happens at 1,023 runes so the ellipsis fits; the existing `skill_test.go` assertion now expects 1,023 runes plus the ellipsis. - `1543666b584` docs(docs/ai-coder/agents): state the 1,023-character cut before the skill index ellipsis. - `96f1da47c9a` and `13f03d095ff` merge the updated settings-ui layer for #30612's cache and Skills link fixes; no changes of their own. - `b03c14c86de` and `41cc078b85a` merge the updated settings-ui layer; `b03c14c86de` moves the `AgentChatPage.tsx` and `ChatMessageInput.tsx` call sites, and their tests and stories, to #30612's split `organizationSkills(...)` query. - `1a32d05c9bc` test(site/src/pages/AgentsPage/components/ChatMessageInput): restore per-source loading stories for the slash menu. - `830b0466982` fix(coderd/x/chatd): fail turn preparation when organization skills cannot load. Main now returns database errors from turn preparation (#30492); organization skills still logged and dropped the failure, so a failed read silently hid them from the model. The new `TestFetchOrganizationSkillMetadataListFailure` covers the returned error. - `84c135f8801` and `a6f8f63ad13` merge the updated settings-ui layer, which brings in main; they resolve `generation_preparer.go` against main's turn preparation error handling. - `19b7880840f` merges #30612's member page test change; no changes of its own. - `c74d597f3c5` merges #30612's read-only status change; no changes of its own. - `f89c232c081` merges #30612's skills test changes; no changes of its own. - `17d5b9bfbc5` docs(docs/ai-coder/agents): describe the member skills organization picker and read-only Enabled status. - `f97b1710f71` merges the updated settings-ui layer (main at `e7b76872098`); no changes of its own. ## Size Production +558/-213 (docs +116/-6), tests +895/-262; total +1453/-475. This is above the 500-line reviewer-friendly limit on purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this stack replaces. ## Replaces #30593 (skill sources), #30594 (chatd), #30601 (alias helper), #30602 (slash menu), #30604 (docs). ## Validation - Go: all 21 packages under `coderd/x/skills` and `coderd/x/chatd` pass on `62dbbd2dfd3`, plus the coverage comparisons above; `coderd/x/chatd/chattool` passes again on `13f03d095ff` after the truncation fix. - Site: `pnpm run lint` and Biome clean; Vitest 102 tests; Storybook Vitest 49 + 4 tests. `pnpm run lint` reran clean on `13f03d095ff`. - On `a6f8f63ad13`, this PR's head before the test-only `19b7880840f` merge: `go test` passes for `coderd/x/skills`, `coderd/x/chatd/chattool`, and the `coderd/x/chatd` skill tests (`-run 'OrganizationSkill|Skill'`); 38 Vitest files covering skills and the slash menu pass, 542 tests with 2 skipped. - Docs: markdownlint 0 findings, Vale 0 findings. - On `17d5b9bfbc5`: Vale clean, markdownlint and `make pre-commit` pass. On `f97b1710f71`: `go build`, the `coderd/x/skills` and `chattool` tests, `pnpm check` and `tsc` pass. - Remote UAT round 7 through Coder Agents: PASS ([chat](https://dogfood.cdr.dev/agents/3426d4d3-2139-4ae1-8e0c-72ddeff413a8)). - Full run on `62dbbd2dfd3`, including an in-place upgrade from main `50c785cc6d7`: personal skills kept their IDs, names, content hashes and timestamps, came up enabled, and worked in chats (`read_skill`) and the `/` menu; create, edit, download and delete worked after the upgrade. The admin page, sharing, the Enabled toggle, the member section, the `/` menu, chats reading organization skills as the owner, limits, audit, authorization and scoped keys, and the docs all passed. - Delta run on `7349eac4389`: an update-only key gets 404 on PATCH with no content in the response; saving permissions refreshes Updated without a reload; smoke of the admin page, auditor View and Download, the `/` menu and `read_skill`. - Delta run on `0f84a30ec69` for `aaa356f0fd5`: read-only View, as an org auditor and as a member, shows no Name hint, focuses no field and starts on Close, and Escape or Close returns focus to the row menu button; Add skill and Edit still show the hint and focus the import field, and a saved edit persisted; smoke of the admin page, the `/` menu organization group and `read_skill`. Screen-reader behavior was not tested. - Delta run on `13f03d095ff` for `698dd83946d`, `f82573cd1c2`, `0e55137de7b` and `fb37822f985`: for an organization admin of org B who is a plain member of org A, the sidebar Skills link drops `?org=` for org A on seven AI settings pages and opens org B's skills, keeps `?org=` for org B, and a typed `/ai/settings/skills?org=` for org A still shows the permission error. A skill deleted and recreated with the same name loads a fresh sharing list showing only Everyone, with no stale grant. A 1,500-character description appears in the chat's skill index as 1,023 characters plus an ellipsis, while `read_skill` returns all of it. Smoke of the admin toggle, the member section, the `/` menu organization group and `read_skill`. - Low findings: the read-only View hint and field focus, fixed in `aaa356f0fd5` and verified by the delta run above. The member section's always-on disabled Enabled switch (also in the old stack) is replaced by a read-only status icon in #30612's `63bb42754e3`, which has no UAT run. Not fixed: `/` shows the `/personal/` prefix while organization skills fail to load (the unknown-list rule above); the shared Switch component's disabled styling (unchanged from main). A user who can read skills in only one organization sees no organization name on the Skills page, because the picker is hidden for a single organization, as on the MCP servers page on main. - Not tested: the workspace skills group (no running agent on the test deployment), the 100-per-user personal cap, and behavior without a Premium license. - Remote UAT round 8 through Coder Agents: PASS on `b03c14c86de` (same chat). The remote grader marked the unknown `read_skill` item FAIL only because the prompt asked for the literal phrase "skill not found"; the result names the skill once and says "not found" once, the same format as main, so the runner graded it PASS on intent. - Member page: starts on the default organization, shows one organization's table with the read-only note once, Export all downloads only the selected organization's skills, the picker is hidden with one organization, and an organization without enabled skills isn't listed. - Personal and admin tables: create, edit, toggle and delete each refetch the list; reopening the editor shows the new content even with the detail request delayed; a toggle changes state once, with no flicker. A skill deleted and recreated with the same name shows only Everyone in sharing. - The sidebar Skills link keeps `?org=` only for an organization whose skills the user can read. A create over 64 KiB returns 400 with the detail "got 70000 bytes, maximum is 65536 bytes: skill is too large", the cause once. The `/` menu shows Commands, Personal skills and Organization skills, and invoking an organization skill loads its body through `read_skill`. - New low findings, not fixed: the member page picker's listbox is labeled "Suggestions" (likely from the shared `OrganizationAutocomplete`); a typed body over 64 KiB shows only the size counter and a disabled Create until Import; `/ai/settings?org=` redirects to the models page without `?org=`. The first and third were not checked against main. - `9002dc60382`, `1a32d05c9bc`, `830b0466982`, `ac3e62c83b7`, `63bb42754e3`, `82b2487ad17`, `17d5b9bfbc5` and the main merges came after `b03c14c86de`; they have tests but no UAT run. - Every UAT round ran the migration as `000615_skills`. The heads ship the same up and down SQL as `000621_skills`, so the upgrade path from main's 000620 to 000621 has no UAT run. > Xum opened this PR on behalf of @ibetitsmike. |
||
|
|
2c432a12a3 |
feat: add organization skill sharing ACL routes (#30611)
## Stack Part of [CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents). This stack adds organization skills to Coder Agents: admins publish a skill once per organization, share it with groups or members, and chats in that organization load it next to personal and workspace skills. It replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to top: 1. #30609 data model: one migration, queries, RBAC and dbauthz 2. #30610 organization skill API routes and the scope-neutral SDK 3. **#30611** sharing ACL routes (this PR) 4. #30612 settings UI: shared skills table, admin page, member section 5. #30613 chats: chatd loading, `/` menu, docs ## What changes This PR adds the routes that let admins choose who can read an organization skill. It reuses the MCP server ACL machinery rather than adding a second implementation. Routes under `/api/experimental/organizations/{organization}/skills/{skillName}`, all behind `httpmw.ExtractOrganizationSkillParam` with `share`, so a caller without share gets 404: - `GET /acl` returns the resolved user and group grants. - `GET /acl/available` returns the organization's users and groups that can be granted, with the same `q`, `after_id`, `limit` and `offset` paging as the MCP endpoint. - `PATCH /acl` takes a sparse `UpdateOrganizationSkillACLRequest`: only the listed principals change, `read` grants and `""` removes. It returns 204 and writes a `write` audit entry with the old and new ACL. **Concurrency (please review closely):** the PATCH transaction first locks the granted users' `organization_members` rows `FOR KEY SHARE` (new query `LockOrganizationMembersByUserIDsForShare`, run as system), then locks the skill row `FOR UPDATE`, then validates the update on the transaction handle. Member removal takes the same locks in the same order (its membership row, then the skill rows through the #30609 trigger), so the two can't deadlock, and a removal can't miss a grant written by a concurrent PATCH. A skill deleted between the middleware read and the row lock stays a 404. Grants are users and groups, the same as MCP server configs (Mike's decision, for parity). Only the `read` role exists; any other role is a validation error, as are users or groups outside the organization. Supporting changes: - `coderd/mcp_acl.go`: the MCP ACL handlers' resolution, candidate listing and validation move into generic helpers (`writeOrganizationACLAvailable`, `validateOrganizationACLUpdate`, `resolveACLUsers`, `resolveACLGroups`) shared by both resources; `acl.Validate` accepts a named `acl.Role` constraint that now includes `codersdk.OrganizationSkillRole`. - `codersdk/skills.go`: `OrganizationSkillRole`, `OrganizationSkillACL` with its user and group entries, `UpdateOrganizationSkillACLRequest`, and client methods. - New sqlc query `UpdateOrganizationSkillACLByID` with its dbauthz wrapper (requires `share`). ## Commits The first commit reproduces the reviewed code from the old stack; each later commit is a labeled trim or fix. - `b1c85560b69` feat: add organization skill sharing ACL routes. Reproduction: every file this commit changes equals the reviewed old `acl-routes` head `80c1c3594e6`; the rest of the tree differs only by #30609's migration merge and main. - `b5d2ee265c8` test(coderd): merge duplicate organization skill ACL route tests (+49/-111). The removed cases repeated `TestMCPServerConfigACL`, `TestMCPServerConfigACLAvailable` or `TestRolePermissions`; with the MCP tests included, the covered block set of `organizationskills_acl.go`, `mcp_acl.go` and `rbac/acl/updatevalidator.go` is identical before and after. Kept: `TestOrganizationSkillACL` (`OrgAdminManagesACL`, `ReadersGetNotFound`, `SparseUpdateChangesReaders` with the audit diff, `RejectsUnsupportedRole`, `ScopedAPIKeys`), `TestOrganizationSkillACLConcurrentDelete`, and the lock order tests `TestOrganizationSkillACLMemberRemoval` (`RemovalBeforeGrant`, `RemovalAfterGrant`). `OrgAdminManagesACL` now also checks that users from another organization are not candidates (mutation checked). Sharing the param extractor with MCP was skipped: it would save about 10 lines of security-sensitive code. - `e09c4dba66b` Merge the updated org-api layer into sharing. Brings in #30610's `ad0a7a37504`; the merge has no changes of its own. - `1d3817dc639` and `c8c88f84d18` merge the updated #30610 layer, including main; no changes of their own. - `c4d22c47990` merges the updated #30610 layer (main at `e7b76872098`); no changes of its own. ## Size Production +431/-102, tests +377/-0, generated +918/-0; total +1726/-102. This is above the 500-line reviewer-friendly limit on purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this stack replaces. ## Replaces #30591 (ACL queries), #30592 (ACL routes). ## Validation - `go build` and `go vet` passed; `make gen` exited 0 with no diff. - `go test` passed for `coderd` (skill, MCP and ACL tests), `coderd/database`, `dbauthz`, `migrations`, `gentest`, `coderd/rbac/...`, `coderd/httpmw`, `coderd/x/skills/...`, `coderd/x/chatd/...`, and the audit and skill tests in `enterprise/audit` and `enterprise/coderd`. - The covered block comparison above, before and after the test merge. - On `c4d22c47990`: the same checks as #30610's head, plus `go test ./coderd/ -run 'Skill|MCP|ACL'`, pass. - Remote UAT round 7 through Coder Agents passed on the whole stack; see #30613's Validation for scope and findings. > Xum opened this PR on behalf of @ibetitsmike. |
||
|
|
db7f5a7703 |
feat: add organization skill API routes (#30610)
## Stack Part of [CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents). This stack adds organization skills to Coder Agents: admins publish a skill once per organization, share it with groups or members, and chats in that organization load it next to personal and workspace skills. It replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to top: 1. #30609 data model: one migration, queries, RBAC and dbauthz 2. **#30610** organization skill API routes and the scope-neutral SDK (this PR) 3. #30611 sharing ACL routes 4. #30612 settings UI: shared skills table, admin page, member section 5. #30613 chats: chatd loading, `/` menu, docs ## What changes This PR adds the organization skill CRUD routes and makes the skill SDK types owner-neutral so personal and organization skills share them. **API contract change (experimental API, personal and organization skills):** skill list and get responses gain `enabled`, and `PATCH .../skills/{skillName}` now takes `{content?, enabled?}`, so `content` is optional and a toggle doesn't resend it. A PATCH with neither field returns 400; `content`, when present, is validated as before. In the SDK, `UserSkill`, `UserSkillMetadata`, `CreateUserSkillRequest` and `UpdateUserSkillRequest` become `Skill`, `SkillMetadata`, `CreateSkillRequest` and `UpdateSkillRequest` (`codersdk/userskills.go` moves to `codersdk/skills.go`), and `UpdateSkillRequest.Content` is now `*string`. The personal client method names are unchanged. The site changes are the handwritten edits that rename forces (`api.ts`, `queries/userSkills.ts`, `testHelpers/skills.ts` and three call sites), with no UI change. Organization routes under `/api/experimental/organizations/{organization}/skills`, not gated by an experiment or license, like the personal ones: - `GET` lists with the caller's own permissions, so admins, the site owner and org auditors see every skill and members see only skills shared with them. `GET /{skillName}` goes through the new `httpmw.ExtractOrganizationSkillParam` and admits only read, so a missing skill and a denied one both return 404. - `POST` checks `create` on the organization before reading the body, then seeds `group_acl` with the Everyone group (whose ID is the organization ID) so a new skill reaches every member until an admin narrows it. The 100-skill cap and a duplicate name return 409. - `PATCH` admits only callers who can read the skill, because its response includes the content; `DELETE` admits callers who can read or delete it. A reader who can't change the skill gets a write-specific 403 from the database wrapper, and everyone else gets 404. PATCH locks the row as system, updates as the caller in the same transaction, and audits the locked row only after the transaction commits. - Audit: `database.AuditableOrganizationSkill` records resource type `organization_skill` with the organization ID; personal skills keep `user_skill`. Personal and organization handlers share one create and update path in `coderd/userskills.go` (`createSkill`, `updateSkill`, and a `skillWriteErrors` table per owner and action). ## Commits The first commit reproduces the reviewed code from the old stack; each later commit is a labeled trim or fix. - `49cb2c84276` feat: add organization skill API routes. Reproduction: every file this commit changes, including the SDK layer's site edits, equals the reviewed old `write-routes` head `aa597100f28`; the rest of the tree differs only by #30609's migration merge and main. - `dc893bc60d6` refactor(coderd): share the skill create and update path across owners (production +164/-188). It keeps the organization create check before the body read, the lock as system then update as caller order, and audit assignment after the transaction. No swagger, `codersdk` or `typesGenerated.ts` change; `make gen` is clean. - `f94925425ef` test(coderd): merge duplicate personal and organization skill tests. `TestSkillsCRUD`, `TestSkillValidationAndConflicts` and `TestSkillAudit` are table-driven over Personal, OrgAdmin and SiteOwner, alongside `TestOrganizationSkillAuditsDeniedWrites` and one `ScopedAPIKeys` subtest; `TestPatchUserSkill` is deleted because none of its blocks were unique. Coverage of `userskills.go`, `organizationskills.go` and `httpmw/organizationskillparam.go` is 101 of 117 blocks before and after, the same block set. - `ad0a7a37504` fix(coderd): require read access to patch an organization skill. The organization PATCH route now admits only `read`, because its response carries the skill's content: a key scoped to `organization_skill:update` without read gets 404, like GET, instead of 200 with the content. Readers without update still get 403, and DELETE is unchanged. `TestOrganizationSkillAccess/ScopedAPIKeys` asserts the 404, that the response has no content, and that the skill is unchanged; against the old route it fails with 200. - `69d00ded0b6` and `f67b79343ec` merge the updated #30609 layer, including main; `69d00ded0b6` resolves a conflict in the personal skills page with main. No other changes of their own. - `18373ffd59e` merges the updated #30609 layer (main at `e7b76872098`) and reapplies the `AuditableOrganizationSkill` entry in `enterprise/audit/table.go` alongside main's new `AuditableChatProjectInstructions` entries. ## Size Production +838/-308, tests +733/-322, generated +801/-274; total +2372/-904. This is above the 500-line reviewer-friendly limit on purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this stack replaces. ## Replaces #30587 (scope-neutral SDK and personal enabled state), #30588 (read routes), #30589 (write routes and audit). ## Validation - The coverage comparison above, before and after the test merge. - `make gen` leaves no diff after the shared create and update refactor. - On `18373ffd59e`: `make gen` is clean; build, vet, the `coderd` and `enterprise/coderd` skill tests, `rbac`, `httpmw`, `dbauthz` and `enterprise/audit` pass; `pnpm check`, `pnpm lint` and `make pre-commit` pass. - Remote UAT round 7 through Coder Agents passed on the whole stack; see #30613's Validation for scope and findings. > Xum opened this PR on behalf of @ibetitsmike. |
||
|
|
b67587c875 |
feat: add the organization skills data model (#30609)
## Stack Part of [CODAGT-1341](https://linear.app/codercom/issue/CODAGT-1341/support-organization-level-skills-in-coder-agents). This stack adds organization skills to Coder Agents: admins publish a skill once per organization, share it with groups or members, and chats in that organization load it next to personal and workspace skills. It replaces the 21-PR draft stack #30584 to #30604 with five PRs, bottom to top: 1. **#30609** data model: one migration, queries, RBAC and dbauthz (this PR) 2. #30610 organization skill API routes and the scope-neutral SDK 3. #30611 sharing ACL routes 4. #30612 settings UI: shared skills table, admin page, member section 5. #30613 chats: chatd loading, `/` menu, docs ## What changes This PR adds the data model and authorization for organization skills. Personal skills keep working unchanged: `git diff origin/main -- codersdk site` shows only generated RBAC and API key scope additions (`apikey_scopes_gen.go`, `rbacresources_gen.go`, `rbacresourcesGenerated.ts`, the RBAC and scope unions in `typesGenerated.ts`) and `codersdk.ResourceTypeOrganizationSkill` with its friendly string. No personal route, SDK type or site component changes, and `coderd/userskills_test.go` changes only by mechanical constant renames. **One migration, `000621_skills`** (please review it closely): - renames `user_skills` to `skills` with its constraints, index and triggers, and recreates the cap function and `delete_deleted_user_resources`, whose PL/pgSQL bodies name the table; - adds `organization_id` and `project_id` (`ON DELETE CASCADE`), `enabled` (default true), and `group_acl` / `user_acl` (`jsonb`, default `{}`), with CHECKs for exactly one owner, ACLs that are JSON objects, and ACLs that stay empty unless an organization owns the row, plus partial unique name indexes per owner kind; - replaces the cap trigger with `enforce_skills_per_owner_limit()`: 100 rows per owner, disabled rows included, locking the owner row `FOR NO KEY UPDATE` so unrelated foreign key checks are not blocked; - adds a `BEFORE DELETE` trigger on `organization_members` that removes a departing member from `user_acl` on that organization's skills, so rejoining doesn't restore a direct grant; - adds the `organization_skill` `resource_type` and `api_key_scope` enum values last; nothing in the migration uses them. The down migration undoes the three old migrations in reverse order: it drops organization and project rows and restores `user_skills`, its names, the cap function and `user_id NOT NULL`. Authorization: a new RBAC resource `organization_skill` (create, read, update, delete, share). Owner and org admin get it; site and org auditors get read; members read only through the skill's ACL, which applies only to members of its organization. `Skill.RBACObject()` returns the organization object with both ACLs; project rows stay denied to everyone. New sqlc queries cover organization insert, get, list (SQL-filtered through `GetAuthorizedOrganizationSkillMetadata` and a `regosql` converter), update and delete, with dbauthz wrappers and the audit table entries. No routes yet. ## Commits The first commit reproduces the reviewed code from the old stack; each later commit is a labeled trim or fix. - `baa3150e3b7` feat: add the organization skills data model. Reproduction: every non-site file this commit changes equals the reviewed old `authz` head `1e16b3004c4`, except that the old stack's migrations 000615, 000616 and 000617 are merged into one migration (then `000615_skills`, now `000621_skills`) with one fixture (`testdata/fixtures/000621_skills.up.sql`) and one migration test (now `testMigration000621Skills`). At that commit, `dump.sql` was byte-identical to the old head's. - `1b84e83463a` test(coderd/database): keep only the SQL paths of the org skill matrix. `TestOrganizationSkillAuthorization` becomes `TestOrganizationSkillQueries` instead of being deleted, because coverage showed it is this PR's only run of the `GetAuthorizedOrganizationSkillMetadata` row scan (80% to 65% without it) and of the organization update and delete queries (100% to 0%). Swapping `group_acl` and `user_acl` in the converter makes `GrantedMember` fail. The removed cases are decided by `TestRolePermissions`, `TestSkillRBACObjectOrganizationACL` and the dbauthz method suite. - `e2931b412e9` test(coderd/database): fold the skill cap cases into existing coverage. The user case is covered by `TestUserSkillLimit` and `TestUserSkillLimitConcurrentCreates`; the organization case folds into `ConcurrentOrganizationInsertsHonorCap`, which now also checks that disabled rows count and another organization is unaffected (mutation checked); the project case stays. - `be62aea9021` test(coderd/rbac): drop `TestOrganizationSkillReadScope`, covered by `TestExternalScopeNames` and the generated scope file. - `0c275ba37de` merges main at `454a2fcc697`, which took 000615 to 000618: it renumbers the migration to 000619 and resolves `dump.sql`, `check_constraint.go` and the generated API docs. `8f2b4b87ee2` merges main at `ad85646164e`, which took 000619: it renumbers the migration to 000620. - `5248d56b64f` merges main at `e7b76872098`, which took 000620 (`000620_audit_chat_project_instructions_resource_type`): it renumbers the migration, fixture and migration test to `000621_skills` (step `Migration000621Skills`, version 621), and resolves `enterprise/audit/table.go` (keeping main's `AuditableChatProjectInstructions` entries and the `Skill` entry), `dump.sql` and `models.go` (the `resource_type` enum gets `chat_project_instructions`, then `organization_skill`) and the regenerated `schemas.md`. The up and down SQL are unchanged by every renumbering. ## Size Production +549/-67, tests +728/-33, generated +881/-314; total +2158/-414. This is above the 500-line reviewer-friendly limit on purpose: Mike asked for 4 to 5 PRs instead of the 21 small ones this stack replaces. ## Replaces #30584 (rename `user_skills` to `skills`), #30585 (skill owners), #30586 (organization skill authorization). ## Validation - Migration test: up keeps the existing personal row and its ID; down restores the `user_skills` names, cap function and `NOT NULL`, and drops organization rows; soft-deleting a user removes their skills after up, after down, and after re-up. - `go test` passed on `be62aea9021`, before the main merges, for `coderd` (skill tests), `coderd/database`, `dbauthz`, `migrations`, `gentest`, `coderd/rbac/...`, `coderd/x/chatd`, `coderd/x/skills`, `enterprise/audit` and `enterprise/coderd`; `make lint/check-scopes` passed; the four personal skills Vitest files pass unchanged. - On `5248d56b64f`: build, vet, `TestMigrate`, `TestMigrationChain`, the `migrations`, `database`, `dbauthz`, `gentest`, `rbac` and `enterprise/audit` packages pass; `make gen` run twice is clean, and `make pre-commit` passes. - Remote UAT round 7 through Coder Agents passed on the whole stack; see #30613's Validation for scope and findings. > Xum opened this PR on behalf of @ibetitsmike. |
||
|
|
97c5260adb |
feat: add chat project instructions API (#30368)
Adds the experimental API for chat project instructions: `GET`, `PUT`,
and `DELETE
/api/experimental/organizations/{organization}/chats/projects/{project}/instructions`,
behind the `chat-projects` experiment.
- `GET` returns 200 with empty instructions and null
`updated_by`/`updated_at` when nothing is set, so clients don't need a
404 path.
- `PUT` requires update access only (the read-back runs under a system
context, so a custom role with update but not read can save). It
sanitizes the text with `SanitizePromptText`. It rejects blank text with
400, pointing the caller to `DELETE`, and rejects text over the chat
prompt byte limit. It records the caller as `updated_by`. The upsert and
the read-back that returns the editor's profile run in one transaction.
- `DELETE` returns 204, including when nothing is set.
- Users without access to the project get 404, like the other project
routes.
- `PUT` and `DELETE` are audited as a new `chat_project_instructions`
resource (`write` and `delete`), with the project as the resource ID and
its name as the target. The diff tracks only the instruction text.
Saving unchanged text and deleting unset instructions are not audited. A
per-project advisory lock serializes reading the previous value with the
write, so concurrent edits produce accurate diffs. Migration `000615`
adds the enum value.
The codersdk client gains `ChatProjectInstructions`,
`UpdateChatProjectInstructions`, and `DeleteChatProjectInstructions`.
**What to scrutinize:** writes are last-writer-wins with no version
precondition, matching the deployment, user, and organization prompt
settings.
**Generated:** `coderd/apidoc/docs.go`, `coderd/apidoc/swagger.json`,
and `docs/reference/api/schemas.md` come from the Swagger annotations;
`site/src/api/typesGenerated.ts` comes from `codersdk`;
`docs/admin/security/audit-logs.md`, `coderd/database/dump.sql`, and
`coderd/database/models.go` come from the audit table and migration.
Together they are about 400 of this PR's lines.
**Validation:** `make gen` leaves no diff. `go test ./coderd -run
TestChatProject` and `go test ./enterprise/coderd -run
TestChatProjectInstructions` pass. `TestChatProjectInstructionsAudit`
checks the audit entries for create, update, and delete, and that no-op
saves and deletes are not audited. It covers unset GET, create, update,
blank and oversized PUT, delete, access denial, and cascade on project
delete.
---
Stack (merge top to bottom). #30377 through #29583 are f0ssel's split of
the original #29583, and this stack sits on #29583:
- #30377 data layer and project dialog (f0ssel)
- #30378 new-chat form locked to a project (f0ssel)
- #30379 project page route (f0ssel)
- #29583 sidebar folders (f0ssel), the base of this stack
- #30291 composer frame
- #30292 project chat list caches
- #30293 project page header
- #30294 project chats list
- #30367 instructions storage and prompt injection
- #30368 instructions API 👈
- #30369 instructions editor dialog
- #30370 instructions Details panel
---------
Co-authored-by: Garrett Delfosse <delfossegarrett@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
||
|
|
dae7967bd1 |
feat: persist script resource addresses and dependencies (#30625)
feat(coderd): persist workspace agent script dependencies Persist Terraform resource addresses and script dependencies supplied by the provisioner (#30451, #30491), and expose them through the SDK and REST API. - Add migration 000618 with `resource_address` and `dependencies` columns, empty defaults, and a JSON-array constraint. API responses always include the address and omit empty dependency lists. - Preserve `success` and `completion` requirements, including scripts on devcontainer subagents. Legacy scripts and older provisioners remain compatible through empty defaults. - Reject empty prerequisite addresses and unsupported requirements, rolling back the entire job. Invalid stored dependencies return HTTP 500 rather than silently dropping ordering. - Add persistence, validation, rollback, devcontainer, API, and migration coverage; regenerate API docs and TypeScript types. Unordered templates retain their existing execution behavior. Dependency lists remain empty until #30556. Agent manifest wiring and the agent API version bump are deferred to a follow-up. Refs PLAT-548. |
||
|
|
2f2169ed19 |
fix: deduplicate template insights family metrics (#30497)
coderd_insights_applications_usage_seconds summed each family's per-app minutes, so a user with VS Code and Cursor open in the same minute was counted as two VS Code minutes. GetTemplateInsightsByTemplate now takes the registry's app-to-family mapping as jsonb, groups the raw agent stats by family, and counts each minute once per user and family. - Keep the metric's four built-in series (Visual Studio Code, JetBrains, Web Terminal, SSH) and their labels; only their values change. The HELP text now says built-in apps are grouped by family. - Add AppFamilyName.DisplayName() and remove the duplicate TemplateBuiltinAppDisplayName* constants from codersdk. The template insights handler returns the same display names. - Pin how the migration 000596 rollback approximates family minutes from per-app rows. Family values can drop wherever the old per-app sum double-counted overlapping apps. No migration or storage changes. |
||
|
|
41f5caafec | fix: fold web searches, answer reasoning, and OpenAI narration into working blocks (#30529) | ||
|
|
8a063ef0d5 |
docs: add Claude Desktop as a supported client (#30653)
Closes [DOCS-1198](https://linear.app/codercom/issue/DOCS-1198/document-claude-desktop-as-a-supported-coder-client) Adds Claude Desktop alongside the other supported clients and IDEs. Once the Coder CLI is installed and logged in, running workspaces appear in Claude Desktop. ## Changes - New page `docs/user-guides/workspace-access/claude-desktop.md`: prerequisites, setup, troubleshooting. - New `## Claude Desktop` section in `workspace-access/index.md`. - Registered the page in `docs/manifest.json`. - Added Claude Desktop to the IDE list in the glossary. ## Notes - Setup steps checked against `docs/reference/cli/` and the existing SSH docs. - `make fmt/markdown`, `lint/markdown`, `lint/docs-manifest`, `lint/emdash`, `lint/docs-html` pass. > 🤖 This PR was created with the help of Coder Agents, and needs a human review. 🧑💻 |
||
|
|
f2ddf215dc |
docs(docs/user-guides/workspace-access): fix broken vscode-coder demo GIF links (#30655)
Closes [DOCS-1201](https://linear.app/codercom/issue/DOCS-1201/fix-broken-vscode-coder-demo-gif-links-in-workspace-access-docs) ## Summary coder/vscode-coder#1134 moved `demo.gif` from the repo root into `media/`, so the VS Code demo GIF embed now returns a 404. Linkspector flagged it on #30653 ([thread](https://github.com/coder/coder/pull/30653#discussion_r4249822055)). ## Changes - Point the demo GIF embed at `media/demo.gif` in `docs/user-guides/workspace-access/index.md` and `vscode.md`. ## Testing - `curl -sIL`: new URL returns 200, old URL returns 404. - `make lint/markdown` and `make fmt/markdown` pass. > 🤖 This PR was created with the help of Coder Agents, and needs a human review. 🧑💻 |
||
|
|
8674e8529e |
docs: note coder_agent dir un-deprecation in 2.29-2.34 ESR upgrade guide (#30533)
## Summary Follow-up to [coder/terraform-provider-coder#549](https://github.com/coder/terraform-provider-coder/pull/549), which un-deprecated `coder_agent.dir`. The 2.29-2.34 ESR upgrade guide still says `dir` is deprecated, warns, and breaks Coder Desktop file sync, and tells admins to set it to `$HOME`. As planned in #549, this keeps the original row as history and appends an **Update** to the New State and Action cells: - Coder Terraform provider 2.20.0 removed the deprecation and warning. - Coder Desktop file sync works with any `dir` on macOS [v0.8.4](https://github.com/coder/coder-desktop-macos/releases/tag/v0.8.4) and Windows [v0.8.5](https://github.com/coder/coder-desktop-windows/releases/tag/v0.8.5) (Mutagen v0.18.5, [coder/mutagen#10](https://github.com/coder/mutagen/pull/10)). The rest of the diff is `markdown-table-formatter` re-padding the table. `markdownlint-cli2` passes. ## Merge timing Opened as a draft. #549 is only in `v2.20.0-pre0` so far; mark ready and merge once provider 2.20.0 is published to the registry. If the release number changes, update the version in the row. Review requested from @aqandrew. --- Opened by Superblink on behalf of @matifali. Co-authored-by: coder[bot] <137810501+coder[bot]@users.noreply.github.com> Co-authored-by: Atif Ali <atif@coder.com> |
||
|
|
d7bf081e57 |
docs: point the 2.29 ESR row at v2.29.21 (#30538)
Updates the latest-patch link for the 2.29 Extended Support Release in the release calendar to [v2.29.21](https://github.com/coder/coder/releases/tag/v2.29.21), released 2026-10-09. One-line change; no other rows touched. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5b060beeb1 |
feat: separate connection log methods from app names (#30466)
Connection logs now record how a connection was made (`connection_method`) separately from which app made it (`app_name`). Storage, the HTTP API, search filters, and the UI move to the new fields. Legacy agent reports and the deprecated `type` field keep working. - Add `connection_method` (`ssh`, `reconnecting_pty`, `workspace_app`, `port_forwarding`, `tunnel`) and optional `app_name` and `app_display_name` to `GET /api/v2/connectionlog`. Deprecate `type` and make it a plain string in the API and the Go SDK. - Add `method:` and repeatable `app:` search filters. `type:` keeps its old results but can't be combined with the new filters. - Replace the Type menu with a Method menu, show the app next to the method in each row, and warn when a filter uses `type:`. - Change the Active SSH connections preset to `method:ssh`, so it also includes SSH sessions from VS Code and JetBrains apps. - Generate `codersdk.ConnectionLogMethod` from the database enum with `typegen dbenums`. - Migration 000617 rewrites `connection_logs` under an ACCESS EXCLUSIVE lock, which takes about 50 seconds for 10 million rows. `vscode` and `jetbrains` rows become `ssh` rows with that app. Rolling back folds apps into the old types and loses per-app names. - Document the new filters and how to replace each `type:` value. Closes #27412 |
||
|
|
f923f4a525 |
chore!: remove the chat automations experiment (#30412)
Removes the experimental Chat Automations feature (`chat-automations` experiment) from main. This reverts the 16-PR stack that added it and adds two forward migrations that undo its schema and credential changes.
> [!WARNING]
> **Upgrade consequences**
>
> - **Automation data is deleted.** Migration 000615 drops the `chat_automations` table and deletes every queued message an automation delivered. Chats, their messages and ordinary queued messages stay. Messages lose their automation provenance (`automation_id`, `input_id`).
> - **Automation-only credentials are revoked.** Migration 000616 deletes API keys, OAuth2 codes and OAuth2 tokens whose only scopes (or allow-list entries) were `chat_automation:*`. Mixed credentials keep their other scopes. Custom roles lose their `chat_automation` permissions. OAuth2 apps that allowed only `chat_automation` scopes get the whitespace allowlist that grants nothing, as in 000595.
> - **A coordinated restart is required.** Stop all old replicas before the new version runs the migrations. Old replicas read the dropped table and columns, so a rolling deploy is not supported.
> - **Remove `--chat-max-automations-per-owner` before upgrading.** The flag, the YAML key `chat.maxAutomationsPerOwner` and the env var `CODER_CHAT_MAX_AUTOMATIONS_PER_OWNER` are removed. A deployment that still sets the flag or the YAML key will not start (`unknown flag` / `unknown option`). The env var is ignored. This includes dogfood. No release or tag contains the flag.
> - **Down migrations restore the schema only.** 000616 down and 000615 down recreate the 000611 schema with empty tables. They do not restore deleted automations, webhook secrets, provenance, queued deliveries, revoked credentials, stripped permissions or the deleted experiment rule.
## What is removed
- The `chat-automations` experiment and its stored runtime rule (`experiment_rule:chat-automations`).
- The `--chat-max-automations-per-owner` deployment option.
- The `chat_automation` RBAC resource, its member and chatd grants, and the `chat_automation:*` API key scopes.
- The automation sqlc queries, dbauthz wrappers and audit table entries.
- The management routes under `/api/experimental/organizations/{organization}/chat-automations`, and the webhook route `POST /api/experimental/chat-automations/{automation}/events` with its rate limiter.
- The chatd management service, webhook publish, schedule loop, the `manage_automations` tool, and the chatstate admission seam and queue promotion guard that only automations used.
- The Agents Automations page, editor, nav entry, chat labels, the Manage automations toggle and the API client.
- The `archived:any` chat search value that the automations "View chats" dialog added.
- `docs/ai-coder/agents/automations.md`, its manifest entry, the glossary entry and the related rows.
Reverted PRs: #30085, #30096, #30112, #30117, #30127, #30134, #30160, #30166, #30167, #30171, #30187, #30207, #30214, #30217, #30219, #30220.
## What stays, and why
- Migrations 000609, 000610 and 000611, their fixture, and the #30297 lock fix with `migration000609_test.go` stay unchanged. Deployments such as dogfood already ran them.
- New migration **000615** reverses the schema changes of 000609 and 000611 against the current schema. It uses the same short-wait lock-and-retry block as 000609, and it rebuilds `chats_expanded` from main's current definition minus the two automation columns. New migration **000616** follows the 000595 Tasks removal for credentials and recreates `api_key_scope` without the five `chat_automation:*` values. It keeps the `chat_project_memory:*` values from 000612.
- The `chat_automation` value stays in the `resource_type` enum, and `codersdk.ResourceTypeChatAutomation` stays. Old audit log rows stay readable, as with `task` after the Tasks removal.
- The 000615 delete fires the existing queue-version trigger, so `queue_version` moves to `snapshot_version` for each affected chat. `snapshot_version` is not bumped: the coordinated restart restarts every stream loop from an empty state, and the site does not read the version fields.
- `coderd/x/chatd/ARCHITECTURE.md` drops the sections the stack added and gets back its pre-stack wording, merged with the later main edits to the same file.
## Notes for reviewers
- #30379 (chat project page) merged while this PR was in progress. It passed `manageAutomationsEnabled` in `AgentCreatePage.test.tsx` and listed an `automations` route in `AgentsPageLayout.test.tsx`. Later main commits also added automation props in `ConversationTimeline.test.tsx` and `ConversationTimelineWorkingBlocks.stories.tsx`. This PR removes all of them.
- Remaining `automation` matches under `coderd`, `codersdk`, `enterprise`, `site/src` and `docs` are intended:
- migrations 000609 to 000611, their fixture and `migration000609_test.go`;
- the new 000615 and 000616 migrations and `migration000615_test.go`;
- the `chat_automation` resource type in `dump.sql`, `models.go`, `codersdk/audit.go`, the generated API docs, `swagger.json` and `typesGenerated.ts`;
- unrelated uses of the word "automation" (docs, `chatlabels_test.go`, `ratelimit.go`, `autostop.go`, `subagent_catalog.go`, `WorkspaceSharingSection.tsx`, `AgentChatPage.stories.tsx`).
Remote UAT on an isolated dev deployment passed. It upgraded a populated pre-removal database, then checked chats, queued messages, tokens, the 404 routes, the removed page and nav entry, and the experiments list.
---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

|
||
|
|
dfa72df9aa |
docs: remove references to unsupported SAML authentication (#30507)
## Summary Coder doesn't support SAML, but a few docs pages implied it did. This PR removes those mentions. Resolves [DOCS-1194](https://linear.app/codercom/issue/DOCS-1194/remove-saml-mentions-from-docs-coder-doesnt-support-saml). ## Changes - `docs/install/index.md` and `docs/install/prepare/index.md`: "OIDC or SAML application" is now "OIDC application". - `docs/.style/style-guide/audience-and-scope.md`: the example snippets no longer mention SAML or link to a `./saml.md` page that doesn't exist. The hub-page example now lists headless authentication instead, and the persona "Coder surface" lines say "OIDC" in place of "OIDC/SAML". <details> <summary>Evidence that Coder doesn't support SAML</summary> Checked against `main`: - No SAML library in `go.mod`, `go.sum`, or `site/package.json`. - The `login_type` enum in `coderd/database/dump.sql` and `codersdk.LoginType` only cover `password`, `github`, `oidc`, `token`, `none`, and `oauth2_provider_app`. - No SAML handlers, endpoints, or deployment options in `coderd/` or `enterprise/`. - The only code mention is a comment in `coderd/userauth.go` about SAML-to-OIDC bridges sending `email_verified` as a string. </details> ## Testing - `pnpm run lint-docs`: 0 errors. - The pre-commit hook passed. - `git grep -i saml -- docs` returns nothing. --- *Generated by Coder Agents on behalf of @nickvigilante.* --------- Co-authored-by: Ben Potter <me@bpmct.net> Co-authored-by: Ben Potter <ben@coder.com> |
||
|
|
86ebc72236 | chore: remove unused autofill-parameters endpoint and experiment (#30525) | ||
|
|
f8e053e385 | docs: document VS Code SSH keepalive and reconnection settings (#30501) | ||
|
|
782fb30f09 |
feat: load whole chat turns per history page (#30524)
Closes [CODAGT-1372](https://linear.app/codercom/issue/CODAGT-1372/load-whole-turns-per-history-page-so-collapsed-working-blocks-fill-in). With collapsed working blocks, a long agent turn renders as one row, but chat history pages hold a fixed 50 messages. A 400-step turn took about eight sequential page loads to fill, and its block showed partial labels ("at least", "or more") until then. `GET /api/v2/chats/{chat}/messages` now returns `turn_start_id` on newest-first pages: the ID of the user prompt that starts the turn containing the page's oldest message. It comes from a new `GetChatTurnStartID` query on the existing `idx_chat_messages_user_prompts` index, so there is no migration. Soft-deleted prompts and model-only user rows never start a turn. The history query then fills each page back to that prompt with requests of up to 200 messages, capped at 1000 messages per page, so a page holds whole turns and a complete block renders without partial labels. Past the cap, or when a fill request fails or returns no messages, the page keeps what loaded and ends mid-turn, and the next page continues it, as before. Because the fill runs inside the page fetch, a chat now waits for its fill requests (one to five) before it first renders: with an injected 500 ms per-request delay, a chat whose newest turn hits the cap appeared after 3.8 s instead of 1.1 s. ## Screenshots From the dogfood UAT, the same 200-step turn with its next history request held, so each label shows only what loaded before it: **Before**, on the base commit `29e876df4da`, after two 50-message pages: "Worked for at least 1m 35s (48 steps or more)", partly hidden by the loading indicator.  **After**, on `186a9b053a0`, after the first page: "Worked for 6m 39s (200 steps)".  A 750-step turn, larger than one 1000-message page, is exact once the next page loads:  A malformed fill response keeps the loaded messages and the partial label instead of showing "Failed to load chat", as `ecdfb27ec29` did:  ## Testing - Go: `TestGetChatMessages_TurnStartID` (pages spanning turns, deleted prompts, model-only user rows, polling and empty pages) and the dbauthz suite entry. - Vitest: fill request parameters, the 1000-message cap, failed, malformed, and empty fill responses, and servers without `turn_start_id`. - Dogfood UAT through Coder Agents: PASS on `186a9b053a0` (round 4): whole-turn first pages, the 1000-message cap and its continuation, fill failures, a live turn, and API checks for deleted prompts and model-only user rows. Round 3 on `ecdfb27ec29` failed: a malformed fill failed the chat load, and an empty fill reporting `has_more` repeated forever. `7266f468290` fixes both, with regression tests. ## Review record - Test audit with mutation checks: the Go test now covers a page spanning two turns, which catches a lookup keyed on the newest message. A re-audit of later test changes changed nothing; the one surviving mutation drops the `!older.has_more` stop, costing one extra request when the prompt is deleted mid-fill. - Frontend review (8 roles, 5 rounds): fixed doc, naming, loose-type, and test findings. Its suggestions to catch only the fill request (DF5) and drop the empty-page stop (SD4) caused the round 3 failures and are reverted. Kept: SD1 (`MAX_MESSAGES_PER_REQUEST` is used once, named like `MESSAGES_PAGE_SIZE`) and round 5 SD4 (`!older.has_more` is the endpoint's pagination signal). Declined DF6: the `queued_messages` refetch race predates this change, and a failed refetch fill only unloads older history that reloads on scroll. - Codex: no findings on `186a9b053a0`. - Known: a hung fill delays the first render (no client timeout); fills are not cancelled when the user leaves; the top of history costs one extra empty request; injected malformed fill rows break the page as they do on the first page. > Xum opened this PR on behalf of @ibetitsmike. |
||
|
|
6bae268487 |
fix: move organization instructions to the Instructions page (#30428)
Moves organization instructions (#30272) from the Coder Agents page to **AI Settings** > **Coder Agents** > **Instructions**, so every Coder Agents instruction is managed on one page. The API and stored data are unchanged. - **Deployment admins** see a "Deployment instructions" section with the existing system prompt and plan mode form, then an "Organization instructions" section. The organization section has an organization picker when there is more than one organization. - **Organization admins and auditors** who can read an organization's chat model configuration get an Instructions entry in the AI settings sidebar and see only the organization section. Auditors get it read-only. - The selected organization is kept in `?org=`, and the sidebar link carries it over from the other AI settings pages. - The Coder Agents page goes back to its layout from before #30272. Its sections and the new page's sections share new `SettingsSection` and `OrganizationSettingsSection` components. - Three docs pages point to the new location. Other behavior changes: - The deployment section shows a loader while loading and an error alert when loading or refreshing fails. Before, the page rendered nothing until both settings loaded. - The deployment forms no longer have their own accessible names, because each section is named by its heading. ## Testing - Vitest for the Instructions page and sidebar link, and stories for the new states. Breaking each of the 9 main code paths, or removing the instructions field's accessible name, fails its test. - The branch merges `main` for #30402, which made the organization picker a combobox. - CI passes on `a0cc6a98660`. - Remote dogfood UAT, [evidence chat](https://dogfood.cdr.dev/agents/1cbf9da4-9671-4890-ade1-c151a1a69cd7): **PASS** on `a0d9c3fca46`, 14 scenarios across every role, `?org=` handling, injected load failures, keyboard use, and a 390 px layout. The remote agent's FAIL (a double-click on Save sends 2 PUTs) also happens on the merge base, so it predates this PR. Delta round on `a0cc6a98660`: **PASS**. When the permission re-check fails, the owner and an organization admin see the alert above the organization section, and the unsaved draft stays and saves. - UAT notes left as is: the fallback for an unreadable `?org=` is read-only, as on the Coder Agents page; `?org=` matching is case-sensitive, as on the Models and Spend pages; the old `/agents/settings/instructions` redirect drops `?org=`; the permission alert shows the server's error message without saying which check failed, as on the Models pages. ## Screenshots From UAT on a test deployment. | Organization admin | Owner, after a failed refresh (unsaved edit kept) | |---|---| |  |  | | **Coder Agents page, no instructions card** | **Unavailable `?org=`: warning and read-only fallback** | |  |  | ## Review record 1. `coder-frontend-review` (8 reviewer agents) on `3dd65e828f9`: fixed in `a0d9c3fca46` (deployment refetch errors were dropped, plus naming, prop types, test waits, and a single-organization story). Declined: `SettingsHeader` in `SettingsSection` and merging the sidebar groups (both change existing layout), and restructuring the moved card (git would stop detecting the move). 2. `frontend-review` (FE1 to FE10) on `a0d9c3fca46`: every rule passes, no changes. 3. Codex, [review](https://github.com/coder/coder/pull/30428#pullrequestreview-5431118231) on `a0d9c3fca46`: 1 P2, a docs sentence wrote "more than 1" where the numbers guide spells out "one". Fixed in `0e71b8f16b9`. 4. Codex, [review](https://github.com/coder/coder/pull/30428#pullrequestreview-5431285875) on `0e71b8f16b9`: 2 findings, each confirmed by a failing test and fixed in `a0cc6a98660`. A failed background re-check of organization permissions showed no alert, unlike the old Coder Agents page and the Models pages (P2). The page tests found the instructions field by its value, so removing its accessible name went unnoticed (P1). 5. `coder-frontend-review` (8 reviewer agents) and `frontend-review` (FE1 to FE10) on `a0cc6a98660`: everything passes, no changes. The round 1 `findByDisplayValue` suggestion is reversed, because FE10 asks for role and name queries. 6. Codex on `a0cc6a98660`: [no major issues](https://github.com/coder/coder/pull/30428#issuecomment-6020794170). > Xum, an AI coding agent, implemented, tested, and opened this PR on behalf of @ibetitsmike. |
||
|
|
befda9b29f |
docs: mention chat reasoning_tokens is part of output_tokens (#30500)
Document that reasoning_tokens is included in the output_tokens on ChatMssageUsage, which is the case for all known providers. Refs CODAGT-1350 |
||
|
|
261269aff0 |
fix: support path-aware OAuth discovery for remote MCP (#30168)
## Problem VS Code discovers Coder's MCP endpoint as a path-qualified OAuth resource, but Coder advertises the deployment root. Accepting MCP-bound tokens also requires keeping REST-backed tool calls within the originating MCP resource rather than granting those tokens direct REST access. ## Fix - Publish path-aware protected resource metadata and authentication challenges; keep authorization-server metadata at the root. - Validate the MCP audience and delegate tool requests through a private in-process transport that retains identity, scopes, expiry, revocation, and streaming cancellation. - Reject unsupported MCP path aliases and validate SDK path components before URL resolution. - Add discovery, audience, authorization, endpoint-isolation, and transport lifecycle regression tests and update integration docs. ## Validation VS Code completed OAuth and returned the authenticated user through a real MCP tool. Official MCP SDK 1.30.1 completed discovery, registration, PKCE, tool execution, and refresh. These live checks preceded the final path hardening; the hardened paths are covered by automated regressions. Affected Go package tests, targeted race tests, backend/SDK lint, and targeted documentation checks passed during self-review. The exact PR commit was also checked separately from the uncommitted consent-scope fix. > [!NOTE] > Tokens are MCP-audience-bound, but grants still include `coder:all`; least-privilege scopes remain a separate requirement ([PLAT-639](https://linear.app/codercom/issue/PLAT-639)). Preview: https://coder.com/docs/@fix/mcp-internal-delegation/ai-coder/mcp-server <details> <summary>Implementation decisions and review context</summary> 1. Treat `/api/experimental/mcp/http` and its single-trailing-slash form as supported MCP resource paths; reject other aliases and descendants before route authentication. 2. Preserve deployment-root discovery and authorization-server metadata for existing REST integrations. 3. Bind private delegation to the authenticated API-key ID. Revalidate the original credential and enforce normal RBAC/scopes on every internal REST request; do not derive delegation from HTTP headers. 4. Keep internal HTTP, streaming, and WebSocket traffic in-process with no network fallback. Close the transport on outer-request cancellation and normal completion. 5. Validate workspace owner/name path segments before SDK URL construction, including tool-level tests that malformed arguments cannot select a different REST endpoint. 6. Keep compatibility and delegated tool execution together: discovery-only changes would allow authentication while leaving real MCP tool calls broken. </details> > 🤖 This PR was created with the help of Coder Agents, and needs a human review. 🧑💻 |
||
|
|
a8303a8f2b |
feat!: add output formats to coder schedule start, stop, and extend (#30136)
`coder schedule start`, `stop`, and `extend` printed the updated schedule as a fixed table with no `-o` or `-c`, while `coder schedule show` has both. All four commands now share one formatter with the same row type, default columns, `-o table|json`, and `-c`, so the output of a change and of `show` is interchangeable. **Behavior change:** Adds `-o` and `-c` to the three commands. The default table output changes slightly: the WORKSPACE column no longer includes the favorite-star prefix, matching `schedule show`. Other columns are unchanged. <details> <summary>Decisions</summary> - Previously these commands rendered `WorkspaceListRow`, which prefixes the workspace name with a favorite icon. Using `scheduleListRow` for consistency with `schedule show` drops that prefix. </details> Closes [CLI-15](https://linear.app/codercom/issue/CLI-15) _This PR was generated by Coder Agents on behalf of @nickvigilante._ |
||
|
|
98bcc3afb7 |
fix!: remove the unused --yes flag from coder autoupdate (#30149)
`coder autoupdate` has registered `-y/--yes` since #10438 but never prompts, so the flag did nothing. This PR removes it. **Breaking change:** `coder autoupdate` no longer accepts `-y/--yes`. Scripts that pass it now fail with `unknown shorthand flag: 'y'`. To fix them, drop the flag; it never had an effect. <details> <summary>Decisions</summary> - The first version kept `-y` as a hidden no-op so existing scripts wouldn't break. - Reviewers preferred removing it outright as a breaking change, since a deprecation period would end in the same removal and the hidden flag is cruft. - The title uses `fix!:` and the PR carries `release/breaking`, so the release tooling lists it under breaking changes. - `cliui.HiddenSkipPromptOption()` landed on `main` through the organizations create PR and stays there for that command; this PR no longer touches it. - The test now pins the new behavior: passing `-y` returns an unknown flag error. </details> Closes [CLI-33](https://linear.app/codercom/issue/CLI-33) _This PR was generated by Coder Agents on behalf of @nickvigilante._ |
||
|
|
c11d60ad8d |
docs: note the pubsub cluster port between HA replicas (#30290)
HA replicas connect to each other's embedded NATS pubsub on TCP 6222. The port is hardcoded ([`coderd/x/nats/pubsub.go`](https://github.com/coder/coder/blob/7f3d35353eddcd8a9e573094e5e2531bd2d73659/coderd/x/nats/pubsub.go#L62)) with no flag or environment variable, and since #29283 NATS pubsub is on by default. The HA page explains `CODER_CLUSTER_HOST` but doesn't name the port, so a firewall or default-deny NetworkPolicy between `coderd` nodes blocks it. This adds the port, and what happens without it, next to `CODER_CLUSTER_HOST`. Measured on v2.37.3 (`CODER_EXPERIMENTS=nats_pubsub`, the default on main) with two replicas on GKE under a default-deny NetworkPolicy, port 8080 open between the replicas in both runs. Through a port-forward to replica B, `PUT /api/v2/workspaces/{id}/extend` publishes a workspace update in the request path. A watcher on `/api/v2/workspaces/{id}/watch` through replica A counts the events. The control sends the same request through A. 6222 blocked: ```text label=blocked A=coder-699ccb59f8-695bj B=coder-699ccb59f8-w8glp baseline_data_events=1 control: extend via A -> HTTP 409; data events on A: 1 (expect 1) test: 5x extend via B -> HTTP 409 409 409 409 409; data events on A: 0 coder-699ccb59f8-695bj :6222 established: 0 coder-699ccb59f8-w8glp :6222 established: 0 ``` 6222 allowed between the replicas (same pods, no restart): ```text label=allowed A=coder-699ccb59f8-695bj B=coder-699ccb59f8-w8glp baseline_data_events=1 control: extend via A -> HTTP 409; data events on A: 1 (expect 1) test: 5x extend via B -> HTTP 409 409 409 409 409; data events on A: 5 coder-699ccb59f8-695bj :6222 established: 4 coder-699ccb59f8-w8glp :6222 established: 4 ``` The 409s are expected because the workspace is stopped; the handler publishes the update before it returns ([`coderd/workspaces.go`](https://github.com/coder/coder/blob/3a248167f6e58462a8a8cddba3b49a8ff72a9f80/coderd/workspaces.go#L1711) at v2.37.3). Would it also make sense for the chart to declare 6222 as a container port, or for the port to be configurable? I left both out of this change. AI involvement: I used an AI assistant to draft this change, and verified it with the runs above against a two-replica deployment. |
||
|
|
020b437ec9 |
docs: document dropping capabilities for restricted Pod Security (#30271)
Following the suggestion in #22543 to have `coder.securityContext.capabilities` in `values.yaml` without a default, this adds it as a commented example, the same way `values.yaml` shows `env` and `initContainers`, and adds one line to the Kubernetes Security Reference. Existing deployments don't change on upgrade. The chart's default security context passes every Pod Security Standards `restricted` check except capabilities, so a namespace that enforces `restricted` rejects the pod. Because the example is commented out, the rendered chart is unchanged: ```console $ diff main.yaml branch.yaml && echo "renders identical ($(wc -l < branch.yaml) lines)" renders identical (208 lines) ``` Server-side dry runs of this branch's chart into a namespace labeled `pod-security.kubernetes.io/enforce=restricted` (GKE, Kubernetes 1.35), using the pod spec from the rendered Deployment, as is and with the example uncommented: ```console $ kubectl create --dry-run=server -n coder -f pod-branch.json Error from server (Forbidden): error when creating "pod-branch.json": pods "pss-main-branch" is forbidden: violates PodSecurity "restricted:latest": unrestricted capabilities (container "coder" must set securityContext.capabilities.drop=["ALL"]) $ kubectl create --dry-run=server -n coder -f pod-branch-drop.json pod/pss-main-branch-drop created (server dry run) ``` A v2.37.3 deployment with the value set runs in a `restricted` namespace, ready with no restarts. AI involvement: I used an AI assistant to draft this change, and verified it with the commands above against a running cluster. |
||
|
|
b4d51012da |
feat: allow template version selection for workspace builds (#30199)
Add named template version selection to `coder start` and `coder stop`, and independent stop/start selection to `coder update` with `--stop-template-version` and `--template-version`. Stop still defaults to the workspace's current version, and update starts with the active version by default. Explicit selections use the selected version for parameter preparation and builds, keep server permissions authoritative, and never silently fall back to the active version. Classic stop builds retain previous parameter values omitted by the selected stop version, so a later start can reuse them across separate commands or an interrupted update. Declared parameters still follow normal validation, and start builds still discard removed parameters. Update now returns an error and retry guidance when a start apply fails after stopping, including unflagged updates that previously returned success. Closes #29100 [PLAT-616](https://linear.app/codercom/issue/PLAT-616/cli-allow-specifying-a-template-version-for-stopstart-builds-and-both) --------- Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com> |
||
|
|
b4fb7901e6 |
docs: clarify that disable-password-auth also applies to owners (#30362)
The `--disable-password-auth` help text says owners can still sign in with a password "to avoid potential lock out", and a comment in `coderd/userauth.go` says the same. Neither is true. #6193 removed the owner bypass on purpose, so the flag blocks password login for everyone. The recovery advice was also wrong. It named a command that doesn't exist (`create-admin`), and any admin that `create-admin-user` creates while the flag is on still can't sign in. This PR changes docs and comments only: - Rewrites the flag description to say it applies to owners too and how to recover access. Regenerated the CLI and config reference docs and the golden files. - Fixes the misleading comment in `coderd/userauth.go`. - Adds the same warning and recovery steps to `docs/admin/users/password-auth.md`. > [!NOTE] > Generated by Coder Agents on behalf of @jdomeracki-coder. |
||
|
|
c9680e4f36 |
docs: correct the CODER_AGENT_BLOCK_FILE_TRANSFER block list (#29705)
## Problem The FAQ entry _"How can I restrict inbound/outbound file transfers from Coder workspaces?"_ documents the wrong block list for `CODER_AGENT_BLOCK_FILE_TRANSFER`. It currently says the list includes `scp`, `rsync`, `ftp`, and `nc`. The actual list in [`agent/agentssh/agentssh.go`](https://github.com/coder/coder/blob/main/agent/agentssh/agentssh.go) is: ```go // BlockedFileTransferCommands contains a list of restricted file transfer commands. var BlockedFileTransferCommands = []string{"nc", "rsync", "scp", "sftp"} ``` So the docs have two errors: - **`ftp` is documented but is not blocked.** An admin reading this page could reasonably believe `ftp` is covered when it is not. - **`sftp` is blocked but is not documented.** This matters operationally, because SFTP is blanket-blocked at the subsystem level (`if session.Subsystem() == "sftp"`), which disables anything built on it. ## Changes 1. Correct the block list to match the source, in the same order as the slice so the two are easy to diff by eye in future: ```diff -block list, which includes `scp`, `rsync`, `ftp`, and `nc`. +block list, which includes `nc`, `rsync`, `scp`, and `sftp`. ``` 2. Per review feedback, add a note to **Important Notice** covering what enabling this actually breaks: SFTP-based tooling, and [Coder Desktop file sync](https://coder.com/docs/user-guides/desktop/desktop-connect-sync). Desktop file sync breaks via `scp` rather than `sftp`. It runs Mutagen over SSH, and Mutagen's SSH transport installs its remote agent binary by shelling out to `scp` ([`pkg/agent/transport/ssh/transport.go`](https://github.com/coder/mutagen/blob/v0.18.3/pkg/agent/transport/ssh/transport.go)), which is on the block list. The note keeps that distinction because an admin debugging it will see an `scp` failure, not an SFTP one. ## Correction An earlier revision of this description claimed `coder cp` is also blocked. **That was wrong — there is no `coder cp` command.** No `cli/cp.go`, no `docs/reference/cli/cp.md`, no `cp` entry in the CLI index. I've removed the claim rather than document a command that doesn't exist. Discussed in the thread below. ## Not included Linking the FAQ to [Agent Firewall](https://coder.com/docs/ai-coder/agent-firewall) from the "For more advanced security needs" line, which currently only says "consider adopting an endpoint security solution." Happy to add if wanted, but it felt out of scope for a correctness fix. Also note I only verified the macOS Desktop client. `coder-desktop-windows` and `coder-desktop-linux` are very likely the same Mutagen setup, but I didn't read them, so the note makes no per-platform claim. Created on behalf of @bartekgatzcoder. --------- Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> |
||
|
|
d56cc3a6c3 |
docs(docs/support): clarify VS Code support bundle requirements and limits (#30430)
Refs VSC-25, #30118 |
||
|
|
fc01bee831 |
fix: keep new API keys within the caller's scopes and allow list (#30256)
A scoped key holding api_key:create could mint a broader key, e.g. a token scoped to [api_key:create user:read] could mint coder:all.
- New keys must be covered by the caller's scopes and allow list, and inherit them when none are requested
- Requests beyond the caller return 403
- New key expiry is capped at the caller's
- Covers POST /users/{user}/keys/tokens, POST /users/{user}/keys, app auth-redirect, and /oauth2/authorize (invalid_scope on excess grants or a restricted session allow list)
- coder:all sessions, including browser logins, behave as before
- Not addressed: workspace start still mints a coder:all key for the owner
|
||
|
|
e4682343e6 |
feat: match PR number prefixes in chat search (#30404)
Chat search now matches PR numbers by prefix, so typing `3028` already finds the chat for PR `30281` instead of showing zero results mid-typing. The free-text `search:` branch in `GetChats` switches from `pr_number = @search::bigint` to `pr_number::text LIKE @search || '%'`, still guarded by a digits-only regex so the value can never carry LIKE wildcards. The lookup stays a correlated per-chat EXISTS on the `chat_diff_statuses` primary key, which leads with `chat_id`, so the cost is the same as before and no new index is needed. The explicit `pr:` filter stays exact, and ordering is unchanged (no exact-match ranking) so cursor pagination is unaffected. Behavior note: values with leading zeros (`030281`) no longer match PR `30281`, since the old bigint cast normalized them. PR numbers never have leading zeros, so this seemed fine. Closes CODAGT-1342 ## Testing - `TestGetChatsSearch` gains prefix (`4` -> PR 42), no-infix (`2` -> none), and LIKE-wildcard (`4%` -> none) cases; the prefix case fails on the old predicate. - Dogfood UAT through Coder Agents on the branch: searching `3`, `302`, `3028`, `30281` all surface the PR-linked chat; `0281` and `302810` do not; `pr:3028` stays exact. > [!NOTE] > This PR was created by Xum acting on behalf of @ibetitsmike. |
||
|
|
21c1abe9ad |
docs(docs/install): reformat to one sentence per line (#30438)
Reformats every Markdown page under `docs/install` to the [one-sentence-per-line convention](https://github.com/coder/coder/blob/main/docs/.style/style-guide/formatting.md#one-sentence-per-line). Addresses DOCS-668. This is a source-layout change only: 28 of the 36 pages change, and rendered HTML is identical for all of them except three wording fixes. Three pre-existing em dashes sat on reflowed lines, which `lint/emdash` flags as new, so they're rewritten with commas or a sentence break (`operate/upgrade/esr-2.24-2.29-upgrade.md`, `operate/upgrade/best-practices.md`). Front matter, fenced code, tables, HTML blocks, and headings are untouched. `Coder.OneSentencePerLine` is not enabled for `docs/install` in `.vale.ini`: the 39 remaining findings are all table rows or code, which the guide puts out of scope, and enabling the rule would break the zero-baseline doctrine. <details> <summary>Implementation and verification notes</summary> **Approach.** A throwaway script reflowed each paragraph. Bullet items, numbered entries, and blockquote lines (including `> [!NOTE]` callouts) are each their own paragraph; extra sentences in a list item continue on indented lines, matching `docs/.style/content-guidelines.md`. Sentence breaks are never inserted inside inline code, link text, URLs, or HTML tags, and abbreviations such as `e.g.` and `etc.` don't count as sentence ends. Images that started their own source line stay on their own line. The script is idempotent: a second pass produces no changes. **Merge with main.** `main` restructured `docs/install` into plan, prepare, server, validate, and operate sections after this branch was cut. The merge takes `main`'s tree and re-runs the reflow over every page now under `docs/install`, so the branch diff against `main` is reflow only. `releases/index.md` and `releases/feature-stages.md` moved out of `docs/install` on `main` and are no longer in scope. **Verification.** - Rendered every page with `marked` from `main` and from this branch and compared normalized HTML: identical except the three em-dash rewrites. - Vale with `Coder.OneSentencePerLine` forced on for `docs/install`: 277 findings on `main`, 39 on this branch, all in table rows or fenced code. - A broader sweep for mid-line sentence boundaries and for false splits (lines starting lowercase, lines ending in an abbreviation) found no prose hits. - `markdownlint-cli2`, `markdown-table-formatter --check`, `make lint/emdash`, and `make pre-commit-light` pass. </details> --- *Generated by Coder Agents on behalf of @ianjevans.* |
||
|
|
44af8a1b56 |
docs: shorten the add-a-language install script copy and note apt reinstalls (#30376)
The "Add a programming language" guide embedded a full copy of the install script that had drifted from the shipped Template Builder base (it used `grep -q` partial matching, not `has_language`). The Final code tab now shows an abbreviated excerpt (helpers plus the new Ruby branch) so it can't drift again, and Step 4 and the "How does Coder install the language you pick?" section use `has_language ruby`. Also adds a short note in Step 4 that `apt-get` installs Ruby into the ephemeral container, so it reinstalls on every start, while home-directory installs persist. The persistent `~/.local` approach from the ticket is not taught because it never landed on `main` (#28485 was closed unmerged). The `has_language` helper is present in the Template Builder base on `main`. The older example template gets it in #30373. Refs DOCS-713. Generated by Coder Agents on behalf of @nickvigilante. |