Skip to content

cellfusion/conjure

Repository files navigation

✨ Conjure

Magically control your panes in Zellij

Conjure is a Zellij plugin that lets you send commands to panes using tab:pane name format. It supports both CLI (via pipe) and an interactive UI, providing a better experience than tmux's send-keys -t.

📖 Table of Contents

🎩 Why "Conjure"?

conjure = "to summon, to make appear as if by magic"

  • 🎯 Magically summon any pane and send commands
  • ✨ Instantly recall panes through interactive UI
  • 🚀 Use intuitive names instead of numeric IDs

🚀 Quick Start

  1. Add plugin to config.kdl:
plugins {
    conjure location="https://github.com/cellfusion/conjure/releases/download/v0.1.0/conjure.wasm"
}
  1. Add keybinding:
keybinds {
    shared_except "locked" {
        bind "Ctrl p" "c" {
            LaunchOrFocusPlugin "conjure" {
                floating true
            }
        }
    }
}
  1. Restart Zellij and press Ctrl+p, c to open Conjure!

For detailed installation instructions, see Installation below.

✨ Features

🖥️ CLI Mode (via Pipe)

# Send command to a pane
zellij action pipe --plugin conjure --name send_command \
  -- '{"pane_name":"terminal","text":"npm run build"}'

# List all panes (returns JSON)
zellij action pipe --plugin conjure --name list_panes

# Search panes by name/process/tab (fuzzy match, AND condition)
zellij action pipe --plugin conjure --name search_panes \
  -- '{"pane_name":"terminal"}'
zellij action pipe --plugin conjure --name search_panes \
  -- '{"process_name":"nvim","tab_name":"Editor"}'

All CLI commands return JSON responses:

{"success":true,"data":[{"pane_id":3,"pane_title":"terminal","tab_name":"Editor","tab_position":0,"is_focused":true,"process_name":"bash"}]}

🎨 Interactive UI Mode

  • Pane Selector: Fuzzy search for quick pane discovery
  • Command Input: Enter commands on the fly with history
  • Presets: Execute frequently-used commands with one click
  • History: Quick access to recently used panes
┌─ Conjure ────────────────────────────────┐
│ Search: term█                            │
├──────────────────────────────────────────┤
│ [Tab: Editor]                            │
│   > terminal (zsh) - /path/to/project    │
│     nvim (nvim file.rs)                  │
│ [Tab: Tests]                             │
│     watch (cargo watch)                  │
└──────────────────────────────────────────┘

🚀 Installation

Method 1: Download from GitHub Releases (Recommended)

Download the latest release from GitHub Releases:

# Download the latest release
wget https://github.com/cellfusion/conjure/releases/download/v0.1.0/conjure.wasm

# Install to Zellij plugins directory
mkdir -p ~/.config/zellij/plugins
mv conjure.wasm ~/.config/zellij/plugins/

Or configure directly from URL in config.kdl (Zellij will download automatically):

plugins {
    conjure location="https://github.com/cellfusion/conjure/releases/download/v0.1.0/conjure.wasm" {
        plugin_select_up "Ctrl p"
        plugin_select_down "Ctrl n"
    }
}

Method 2: Build from Source

For developers or those who want the latest development version:

# Add wasm target (first time only)
rustup target add wasm32-wasip1

# Clone the repository
git clone https://github.com/YOUR_USERNAME/conjure.git
cd conjure

# Build
cargo build --target wasm32-wasip1 --release

# Install plugin
mkdir -p ~/.config/zellij/plugins
cp target/wasm32-wasip1/release/conjure.wasm ~/.config/zellij/plugins/

Configure Zellij

Add the following to your ~/.config/zellij/config.kdl:

Using GitHub Releases URL (Recommended)

keybinds clear-defaults=true {
    // ... your other keybindings ...
    
    shared_except "locked" {
        // Open Conjure UI
        bind "Ctrl p" "c" {
            LaunchOrFocusPlugin "conjure" {
                floating true
                move_to_focused_tab true
            }
        }
        
        // Show presets
        bind "Ctrl p" "C" {
            MessagePlugin "conjure" {
                name "show_presets"
            }
        }
        
        // Show history
        bind "Ctrl p" "h" {
            MessagePlugin "conjure" {
                name "show_history"
            }
        }
    }
}

plugins {
    conjure location="https://github.com/cellfusion/conjure/releases/download/v0.1.0/conjure.wasm" {
        // UI keybindings (inside the plugin)
        plugin_select_up "Ctrl p"
        plugin_select_down "Ctrl n"
        plugin_navigate_to "Enter"
        plugin_hide "Esc"
    }
}

Using Local File Path

If you downloaded or built the plugin locally:

plugins {
    conjure location="file:~/.config/zellij/plugins/conjure.wasm" {
        plugin_select_up "Ctrl p"
        plugin_select_down "Ctrl n"
        plugin_navigate_to "Enter"
        plugin_hide "Esc"
    }
}

Important: By defining the plugin in the plugins section, you can use the short name conjure in CLI commands:

# Short form (after config.kdl setup)
zellij action pipe --plugin conjure --name send_command -- '...'

# vs. Long form (without config.kdl)
zellij action pipe --plugin file:$HOME/.config/zellij/plugins/conjure.wasm --name send_command -- '...'

Create Presets (Optional)

Create ~/.config/zellij/conjure_presets.json:

{
  "presets": [
    {
      "name": "Run Tests",
      "target": "Tests:watch",
      "command": "cargo test --all",
      "description": "Run all unit tests"
    },
    {
      "name": "Build Project",
      "target": "Editor:terminal",
      "command": "npm run build",
      "description": "Production build"
    }
  ]
}

📚 Usage

CLI Mode (Pipe Commands)

When you define the plugin in config.kdl under the plugins section, you can use the plugin name directly instead of the full path.

Send Command to Named Pane

# Pane name only (searches all tabs)
zellij action pipe --plugin conjure --name send_command \
  -- '{"pane_name":"terminal","text":"ls -la"}'

# Tab:Pane format (narrow search to specific tab)
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Editor","pane_name":"terminal","text":"npm run build"}'

# Without pressing Enter (send_enter defaults to true)
zellij action pipe --plugin conjure --name send_command \
  -- '{"pane_name":"terminal","text":"git status","send_enter":false}'

Note: If the plugin is not defined in config.kdl, use the full path:

zellij action pipe --plugin file:$HOME/.config/zellij/plugins/conjure.wasm --name send_command \
  -- '{"pane_name":"terminal","text":"echo hello"}'

List All Panes

zellij action pipe --plugin conjure --name list_panes

Returns JSON with all available panes:

{"success":true,"data":[{"pane_id":3,"pane_title":"terminal","tab_name":"Editor","tab_position":0,"is_focused":true,"process_name":"bash"}]}

Search Panes

# Search by pane name (fuzzy match)
zellij action pipe --plugin conjure --name search_panes \
  -- '{"pane_name":"term"}'

# Search by process name
zellij action pipe --plugin conjure --name search_panes \
  -- '{"process_name":"nvim"}'

# Search by multiple fields (AND condition)
zellij action pipe --plugin conjure --name search_panes \
  -- '{"process_name":"nvim","tab_name":"Editor"}'

Interactive UI Mode

Pane Selector Mode

  • ↑↓ / Ctrl p/n: Navigate through panes
  • Enter: Select pane and open command input
  • Esc: Close
  • Type: Fuzzy search filter

Command Input Mode

  • Enter: Send command
  • ↑↓: Navigate command history
  • Esc: Cancel

Keybindings

Global Keybindings (outside plugin)

Keybinding Description Config Key
Ctrl p, c Open Conjure UI (pane selector) LaunchOrFocusPlugin
Ctrl p, C Show presets list MessagePlugin "show_presets"
Ctrl p, h Show history MessagePlugin "show_history"

Plugin Keybindings (inside plugin UI)

Keybinding Description Config Key
Up/Down Move selection plugin_select_up/plugin_select_down
Enter Select and navigate plugin_navigate_to
Esc Close plugin plugin_hide

Customize Keybindings

Modify the plugins section in config.kdl:

plugins {
    conjure location="file:~/.config/zellij/plugins/conjure.wasm" {
        plugin_select_up "Ctrl p"      # Default: Up
        plugin_select_down "Ctrl n"    # Default: Down
        plugin_navigate_to "Enter"     # Default: Enter
        plugin_hide "Esc"              # Default: Esc
    }
}

Use an empty string to disable a keybinding:

plugins {
    conjure location="file:~/.config/zellij/plugins/conjure.wasm" {
        plugin_select_up ""  # Disabled
    }
}

🎯 Use Cases

Development Workflow

# Start dev server
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Server","pane_name":"dev","text":"npm run dev","send_enter":true}'

# Run tests
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Tests","pane_name":"unit","text":"cargo test","send_enter":true}'

Automation Scripts

#!/bin/bash
# deploy.sh

# Run tests first
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Tests","pane_name":"unit","text":"cargo test --all","send_enter":true}'

sleep 5

# Build project
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Build","pane_name":"prod","text":"cargo build --release","send_enter":true}'

sleep 10

# Deploy
zellij action pipe --plugin conjure --name send_command \
  -- '{"tab_name":"Deploy","pane_name":"terminal","text":"./scripts/deploy.sh","send_enter":true}'

🏗️ Project Structure

conjure/
├── src/
│   ├── main.rs              # Plugin entry point
│   ├── state.rs             # State management
│   ├── matcher.rs           # Pane search logic
│   ├── pipe_handler.rs      # CLI message handling
│   ├── ui/                  # UI components
│   │   ├── pane_selector.rs
│   │   ├── command_input.rs
│   │   ├── preset_list.rs
│   │   └── history.rs
│   ├── history.rs           # History management
│   ├── presets.rs           # Preset management
│   └── config.rs            # Configuration
├── examples/
│   ├── conjure_presets.json
│   ├── config.kdl
│   └── automation.sh
└── README.md

🛠️ Development

For developers who want to contribute or build from source.

Prerequisites

  • Rust 1.75+
  • wasm32-wasip1 target

Build from Source

# Add wasm target (first time only)
rustup target add wasm32-wasip1

# Clone the repository
git clone https://github.com/YOUR_USERNAME/conjure.git
cd conjure

# Build
cargo build --target wasm32-wasip1 --release

# The compiled plugin will be at:
# target/wasm32-wasip1/release/conjure.wasm

Install Locally

# Install to Zellij plugins directory
mkdir -p ~/.config/zellij/plugins
cp target/wasm32-wasip1/release/conjure.wasm ~/.config/zellij/plugins/

Test

# Test the plugin
zellij plugin -- file:$HOME/.config/zellij/plugins/conjure.wasm

# Test CLI mode (after adding plugin to config.kdl)
zellij action pipe --plugin conjure --name send_command \
  -- '{"pane_name":"terminal","text":"echo hello","send_enter":true}'

# Test CLI mode (without config.kdl definition)
zellij action pipe --plugin file:$HOME/.config/zellij/plugins/conjure.wasm --name send_command \
  -- '{"pane_name":"terminal","text":"echo hello","send_enter":true}'

For detailed development information, see CLAUDE.md.

📖 Documentation

🎨 Inspiration

This project is inspired by:

🤝 Contributing

Contributions are welcome!

  1. Fork this repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📝 License

MIT License - See LICENSE file for details

🙏 Acknowledgments


Control your panes magically ✨

About

A Zellij plugin to magically send commands to panes by name — with interactive UI, fuzzy search, history, and presets.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages