메뉴
HN
Hacker News 41일 전

코드를 직접 실행하는 AI 코드 리뷰어, TREX

IMP
8/10
핵심 요약

Greptile이 단순히 코드를 읽는 것을 넘어 직접 코드를 실행하여 런타임 버그를 잡아내는 AI 코드 리뷰어 'TREX'를 개발했습니다. 이 도구는 메인 리뷰 에이전트가 문제를 식별하면 하위 에이전트를 병렬로 파견하여 실제 환경에서 코드를 테스트하고 그 결과를 시각적으로 제공합니다. 개발자들은 코드 리뷰 과정에서 기존 AI 도구로는 발견하기 어려웠던 논리적 오류나 UI 회귀 등의 복잡한 버그를 효과적으로 찾아낼 수 있게 되었습니다.

번역된 본문

안녕하세요, Greptile의 소프트웨어 엔지니어인 Shlok입니다. 저희는 최근에 풀 리퀘스트(Pull Request)를 검토하는 것은 물론, 실제로 코드를 실행하여 무엇이 잘못되었는지 보여주는 코드 리뷰어를 개발했습니다.

1976년, Michael Fagan은 IBM에서 공식적인 코드 인스펙션(Code Inspection)을 도입하는 논문을 발표했습니다. 당시 개발자들은 코드 프린트물을 뽑아서 한 방에 같이 앉아 한 줄씩 코드를 읽어 내려갔습니다. 오늘날에도 우리는 여전히 화면상에서 diff(변경 사항)를 읽습니다. AI 도구들이 이 과정을 더 빠르게 만들긴 했지만, 대부분은 여전히 코드를 '읽는' 수준에 불과합니다.

이러한 접근 방식은 코드 자체에 명백하게 드러나는 버그를 찾는 데는 효과적입니다. 하지만 문제는 코드상에는 전혀 나타나지 않고 프로그램이 실행될 때만 존재하는 부류의 버그들이 있다는 것입니다. 특정 상태(State)의 순서가 필요한 논리적 오류, 페이지 로딩 후에 나타나는 UI 회귀(Regression), 실제 요청이 필요한 레이스 컨디션(Race condition) 등을 떠올려 보십시오. 변경 사항을 완벽하게 읽더라도 이런 유형의 버그는 완전히 놓칠 수밖에 없습니다. 정적 코드 리뷰에는 한계가 있습니다. 코드가 '무엇이라고 말하는지'는 추론할 수 있지만, 실제로 '무엇을 하는지'는 알려줄 수 없습니다.

TREX("Test, Run, Execute"의 약자)는 Greptile이 이러한 한계에 대응하여 내놓은 해결책입니다. 즉, 코드 리뷰에 직접 통합된 실행 계층(Execution layer)입니다.

문맥(Context) 낭비 없는 에이전트 오케스트레이션 TREX는 처음에 테스트를 생성하고 실행하는 독립적인 에이전트로 시작했으며, Greptile과는 완전히 별개의 제품이었습니다. 저희는 이 과정에서 버그가 자연스럽게 발견될 것이라 기대했습니다. 하지만 그렇지 않았습니다. 테스트를 생성하는 것은 버그를 찾는 것과 같은 활동이 아니었습니다. 분리된 TREX 에이전트가 테스트를 작성해 보았지만, 그 테스트들은 사용자가 실제로 하려는 것과는 전혀 관련이 없었습니다. 이는 불필요한 노이즈를 만들어냈고 엣지 케이스(Edge case)들도 놓쳤습니다. 지금 와서 보면 당연한 사실이지만, 저희가 이 교훈을 깨닫는 데는 예상보다 훨씬 오랜 시간이 걸렸습니다.

처음에는 각 에이전트에 고유한 문맥 창(Context window)을 제공할 수 있다는 가정하에 이 에이전트들을 분리하여 구축했습니다. 하지만 이는 두 에이전트가 지식을 공유하지 않은 채 별도로 실행된다는 것을 의미했습니다. 그 결과, 종종 동일한 코드베이스 부분을 두 번이나 탐색하며 겹치는 작업을 했고 서로 무엇을 찾았는지 알지 못해 결국 컴퓨팅 리소스만 낭비했습니다.

가장 명확한 해결책은 이들을 하나의 에이전트로 합치는 것처럼 보였습니다. 저희는 그렇게 시도해 보았고, 또 다른 문제에 부딪혔습니다. 전체 리뷰를 처리하는 단일 에이전트가 과부하에 걸린 것입니다. 서비스를 구동하고, 스크린샷을 찍고, 테스트를 실행하는 등 모든 과정을 거치자, 하나의 에이전트가 깔끔하게 처리하기에는 감당해야 할 문맥(Context)이 너무 많았습니다.

해결책은 TREX를 완전히 별개의 제품으로 존재하게 하는 대신, 기존 Greptile 리뷰어와 동일한 문맥을 공유하도록 만드는 것이었습니다. 이는 에이전트 내부에서 다른 에이전트들을 관리한 저희의 첫 사례였습니다. 두 개의 독립적인 에이전트와 달리, 이는 TREX가 제로 베이스에서 시작하지 않음을 의미합니다. TREX는 Greptile 리뷰어 에이전트가 이미 발견한 내용을 상속받고, 자체적인 문맥 창을 가지며, 조사해 달라고 요청받은 특정 문제에만 범위가 제한됩니다.

Greptile 리뷰어 에이전트가 오케스트레이터(Orchestrator, 지휘자) 역할을 합니다. 이 메인 에이전트가 diff를 읽고, 조사할 가치가 있는 문제를 식별한 뒤, 문제마다 전용 TREX 에이전트를 실행하여 모두 병렬로 처리합니다. 이렇게 파생된 TREX 에이전트들은 오케스트레이터 에이전트의 지식을 바탕으로, 필요한 컴퓨팅 권한과 자유를 가지고 작동합니다.

좋은 예시로 인증 게이트(Auth gate) 뒤에 숨겨진 UI 기능을 들 수 있습니다. 이를 로컬에서 테스트하려면 환경을 설정하고 인증을 처리한 다음 기능 플래그(Feature flag)를 올바른 상태로 만들어야 합니다. 하위 에이전트(Subagent)는 이 모든 과정을 스스로 파악하고 처리한 뒤, 렌더링된 기능의 스크린샷을 캡처하여 돌아옵니다.

작업 과정을 보여주는 멀티모달 아티팩트(Multi-modal artifacts) 설계 초기 버전의 TREX는 테스트한 내용과 그 결과를 글머리 기호(Bullet point) 형태로 나열하여 출력했습니다. 합리적인 출발점이었지만, 충분한 정보를 제공하지는 못했습니다. 에이전트나 인간 리뷰어가 "결제 흐름(Checkout flow)을 테스트했고 실패를 발견함"이라는 글머리 기호를 읽는다 해도 큰 도움이 되지 않을 것입니다. 프로세스의 어느 부분에서 문제가 발생했는지 알 수 없기 때문입니다. 테스트가 실패했다면, 그것이 설정 문제였습니까? 검증(Assertion) 문제였습니까? 아니면 환경 문제였습니까? 저희는 초기 버전에서 (이 한계를 깨닫고 시각화를 도입했습니다.)

원문 보기
원문 보기 (영어)
I'm Shlok, a software engineer at Greptile. We recently built a code reviewer that, in addition to reviewing pull requests, actually runs the code and shows you what went wrong. In 1976, Michael Fagan published a paper introducing formal code inspection at IBM. Developers would print out listings, sit in a room together, and read through the code line by line. Today we still read a diff on a screen. AI tools have made that faster, though most of them are still just reading the code. This approach works for a lot of bugs, the ones that announce themselves plainly in code. The problem is there's a whole category of bugs that don't show up in code at all; they exist when the program is running. Think of the logic error that needs a specific sequence of state, the UI regression that appears after the page loads, or the race condition that needs a real request. You can read the diff perfectly and still miss these types of bugs completely. Static code review has a ceiling. It can reason about what the code says. It can't tell you what it does. TREX (which stands for "Test, Run, Execute") is Greptile's response to that ceiling: an execution layer built directly into code review. Orchestrating agents without wasting context TREX started as a completely separate product from Greptile, as a standalone agent that generated and ran tests. We hoped that bugs would surface as a result. They didn't. Generating tests wasn't the same activity as finding bugs. When the separate TREX agent tried to write tests, the tests weren't relevant to what the user was trying to do. This created unnecessary noise, and it also missed edge cases. This sounds obvious in hindsight, but it took us more time than expected to learn this lesson. We'd built these agents to be separate with the assumption it would give each agent its own context window. It also meant both agents ran separately without sharing knowledge. They often overlapped, exploring the same parts of the codebase twice without either agent knowing what the other had already found, ultimately leading to wasted compute. The obvious fix seemed like combining them into one agent. We tried that, and ran into a different problem: a single agent handling the full review got overloaded. Between spinning up services, taking screenshots, running tests, there was too much context for one agent to manage cleanly. The solution was to make TREX share the same context as the main Greptile reviewer rather than having it exist entirely as a separate product. It was the first time we were managing agents from within an agent. Unlike two independent agents, this means TREX doesn't start from scratch. It inherits what the Greptile reviewer agent already found, has its own context window, and is scoped to the specific problem it's been asked to investigate. The Greptile reviewer agent acts as an orchestrator. It reads the diff, identifies issues worth investigating, and spins up a dedicated TREX agent per issue, all running in parallel. The TREX agents have the liberty, the compute, and the knowledge of the orchestrator agent. A good example of this is a UI feature hidden behind an auth gate. Testing it locally means setting up the environment, handling authentication, getting the feature flag in the right state. A subagent figures all of that out on its own and comes back with a screenshot of the rendered feature. Designing multi-modal artifacts to show the work The first version of TREX output findings as bullet points listing out what was tested and what happened. This was a reasonable starting point, but it didn't provide sufficient information. An agent or a human reviewer reading a bullet point like, "Tested the checkout flow, found failure" wouldn't find it very useful. They wouldn't be able to tell where in the process something went wrong. If the test failed, was it the setup? The assertion? An environment issue? We found an early version of the agent would sometimes hallucinate about how thoroughly it had tested something, claiming to have tried something it hadn't. Bullet points gave us no way to verify. The fix was to back the bullet point list with a multi-modal artifact set for each TREX finding: screenshots, logs, API traces, execution scripts. Each modality covers a different part of the story. Having a comprehensive picture of everything that was tested for a specific issue is what actually matters. The first artifact that made us say "Wow" was video. If you push an animation change, TREX captures a video of it playing. You can see exactly what the animation looks like without opening a local environment. Artifacts also need to be trustworthy. Every artifact has to give the reviewer enough to verify the run themselves. The screenshots, logs, traces, and scripts are all there so a person or downstream agent can look at exactly what happened and confirm it. Bad evidence is worse than no evidence. The reason artifacts matter, especially for agents downstream, is the same reason teachers require students to show their work. It's analogous to grade school math; you don't know where your answer was wrong until you show the steps. Agents are the same way. If an artifact shows proof of everything the test did to reach a conclusion, the agent can identify exactly which step went wrong. Without that trace, all it has is the answer, and the answer tells you nothing about where to fix it. If TREX finds a bug, it becomes a comment on the PR. If it runs a feature and everything works, that goes in the summary as proof the change was actually tested. Not every run needs to find something wrong to be useful. Building a model-agnostic evaluation harness The frontier race between model providers moves fast. A model that leads on code tasks one month can be behind the next. Building tightly around any single provider's API means rebuilding when rankings shift. That's not a viable long-term strategy. From the start, we designed TREX around a model-agnostic harness that allows hot-swapping between frontier models without rebuilding. The flexibility goes deeper than most people expect: the main agent and the subagents can use different providers. We can have multiple models running within the same review. This makes it easy for us to pick the best model at any given point, based on internal evals. Our current evaluation involves measuring recall (e.g., how many real bugs are caught, measured against open-source PRs or customer data where comments were addressed) and precision (e.g., consistency across runs: if you review the same PR twice, are you finding roughly the same set of issues?). We intentionally deprioritize latency in our evaluation. A developer waiting on a review would rather wait a little longer and get something accurate than get a fast answer they can't trust. The open source evaluation harness we use performs on par with native provider harnesses. There's no meaningful quality penalty for being model-agnostic which, if you'd asked me to guess before we tested it, I wouldn't have been confident about. TREX's differentiation is not which model it's running. It's the infrastructure around the model: the codebase indexing, the orchestration, the artifact generation, the evaluation framework. We don't need to care about intelligence as a differentiator, because intelligence is something that will continuously improve. Greptile's job is to build the harness, the architecture, and the artifact pipeline that makes the difference in practice. Code execution as a first-class review primitive Every TREX review spins up a disposable sandboxed environment: an isolated compute instance per review, started fresh in milliseconds, thrown away when the run is done. These environments start fast, isolate execution properly, and can run real projects; not just unit tests against a mock, but actual services wi