I found a tiling window manager and AI companion in iTerm2. It’s been a while since I wrote a post. In the past few days I stumbled upon a few fascinating things that I’ve been waiting for for a while now and I wanted to share it.

Last year recap

The AI boom that we experience nowadays took away my motivation. Many people jumped up in the hype, and their productivity skyrocketed, and kept people informed about the new trends. I felt that I could spend a few hours trying to summarize a topic or write my experiences on it, but an AI tool could do it in a way more consumable way. And its result has the option to chat with it, and fine tune the results it it does not fit your needs. I felt like it’s hard to compete with that. Also I did not want to pollute my blog with AI generated texts like that, so I turned to other hobbies.

Hobbies

Last year I was fascinated by things that did not quite feel like it would fit into the theme of the blog I had here so far.

I went ahead and lived my life. I had major life events, like moving town, getting married, and we got into the endless rabbithole of house renovation.

In the meantime I continued my journey into electronics. I learned how to solder, I wrote firmware to ESP32 devices. I experimented with controlling sensors via raspberry pi. I started to explore the modular world. I looked into communication via protocols like I2C. Got into robotics via ROS2. I took my spin in the #100DaysOfHardware challenge, and tracked my journey on Twitter (now called X). I still haven’t finished it though.

I also got into calligraphy. I attended many local in-person workshops. I practiced a modern version of it most of the time. Also learned how to write fraktur letters, and how to write on unusual surfaces like mugs and christmas ornaments.

In october I got into watercolor painting, and it stick with me. I occasionally create small graphics and greeting cards using this technique.

But get back to the show. We’re here for other stories.

Tiling layout in MacOSAerospace

My window managers over time

I grew up using Microsoft operating systems. So my baseline is that its window management feels natural. I always knew if an app has a window open (bewel on the taskbar), is minimized (embossed in the taskbar) or runs in the background (its icon is next to the clock).

Going to linux default window managers and macos way of thinking about windows was a bit confusing for me. It shows a dot if the application is running, but that does not necessarily mean that it has a window as well.

I’ve been using macOS for over 7 years now, and over the years I come up with my technique to survive. I got used to finding the proper windows by relying to the mission control, but by only using trackpad it’s a lot of wasted gestures and mouse movement.

i3 tiling window manager

A few years ago I worked with an awesome chap who used Ubuntu with i3 tiling manager. He basically navigated with vim keybinding everywhere. To top that his keyboard does not have labels, by which I’m still amazed. I think he only ever used his keyboard to interact with web pages and debug them.

This tiling manager stuck with me, he was navigating between windows blazing fast. Sadly as far as I know it’s only for linux.

On macOS I tried window tools like Amethyst and Rectangle. These improved my general experience, but I still felt it could be better.

MacOS window tricks without additional tools

When I started out with macOS I got a few suggestions:

  • use fullscreen apps
  • slide navigate between them
  • never use the minimize button

I liked the fact that I never needed to restart my machine, and when I logged in my windows were there just the way I left them.

Because the most tiring thing for me was to reorganize the windows

Aerospace

Last week one of my friends showed me a tool called Aerospace. I immediately jumped on it to try it.

After setting up a few keystrokes, it was way better than I expected. For a brief second I was sad about some keybinding that are overrode some of the characters in the Hungarian keyboard layout, but for one, I can just easily switch between US keyboard, second option is to exclude these workspaces.

Basically you have workspaces that can have your regular windows organized in a splitted way. You have keyboard shortcuts to move the windows around the splits and around the workspaces even between displays. And you can set event handlers for things like what should happen if a specific program has been opened, or if a new display is detected.

Aerospace Config

Here is the go to guide for Aerospace.

And I attached an excerpt from my config file below to emphasize my point (you can see it in full):

alt-1 = 'workspace 1'
alt-2 = 'workspace 2'

alt-shift-1 = 'move-node-to-workspace 1'
alt-shift-2 = 'move-node-to-workspace 2'

# osascript -e 'id of app "Code"'
[[on-window-detected]]
if.app-id = 'com.microsoft.VSCode'
run = 'move-node-to-workspace 1'

I set up most of the apps that I think I usually use, and I’ll see how it sticks.

Experience so far with Aerospace

Now, after a few days, I really like the effectiveness of switching between workspaces. I also love the ease of moving windows around or putting them away.

I still need time to remember what default workspaces I set for each application

A simple use case is that I want to share a few files in Slack by dropping them to its window.

hit `option+A` -> go to workspace A that has my finder window
hit `option+shift+Q` -> ask the selected window to move next to my Slack window
`drag-file` -> upload the file
hit `option+shift+A` -> put the finder back where I found it

Start the day like a Developer

Terminal emulators

It’s a hot topic in my team to try out new terminal emulators whenever they are shiny and new.

Emulators wort to mention here are alacritty, kitty, wezterm.

I’m quite happy with my oh-my-zsh shell running on iTerm2. It’s good enough for my terminal needs. I can create tabs and split them.

As a sidenote on Windows I liked conemu, but it’s been a while since I used it.

Since I needed to reinstall my machine recently I looked into new configurations.

Workflow I wanted

The only thing I miss from my daily workfow upon sitting down to a fresh restarted machine is to have a script that does the folowing:

  1. open a new tab in the terminal emulator
  2. open preconfigured folder locations
  3. start commands in specific tabs

For example start the full stack web application locally with backend(s), frontend, component library tool, database(s) in a single tab. Without having to manually start any of them.

In iterm2 it’s possible to save window arrangements and achieve the first 2 part. I can load them back, color and name the tab. Rename the splits as I needed.

But as far as I know it lacks the feature to save the commands I used in each session, and it does not keep the history for these windows, so that starting up is not as simple as click in the split, press up arrow and hit enter.

Today I found a way!

Iterm2 Python API

Upon looking at the iterm2 capabilites I stumbled upon the python API docs.

I wrote a python script code to split the tabs as I need and send commands to the shells. I send a change directory command and an arbitrary command to run.

import iterm2
# a simple custom config class to hide project details
from open_config import Iterm2Config

async def setup_session(session, path, command):
    if path:
        await session.async_send_text(f"cd {path}\n")
    if command:
        await session.async_send_text(f"{command}\n")

async def main(connection):
    app = await iterm2.async_get_app(connection)
    window = app.current_window
    if window is None:
        print("No available window. Create a new one and try again.")
        return
    tab = await window.async_create_tab()
    session = tab.current_session
    config = Iterm2Config()
    change = iterm2.LocalWriteOnlyProfile()
    color = iterm2.Color(*config.tab_color)
    change.set_tab_color(color)
    change.set_use_tab_color(True)

    await session.async_set_profile_properties(change)
    await tab.async_set_title(config.tab_title)

    top_left_session = session
    await setup_session(top_left_session, config.top_left_path, config.top_left_command)
    top_right_session = await session.async_split_pane(vertical=True)
    await setup_session(top_right_session, config.top_right_path, config.top_right_command)
    bottom_right_session = await top_right_session.async_split_pane(vertical=False)
    await setup_session(bottom_right_session, config.bottom_right_path, config.bottom_right_command)
    bottom_left_session = await top_left_session.async_split_pane(vertical=False)
    await setup_session(bottom_left_session, config.bottom_left_path, config.bottom_left_command)

if __name__ == "__main__":
    iterm2.run_until_complete(main)

The best part is that I can run this code from the shell or from the Scripts menu bar as well.

AI Suggestions in the Shell

Last year I tried out a few AI companions for coding. Like ChatGPT, Github Copilot, Claude. They are capable of producing impressive results.

These are awesome when you are online. I grew up with less than 128kbit ADSL internet access with ping over 300, so I love tools that work offline without a subscription, they have a special place in my heart.

There’s a nice tool called ollama, which let you run popular models locally. It works perfectly fine for simple topics for my hobby projects.

iTerm2 AI

Getting back to iTerm2 I saw last year that they added a plugin for interacting with AI. I saw that it could only use ChatGPT as its backend back then. I saw some people tried to make it work with ollama, but it seemed complicated.

As I looked around the options now it seemed straightfirward without any tweaks necessary.

All I needed is:

  • an AI prompt:

    Return commands suitable for copy/pasting into \(shell) on \(uname). 
    Do NOT include commentary NOR Markdown triple-backtick code blocks 
    as your whole response will be copied into my terminal automatically.
    Do not wrap the result in a code section.
    The script should do this: \(ai.prompt)
    
  • a backend address: http://localhost:11434/v1/chat/completions

  • set the token limit: 99 999

  • pull the proper ollama modell: ollama pull llama3.2:latest

How to use

  1. Hit cmd+Y to open the dialog to ask my question
  2. Hit shift+Enter to send the question to the model
  3. Wait for the response (it can take a while…)
  4. You could Hit shift+enter to send the whole response to the terminal, though I do not suggest you to run arbitrary code in the terminal.
  5. I’d open fc zsh command to edit the previous command with my preferred editor, and put together a nice command by copy-pasting the parts I think would work as I intend.
What’s the weather like in Budapest?

What’s the weather like in Budapest?

My experience so far

I haven’t really felt the need to write custom terminal scripts in the past few days, but you never know. Either way setting it up was a smooth experience.

I encountered a strance behaviour that when I hit shift+enter my machine added a ctrl+k character at the start of the code, that made the first line of the command fail. Luckily I rarely use this emacs combo in my shell to delete the command until the end of the line. So I just added bindkey -r '^K' to my .zshrc file to ignore this control sequence.

Disclaimer

I’m not affiliated with any of these tools, I just wanted to shoutout to them on how awesome they are.

Happy coding!