diff --git a/.icons/zellij.svg b/.icons/zellij.svg
new file mode 100644
index 000000000..ef77c1dd2
--- /dev/null
+++ b/.icons/zellij.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/registry/jang2162/.images/avatar.png b/registry/jang2162/.images/avatar.png
new file mode 100644
index 000000000..331be9af9
Binary files /dev/null and b/registry/jang2162/.images/avatar.png differ
diff --git a/registry/jang2162/README.md b/registry/jang2162/README.md
new file mode 100644
index 000000000..4427ac733
--- /dev/null
+++ b/registry/jang2162/README.md
@@ -0,0 +1,11 @@
+---
+display_name: "Byeong-Hyun"
+bio: "ㅎㅇ means Hi"
+avatar: "./.images/avatar.png"
+github: "jang2162"
+status: "community"
+---
+
+# Byeong-Hyun
+
+ㅎㅇ means "Hi"
diff --git a/registry/jang2162/modules/zellij/README.md b/registry/jang2162/modules/zellij/README.md
new file mode 100644
index 000000000..f2707c0cc
--- /dev/null
+++ b/registry/jang2162/modules/zellij/README.md
@@ -0,0 +1,113 @@
+---
+display_name: Zellij
+description: Modern terminal workspace with session management
+icon: ../../../../.icons/zellij.svg
+verified: false
+tags: [zellij, terminal, multiplexer]
+---
+
+# Zellij
+
+Automatically install and configure [zellij](https://github.com/zellij-org/zellij), a modern terminal workspace with session management. Supports terminal and web modes, custom configuration, and session persistence.
+
+```tf
+module "zellij" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/jang2162/zellij/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+}
+```
+
+## Features
+
+- Installs zellij if not already present (version configurable, default `0.43.1`)
+- Configures zellij with sensible defaults
+- Supports custom configuration (KDL format)
+- Session serialization enabled by default
+- **Two modes**: `terminal` (Coder built-in terminal) and `web` (browser-based via subdomain proxy)
+- Cross-platform architecture support (x86_64, aarch64)
+
+## Examples
+
+### Basic Usage (Terminal Mode)
+
+```tf
+module "zellij" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/jang2162/zellij/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+}
+```
+
+### Web Mode
+
+```tf
+module "zellij" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/jang2162/zellij/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ mode = "web"
+ web_port = 8082
+ group = "Terminal"
+ order = 1
+}
+```
+
+### Custom Configuration
+
+```tf
+module "zellij" {
+ count = data.coder_workspace.me.start_count
+ source = "registry.coder.com/jang2162/zellij/coder"
+ version = "1.0.0"
+ agent_id = coder_agent.example.id
+ zellij_config = <<-EOT
+ keybinds {
+ normal {
+ bind "Ctrl t" { NewTab; }
+ }
+ }
+ theme "dracula"
+ EOT
+}
+```
+
+## How It Works
+
+### Installation & Setup (scripts/run.sh)
+
+1. **Version Check**: Checks if zellij is already installed with the correct version
+2. **Architecture Detection**: Detects system architecture (x86_64 or aarch64)
+3. **Download**: Downloads the appropriate zellij binary from GitHub releases
+4. **Installation**: Installs zellij to `/usr/local/bin/zellij`
+5. **Configuration**: Creates default or custom configuration at `~/.config/zellij/config.kdl`
+6. **Web Mode Only**:
+ - Prepends a `TERM` fix to `~/.bashrc` (sets `TERM=xterm-256color` inside zellij when `TERM=dumb`)
+ - Starts the zellij web server as a daemon and creates an authentication token
+
+### Session Access
+
+- **Terminal mode**: Opens zellij in the Coder built-in terminal via `zellij attach --create default`
+- **Web mode**: Accesses zellij through a subdomain proxy in the browser (authentication token required on first visit)
+
+## Default Configuration
+
+The default configuration includes:
+
+- Session serialization enabled for persistence
+- 10,000 line scroll buffer
+- Copy on select enabled (system clipboard)
+- Rounded pane frames
+- Key bindings: `Ctrl+s` (new pane), `Ctrl+q` (quit)
+- Default theme
+- Web mode: web server IP/port automatically appended
+
+> [!IMPORTANT]
+>
+> - Custom `zellij_config` replaces the default configuration entirely
+> - Requires `curl` and `tar` for installation
+> - Uses `sudo` to install to `/usr/local/bin/`
+> - Supported architectures: x86_64, aarch64
diff --git a/registry/jang2162/modules/zellij/main.test.ts b/registry/jang2162/modules/zellij/main.test.ts
new file mode 100644
index 000000000..687f7ce92
--- /dev/null
+++ b/registry/jang2162/modules/zellij/main.test.ts
@@ -0,0 +1,63 @@
+import { describe, expect, it } from "bun:test";
+import {
+ runTerraformApply,
+ runTerraformInit,
+ testRequiredVariables,
+} from "~test";
+
+describe("zellij", async () => {
+ await runTerraformInit(import.meta.dir);
+
+ testRequiredVariables(import.meta.dir, {
+ agent_id: "foo",
+ });
+
+ it("default mode should be terminal", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "foo",
+ });
+ const terminalApp = state.resources.find(
+ (r) => r.type === "coder_app" && r.name === "zellij_terminal",
+ );
+ const webApp = state.resources.find(
+ (r) => r.type === "coder_app" && r.name === "zellij_web",
+ );
+ expect(terminalApp).toBeDefined();
+ expect(terminalApp!.instances.length).toBe(1);
+ expect(terminalApp!.instances[0].attributes.command).toBe(
+ "zellij attach --create default",
+ );
+ expect(webApp).toBeUndefined();
+ });
+
+ it("web mode should create web app", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "foo",
+ mode: "web",
+ });
+ const webApp = state.resources.find(
+ (r) => r.type === "coder_app" && r.name === "zellij_web",
+ );
+ const terminalApp = state.resources.find(
+ (r) => r.type === "coder_app" && r.name === "zellij_terminal",
+ );
+ expect(webApp).toBeDefined();
+ expect(webApp!.instances.length).toBe(1);
+ expect(webApp!.instances[0].attributes.subdomain).toBe(true);
+ expect(webApp!.instances[0].attributes.url).toBe("http://localhost:8082");
+ expect(terminalApp).toBeUndefined();
+ });
+
+ it("web mode should use custom port", async () => {
+ const state = await runTerraformApply(import.meta.dir, {
+ agent_id: "foo",
+ mode: "web",
+ web_port: 9090,
+ });
+ const webApp = state.resources.find(
+ (r) => r.type === "coder_app" && r.name === "zellij_web",
+ );
+ expect(webApp).toBeDefined();
+ expect(webApp!.instances[0].attributes.url).toBe("http://localhost:9090");
+ });
+});
diff --git a/registry/jang2162/modules/zellij/main.tf b/registry/jang2162/modules/zellij/main.tf
new file mode 100644
index 000000000..86712c910
--- /dev/null
+++ b/registry/jang2162/modules/zellij/main.tf
@@ -0,0 +1,104 @@
+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 "zellij_version" {
+ type = string
+ description = "The version of zellij to install."
+ default = "0.43.1"
+}
+
+variable "zellij_config" {
+ type = string
+ description = "Custom zellij configuration to apply."
+ default = ""
+}
+
+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/zellij.svg"
+}
+
+variable "mode" {
+ type = string
+ description = "How to run zellij: 'web' for web client with subdomain proxy, 'terminal' for Coder built-in terminal."
+ default = "terminal"
+
+ validation {
+ condition = contains(["web", "terminal"], var.mode)
+ error_message = "mode must be 'web' or 'terminal'."
+ }
+}
+
+variable "web_port" {
+ type = number
+ description = "The port for the zellij web server. Only used when mode is 'web'."
+ default = 8082
+}
+
+
+resource "coder_script" "zellij" {
+ agent_id = var.agent_id
+ display_name = "Zellij"
+ icon = "/icon/zellij.svg"
+ script = templatefile("${path.module}/scripts/run.sh", {
+ ZELLIJ_VERSION = var.zellij_version
+ ZELLIJ_CONFIG = var.zellij_config
+ MODE = var.mode
+ WEB_PORT = var.web_port
+ })
+ run_on_start = true
+ run_on_stop = false
+}
+
+# Web mode: subdomain proxy to zellij web server
+resource "coder_app" "zellij_web" {
+ count = var.mode == "web" ? 1 : 0
+
+ agent_id = var.agent_id
+ slug = "zellij"
+ display_name = "Zellij"
+ icon = var.icon
+ order = var.order
+ group = var.group
+ url = "http://localhost:${var.web_port}"
+ subdomain = true
+}
+
+# Terminal mode: run zellij in Coder built-in terminal
+resource "coder_app" "zellij_terminal" {
+ count = var.mode == "terminal" ? 1 : 0
+
+ agent_id = var.agent_id
+ slug = "zellij"
+ display_name = "Zellij"
+ icon = var.icon
+ order = var.order
+ group = var.group
+ command = "zellij attach --create default"
+}
diff --git a/registry/jang2162/modules/zellij/scripts/run.sh b/registry/jang2162/modules/zellij/scripts/run.sh
new file mode 100644
index 000000000..14ebf69fc
--- /dev/null
+++ b/registry/jang2162/modules/zellij/scripts/run.sh
@@ -0,0 +1,239 @@
+#!/usr/bin/env bash
+
+BOLD='\033[0;1m'
+
+# Convert templated variables to shell variables
+ZELLIJ_VERSION="${ZELLIJ_VERSION}"
+ZELLIJ_CONFIG="${ZELLIJ_CONFIG}"
+MODE="${MODE}"
+WEB_PORT="${WEB_PORT}"
+
+# Function to check if zellij is already installed
+is_installed() {
+ command -v zellij > /dev/null 2>&1
+}
+
+# Function to get installed version
+get_installed_version() {
+ if is_installed; then
+ zellij --version | grep -oP 'zellij \K[0-9]+\.[0-9]+\.[0-9]+'
+ else
+ echo ""
+ fi
+}
+
+# Function to install zellij
+install_zellij() {
+ printf "Checking for zellij installation\n"
+
+ INSTALLED_VERSION=$(get_installed_version)
+
+ if [ -n "$INSTALLED_VERSION" ]; then
+ if [ "$INSTALLED_VERSION" = "$ZELLIJ_VERSION" ]; then
+ printf "zellij version $ZELLIJ_VERSION is already installed \n\n"
+ return 0
+ else
+ printf "zellij version $INSTALLED_VERSION is installed, but version $ZELLIJ_VERSION is required\n"
+ fi
+ fi
+
+ printf "Installing zellij version $ZELLIJ_VERSION \n\n"
+
+ # Detect architecture
+ ARCH=$(uname -m)
+ case "$ARCH" in
+ x86_64)
+ ARCH="x86_64"
+ ;;
+ aarch64 | arm64)
+ ARCH="aarch64"
+ ;;
+ *)
+ printf "ERROR: Unsupported architecture: $ARCH\n"
+ exit 1
+ ;;
+ esac
+
+ # Download and install zellij
+ DOWNLOAD_URL="https://github.com/zellij-org/zellij/releases/download/v$${ZELLIJ_VERSION}/zellij-$${ARCH}-unknown-linux-musl.tar.gz"
+ TEMP_DIR=$(mktemp -d)
+
+ printf "Downloading zellij version $ZELLIJ_VERSION for $ARCH...\n"
+ printf "URL: $DOWNLOAD_URL\n"
+
+ if ! curl -fsSL "$DOWNLOAD_URL" -o "$TEMP_DIR/zellij.tar.gz"; then
+ printf "ERROR: Failed to download zellij\n"
+ rm -rf "$TEMP_DIR"
+ exit 1
+ fi
+
+ printf "Extracting zellij...\n"
+ tar -xzf "$TEMP_DIR/zellij.tar.gz" -C "$TEMP_DIR"
+
+ printf "Installing zellij to /usr/local/bin...\n"
+ sudo mv "$TEMP_DIR/zellij" /usr/local/bin/zellij
+ sudo chmod +x /usr/local/bin/zellij
+
+ # Cleanup
+ rm -rf "$TEMP_DIR"
+
+ # Verify installation
+ if is_installed; then
+ FINAL_VERSION=$(get_installed_version)
+ printf "✓ zellij version $FINAL_VERSION installed successfully\n"
+ else
+ printf "ERROR: zellij installation failed\n"
+ exit 1
+ fi
+}
+
+# Function to setup zellij configuration
+setup_zellij_config() {
+ printf "Setting up zellij configuration \n"
+
+ local config_dir="$HOME/.config/zellij"
+ local config_file="$config_dir/config.kdl"
+
+ mkdir -p "$config_dir"
+
+ if [ -n "$ZELLIJ_CONFIG" ]; then
+ printf "$ZELLIJ_CONFIG" > "$config_file"
+ printf "$${BOLD}Custom zellij configuration applied at $config_file \n\n"
+ else
+ cat > "$config_file" << 'CONFIGEOF'
+// Zellij Configuration File
+
+keybinds {
+ normal {
+ // Session management
+ bind "Ctrl s" { NewPane; }
+ bind "Ctrl q" { Quit; }
+ }
+}
+
+// UI configuration
+ui {
+ pane_frames {
+ rounded_corners true
+ }
+}
+
+// Session configuration
+session_serialization true
+pane_frames true
+simplified_ui false
+
+// Scroll settings
+scroll_buffer_size 10000
+copy_on_select true
+copy_clipboard "system"
+
+// Theme
+theme "default"
+CONFIGEOF
+
+ # Append web server config only in web mode
+ if [ "$MODE" = "web" ]; then
+ cat >> "$config_file" << EOF
+
+// Web server configuration
+web_server_ip "127.0.0.1"
+web_server_port $WEB_PORT
+EOF
+ fi
+ printf "zellij configuration created at $config_file \n\n"
+ fi
+}
+
+# Function to fix TERM for zellij web client (sets TERM=dumb)
+# Must be prepended to .bashrc so it runs BEFORE prompt color detection
+fix_term_for_web() {
+ local bashrc="$HOME/.bashrc"
+ local marker="# zellij-term-fix"
+
+ if ! grep -q "$marker" "$bashrc" 2> /dev/null; then
+ printf "Prepending TERM fix for Zellij web client to $bashrc\n"
+ local fix
+ fix=$(
+ cat << 'TERMFIX'
+# Fix TERM for Zellij web client (TERM=dumb breaks colors) # zellij-term-fix
+if [ -n "$ZELLIJ" ] && [ "$TERM" = "dumb" ]; then
+ export TERM=xterm-256color
+fi
+
+TERMFIX
+ )
+ # Prepend to .bashrc so TERM is set before prompt color detection
+ if [ -f "$bashrc" ]; then
+ local tmp
+ tmp=$(mktemp)
+ printf '%s\n' "$fix" | cat - "$bashrc" > "$tmp" && mv "$tmp" "$bashrc"
+ else
+ printf '%s\n' "$fix" > "$bashrc"
+ fi
+ fi
+}
+
+# Function to start zellij web server and create auth token
+start_web_server() {
+ printf "Starting zellij web server on port $WEB_PORT...\n"
+
+ # Stop any existing web server
+ zellij web --stop 2> /dev/null || true
+
+ # Start web server in daemon mode
+ zellij web -d
+
+ # Wait for web server to be ready
+ sleep 2
+
+ # Create auth token if not exists or invalid
+ local token_file="$HOME/.zellij-web-token"
+ local need_token=false
+
+ if [ ! -f "$token_file" ]; then
+ need_token=true
+ elif ! grep -qP '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' "$token_file"; then
+ printf "Invalid token file detected, regenerating...\n"
+ rm -f "$token_file"
+ need_token=true
+ fi
+
+ if [ "$need_token" = true ]; then
+ printf "Creating authentication token...\n"
+ # Extract UUID token from output (format: "token_N: ")
+ TOKEN=$(zellij web --create-token 2>&1 | grep -oP '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
+ echo "$TOKEN" > "$token_file"
+ printf "$${BOLD}===========================================\n"
+ printf "$${BOLD} Zellij Web Token: $TOKEN\n"
+ printf "$${BOLD} Saved to: ~/.zellij-web-token\n"
+ printf "$${BOLD} Enter this token on first browser visit.\n"
+ printf "$${BOLD}===========================================\n\n"
+ else
+ printf "Auth token: $(cat "$token_file")\n\n"
+ fi
+}
+
+# Main execution
+main() {
+ printf "$${BOLD}🛠️ Setting up zellij! \n\n"
+ printf ""
+
+ # Install zellij
+ install_zellij
+
+ # Setup zellij configuration
+ setup_zellij_config
+
+ # Web mode: fix TERM and start web server
+ if [ "$MODE" = "web" ]; then
+ fix_term_for_web
+ start_web_server
+ fi
+
+ printf "$${BOLD}✅ zellij setup complete! \n\n"
+ printf "$${BOLD}Access zellij via the Coder dashboard.\n"
+}
+
+# Run main function
+main
diff --git a/registry/jang2162/modules/zellij/zellij.tftest.hcl b/registry/jang2162/modules/zellij/zellij.tftest.hcl
new file mode 100644
index 000000000..8acdda0c0
--- /dev/null
+++ b/registry/jang2162/modules/zellij/zellij.tftest.hcl
@@ -0,0 +1,136 @@
+run "required_variables" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+}
+
+run "default_terminal_mode" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].command == "zellij attach --create default"
+ error_message = "Terminal mode should use 'zellij attach --create default' command"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].slug == "zellij"
+ error_message = "Terminal app slug should be 'zellij'"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].display_name == "Zellij"
+ error_message = "Terminal app display name should be 'Zellij'"
+ }
+
+ assert {
+ condition = length(resource.coder_app.zellij_web) == 0
+ error_message = "Web app should not be created in terminal mode"
+ }
+}
+
+run "web_mode" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ mode = "web"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_web[0].url == "http://localhost:8082"
+ error_message = "Web app should use default port 8082"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_web[0].subdomain == true
+ error_message = "Web app should use subdomain"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_web[0].slug == "zellij"
+ error_message = "Web app slug should be 'zellij'"
+ }
+
+ assert {
+ condition = length(resource.coder_app.zellij_terminal) == 0
+ error_message = "Terminal app should not be created in web mode"
+ }
+}
+
+run "web_mode_custom_port" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ mode = "web"
+ web_port = 9090
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_web[0].url == "http://localhost:9090"
+ error_message = "Web app should use custom port 9090"
+ }
+}
+
+run "custom_order_and_group" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ order = 3
+ group = "Terminal"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].order == 3
+ error_message = "App order should be 3"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].group == "Terminal"
+ error_message = "App group should be 'Terminal'"
+ }
+}
+
+run "custom_icon" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ icon = "/icon/custom.svg"
+ }
+
+ assert {
+ condition = resource.coder_app.zellij_terminal[0].icon == "/icon/custom.svg"
+ error_message = "App should use custom icon"
+ }
+}
+
+run "coder_script_config" {
+ command = plan
+
+ variables {
+ agent_id = "test-agent-id"
+ }
+
+ assert {
+ condition = resource.coder_script.zellij.display_name == "Zellij"
+ error_message = "Script display name should be 'Zellij'"
+ }
+
+ assert {
+ condition = resource.coder_script.zellij.run_on_start == true
+ error_message = "Script should run on start"
+ }
+
+ assert {
+ condition = resource.coder_script.zellij.run_on_stop == false
+ error_message = "Script should not run on stop"
+ }
+}