Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b66aead
feat: basic tmux module
35C4n0r Jul 14, 2025
3e894dc
fix: echo statements
35C4n0r Jul 14, 2025
b3680df
feat: replace echo with printf
35C4n0r Jul 14, 2025
9d735c8
feat: add test
35C4n0r Jul 14, 2025
b27641f
feat: update readme and format
35C4n0r Jul 14, 2025
f36ce27
feat: update readme
35C4n0r Jul 14, 2025
25857a4
Merge branch 'main' into feat-tmux
35C4n0r Jul 14, 2025
8b05a5d
feat: update readme
35C4n0r Jul 14, 2025
c031c3b
Merge branch 'main' into feat-tmux
35C4n0r Jul 14, 2025
dac1878
ci: bun fmt
35C4n0r Jul 14, 2025
200d922
Merge remote-tracking branch 'origin/feat-tmux' into feat-tmux
35C4n0r Jul 14, 2025
a06d185
Merge branch 'main' into feat-tmux
35C4n0r Jul 16, 2025
427586d
feat: add frontmatter
35C4n0r Jul 16, 2025
cf8014f
feat: add tmux svg
35C4n0r Jul 16, 2025
26e4c12
Merge branch 'main' into feat-tmux
35C4n0r Jul 18, 2025
d9f8c95
feat: update readme
35C4n0r Jul 19, 2025
0c243cc
feat: start.sh
35C4n0r Jul 22, 2025
a1b4848
feat: enhance tmux session management and configuration
35C4n0r Jul 22, 2025
6d0c19d
feat: add multi-session support for tmux in Coder UI
35C4n0r Jul 22, 2025
306bec1
Merge branch 'main' into feat-tmux
35C4n0r Jul 22, 2025
9f32bd5
docs: change NOTE to IMPORTANT and add tmux icon
35C4n0r Jul 24, 2025
8c0e7b3
Merge branch 'main' into feat-tmux
35C4n0r Jul 24, 2025
c82fe73
docs: update README with module source and example for tmux
35C4n0r Jul 24, 2025
41c8636
fix: add versions
35C4n0r Jul 24, 2025
fddc6ea
fix: fix README.md
35C4n0r Jul 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,6 @@ dist

# Generated credentials from google-github-actions/auth
gha-creds-*.json

# IDEs
.idea
18 changes: 18 additions & 0 deletions .icons/tmux.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added registry/anomaly/.images/avatar.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions registry/anomaly/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
display_name: "Jay Kumar"
bio: "I'm a Software Engineer :)"
avatar_url: "./.images/avatar.png"
github: "35C4n0r"
linkedin: "https://www.linkedin.com/in/jaykum4r"
support_email: "work.jaykumar@gmail.com"
status: "community"
---

# Your Name

I'm a Software Engineer :)
91 changes: 91 additions & 0 deletions registry/anomaly/modules/tmux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
display_name: "Tmux"
description: "Tmux for coder agent :)"
icon: "../../../../.icons/tmux.svg"
verified: false
tags: ["tmux", "terminal", "persistent"]
---

# tmux

This module provisions and configures [tmux](https://github.com/tmux/tmux) with session persistence and plugin support
for a Coder agent. It automatically installs tmux, the Tmux Plugin Manager (TPM), and a set of useful plugins, and sets
up a default or custom tmux configuration with session save/restore capabilities.

## Features

- Installs tmux if not already present
- Installs TPM (Tmux Plugin Manager)
- Configures tmux with plugins for sensible defaults, session persistence, and automation:
- `tmux-plugins/tpm`
- `tmux-plugins/tmux-sensible`
- `tmux-plugins/tmux-resurrect`
- `tmux-plugins/tmux-continuum`
- Supports custom tmux configuration
- Enables automatic session save
- Configurable save interval
- **Supports multiple named tmux sessions, each as a separate app in the Coder UI**

## Usage

```tf
module "tmux" {
source = "path/to/this/module"
agent_id = coder_agent.example.id
tmux_config = "" # Optional: custom tmux.conf content
save_interval = 1 # Optional: save interval in minutes
sessions = ["default", "dev", "ops"] # Optional: list of tmux sessions
order = 1 # Optional: UI order
group = "Terminal" # Optional: UI group
icon = "/icon/tmux.svg" # Optional: app icon
}
```

## Multi-Session Support

This module can provision multiple tmux sessions, each as a separate app in the Coder UI. Use the `sessions` variable to specify a list of session names. For each session, a `coder_app` is created, allowing you to launch or attach to that session directly from the UI.

- **sessions**: List of tmux session names (default: `["default"]`).

## How It Works

- **tmux Installation:**
- Checks if tmux is installed; if not, installs it using the system's package manager (supports apt, yum, dnf,
zypper, apk, brew).
- **TPM Installation:**
- Installs the Tmux Plugin Manager (TPM) to `~/.tmux/plugins/tpm` if not already present.
- **tmux Configuration:**
- If `tmux_config` is provided, writes it to `~/.tmux.conf`.
- Otherwise, generates a default configuration with plugin support and session persistence (using tmux-resurrect and
tmux-continuum).
- Sets up key bindings for quick session save (`Ctrl+s`) and restore (`Ctrl+r`).
- **Plugin Installation:**
- Installs plugins via TPM.
- **Session Persistence:**
- Enables automatic session save/restore at the configured interval.

## Example

```tf
module "tmux" {
source = "./registry/anomaly/modules/tmux"
agent_id = var.agent_id
sessions = ["default", "dev", "anomaly"]
tmux_config = <<-EOT
set -g mouse on
set -g history-limit 10000
EOT
group = "Terminal"
order = 2
}
```

> [!NOTE]
>
> - If you provide a custom `tmux_config`, it will completely replace the default configuration. Ensure you include plugin
> and TPM initialization lines if you want plugin support and session persistence.
> - The script will attempt to install dependencies using `sudo` where required.
> - If `git` is not installed, TPM installation will fail.
> - If you are using custom config, you'll be responsible for setting up persistence and plugins.
> - The `order`, `group`, and `icon` variables allow you to customize how tmux apps appear in the Coder UI.
> - In case of session restart or shh reconnection, the tmux session will be automatically restored :)
35 changes: 35 additions & 0 deletions registry/anomaly/modules/tmux/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, it, expect } from "bun:test";
import {
runTerraformApply,
runTerraformInit,
testRequiredVariables,
findResourceInstance,
} from "~test";
import path from "path";

const moduleDir = path.resolve(__dirname);

const requiredVars = {
agent_id: "dummy-agent-id",
};

describe("tmux module", async () => {
await runTerraformInit(moduleDir);

// 1. Required variables
testRequiredVariables(moduleDir, requiredVars);

// 2. coder_script resource is created
it("creates coder_script resource", async () => {
const state = await runTerraformApply(moduleDir, requiredVars);
const scriptResource = findResourceInstance(state, "coder_script");
expect(scriptResource).toBeDefined();
expect(scriptResource.agent_id).toBe(requiredVars.agent_id);

// check that the script contains expected lines
expect(scriptResource.script).toContain("Installing tmux");
expect(scriptResource.script).toContain("Installing Tmux Plugin Manager (TPM)");
expect(scriptResource.script).toContain("tmux configuration created at");
expect(scriptResource.script).toContain("✅ tmux setup complete!");
});
});
78 changes: 78 additions & 0 deletions registry/anomaly/modules/tmux/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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 "tmux_config" {
type = string
description = "Custom tmux configuration to apply."
default = ""
}

variable "save_interval" {
type = number
description = "Save interval (in minutes)."
default = 1
}

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 "icon" {
type = string
description = "The icon to use for the app."
default = "/icon/tmux.svg"
}

variable "sessions" {
type = list(string)
description = "List of tmux sessions to create or start."
default = ["default"]
}

resource "coder_script" "tmux" {
agent_id = var.agent_id
display_name = "tmux"
icon = "/icon/terminal.svg"
script = templatefile("${path.module}/scripts/run.sh", {
TMUX_CONFIG = var.tmux_config
SAVE_INTERVAL = var.save_interval
})
run_on_start = true
run_on_stop = false
}

resource "coder_app" "tmux_sessions" {
for_each = toset(var.sessions)

agent_id = var.agent_id
slug = "tmux-${each.value}"
display_name = "tmux - ${each.value}"
icon = var.icon
order = var.order
group = var.group

command = templatefile("${path.module}/scripts/start.sh", {
SESSION_NAME = each.value
})
}
Loading