기존 리눅스 시스템 콜 추적 도구인 strace의 불편함을 해소하기 위해 개발된 대화형 터미널 UI 도구 'strace-ui'를 소개합니다. 이 도구는 실시간 필터링, 파일 디스크립터(FD) 추적, DNS 확인 등의 기능을 제공하여 개발자의 디버깅 경험을 극적으로 개선합니다. 이러한 혁신은 최근 웹 개발에서 사용하던 함수형 반응형 UI 프레임워크인 'Bonsai'를 터미널 환경에 적용하면서 가능해졌으며, 복잡한 대규모 애플리케이션의 코드 관리를 용이하게 합니다.
번역된 본문
저희는 항상 strace를 유용하다고 생각했지만, 다루기가 다소 까다롭다고 느꼈습니다. strace의 출력은 종종 이해하기 어렵고, 서브프로세스나 스레드를 따라가기 힘들며, 시스템 콜(syscall)을 필터링하려면 매번 플래그를 지정하여 트레이스를 다시 실행해야 합니다. 디버깅에 필요한 것은 데이터를 탐색하고 정제할 수 있는 도구지만, strace는 이를 꽤 어렵게 만듭니다.
바로 이 점을 해결하기 위해 strace를 대화형 터미널 UI로 바꾸는 strace-ui가 등장했습니다. strace-ui는 PID(프로세스 ID)에 짧은 ID를 할당하여 훑어보기를 쉽게 만들고, 구조체(struct)를 보기 좋게 포맷팁하며, 버퍼를 단순 문자열 대신 헥스덤프(hexdump)로 렌더링합니다. 또한 스크린샷에서는 확인할 수 없는 몇 가지 훌륭한 기능도 있습니다:
대화형 필터링: 비동기 OCaml 프로세스를 추적하고 있나요? -e '!futex,timerfd_settime,epoll_wait' 플래그를 넘기는 것을 잊으셨나요? 걱정하지 마세요. h 키를 눌러 관심 없는 시스템 콜을 숨길 수 있습니다.
특정 파일 디스크립터(FD) 추적: > 또는 < 키를 눌러 동일한 파일 디스크립터를 참조하는 다음/이전 시스템 콜로 바로 이동할 수 있습니다. 또는 F 키를 눌러 주어진 FD와 관련된 시스템 콜만 포함하도록 필터를 변경할 수 있습니다. (단순한 숫자 FD 필터링보다 조금 더 똑똑하게 작동하여 FD 재사용을 추적하고 포크(fork)를 넘어 추적을 시도합니다. 다만 이미 FD를 열어둔 프로세스에 연결할 경우 이 추적이 완벽하게 작동하지는 않습니다.)
rt_sigprocmask가 대체 뭔가요? m 키를 눌러 매뉴얼 페이지를 열고 알아보세요.
서브프로세스나 스레드에 일반 PID 대신 짧은 숫자 레이블이 할당되어, 복잡한 strace -f 호출을 더 쉽게 따라갈 수 있습니다. (PID별로 필터링하거나 특정 PID를 제외할 수도 있습니다.)
DNS 해석: strace의 --decode-fds=all 옵션은 파일 디스크립터를 14TCP:[55.55.555.555:12345-11.11.11.11:56789]>처럼 출력하며, 이것만으로도 훌륭합니다. strace-ui는 여기서 한 발짝 더 나아가 14TCP:[a-real-hostname:12345-another-hostname:56789]>처럼 출력해 줍니다. 덕분에 프로세스가 정확히 무슨 작업을 하고 있는지 한눈에 파악하기 쉬워집니다.
저희 개발팀의 이안 헨리(Ian Henry)는 본인의 필요를 충족시키기 위해 strace-ui를 만들었습니다. 2017년에 그는 이런 도구를 찾아 헤맸지만 끝내 찾지 못했습니다. 그는 (lambda_term을 사용하는 OCaml 등에서) 대화형 터미널 UI를 구축해 본 경험이 있었기에, 그 작업이 얼마나 어렵고 불편할 수 있는지 잘 알고 있었습니다. 이 아이디어는 수년 동안 마음속에 맴돌았지만 실행할 가치가 없다고 느껴졌습니다. 그러다 최근 몇 가지 요인들이 결합하면서 터미널 UI 개발이 실제로 꽤 즐거운 작업이 되었습니다.
반응형 UI를 위한 강력한 프레임워크, Bonsai
수년 동안 저희는 Elm에서 느슨한 영감을 받아 자체 개발한 Bonsai라는 라이브러리를 사용하여 함수형 스타일로 OCaml 웹 애플리케이션을 구축해 왔습니다. 약간의 상호작용이 포함된 간단한 Bonsai 컴포넌트는 다음과 같이 생겼습니다:
module Dice = struct
let faces = ...
let component ( graph @ local ) =
let face , set_face = Bonsai . state ( List . hd_exn faces ) graph in
let % arr face and set_face in
{% html |
< div > You rolled a #{ face }
< button style = "" on_click =%{ fun _ -> let index = Random . int ( List . length faces ) in set_face ( List . nth_exn faces index )} > Roll the dice </ button >
</ div > |}
end
컴포넌트는 순수 함수형 상태 머신으로 구현되며, 쉽게 조합(composable)할 수 있습니다. 프레임워크 내부의 증분 계산(incrementalization) 메커니즘 덕분에 필요할 때까지 값이 다시 계산되지 않습니다. 이는 뷰(View)에만 국한되지 않고 모든 값에 적용됩니다. Bonsai의 진정한 미덕은 상태와 증분 계산 원시(primitive) 요소들을 필요에 따라 자유롭게 조합할 수 있게 해준다는 것입니다. 사용자 상호작용 중에 전체 페이지를 다시 렌더링하지 않도록 막아주는 동일한 원시 요소들을, 실시간으로 업데이트되는 데이터셋의 비용이 많이 드는 비즈니스 로직 계산을 증분 계산하는 데에도 사용할 수 있습니다. (React에 익숙하다면, 모든 것이 훅(Hook)과 매우 유사한 방식으로 작동하고 상태가 컴포넌트 계층 구조 외부에서 관리된다고 상상해 보세요.)
그리고 Bonsai가 OCaml로 작성되었기 때문에 백엔드와 프론트엔드 모두에서 동일한 언어와 타입을 사용하는 것이 가능해집니다. 특히 OCaml의 타입 시스템을 광범위하게 활용할 때, 이것이 대규모 웹 애플리케이션의 코드베이스를 관리 가능한 상태로 유지하는 데 미치는 영향은 아무리 강조해도 지나치지 않습니다.
strace-ui, Bonsai_term, and the TUI renaissance May 26, 2026 | 10 min read Share on Facebook Share on Twitter Share on LinkedIn By: James Somers We’ve always found strace useful but somewhat hard to work with. Its output is often inscrutable, it’s hard to follow subprocesses or threads, and if you want to filter syscalls you have to rerun the trace with a flag for each one. What you want in debugging is a tool for exploring, refining, etc., but strace can make this difficult. Enter strace-ui, which turns strace into an interactive terminal UI: strace-ui assigns short IDs to PIDs to make them easier to scan, formats structs, and renders buffers as hexdumps instead of strings. It has some other nice features that you can’t see in the screenshot: Interactive filtering. Tracing an async OCaml process? Did you forget to pass -e '!futex,timerfd_settime,epoll_wait' ? Don’t worry: press h to hide any syscall you don’t care about. Trace a particular file-descriptor. Press > or < to jump to the next/previous syscall that referenced the same file descriptor, or press F to change your filter to only include syscalls that touch a given FD. (it’s slightly smarter than just numeric FD filtering: strace-ui tries to track FD re-use and follow across forks, but it doesn’t do a great job of that if you attach to a process that’s already opened FDs.) What even is rt_sigprocmask ? Press m to open the man page and find out. Subprocesses or threads are assigned short numeric labels, instead of showing you the raw pid, making it easier to follow a complex strace -f calls. (You can also filter by PID or exclude PIDs.) DNS resolution: strace’s --decode-fds=all will print file descriptors as 14<TCP:[55.55.555.555:12345->11.11.11.11:56789]>, which is great. strace-ui goes one step further and prints 14<TCP:[a-real-hostname:12345->another-hostname:56789]> , which makes it easier to see at a glance exactly what your process is doing. Ian Henry , a dev here, made strace-ui to scratch his own itch. In 2017, he’d gone looking for such a tool but never found it. Having had experience building interactive terminal UIs (including in OCaml, using lambda_term), he knew how difficult and unpleasant it could be. The idea percolated over the years, never feeling worth it, until recently when a few forces converged to make terminal UI development actually kind of delightful. Bonsai, a powerful framework for reactive UIs For years now we’ve been building web applications with OCaml in a functional style, using a library we developed called Bonsai , loosely inspired by Elm . A simple Bonsai component with a little interactivity looks like this: module Dice = struct let faces = ... let component ( graph @ local ) = let face , set_face = Bonsai . state ( List . hd_exn faces ) graph in let % arr face and set_face in {% html | < div > You rolled a #{ face } < button style = "" on_click =%{ fun _ -> let index = Random . int ( List . length faces ) in set_face ( List . nth_exn faces index )} > Roll the dice </ button > </ div > |} end Components are implemented as purely functional state machines, and are easily composable. Incrementalization inside the framework means that values don’t get recomputed until necessary. This applies to every value, not just the view. What’s neat about Bonsai is that it allows you to compose state and incrementality primitives a la carte. The same primitives that prevent re-rendering the entire page during user interaction can also be used to incrementalize an expensive business logic computation on a live-updating dataset. (If you’re used to React, imagine if everything used something very similar to hooks, and state was managed outside of the component hierarchy.) And because Bonsai is written in OCaml, it becomes possible to use the same language and types on both the backend and frontend. It’s hard to overstate the impact this has on keeping a large web app’s codebase manageable, especially when you make pervasive use of OCaml’s type system. Bonsai is not really a web framework So far we’ve actually been talking about Bonsai_web. Bonsai itself is agnostic to the frontend, because when you think about it, all UIs can fundamentally be expressed as stateful incremental computations, in which different components know how to render themselves as their underlying data changes. If Bonsai is a library for managing the lifecycle and scoping of state, with a layer on top for expressing the particulars of a given UI surface, you can see how the same underlying core can be adapted. And that is where Bonsai_term came from. When Ty Overby made Bonsai in 2019, the idea that it’d eventually end up being used for terminal apps was a running joke. In some ways the whole point of Bonsai was that at Jane Street we felt somewhat underpowered when it came to web development. Some of our most important apps were built on the ancient and somewhat difficult curses library, which lives up to its name. Terminal apps are fast and keyboard-centric, which we like, but the web also has a lot going for it. It’s hard to beat the ergonomics of clicking a hyperlink; and of course the web gives you a vast palette for constructing UIs, including charts and graphics that aren’t practical on the command line, and integrated help (via tooltips and the like). In the years after the release of Bonsai_web there was a huge flowering of web apps, including many that were ported directly from the terminal. But here we are in 2026 and it feels like another renaissance is afoot, this time in the opposite direction. Terminal UIs experience a comeback — the Claude Code effect? Bonsai_term began as a personal hobby project in the summer of 2024, when Jose Rodriguez—one of our devs—built it to write a manga reader with the kitty graphics protocol. It showed enough promise that he later made some ncdu-style tools for wider Jane Street use. In April 2025, Bonsai_term had enough traction that we started productionizing it in earnest. It so happened that AI agents were coming onto the scene, and it was the arrival of Claude Code in February 2025 that kicked everything into gear. It became clear fairly quickly that a well-made terminal app was winning out over full-featured IDEs, in large part because of the speed, simplicity, and portability of the terminal itself. Terminal emulators are everywhere and deeply integrated into editors; TUIs met devs where they already were. In the beginning was the command line , and so it remains—ubiquitous and always at hand. We doubled down on Bonsai_term, and pretty soon a feedback loop came into being. We developed our own Claude Code–ish tool, called AIDE, (which we built to maintain the freedom to choose between different model vendors, to suit our unusual development environment, and to better control the execution sandbox), which became both a demo of Bonsai_term and a partner in creating it. While building AIDE into a full-featured agent-harness, we threw off a rich library of UI components that other apps could then take advantage of. Developers who became acquainted with this unusually good TUI were pleased to discover that they could make their own terminal apps with just as much polish thanks to the new framework it was built in. Bonsai_term would feel familiar to anyone who’d ever done web development here, and it had the huge advantage of being especially amenable to AI assistance. It was actually somewhat of a mystery to us how good the models were at writing Bonsai_term code, given how relatively obscure it is and how it relies, for example, on OxCaml -only features. (We think it might have something to do with the testing story, discussed below.) Then, recently, with the advent of Bonsai_term and AI agents, Ian found he could make a working prototype in less than ten minutes. The prototype was useful enough to justify the ongoing time spent making it real. Notice how the 'expect' block in these tests contains a rendering of the actual UI Closing the loop with screens