Skip to main content
D
Dioni.dev
Back to home
Indie10 min read

Shirei is no longer a terminal with tabs: it's where my whole session lives

I'm still working the same idea from when I launched Shirei: never leave the app while working with agents. In 19 days that meant adding an editor with visual git, panels that stack over the terminal and now a native browser pane... and leaving what's still missing right there in the roadmap, in plain sight.

Dioni avatar

Dioni

Updated:

Share:
Shirei with the pinned dock active: a live dev server next to the terminal, without switching windows.

When I launched Shirei on June 24, I launched it as a terminal with tabs: lightweight, never losing track of the agents running in parallel. A few releases later it's changed a lot, and today I'm actually getting my whole dev session to live in there. I added an editor with visual git, panels that stack on top, a native browser pane. The core idea never changed, don't leave the app while I work with agents, what changed is how much of that idea I've actually built.

From multi-agent terminal to a CLI-agnostic session host

My internal CLAUDE.md doesn't say multi-agent terminal anymore. It says the home for AI agent sessions, CLI-agnostic, with satellite tools that install as plugins. The change didn't happen overnight: it started as tab management with a timer showing how long since I'd last touched each project, and it turned into, mostly, knowing which session needs me right now, whether it's running Claude Code, Codex or any other CLI. That's the goal, and I already designed the architecture to get there, but today, in production, only Claude Code is actually tested. The rest is still pending, and I'll turn the others on one at a time. What frustrated me most about my own sessions was never the lack of tabs. It was opening different apps, not knowing at a glance which of the six or seven windows open was waiting on me, and losing time or leaving an agent hanging when it needed me. That was already happening before launch, in the long days that got me to build Shirei in the first place, only with fewer agents running in parallel it was easier to hide. That's the problem I've been chasing release after release since launch.

Part of chasing that was deciding what not to build. In v0.13.0 I added the editor and made it a viewer. Today I review every .md I generate through it, and my CMD+P flow, find the file, open it in the same pane or send it to a new one, I love it. Then I needed to look closer at git changes, so instead of running that in the terminal I moved it into the same editor: I review the diff inline right there, and if I need to act or decide on something, I can do that too. I see line-by-line blame with a hover card and keep each file's history commit by commit. But committing, staging or switching branches stays in the console, on purpose. I looked into adding hunk-level staging straight into the editor and dropped it: the console already does that job well, and I'd rather keep a terminal cockpit than end up building an IDE on top of it. I didn't even add LSP. I left the space reserved in the editor's code, but I'm not building it until I actually feel the need.

I didn't give the editor its own theme. I made it pull the same ANSI palette I already use in the terminal and tuned the contrast with APCA to keep the text readable, so it reads as an extension of the terminal, not another app's window bolted on the side. I built it on top of CM6, so I didn't have to add a single new dependency.

For markdown I left Obsidian-style live preview on by default, indentation guides, bracket matching, find/replace with a match counter. Everything I'm used to having now lives in Shirei.

The real milestones since launch: editor, panels, browser pane

On June 24 I shipped v0.12.0: i18n from day one with English as the default, tabs with the time-since-last-touch indicator. Two days later I upgraded the whole toolchain without it showing from the outside: Rust 1.96, Tauri 2.11.3, Vite 8 with Rolldown, TypeScript 6. I'd rather pay that infrastructure debt early, with the app just published and few features on top, than drag it for six months and end up migrating with real users inside. Four days later, in v0.13.0, I shipped the editor with visual git I mentioned above.

On July 3, in v0.14.3, I added multi-type panels: files open stacked over the terminal, never replacing it, I cycle between them with ⌘⌥1-3, and I added quick open with Tab to switch scope between project and home. That's when I started switching windows less and less. The same week I added auto-update inside the app itself, with an explicit consent modal, never silent. I'd rather spend a bit longer on every release than risk updating something under the user without them knowing. The following days I spent paying down debt on persistent sessions: TUI reattach sometimes left a ghost cursor on screen; if the daemon crashed while I was working in an editor pane, copy, paste and scroll went dead until I reopened it. Nothing glamorous, but the kind of fix that makes me trust leaving a session running overnight.

I have mux baked in: turn on the daemon and if I close everything, it comes back exactly the way it was, what I liked about tmux minus the tedious per-project config.

On July 10, in v0.15.0, I added the browser pane and a pinned dock: a fixed column with two cells where I keep the browser or a second terminal always visible, with its own shortcuts (⌘⌃P to pin, ⌘⌃T and ⌘⌃B to move between cells), no matter which tab I'm on. I pulled it out of the stacked panel system on purpose: I wanted a column that wouldn't move when I switch tabs, and if the browser lived inside the regular panels I'd lose it every time I jumped projects. That's, as of today, the last version with a real tag and a published release on GitHub.

I'm a sucker for Study With Me videos, or Night Drive lofi beats playing in the background while I work, so this fits perfectly into my dev sessions.

The quick open I added in v0.14.3 needed reinforcing that same week: it cached the index per project, but if I switched scope fast, from project to home and back, it sometimes showed me stale results from the previous search. I added a generation token to the cache so any old result gets dropped the moment I switch scope. A small detail nobody notices until it breaks, but it matters once you're actually using it.

In 19 days I went from v0.12.0 to v0.15.10 in my internal changelog: 20 version entries. Of those, 12 have a real tag and a published release on GitHub. The last eight, the agent orchestration epic, still live on a local branch I haven't published. I'll get back to that at the end.

With all of that running at once, I got worried about the footprint. I ran my own measurement script: at rest, my session sits around 153 MB and 0% CPU. With a real session of 24 open panels, that jumps to 844 MB and 11% CPU, and that's the browser pane's WebKit and its GPU processes, not the agents' work inside the terminals. Something I'll keep trying to optimize going forward, but for everything that's open right now it's still pretty well optimized, and performance holds up well as far as I can tell.

The browser pane I added isn't YouTube support

I looked into adding a dedicated YouTube pane and dropped it. The video throws Error 153 the moment it runs inside the tauri:// context, and there's no way around it without moving the whole app to a real http origin, which breaks the privacy-first, offline model I want to keep for the rest of the product. I might revisit it later, but I don't know, it doesn't convince me yet. I don't want to change the entire architecture for a single page. So instead of a YouTube integration I built a generic browser pane: native webview with its own address bar, back and forward, auto-hide chrome when I don't need it, and I made localhost:PORT work without having to type the scheme, something I use every day to check my own dev server while I change code.

The browser pane I added in v0.15.0 isn't a YouTube integration. I built a generic webview: I open any page there, YouTube included, without leaving the app. I keep it pinned in the dock: I check the preview of whatever I'm building in one cell, and in the other I leave a video running in the background while I work in another tab. It's the same piece.

Does it work with Codex, Gemini or other CLIs, or just Claude Code?

The state detector I built for this, on the same unpublished branch I mentioned above, doesn't read anything specific to Claude Code: it looks at the same things any terminal exposes, OSC 9, 777 and 99 escape sequences, dynamic titles, CPU and idle timing. Before calling it done I verified it byte by byte against Gemini (which sends OSC 9, 777 and a dynamic title), Qwen (identified by TERM_PROGRAM), Codex (OSC 9), Crush and Devin, so the architecture itself is already CLI-agnostic. But in the version I'm running today, still unpublished, Settings → Agents only lists Claude Code as live, the rest is marked Soon, switched off on purpose until I test each one for real, one at a time, before letting it run for anyone who installs the app. The rollout will be incremental even though the foundation no longer depends on a single CLI.

What broke along the way

One day after shipping the editor, I released v0.13.2 because session keep-alive was completely broken in release builds: shirei-mux, the daemon that keeps terminals alive, wasn't being bundled with the app. Anyone who updated lost their persistent sessions with no warning, even though the dev build ran fine on my machine. That's when I learned that testing only in dev mode told me nothing about what would happen with the real bundle. I fixed it the next day by adding the binary to the bundle at build step.

On July 6, I shipped v0.14.10 for a smaller but more annoying bug: file search was walking the entire ~/Library, including other apps' data I didn't even touch, and macOS started asking for permissions in a loop every time the path got near a protected folder. Indexing everything for convenience was costing me more than just scoping it right from the start, so I narrowed it down to project and home, nothing else, instead of indexing the whole disk.

What's next: agent orchestration, still unpublished

The agent orchestration epic is what I'm building right now, while I write this post, it's next on the roadmap. After that I want to revisit performance again and improve the visual side of the app, fix whatever needs fixing in the design so it's genuinely nice to look at.

I want to start tracking the time I spend in sessions, a brief for each one, review, patterns... a bunch of things in mind, and I'll figure out how to sort the backlog and what to prioritize as I go. Today I'm still working the same idea as June 24: don't leave the app while I work. Every release gets a little closer, and the changelog documents what broke along the way too, and what I left out on purpose. The code and the roadmap are on GitHub, at github.com/zeroblack/shirei. If you try it and it's useful, now you know where to find it.

#shirei#build-in-public#terminal#ai-agents#indie

If this resonated, let me know

Dioni avatar

Dioni

Solo developer documenting the journey of building products as an indie hacker. Focused on productivity, applied AI, and sustainable development practices.

Related Posts