A real engineering workspace for Claude Code. In your terminal.

Parallel Claude Code sessions in live panes, with the file tree, the diff and your own checks right beside them. Built for engineers who read the code before they ship it.

omatty runs your project's own check line inside each session's worktree and puts the verdict on the session's card.

curl -fsSL https://omatty.com/install.sh | sh
Read the source

v0.11.0, pre-1.0. For macOS and Linux, with git and Claude Code.

A real omatty session
 projects · 2               │ parser ▎ quoted fields · quoted-fields · ✓ done <1m   │ diff · 2 files · 0 comments
────────────────────────────┼───────────────────────────────────────────────────────┼─ diff ───────────────────────────×
  ▾ ledger                  │  ⎿  Added 7 lines                                     │ fields.go +25 -4 1/2
  ✓ round to cents      <1m │      18      t.Fatalf("Fields = %q, want %q", g       │ @@ -1,9 +1,30 @@
    round-to-cents   +10 −2 │          ot, want)                                    │  // Package parser reads comma-sep
    ✓✓✓  READY              │      19    }                                          │  package parser
  ▾ parser                  │      20  }                                            │
▎ ✓ quoted fields       <1m │      21 +                                             │ -import "strings"
▎   quoted-fields    +39 −4 │      22 +func TestFieldsEscapedQuote(t *testing       │ -
▎   ✓✓✓  READY              │         +.T) {                                        │ -// Fields splits one CSV line int
                            │      23 +  got := Fields(`a,"b""c",d`)                │ +// Fields splits one CSV line int
                            │      24 +  if want := []string{"a", `b"c`, "d"}       │ +// double-quoted field is kept as
                            │         +; !reflect.DeepEqual(got, want) {            │ +// themselves are dropped.
                            │      25 +    t.Fatalf("Fields = %q, want %q", g       │  func Fields(line string) []string
                            │         +ot, want)                                    │ -    return strings.Split(line, ",
                            │      26 +  }                                          │ +    var fields []string
                            │      27 +}                                            │ +    var field []byte
                            │                                                       │ +    inQuotes := false
                            │⏺ Added doubled-quote handling: "" inside a quoted     │ +
                            │  field now emits a literal " instead of toggling quote│ +    for i := 0; i < len(line); i+
                            │  state (fields.go:15-17), and added                   │ +        c := line[i]
                            │  TestFieldsEscapedQuote for a,"b""c",d → b"c.         │ +        switch {
                            │                                                       │ +        case c == '"' && inQuotes
                            │✻ Sautéed for 12s · done 12:28 PM                      │ +            field = append(field,
                            │                                                       │ +            i++
                            │───────────────────────────────────────────────────────│ +        case c == '"':
                            │❯                                                      │   >> (sent 12:27) Handle a doubled
                            │───────────────────────────────────────────────────────│ +            inQuotes = !inQuotes
                            │  ⏵⏵ auto mode on (shift+tab to cycle) · ← for agents  │ +        case c == ',' && !inQuote
 ctrl+o q quit  ctrl+o ? keys  ctrl+o j/k switch  ctrl+o n new  ctrl+o d diff                                 2 sessions

Real omatty v0.11.0 and real Claude Code, in two Go repositories: both sessions work at once, the file tree marks what changed, the gate lands on each card, and a review comment goes back and stays on its line while Claude edits. The keys and the two prompts are scripted; the rest is not. Long waits are shortened in playback.

Your agents are in one place. Your engineering is everywhere else.

You already run Claude Code in parallel: a session per task, a worktree per session, often across more than one repository. Starting them takes seconds.

Everything you need to judge their work lives somewhere else: panes in tmux, files in an editor, the diff in a git client, the tests in one more terminal per worktree, the pull request in a browser tab. The agents are fast. You are the one switching between all of it.

What the switching costs you

  • You lose the thread

    Which worktree is this file in, and which session changed it? With four sessions running, every look starts with finding the right window.

  • You become the test runner

    Three worktrees means changing directory, running the suite and reading the output three times, and again after the next turn.

  • Every correction is retyped

    Telling a session what broke means copying output, switching panes and explaining it again, while Claude keeps editing the file you are pointing at.

What if the whole loop lived in one window?

Picture every session in a live pane, its files and its diff beside it, your own checks already run on its latest turn, and the failures one key away from the session that caused them. Nothing to switch to, and nothing that leaves your terminal.

One window, the whole engineering loop

  1. Claude works in live panes

    Each session is the real claude binary in a pane you type into, in a worktree of its own, with sessions from several repositories side by side. The sidebar tells you which one is working, which is waiting for you and which is done, read from Claude's own hooks, never from the screen.

  2. The file tree follows each session

    ctrl+o f shows the worktree of the session you are on and moves with you to the next one. When Claude finishes a turn, the tree lists itself again and marks every file Claude added, changed or deleted, so you open the ones that matter. If Claude moves into another worktree of the repository, the tree and the diff follow it there. Mark a file read, and it tells you when it changes again.

  3. Read the diff, and answer it

    Everything the session changed, syntax-highlighted, with the lines no test covers marked. Comment on the lines you disagree with and send every comment back as one message. Comments anchor to a line's content, not its number, so they stay put while Claude edits the file.

  4. Your gate runs on every session

    The fmt, vet, lint, test and coverage line your project already uses, run in that session's worktree on one key, or on its own when a turn ends. One mark per step on the card, and a step passes only when its process exits 0. S sends the failing output back into the session that caused it.

  5. Ship it, or take it back

    ctrl+o p pushes and opens the pull request, or merges it when your gate and the forge's checks are both already green. ctrl+o u puts the worktree back to where the last turn began. ctrl+o i shows the project's issues and pull requests in the same column, whether it lives on GitHub, GitLab, Gitea, Bitbucket or Azure DevOps, and an issue can start a session of its own.

The rest of it, by the key you press

Every keystroke goes to Claude except ctrl+o. These are the keys and commands that do the rest.

ctrl+o g
Open the gate pane and run the gate for the session you are in.
ctrl+o d
Everything the session changed, syntax-highlighted, with the lines it added that no test covers marked.
ctrl+o u
Put the session's worktree back to where its last turn began.
ctrl+o p
Push and open the pull request, or merge it when your gate and the forge's checks are both already green.
omatty discover
Pick from the repositories Claude Code already knows you use.
omatty adopt
Bring in the Claude sessions you already have in a repository.
ssh -t box omatty
It is a terminal program, so it works over SSH on a headless machine. With dtach installed, quitting detaches instead of ending your sessions.
omatty gate
Shows a project's gate, or proposes one from the repository and runs nothing until you confirm. It also reports lead time and how often the gate passes first time, and those numbers never leave your machine.

It never writes your ~/.claude/settings.json, or any other agent's configuration. Hooks are passed to each session it starts, and status comes from those hooks and Claude's transcripts, never from reading the screen.

Built to judge the work, not just to run it

Most tools for parallel agents are built to put more work in flight. omatty is built for what comes after: finding out which of it is good.

What you needomattyherdrwith herdr‑reviewrOrcadesktop appclaude agentsbuilt into Claude Code
Your own check line runs in each session's worktree, a verdict per step on its cardYesNoNoNo
Your gate's failures go back to the session with one keyYesNoNoNo
Review comments stay on the right line while Claude editsYesNoNoNo

As of 27 September 2026. Every cell is sourced in the full comparison. Read the full comparison

What it will not do

omatty does not delegate, plan, schedule or decide for you. There is no coordinator, no agent-to-agent messaging, no unattended queue and no cloud. You stay the part of the loop that catches things; omatty's job is to get you there sooner.

Why, feature by feature

Questions

What is a terminal ADE?

An agent development environment that lives in your terminal: the agents run in panes, and the tools for judging their work (the diff, the review, the gate) sit around them. omatty runs the real claude binary; it does not reimplement Claude's interface.

How is this different from claude agents?

claude agents lists your background sessions across all your projects, each in a worktree, shows each pull request's checks, and it is free and in the box. omatty puts several live sessions side by side, adds a review loop, and runs your own check line in each session's directory before anything is pushed.

How is this different from herdr?

herdr is a terminal workspace for many kinds of agent, and it is ahead of omatty on breadth: more agents, more operating systems, and several machines in one window. omatty is narrower. It reads Claude's status from hooks and transcripts rather than the screen, never writes your Claude settings, keeps review comments on the right line while Claude edits, and runs your gate on every session.

Does it send anything anywhere?

No. omatty talks to git, to claude and to your forge, through the forge's own CLI if you have it installed (gh, glab, tea or az), or its API with a token you already set, which omatty never stores. The two numbers it keeps about itself stay in ~/.omatty.

What do I need to run it?

macOS or Linux (no Windows yet), git and Claude Code. dtach is optional and keeps your sessions running when you quit. Your forge's CLI, or a token for its API, is optional and turns on pull requests and issues. omatty is pre-1.0, so keys and config can still change between minor releases.

Does it work with GitLab, Bitbucket or Azure DevOps?

Yes. The pull request on each card, the issues in ctrl+o i and ctrl+o p work on GitHub, GitLab, Gitea, Forgejo and Codeberg, Bitbucket Cloud and Data Center, and Azure DevOps, through the forge's own CLI (gh, glab, tea or az) or its API with a token from your environment. Azure DevOps Server is not read yet. The README's Forges table says which forges a real run has shown.

Which agents does it run?

Claude Code, as the real claude binary, with everything on this page, and OpenAI's Codex, as the real codex binary, its status and token usage read from its own hooks and rollout. Any other agent runs in a pane too: declare its command in ~/.omatty/config.toml and choose it per session, per project or as the default. For those, omatty shows whether the agent is running and says plainly what it cannot know, rather than guessing. OpenCode, Gemini and others are on the way to the same support.

What does it cost?

Nothing. omatty is free and MIT-licensed. Claude Code is billed by Anthropic as usual.

Does it change my Claude Code setup?

No. It never writes ~/.claude/settings.json. Its hooks are handed to each session it starts, on that session's command line, so running omatty leaves no trace in your Claude configuration.

What if my project has no gate yet?

omatty gate <project> reads the repository and proposes the line it already uses: gofmt, go vet and go test; cargo fmt, clippy and test; ruff and pytest; or the lint and test scripts in package.json. Nothing is written or run until you confirm it.

How do I install it without Homebrew?

Run curl -fsSL https://omatty.com/install.sh | sh. It downloads the release archive for your macOS or Linux machine (amd64 or arm64), refuses it unless it matches checksums.txt, and installs to ~/.local/bin without sudo; with Homebrew present it uses the tap instead. The script is scripts/install.sh in the repository, so you can read it first. Or build it with go install github.com/WilsonSousajr/omatty/cmd/omatty@latest.

Run it, and tell us what broke.

omatty is young, and the fastest way it gets better is someone other than its author using it. Install it, point it at a repository you work in, and open an issue for anything that surprised you.

curl -fsSL https://omatty.com/install.sh | sh
brew install WilsonSousajr/tap/omatty
Open an issue