A session manager for tmux written in Go

Smug - tmux session manager

Actions Status Go Report Card

Inspired by tmuxinator and tmuxp.

Smug automates your tmux workflow. You can create a single configuration file, and Smug will create all the required windows and panes from it.

gif

The configuration used in this GIF can be found here.

Installation

Download from the releases page

Download the latest version of Smug from the releases page and then run:

mkdir smug && tar -xzf smug_0.1.0_Darwin_x86_64.tar.gz -C ./smug && sudo mv smug/smug /usr/local/bin && rm -rf smug

Don't forget to replace smug_0.1.0_Darwin_x86_64.tar.gz with the archive that you've downloaded.

Git

Prerequisite Tools

Fetch from GitHub

The easiest way is to clone Smug from GitHub and install it using go-cli:

cd /tmp
git clone https://github.com/ivaaaan/smug.git
cd smug
go install

Usage

smug  [] [-f, --file ] [-w, --windows ]... [-a, --attach] [-d, --debug]

Options:

-f, --file A custom path to a config file
-w, --windows List of windows to start. If session exists, those windows will be attached to current session.
-a, --attach Force switch client for a session
-d, --debug Print all commands to ~/.config/smug/smug.log

Examples

To create a new project, or edit an existing one in the $EDITOR:

xyz@localhost:~$ smug new project

xyz@localhost:~$ smug edit project

To start/stop a project and all windows, run:

xyz@localhost:~$ smug start project

xyz@localhost:~$ smug stop project

When you already have a running session, and you want only to create some windows from the configuration file, you can do something like this:

xyz@localhost:~$ smug start project:window1

xyz@localhost:~$ smug start project:window1,window2

xyz@localhost:~$ smug start project -w window1

xyz@localhost:~$ smug start project -w window1 -w window2

xyz@localhost:~$ smug stop project:window1

xyz@localhost:~$ smug stop project -w window1 -w window2

Also, you are not obliged to put your files in the ~/.config/smug directory. You can use a custom path in the -f flag:

xyz@localhost:~$ smug start -f ./project.yml

xyz@localhost:~$ smug stop -f ./project.yml

xyz@localhost:~$ smug start -f ./project.yml -w window1 -w window2

Configuration

Configuration files stored in the ~/.config/smug directory in the YAML format, e.g ~/.config/smug/your_project.yml.

Examples

Example 1

session: blog

root: ~/Developer/blog

before_start:
  - docker-compose -f my-microservices/docker-compose.yml up -d # my-microservices/docker-compose.yml is a relative to `root`

stop:
  - docker stop $(docker ps -q)

windows:
  - name: code
    root: blog # a relative path to root
    manual: true # you can start this window only manually, using the -w arg
    layout: main-vertical
    commands:
      - docker-compose start
    panes:
      - type: horizontal
        root: .
        commands:
          - docker-compose exec php /bin/sh
          - clear

  - name: infrastructure
    root: ~/Developer/blog/my-microservices
    layout: tiled
    panes:
      - type: horizontal
        root: .
        commands:
          - docker-compose up -d
          - docker-compose exec php /bin/sh
          - clear

Example 2

session: blog

root: ~/Code/blog

before_start:
  - docker-compose up -d

stop:
  - docker-compose stop

windows:
  - name: code
    layout: main-horizontal
    commands:
      - $EDITOR app/dependencies.php
    panes:
      - type: horizontal
        commands:
          - make run-tests
  - name: ssh
    commands:
      - ssh -i ~/keys/blog.pem [email protected]
Comments
  • Feature: smug stop within session

    Feature: smug stop within session

    It might be useful to look up the current tmux session, and allow users to run smug stop without a session name within a smug managed session, by using tmux display-message -p '#S'1 and looking to see if it matches an expected session name.

  • example for main-vertical with 3 panes

    example for main-vertical with 3 panes

    I'm trying to get this layout, but I don't succeed. Can you help me with an example ?

    |-----------------------|-----------------------|
    |                       |                       |
    |                       |         echo 2        |
    |                       |                       |
    |      echo 1           |-----------------------|
    |                       |                       |
    |                       |         echo 3        |
    |                       |                       |
    |-----------------------|-----------------------|
    
  • Add `create` and `edit` commands

    Add `create` and `edit` commands

    We want to add an ability to create and edit configuration files within smug command.

    smug <edit|create> <project> should open ~/.config/smug/project.yml in the $EDITOR

    This is a simple task, and doesn't require any prior knowledge of the project. If you would like to contribute, reach me out, I'll be happy to assist with any questions.

  • No auto-attach on new session, extra window created.

    No auto-attach on new session, extra window created.

    Thanks for creating this! Per the title, I'm having trouble getting tmux to start/attach properly using smug. I'm running macOS 11.2, iTerm2 3.4.3, tmux 3.1c installed via Homebrew.

    My config, intent is to start a session with a single window containing my Zettellkasten.

    $ cat ~/.config/smug/zettel.yml
    session: zettel
    
    windows:
      - name: wiki
        commands:
          - vim +VimwikiIndex
    

    Attempting to run it:

    $ tmux ls
    no server running on /private/tmp/tmux-501/default
    
    $ smug start zettel
    Starting a new session...
    Cannot run "tmux kill-window -t zettel:0". Error exit status 1
    
    $ smug start zettel:wiki
    Starting a new session...
    

    I'm returned to my shell prompt, and tmux does not open, but it was started!

    $ tmux ls
    zettel: 2 windows (created Mon Dec 21 17:15:45 2020)
    

    Once I run tmux attach I see that 2 windows have been created. A blank shell which is the window I'm started in, and the wiki window.

    image image

    Hope I've provided enough info to help, let me know if there is a debug/verbose mode I can try out, or anything else!

  • Create edit commands

    Create edit commands

    What?

    • Adding smug create <project> to create a .yml file at ~/.config/smug If the file already exists, the terminal will output "File already exists"

    • Adding smug edit <project> to edit an existing .yml file on the $EDITOR (or vim, if $EDITOR is not set) If the file doesn't exist, the terminal will output "[...]no such file or directory"

    Testing?

    Working on it.

    Anything that can improve?

    I think it would be great to add autocomplete on tab when using smug edit <project> so it shows any existing projects on ~/.config/smug. This could be done with the complete package.

    Screenshots (Updated: 31 December, 2020)

    https://user-images.githubusercontent.com/45673971/103425323-365a2180-4b77-11eb-9f28-57d92d5057fa.mov

  • Support passing args

    Support passing args

    I am excited to see another competitor to tmuxinator. I would love to drop it since its my only ruby dependency left in my dotfiles.

    Wondering if there are plans to support passing in arguments to projects when invoking smug. This is the only feature of tmuxinator that I use that would make switching a little bit differerent. I have scripting around launching projects in tmux, if a tmuxinator/smug project would exist it would launch that, otherwise it launches a default project that gives me some standard windows. In tmuxinator it looks like this.

    name: <%= @settings["name"].upcase().split(/[-_]/).join(' ') %>
    root: <%= @settings["root"] %>
    
    windows:
      - editor: nvim
      - console: clear
    

    I could move this to a custom script instead of using smug/tmuxinator but it was kinda nice defining it and keeping it in tmuxinator.

  • Cannot open manual window with latest smug version

    Cannot open manual window with latest smug version

    Describe the bug I have a config defined with two windows. One is configured as manual: true. I open a session with smug start myconfig. This opens the first window successfully with the configured panes and commands.

    Then I smug start myconfig:test2 which is the manual one. It fails to open.

    Smug config

    session: 'MyConfig'
    windows:
      - name: test1
        commands: [ls]
        panes:
          - commands: [ls]
      - name: test2
        manual: true
        commands: [ls]
        panes:
          - commands: [ls]
    

    Expected behavior The test2 window should open successfully with the defined layout

    Output of cat ~/.config/smug/smug.log

    tmux has-session -t MyConfig:
    tmux neww -Pd -t MyConfig: -c  -F #{window_id} -n test2
    tmux send-keys -t @3 ls Enter
    tmux split-window -Pd -t @3 -c  -F #{pane_id}
    tmux select-layout -t @3 tiled
    tmux send-keys -t @3.%6 ls Enter
    tmux select-layout -t @3 even-horizontal
    tmux kill-window -t MyConfig:smug_def
    exit status 1 can't find window: smug_def
    
    tmux kill-window -t MyConfig:test2
    

    It seems smug_def window is not being created in this scenario, which is expected to exist.

    Smug version

    Smug - tmux session manager. Version 0.3.1
    

    OS you're using MacOS Monterey 12.4

  • initial implementation of stop-within-session without name

    initial implementation of stop-within-session without name

    This PR closes #84.

    It accomplishes this with two main changes:

    Env Vars

    It adds three env vars to all smug-created tmux sessions.

    • $SMUG_SESSION - always equal to "true". Allows users to do easier scripting and detection if it's a smug-managed session
    • $SMUG_SESSION_NAME - name of the tmux session smug created
    • $SMUG_SESSION_CONFIG_PATH - full filepath of the smug config file that created this session

    Config parser

    If the --file arg is not specified, but $SMUG_SESSION_CONFIG_PATH is set, the value of the env var is put into the --file value variable, allowing all normal commands that would work with --file manually specified to work automatically within a smug session. This lets smug be aware of it's current context if existing within a smug session, and operate on it by default unless you force it to do something else. For example, smug stop or smug edit work without any additional args.

  • Allow tmux-style short commands

    Allow tmux-style short commands

    I'd love support for short commands, like tmux does.

    In cases where there's no ambiguity, it would be very handy to be able to use "n" for "new", "e" for "edit", "l" or "ls" for "list", etc.

    Of course, cases like "s" would be ambiguous (start/stop), so would need to be used in it's fuller form, the same way tmux does.

  • Tag for v0.2 doesn't include version

    Tag for v0.2 doesn't include version

  • set a custom timeout before executing send-keys for commands

    set a custom timeout before executing send-keys for commands

    In some situations send-keys might fire before the shell prompt finished initilization. It happened for me when using fish shell and oh-my-fish which makes the send-keys start executing bofore my shell is ready and I endup with a written command that is not executed

    This patch adds a custom sendkeys_timeout as a top level option that takes an integer in milliseconds. It will ensure a Sleep call is made before.

  • Allow to group projects into directories

    Allow to group projects into directories

    I want to allow users to group their configs into directories, e.g:

    smug
    ├── my-awesome-project
    │   ├── app.yml
    │   └── backend.yml
    

    Now command smug start my-awesome-project should create multiple tmux sessions, and attach to the last one created. Config option always_attach: true on the config root level may be added

  • [feature request] ready-command

    [feature request] ready-command

    [feature request] ready-command

    ready-command: - do-this-then-that-later

    This would allow to have the command echoed to the prompt but NOT yet executed.

  • Name Conflict Resolution

    Name Conflict Resolution

    Describe the bug If there are two or more smug config with name prefixed from one of them, and then the prefix of the name itself is running last (as it uses $(smug config)

    To get the situation here:

    • Running a smug config will give you a list, with prefixer to come later from prefixed name. image
    • Executing whole batch using for VAR in $(smug config) will execute everything except the last one, due to prefixing issue. On the picture it's yohane-irc vs yohane which is shadowed by yohane-irc upon doing smug start yohane until the yohane-irc window got stopped.

    However:

    • If I decide to smug config | sort, or at least sorting the naming order from smug config output, which happens to give different output from just smug config. Things works normally.
    • Execution order changed from yohane to yohane-irc instead vice versa. No naming conflict like what happened above.

    Smug config smug config does not matter

    Expected behavior

    • Both yohane-irc and yohane should be executed alongside in any order of execution.

    Output of cat ~/.config/smug/smug.log output log does not matter.

    Smug version 0.2.7

    OS you're using Linux

  • Request for `-L` option

    Request for `-L` option

    Tmux has the -L option to specify the socket name (and -S to specify the socket path). This is very useful to group sessions in different sockets (isolated tmux servers).

    It would be nice to have this option in smug.

    Other tmux managers allow users to set the socket name in the yaml files which I haven't used, but could also be useful.

    I have the intention of creating a PR for this, but I would have to learn at least some basic Go to do this 😅

    What do you think @ivaaaan? Do you see value in this? Should I create a PR or is it easy for you to do?

    Thank you!

  • Port CLI interface to github.com/urfave/cli/v2

    Port CLI interface to github.com/urfave/cli/v2

    If you implement this CLI library you loose a lot of overhead code for your commands and options. Beside this you get usage documentation and autocomplete without extra coding. If you like I can help.

The package manager for macOS you didn’t know you missed. Simple, functional, and fast.
The package manager for macOS you didn’t know you missed. Simple, functional, and fast.

Stew The package manager for macOS you didn’t know you missed. Built with simplicity, functionality, and most importantly, speed in mind. Installation

Mar 30, 2022
gosignal is expected to be used in minimal window manager configurations

gosignal is expected to be used in minimal window manager configurations. It provides a simple battery monitor , which notifies of battery events. It has a config file where you can configure the notification messages given

Mar 21, 2022
Listmonk - a standalone, self-hosted, newsletter and mailing list manager
Listmonk - a standalone, self-hosted, newsletter and mailing list manager

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a Postg

Jan 13, 2022
Random fake data generator written in go
Random fake data generator written in go

Gofakeit Random data generator written in go Features 160+ Functions!!! Concurrent Global Rand Struct Generator Custom Functions Http Server Command L

Jan 1, 2023
Genetic Algorithm written in go

This genetic algorithm is designed to minimise the problem specific code from a genetic algorithm. The three interfaces Gene, Initialiser, an Evaluato

Feb 15, 2022
Simple and expressive toolbox written in Go

ugo Simple and expressive toolbox written with love and care in Go. Deeply inspired by underscore.js and has the same syntax and behaviour Fully cover

Sep 27, 2022
An example client implementation written in GO to access the CyberVox platform API

About This is an example client implementation written in GO to access the CyberVox platform API.

Nov 7, 2022
💥 Fusion is a tiny stream processing library written in Go.

?? Fusion Fusion is a tiny stream processing library written in Go. See reactor for a stream processing tool built using fusion. Features Simple & lig

Jun 30, 2021
Airplay 2 Receiver written in go

Go Play 2 This is a work in progress Airplay 2 Speaker implementation largely inspired by airplay2-receiver Status Can be paired manually on IOS 14.x

Dec 25, 2022
Simple 'UserKit' for Malware written in Go. Startup, Hidden Files, Critical Process and Registry Watcher

GoUserKit Simple UserKit for Malware written in Go Features Makes Process Critical (NtSetInformationProcess) Hides Files Simple Add to Startup (HKCU R

Jan 3, 2023
jacobin - A more than minimal JVM written in Go and capable of running Java 11 bytecode.

This overview gives the background on this project, including its aspirations and the features that it supports. The remaining pages discuss the basics of JVM operation and, where applicable, how Jacobin implements the various steps, noting any items that would be of particular interest to JVM cognoscenti.

Dec 29, 2022
A wrapper for the Wandbox API, written in Golang!

GoWandBox A simple wrapper for the WandBox API, written in Golang! Documentation can be found at classpythonaddike.github.io/gowandbox/ Note: This wra

Sep 19, 2021
A simple typewriter written in go for KOBO e-readers
A simple typewriter written in go for KOBO e-readers

Kobowriter This small project aims to let you use your old KOBO e-reader (mine is a GLO HD) as a simple, distraction free typewriter. For years I thou

Dec 25, 2022
fccCoin Clone written in GoLang

fccCoin Description fccCoin Clone written in GoLang Actual Code for fccCoin written in Python

Oct 2, 2021
Conventional Commits parser written in Go

Conventional Commit Parser This is a parser for Conventional Commits go get -u github.com/release-lab/conventional-commit-parser package main import

Feb 4, 2022
Polarite is a Pastebin alternative made for simplicity written in Go.
 Polarite is a Pastebin alternative made for simplicity written in Go.

Polarite is a Pastebin alternative made for simplicity written in Go. Usage Web Interface Visit https://polarite.teknologiumum.com API Send a POST req

Dec 1, 2022
A boilerplate showing how to create a Pulumi component provider written in Go

xyz Pulumi Component Provider (Go) This repo is a boilerplate showing how to create a Pulumi component provider written in Go. You can search-replace

Mar 4, 2022
Person is a simple CRUD application written in go which exposes API endpoint to create the person.

Person Person is a simple CRUD application written in go which exposes API endpoint to create the person. Installation Install docker in your local sy

Oct 18, 2021
Chief Client Go is a cross platform Krunker client written in Go Lang

Chief Client Go Chief Client Go is a client for Mac and Linux written in GoLang Features Ad Blocker Option to use proxy Installation To install this c

Nov 6, 2021