diff --git a/.icons/parsec.svg b/.icons/parsec.svg
new file mode 100644
index 000000000..3c88e320d
--- /dev/null
+++ b/.icons/parsec.svg
@@ -0,0 +1,5 @@
+
diff --git a/registry/coder/modules/parsec/README.md b/registry/coder/modules/parsec/README.md
new file mode 100644
index 000000000..93b9351bc
--- /dev/null
+++ b/registry/coder/modules/parsec/README.md
@@ -0,0 +1,160 @@
+---
+display_name: Parsec
+description: Install Parsec for low-latency cloud gaming and remote desktop on Windows workspaces
+icon: ../../../../.icons/parsec.svg
+verified: false
+tags: [windows, gaming, streaming, remote-desktop]
+---
+
+# Parsec
+
+Enable [Parsec](https://parsec.app/) for low-latency cloud gaming and remote desktop access on Windows workspaces. Parsec provides high-performance streaming with support for 4K, 60fps, and low-latency input.
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+}
+```
+
+## Features
+
+- **Low-latency streaming**: Sub-16ms latency for responsive gaming and productivity
+- **High quality video**: Up to 4K resolution at 60fps
+- **GPU acceleration**: Hardware encoding for smooth performance
+- **Multi-monitor support**: Virtual monitors for cloud workspaces
+- **Teams support**: Enterprise deployment with team computer keys
+
+## Requirements
+
+- Windows workspace with GPU support (recommended)
+- Parsec account (free tier available)
+- Parsec client installed on your local machine
+
+## Examples
+
+### Basic Installation
+
+Install Parsec with default settings:
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+}
+```
+
+### With Custom Hostname
+
+Set a custom hostname for easier identification:
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+ host_name = "my-gaming-workspace"
+}
+```
+
+### Parsec Teams Deployment
+
+For enterprise/team deployments with automated authentication:
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+ parsec_team_id = var.parsec_team_id
+ parsec_team_key = var.parsec_team_key
+}
+```
+
+### AWS Windows Template
+
+Complete example with AWS Windows instance:
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+}
+
+# Recommended: Use GPU instance types like g4dn.xlarge for best performance
+```
+
+### GCP Windows Template
+
+Complete example with Google Cloud Windows instance:
+
+```tf
+module "parsec" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/coder/parsec/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.main.id
+}
+
+# Recommended: Use N1 with NVIDIA T4 GPU for best performance
+```
+
+## Connecting to Your Workspace
+
+1. **Install Parsec client** on your local machine from [parsec.app/downloads](https://parsec.app/downloads)
+2. **Log in** to your Parsec account (same account as the workspace or Teams account)
+3. **Find your workspace** in the Parsec computer list
+4. **Click Connect** to start streaming
+
+## Configuration Options
+
+| Variable | Description | Default |
+| ----------------- | ------------------------------------------- | -------------------- |
+| `agent_id` | The ID of a Coder agent | Required |
+| `display_name` | Display name for the Parsec app | `"Parsec"` |
+| `slug` | Slug for the Parsec app | `"parsec"` |
+| `icon` | Icon path | `"/icon/parsec.svg"` |
+| `order` | App order in UI | `null` |
+| `group` | App group name | `null` |
+| `parsec_team_id` | Parsec Team ID for enterprise deployments | `""` |
+| `parsec_team_key` | Parsec Team Computer Key for authentication | `""` |
+| `host_name` | Custom hostname for the Parsec host | Workspace name |
+| `auto_start` | Start Parsec service automatically | `true` |
+
+## GPU Recommendations
+
+For the best cloud gaming experience, use instances with dedicated GPUs:
+
+| Cloud Provider | Recommended Instance Types |
+| -------------- | -------------------------- |
+| AWS | g4dn.xlarge, g5.xlarge |
+| GCP | n1-standard-4 + NVIDIA T4 |
+| Azure | Standard_NV6 |
+
+## Troubleshooting
+
+### Parsec not starting
+
+- Ensure the workspace has GPU drivers installed
+- Check Windows Event Viewer for Parsec service errors
+- Verify network allows UDP traffic on ports 8000-8200
+
+### High latency
+
+- Use an instance in a region close to you
+- Ensure hardware encoding is enabled (requires GPU)
+- Check network quality between client and workspace
+
+### Computer not appearing in Parsec
+
+- Wait 1-2 minutes after workspace starts
+- Verify Parsec service is running: `Get-Service parsec`
+- Check Parsec logs in `%APPDATA%\Parsec\logs`
diff --git a/registry/coder/modules/parsec/install-parsec.ps1 b/registry/coder/modules/parsec/install-parsec.ps1
new file mode 100644
index 000000000..7f9d4a69c
--- /dev/null
+++ b/registry/coder/modules/parsec/install-parsec.ps1
@@ -0,0 +1,153 @@
+# Parsec Installation Script for Coder Workspaces
+# This script installs and configures Parsec for cloud gaming and remote desktop
+
+$ErrorActionPreference = "Stop"
+
+Write-Output "=== Installing Parsec for Coder Workspace ==="
+
+# Configuration from Terraform variables
+$ParsecTeamId = "${parsec_team_id}"
+$ParsecTeamKey = "${parsec_team_key}"
+$HostName = "${host_name}"
+$AutoStart = [System.Convert]::ToBoolean("${auto_start}")
+
+# Parsec download URL and paths
+$ParsecMsiUrl = "https://builds.parsec.app/package/parsec-windows.msi"
+$ParsecInstallDir = "$env:ProgramFiles\Parsec"
+$TempDir = "$env:TEMP\parsec-install"
+$ParsecMsiPath = "$TempDir\parsec-windows.msi"
+
+# Create temp directory
+if (-not (Test-Path $TempDir)) {
+ New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
+}
+
+# Check if Parsec is already installed
+$ParsecInstalled = Test-Path "$ParsecInstallDir\parsecd.exe"
+
+if (-not $ParsecInstalled) {
+ Write-Output "Downloading Parsec..."
+
+ # Download Parsec MSI
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ try {
+ Invoke-WebRequest -Uri $ParsecMsiUrl -OutFile $ParsecMsiPath -UseBasicParsing
+ } catch {
+ Write-Error "Failed to download Parsec: $_"
+ exit 1
+ }
+
+ Write-Output "Installing Parsec..."
+
+ # Install Parsec silently
+ $InstallArgs = @(
+ "/i"
+ "`"$ParsecMsiPath`""
+ "/qn"
+ "/norestart"
+ "ALLUSERS=1"
+ )
+
+ $InstallProcess = Start-Process -FilePath "msiexec.exe" -ArgumentList $InstallArgs -Wait -PassThru
+
+ if ($InstallProcess.ExitCode -ne 0) {
+ Write-Error "Parsec installation failed with exit code: $($InstallProcess.ExitCode)"
+ exit 1
+ }
+
+ Write-Output "Parsec installed successfully."
+} else {
+ Write-Output "Parsec is already installed."
+}
+
+# Configure Parsec for headless/team deployment if credentials provided
+$ParsecConfigDir = "$env:APPDATA\Parsec"
+$ParsecConfigFile = "$ParsecConfigDir\config.txt"
+
+if (-not (Test-Path $ParsecConfigDir)) {
+ New-Item -ItemType Directory -Path $ParsecConfigDir -Force | Out-Null
+}
+
+# Build configuration
+$ConfigLines = @()
+
+# Set hostname if provided
+if ($HostName -ne "") {
+ $ConfigLines += "host_name = $HostName"
+ Write-Output "Setting Parsec host name to: $HostName"
+}
+
+# Enable hosting
+$ConfigLines += "host_virtual_monitors = 1"
+$ConfigLines += "host_privacy_mode = 0"
+
+# Write config if we have any settings
+if ($ConfigLines.Count -gt 0) {
+ # Read existing config if present
+ $ExistingConfig = @()
+ if (Test-Path $ParsecConfigFile) {
+ $ExistingConfig = Get-Content $ParsecConfigFile
+ }
+
+ # Merge configs (new values override existing)
+ $ConfigHash = @{}
+ foreach ($line in $ExistingConfig) {
+ if ($line -match "^([^=]+)=(.*)$") {
+ $ConfigHash[$Matches[1].Trim()] = $Matches[2].Trim()
+ }
+ }
+ foreach ($line in $ConfigLines) {
+ if ($line -match "^([^=]+)=(.*)$") {
+ $ConfigHash[$Matches[1].Trim()] = $Matches[2].Trim()
+ }
+ }
+
+ # Write merged config
+ $FinalConfig = $ConfigHash.GetEnumerator() | ForEach-Object { "$($_.Key) = $($_.Value)" }
+ $FinalConfig | Out-File -FilePath $ParsecConfigFile -Encoding UTF8
+
+ Write-Output "Parsec configuration updated."
+}
+
+# Configure for Parsec Teams if credentials provided
+if ($ParsecTeamId -ne "" -and $ParsecTeamKey -ne "") {
+ Write-Output "Configuring Parsec Teams authentication..."
+
+ # For Parsec Teams, we need to configure the team computer key
+ $TeamConfigFile = "$ParsecConfigDir\team_config.txt"
+ @"
+team_id = $ParsecTeamId
+team_computer_key = $ParsecTeamKey
+"@ | Out-File -FilePath $TeamConfigFile -Encoding UTF8
+
+ Write-Output "Parsec Teams configuration saved."
+}
+
+# Start Parsec if auto_start is enabled
+if ($AutoStart) {
+ Write-Output "Starting Parsec..."
+
+ $ParsecExe = "$ParsecInstallDir\parsecd.exe"
+
+ if (Test-Path $ParsecExe) {
+ # Start Parsec in the background
+ Start-Process -FilePath $ParsecExe -WindowStyle Hidden
+ Write-Output "Parsec started successfully."
+ } else {
+ Write-Warning "Parsec executable not found at: $ParsecExe"
+ }
+}
+
+# Cleanup
+if (Test-Path $TempDir) {
+ Remove-Item -Path $TempDir -Recurse -Force -ErrorAction SilentlyContinue
+}
+
+Write-Output "=== Parsec installation complete ==="
+Write-Output ""
+Write-Output "To connect to this workspace:"
+Write-Output "1. Install Parsec client on your local machine: https://parsec.app/downloads"
+Write-Output "2. Log in to your Parsec account"
+Write-Output "3. This computer will appear in your Parsec computer list"
+Write-Output ""
+Write-Output "For Teams deployment, ensure you have configured team_id and team_computer_key."
diff --git a/registry/coder/modules/parsec/main.test.ts b/registry/coder/modules/parsec/main.test.ts
new file mode 100644
index 000000000..9e89679ac
--- /dev/null
+++ b/registry/coder/modules/parsec/main.test.ts
@@ -0,0 +1,177 @@
+import { describe, expect, it } from "bun:test";
+import {
+ type TerraformState,
+ runTerraformApply,
+ runTerraformInit,
+ testRequiredVariables,
+} from "~test";
+
+type TestVariables = Readonly<{
+ agent_id: string;
+ display_name?: string;
+ slug?: string;
+ icon?: string;
+ order?: number;
+ group?: string;
+ parsec_team_id?: string;
+ parsec_team_key?: string;
+ host_name?: string;
+ auto_start?: boolean;
+}>;
+
+function findParsecScript(state: TerraformState): string | null {
+ for (const resource of state.resources) {
+ const isParsecScriptResource =
+ resource.type === "coder_script" && resource.name === "parsec";
+
+ if (!isParsecScriptResource) {
+ continue;
+ }
+
+ for (const instance of resource.instances) {
+ if (
+ instance.attributes.display_name === "Parsec" &&
+ typeof instance.attributes.script === "string"
+ ) {
+ return instance.attributes.script;
+ }
+ }
+ }
+
+ return null;
+}
+
+function findParsecApp(
+ state: TerraformState,
+ appName: string = "parsec",
+): Record | null {
+ for (const resource of state.resources) {
+ if (resource.type === "coder_app" && resource.name === appName) {
+ for (const instance of resource.instances) {
+ return instance.attributes;
+ }
+ }
+ }
+ return null;
+}
+
+describe("Parsec Module", async () => {
+ await runTerraformInit(import.meta.dir);
+
+ testRequiredVariables(import.meta.dir, {
+ agent_id: "test-agent-id",
+ });
+
+ it("Has the PowerShell script download and install Parsec", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ });
+
+ const script = findParsecScript(state);
+ expect(script).toBeString();
+ expect(script).toContain(
+ "https://builds.parsec.app/package/parsec-windows.msi",
+ );
+ expect(script).toContain("msiexec.exe");
+ expect(script).toContain("Parsec installed successfully");
+ });
+
+ it("Creates external Parsec app link", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ });
+
+ const app = findParsecApp(state, "parsec");
+ expect(app).not.toBeNull();
+ expect(app?.display_name).toBe("Parsec");
+ expect(app?.url).toBe("https://web.parsec.app/");
+ expect(app?.external).toBe(true);
+ });
+
+ it("Creates Parsec docs app link", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ });
+
+ const app = findParsecApp(state, "parsec-docs");
+ expect(app).not.toBeNull();
+ expect(app?.display_name).toBe("Parsec Docs");
+ expect(app?.url).toBe("https://support.parsec.app/hc/en-us");
+ expect(app?.external).toBe(true);
+ });
+
+ it("Configures custom hostname when provided", async () => {
+ const customHostname = "my-gaming-pc";
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ host_name: customHostname,
+ });
+
+ const script = findParsecScript(state);
+ expect(script).toBeString();
+ expect(script).toContain(`$HostName = "${customHostname}"`);
+ expect(script).toContain(`host_name = ${customHostname}`);
+ });
+
+ it("Configures Parsec Teams credentials when provided", async () => {
+ const teamId = "team-12345";
+ const teamKey = "secret-key-abc";
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ parsec_team_id: teamId,
+ parsec_team_key: teamKey,
+ });
+
+ const script = findParsecScript(state);
+ expect(script).toBeString();
+ expect(script).toContain(`$ParsecTeamId = "${teamId}"`);
+ expect(script).toContain(`$ParsecTeamKey = "${teamKey}"`);
+ expect(script).toContain("Configuring Parsec Teams authentication");
+ });
+
+ it("Supports custom display name and slug", async () => {
+ const customDisplayName = "Cloud Gaming";
+ const customSlug = "cloud-gaming";
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "test-agent-id",
+ display_name: customDisplayName,
+ slug: customSlug,
+ });
+
+ const app = findParsecApp(state, "parsec");
+ expect(app).not.toBeNull();
+ expect(app?.display_name).toBe(customDisplayName);
+ expect(app?.slug).toBe(customSlug);
+ });
+
+ it("Configures auto_start behavior", async () => {
+ // Test with auto_start enabled (default)
+ const stateAutoStart = await runTerraformApply(
+ import.meta.dir,
+ {
+ agent_id: "test-agent-id",
+ auto_start: true,
+ },
+ );
+
+ const scriptAutoStart = findParsecScript(stateAutoStart);
+ expect(scriptAutoStart).toContain(
+ '$AutoStart = [System.Convert]::ToBoolean("true")',
+ );
+ expect(scriptAutoStart).toContain("Starting Parsec...");
+
+ // Test with auto_start disabled
+ const stateNoAutoStart = await runTerraformApply(
+ import.meta.dir,
+ {
+ agent_id: "test-agent-id",
+ auto_start: false,
+ },
+ );
+
+ const scriptNoAutoStart = findParsecScript(stateNoAutoStart);
+ expect(scriptNoAutoStart).toContain(
+ '$AutoStart = [System.Convert]::ToBoolean("false")',
+ );
+ });
+});
diff --git a/registry/coder/modules/parsec/main.tf b/registry/coder/modules/parsec/main.tf
new file mode 100644
index 000000000..f21711da6
--- /dev/null
+++ b/registry/coder/modules/parsec/main.tf
@@ -0,0 +1,112 @@
+terraform {
+ required_version = ">= 1.0"
+
+ required_providers {
+ coder = {
+ source = "coder/coder"
+ version = ">= 2.5"
+ }
+ }
+}
+
+variable "agent_id" {
+ type = string
+ description = "The ID of a Coder agent."
+}
+
+variable "display_name" {
+ type = string
+ description = "The display name for the Parsec application."
+ default = "Parsec"
+}
+
+variable "slug" {
+ type = string
+ description = "The slug for the Parsec application."
+ default = "parsec"
+}
+
+variable "icon" {
+ type = string
+ description = "The icon for the Parsec application."
+ default = "/icon/parsec.svg"
+}
+
+variable "order" {
+ type = number
+ description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
+ default = null
+}
+
+variable "group" {
+ type = string
+ description = "The name of a group that this app belongs to."
+ default = null
+}
+
+variable "parsec_team_id" {
+ type = string
+ description = "Parsec Team ID for enterprise/team deployments. Leave empty for personal use."
+ default = ""
+}
+
+variable "parsec_team_key" {
+ type = string
+ description = "Parsec Team Computer Key for headless authentication. Required for automated deployments."
+ default = ""
+ sensitive = true
+}
+
+variable "host_name" {
+ type = string
+ description = "Custom hostname for the Parsec host. Defaults to workspace name."
+ default = ""
+}
+
+variable "auto_start" {
+ type = bool
+ description = "Automatically start Parsec service after installation."
+ default = true
+}
+
+resource "coder_script" "parsec" {
+ agent_id = var.agent_id
+ display_name = "Parsec"
+ icon = var.icon
+
+ script = templatefile("${path.module}/install-parsec.ps1", {
+ parsec_team_id = var.parsec_team_id
+ parsec_team_key = var.parsec_team_key
+ host_name = var.host_name
+ auto_start = var.auto_start
+ })
+
+ run_on_start = true
+}
+
+resource "coder_app" "parsec" {
+ agent_id = var.agent_id
+ slug = var.slug
+ display_name = var.display_name
+ url = "https://web.parsec.app/"
+ icon = var.icon
+ external = true
+ order = var.order
+ group = var.group
+}
+
+resource "coder_app" "parsec-docs" {
+ agent_id = var.agent_id
+ display_name = "Parsec Docs"
+ slug = "parsec-docs"
+ icon = "/icon/book.svg"
+ url = "https://support.parsec.app/hc/en-us"
+ external = true
+}
+
+data "coder_workspace" "me" {}
+
+output "host_name" {
+ description = "The hostname configured for this Parsec host"
+ value = var.host_name != "" ? var.host_name : data.coder_workspace.me.name
+}
diff --git a/registry/coder/modules/parsec/parsec.tftest.hcl b/registry/coder/modules/parsec/parsec.tftest.hcl
new file mode 100644
index 000000000..565bf8181
--- /dev/null
+++ b/registry/coder/modules/parsec/parsec.tftest.hcl
@@ -0,0 +1,97 @@
+# Test that the module initializes correctly with required variables
+run "parsec_basic_test" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+
+ assert {
+ condition = coder_script.parsec.display_name == "Parsec"
+ error_message = "Parsec script display name should be 'Parsec'"
+ }
+
+ assert {
+ condition = coder_script.parsec.run_on_start == true
+ error_message = "Parsec script should run on start"
+ }
+
+ assert {
+ condition = coder_app.parsec.display_name == "Parsec"
+ error_message = "Parsec app display name should be 'Parsec'"
+ }
+
+ assert {
+ condition = coder_app.parsec.external == true
+ error_message = "Parsec app should be external"
+ }
+
+ assert {
+ condition = coder_app.parsec.url == "https://web.parsec.app/"
+ error_message = "Parsec app URL should be https://web.parsec.app/"
+ }
+}
+
+# Test custom display name and slug
+run "parsec_custom_name_test" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ display_name = "Cloud Gaming"
+ slug = "cloud-gaming"
+ }
+
+ assert {
+ condition = coder_app.parsec.display_name == "Cloud Gaming"
+ error_message = "Custom display name should be applied"
+ }
+
+ assert {
+ condition = coder_app.parsec.slug == "cloud-gaming"
+ error_message = "Custom slug should be applied"
+ }
+}
+
+# Test that docs app is created
+run "parsec_docs_app_test" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+
+ assert {
+ condition = coder_app.parsec-docs.display_name == "Parsec Docs"
+ error_message = "Parsec docs app should be created"
+ }
+
+ assert {
+ condition = coder_app.parsec-docs.url == "https://support.parsec.app/hc/en-us"
+ error_message = "Parsec docs URL should point to support site"
+ }
+
+ assert {
+ condition = coder_app.parsec-docs.external == true
+ error_message = "Parsec docs app should be external"
+ }
+}
+
+# Test default values
+run "parsec_defaults_test" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+
+ assert {
+ condition = coder_app.parsec.slug == "parsec"
+ error_message = "Default slug should be 'parsec'"
+ }
+
+ assert {
+ condition = coder_app.parsec.icon == "/icon/parsec.svg"
+ error_message = "Default icon should be /icon/parsec.svg"
+ }
+}