Implement the backend for the desktop feature for agents.
- Adds a new `/api/experimental/chats/$id/desktop` endpoint to coderd
which exposes a VNC stream from a
[portabledesktop](https://github.com/coder/portabledesktop) process
running inside the workspace
- Adds a new `spawn_computer_use_agent` tool to chatd, which spawns a
subagent that has access to the `computer` tool which lets it interact
with the `portabledesktop` process running inside the workspace
- Adds the plumbing to make the above possible
There's a follow up frontend PR here:
https://github.com/coder/coder/pull/23006
I keep running into the same couple of issues with subagents:
- when I request code analysis, the main agent tends to spawn subagents
to read files and output them verbatim to the main chat
- when I request to implement a feature, the main agent often spawns
subagents that edit the same files and conflict with one another,
reverting each other's changes.
This PR updates the `spawn_agent` tool description to mitigate those
issues.
## Problem
`TestE2E_WriteFileTriggersGitWatch` and `TestE2E_SubagentAncestorWatch`
flake intermittently in `test-go-race-pg` with:
```
agentgit_test.go:1271: timed out waiting for server message
```
## Root Cause
In `handleWatch()`, `GetPaths(chatID)` was called **before**
`Subscribe(chatID)` on the PathStore. If `AddPaths()` fired between
those two calls:
1. `GetPaths()` returned empty (paths not added yet).
2. `AddPaths()` stored the paths and called `notifySubscribers()` — but
the subscription channel didn't exist yet, so the notification was a
no-op.
3. `Subscribe()` created the channel, but the notification was already
lost.
4. The handler never scanned, and the mock clock never advanced the 30s
fallback ticker → timeout.
Both failing tests connect the WebSocket with an empty PathStore and
immediately call `AddPaths()` from the test goroutine, making them
vulnerable to this scheduling interleaving.
## Fix
Swap the order: call `Subscribe()` first, then `GetPaths()`. This
guarantees:
| `AddPaths` fires... | `Subscribe` sees it? | `GetPaths` sees it? |
Outcome |
|---|---|---|---|
| Before `Subscribe` | No | **Yes** | Picked up by `GetPaths` |
| Between the two calls | **Yes** (queued) | **Yes** | Redundant but
safe (delta dedupes) |
| After `GetPaths` | **Yes** | No | Goroutine handles it |
No window exists where both miss it.
Verified with 10,000 iterations (`-race -count=5000`) — zero failures.
Fixescoder/internal#1389
go-git has bugs in gitignore logic. With more complex gitignores, some
paths that should be ignored aren't. That caused extra, unexpected files
to appear in the git diff panel.
If the git cli isn't available in a workspace, the /git/watch endpoint
will still allow the frontend to connect, but no git changes will ever
be transmitted.
Replaces the single-purpose PR diff right panel with a tabbed sidebar
that shows both the existing PR diff and real-time git repository
changes from the workspace agent.
There's an accompanying backend PR
[here](https://github.com/coder/coder/pull/22565).
https://github.com/user-attachments/assets/bbd53f1c-d753-4574-a159-6dad5989e5e3
## Backend surface
One endpoint drives this feature:
- **`WS /api/experimental/workspaceagents/{id}/git/watch`** —
bidirectional WebSocket. The client sends `refresh` messages; the agent
responds with `changes` messages containing per-repo branch and unified
diff. The workspace agent also automatically pushes changes as they
occur in the workspace.
Adds real-time git status watching for workspace agents, so the frontend
can subscribe over WebSocket and show
git file changes in near real-time.
1. Subscription is scoped to a **chat** via `GET
/api/experimental/chats/{chat}/git/watch`.
2. The workspace agent automatically determines which paths to watch
based on tool calls made by the chat (and its ancestor chats).
3. Workspace agent polls subscribed repo working trees on a 30s
interval, on tools calls, and on explicit `refresh` from the client.
4. Scans are rate-limited to at most once per second.
5. Edited paths are tracked **in-memory** inside the workspace agent.
There is no database persistence — state is lost on agent restart. This
will be addresses in a future PR.
6. Messages sent over WebSocket include a full-repo snapshot (unified
diff, branch, origin). A new message is emitted only when the snapshot
changes.
This PR was implemented with AI with me closely controlling what it's
doing. The code follows a plan file that was updated continuously during
implementation. Here's the file if you'd like to see it:
[project.md](https://gist.github.com/hugodutka/8722cf80c92f8a56555f7bc595b770e2).
It reflects the current state of the PR.
I noticed that our docs mention the possibility of using the
Tailscale-managed DERP server fleet.
https://github.com/coder/coder/pull/15901 changed the phrasing from
> However, Tailscale has graciously allowed us to use
to
> However, our Wireguard integration through Tailscale has graciously
allowed us to use
This change alters the original meaning of the sentence. AFAIK, the
original meant that we contacted Tailscale directly and asked if it
would be ok for our customers to use the Tailscale-managed DERP server
fleet, and Tailscale graciously agreed. The new phrasing conveys
something different. This PR reverts the phrasing to the original.
---------
Co-authored-by: david-fraley <67079030+david-fraley@users.noreply.github.com>
This PR reverts github.com/mark3labs/mcp-go to 0.32.0, which was the
version used by https://github.com/coder/coder/pull/18670 that
introduced MCP HTTP support in Coder, and ensures dependabot doesn't
upgrade it automatically.
A bug has been introduced in a recent version of mcp-go that causes some
HTTP MCP requests to fail with the error message
```
[erro] coderd.mcp: Failed to handle sampling response: no active session found for session mcp-session-e3cb7333-284f-46bd-a009-d611f1b690f6
```
The bug may be related to this issue:
https://github.com/mark3labs/mcp-go/issues/554.
This PR starts running the full test suite on Windows and macOS in the
nightly gauntlet, since the regular CI only runs agent and cli tests.
The full suite is too slow to be run on every PR.
Previously, we displayed apps in iframes on the task page without
waiting for them to initialize. This would result in 502 errors shown to
the user. This PR makes sure that we only display the app after it
initializes.
### Before
<img width="1920" alt="Screenshot 2025-06-30 at 14 59 07 (2)"
src="https://github.com/user-attachments/assets/63564ac9-abce-4a0c-b58e-b988772fae82"
/>
Use the `/workspaces?q=has-ai-task=true`,
`/templates?q=has-ai-task=true` and `/aitasks/prompts` endpoints to
fetch Task templates and workspaces on the `/tasks` page.
Also:
- remove documentation link placeholders: the documentation is not in
place yet and is not going to be available before the June 24th code
freeze
- load workspaces and templates in parallel
- replace loading spinners with content skeletons
Related to https://github.com/coder/coder/issues/18454 and
https://github.com/coder/internal/issues/660.
Add an endpoint to fetch AI task prompts for multiple workspace builds
at the same time. A prompt is the value of the "AI Prompt" workspace
build parameter. On main, the only way our API allows fetching workspace
build parameters is by using the `/workspacebuilds/$build_id/parameters`
endpoint, requiring a separate API call for every build.
The Tasks dashboard fetches Task workspaces in order to show them in a
list, and then needs to fetch the value of the `AI Prompt` parameter for
every task workspace (using its latest build id), requiring an
additional API call for each list item. This endpoint will allow the
dashboard to make just 2 calls to render the list: one to fetch task
workspaces, the other to fetch prompts.
<img width="1512" alt="Screenshot 2025-06-20 at 11 33 11"
src="https://github.com/user-attachments/assets/92899999-e922-44c5-8325-b4b23a0d2bff"
/>
Related to https://github.com/coder/internal/issues/660.
The fields must be nullable because there’s a period of time between
inserting a row into the database and finishing the “plan” provisioner
job when the final value of the field is unknown.
Adds database migrations required for the Tasks feature.
There's a slight difference between the migrations in this PR and the
RFC: this PR adds `NOT NULL` constraints to the `has_ai_task` columns.
It was an oversight on my part when I wrote the RFC - I assumed the
`DEFAULT FALSE` value would make the columns implicitly NOT NULL, but
that's not the case with Postgres. We have no use for the NULL value.
The `DEFAULT FALSE` statement ensures that the migration will pass even
when there are existing rows in the template version and workspace
builds tables, so there's no danger in adding the `NOT NULL`
constraints.
- hardcode a custom pathname (`/chat/embed`) to use in the sidebar
iframe. this is a temporary fix so that the agentapi chat displays
properly
- make the sidebar a bit wider so that the chat fits without line
wrapping
<img width="1512" alt="Screenshot 2025-06-04 at 15 32 30"
src="https://github.com/user-attachments/assets/8be5d053-d7b3-40da-8b62-a6151975527d"
/>
Related to https://github.com/coder/coder/issues/15109.
Running postgres tests used to create a new postgres docker container
every time. I believe the slow down might've been caused by that and was
misattributed to postgres performance.
```
coder@main ~/coder ((0e90ac29))> DB=ci gotestsum --packages="./coderd/idpsync" -- -count=1
✓ coderd/idpsync (1.471s)
DONE 91 tests in 4.766s
```
This PR starts running test-go-pg on macOS and Windows in regular CI.
Previously this suite was only run in the nightly gauntlet for 2
reasons:
- it was flaky
- it was slow (took 17 minutes)
We've since stabilized the flakiness by switching to depot runners,
using ram disks, optimizing the number of tests run in parallel, and
automatically re-running failing tests. We've also [brought
down](https://github.com/coder/coder/pull/17756) the time to run the
suite to 9 minutes. Additionally, this PR allows test-go-pg to use cache
from previous runs, which speeds it up further. The cache is only used
on PRs, `main` will still run tests without it.
This PR also:
- removes the nightly gauntlet since all tests now run in regular CI
- removes the `test-cli` job for the same reason
- removes the `setup-imdisk` action which is now fully replaced by
[coder/setup-ramdisk-action](https://github.com/coder/setup-ramdisk-action)
- makes 2 minor changes which could be separate PRs, but I rolled them
into this because they were helpful when iterating on it:
- replace the `if: always()` condition on the `gen` job with a `if: ${{
!cancelled() }}` to allow the job to be cancelled. Previously the job
would run to completion even if the entire workflow was cancelled. See
[the GitHub
docs](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#always)
for more details.
- disable the recently added `TestReinitializeAgent` since it does not
pass on Windows with Postgres. There's an open issue to fix it:
https://github.com/coder/internal/issues/642
This PR will:
- unblock https://github.com/coder/coder/issues/15109
- alleviate https://github.com/coder/internal/issues/647
I tested caching by temporarily enabling cache upload on this PR: here's
[a
run](https://github.com/coder/coder/actions/runs/15119046903/job/42496939341?pr=17853#step:13:1296)
showing cache being used.
This PR ensures that waits on channels will time out according to the
test context, rather than waiting indefinitely. This should alleviate
the panic seen in https://github.com/coder/internal/issues/645 and, if
the deadlock recurs, allow the test to be retried automatically in CI.
This PR introduces failing test retries in CI for e2e tests, Go tests
with the in-memory database, Go tests with Postgres, and the CLI tests.
Retries are not enabled for race tests.
The goal is to reduce how often flakes disrupt developers' workflows.
This PR speeds up the "Upload tests to datadog" step by downloading the
`datadog-ci` binary directly from GitHub releases. Most of the time used
to be spent in `npm install`, which consistently timed out on Windows
after a minute. [Now it takes 3
seconds](https://github.com/coder/coder/actions/runs/14834976784/job/41644230049?pr=17668#step:10:1).
I updated it to version v2.48.0 because v2.21.0 didn't have the
artifacts for arm64 macOS.
This PR focuses on optimizing go-test CI times on Windows. It:
- backs the `$RUNNER_TEMP` directory with a RAM disk. This directory is
used by actions like cache, setup-go, and setup-terraform as a staging
area
- backs `GOCACHE`, `GOMODCACHE`, and `GOPATH` with a RAM disk
- backs `$GITHUB_WORKSPACE` with a RAM disk - that's where the
repository is checked out
- uses preinstalled Go on Windows runners
- starts using the depot Windows runner
From what I've seen, these changes bring test times down to be on par
with Linux and macOS. The biggest improvement comes from backing
frequently accessed paths with RAM disks. The C drive is surprisingly
slow - I ran some performance tests with
[fio](https://fio.readthedocs.io/en/latest/fio_doc.html#) where I tested
IOPS on many small files, and the RAM disk was 100x faster.
Additionally, the depot runners seem to have more consistent performance
than the ones provided by GitHub.
Addresses https://github.com/coder/internal/issues/322.
This PR starts caching Terraform providers used by `TestProvision` in
`provisioner/terraform/provision_test.go`. The goal is to improve the
reliability of this test by cutting down on the number of network calls
to external services. It leverages GitHub Actions cache, which [on depot
runners is persisted for 14 days by
default](https://depot.dev/docs/github-actions/overview#cache-retention-policy).
Other than the aforementioned `TestProvision`, I couldn't find any other
tests which depend on external terraform providers.
Dependabot recently upgraded `coder/start-workspace-action` to the
latest version. Compared to the version we were using previously, the
new version expects a different configuration.
There's a flake reported in https://github.com/coder/internal/issues/549
that was caused by the built-in Postgres failing to start. However, the
test was written in a way that didn't log the actual error which caused
Postgres to fail. This PR improves error logging in the affected test so
that the next time the error happens, we know what it is.
The [OAuth2
specification](https://datatracker.ietf.org/doc/html/rfc8628) describes
how clients in the device flow should handle retrying requests when they
are rate limited.
We didn't respect it, which sometimes prevented users from logging in or
setting up external auth. They'd see a `slow_down` error in the UI and
would be unable to complete the authentication flow. This PR implements
rate limit handling according to the spec.
Add the `--github-user-id` option to `coder users list`, which makes the
command only return users with a matching GitHub user id. This will
enable https://github.com/coder/start-workspace-action to find a Coder
user that corresponds to a GitHub user requesting to start a workspace.
The workflow triggers when an issue is created or a comment is posted.
If the string "@coder" appears in the body of the issue or comment, a
Coder workspace owned by the issue creator or commentator will be
created with the parameters specified in the workflow.
Addresses https://github.com/coder/nexus/issues/195. Specifically, just
the "tracking templates" requirement:
> ## Tracking in templates
> To enable resource alerts, a user must add the resource_monitoring
block to a template's coder_agent resource. We'd like to track if
customers have any resource monitoring enabled on a per-deployment
basis. Even better, we could identify which templates are using resource
monitoring.
This PR fixes 2 bugs:
## Problem 1
The server would fail to start when the default github provider was
configured and the flag `--oauth2-github-allowed-orgs` was set. The
error was
```
error: configure github oauth2: allow everyone and allowed orgs cannot be used together
```
This PR fixes it by enabling "allow everone" with the default provider
only if "allowed orgs" isn't set.
## Problem 2
The default github provider uses the device flow to authorize users, and
that's handled differently by our web UI than the standard oauth flow.
In particular, the web UI only handles JSON responses rather than HTTP
redirects. There were 2 code paths that returned redirects, and the PR
changes them to return JSON messages instead if the device flow is
configured.
For production deployments we recommend disabling the default GitHub
OAuth2 app managed by Coder. This PR mentions it in k8s installation
docs and the helm README so users can stumble upon it more easily.
## Changes
1. Update the `0.0.0.0:3001` web UI address to `localhost:3000`. Coder
starts on port 3000 by default. It'd use 3001 only if 3000 was already
taken.
2. Update the screenshot of the `/setup` page to reflect how it will
look like after merging https://github.com/coder/coder/pull/16662. Note:
this PR should be merged only after the other one is.
3. Minor phrasing changes.
---------
Co-authored-by: EdwardAngert <17991901+EdwardAngert@users.noreply.github.com>
Third and final PR to address
https://github.com/coder/coder/issues/16230.
This PR enables GitHub OAuth2 login by default on new deployments.
Combined with https://github.com/coder/coder/pull/16629, this will allow
the first admin user to sign up with GitHub rather than email and
password.
We take care not to enable the default on deployments that would upgrade
to a Coder version with this change.
To disable the default provider an admin can set the
`CODER_OAUTH2_GITHUB_DEFAULT_PROVIDER` env variable to false.