에이전트가 생각하는 동안 타이핑하기
요약
AI 에이전트의 작업 대기 시간 동안 개발자의 생산성을 높이기 위한 글쓰기 연습 도구 'wordwright'를 소개합니다. 단순한 타이핑 연습을 넘어, 문장 구조와 문법적 원리를 학습하며 짧은 공백을 효율적으로 활용하는 방법을 제안합니다.
핵심 포인트
- AI 에이전트 실행 중 발생하는 1~5분 사이의 유휴 시간 활용 방안 제시
- 단순 타이핑 속도 향상이 아닌, 명확한 기술 문서 작성을 위한 글쓰기 훈련
- 문장 구조와 문법적 패턴을 학습할 수 있는 wordwright 도구 설계
- 에이전트 작업 완료 시 즉시 복귀 가능한 짧은 작업 단위(문장) 중심의 설계
나는 Claude Code에게 모듈 리팩토링을 요청하고 나서 그냥 앉아 있었다.
오래는 아니었다. 브라우저 탭을 하나 열고, 관심도 없는 내용에 대한 스레드를 절반쯤 읽고, 머릿속에 담아두었던 것을 놓쳐버릴 정도의 시간이었다. 실행이 끝났을 때, 나는 내가 무엇을 요청했는지 기억하기 위해 내가 쓴 프롬프트를 다시 읽어야만 했다.
이제 이런 일이 하루에도 여러 번 일어난다. 제대로 측정해 본 적은 없으며 그런 척할 생각도 없지만, 그 양상은 명확하다. 실행 시간이 1분 미만인 경우는 드물고, 때로는 5분까지 걸리는데, 그 공백은 정확히 잘못된 길이이다. 멍하니 바라보기에는 너무 길고, 무언가를 시작하기에는 너무 짧다.
그래서 나는 그 구멍을 채울 무언가를 찾아 나섰고, 내가 시도한 모든 것들은 똑같은 방식으로 잘못되어 있었다. 타이핑 연습기(Typing trainer)는 뒤섞인 단어들을 제공하고 당신은 키를 치는 속도가 빨라지게 만든다. 그게 전부다. 하루에 20분을 투자해도 개선되는 유일한 것은 근육뿐이다. 반면 내 일과에서 실제 병목 현상(bottleneck)은 내 손가락이 얼마나 빨리 움직이느냐가 아니다. 명확한 Pull Request(PR) 설명, 티켓, 혹은 이 글과 같은 한 단락을 쓰는 데 얼마나 시간이 걸리느냐이다.
글쓰기를 연습하기에 가장 좋은 2분은 기계가 글쓰기를 마치기를 기다리며 보내는 그 2분이다.
제약 사항
에이전트가 멈추는 순간 작업도 끝나야 한다. 이것이 전체 설계 문제의 핵심이다.
모든 것이 여기서 파생된다. 로그인은 안 된다. 로그인은 이 공백보다 더 많은 비용이 들기 때문이다. 네트워크도 안 된다. 2분이라는 시간 창 안에서 스피너(spinner)가 돌아가는 것은 실패와 마찬가지이기 때문이다. 완료해야 하는 세션도 없어야 한다. 실제로 하고 있던 일이 예측할 수 없는 순간에 돌아오기 때문에, 문장 중간에 아무런 손실 없이 바로 떠날 수 있어야 하기 때문이다. 그리고 작업 단위는 한 단락이 아니라 한 문장이어야 한다. 한 문장이 딱 맞기 때문이다.
문장을 의도적으로 선택하기만 한다면, 한 문장만으로도 무언가를 가르치기에 충분하다는 것이 밝혀졌다.
기능
이것의 이름은 wordwright이다. 당신이 문장을 타이핑하면, 시스템이 당신을 측정하고, 그 문장이 왜 그런 방식으로 구성되었는지 알려준다.
wordwright intermediate · drill 3/8
────────────────────────────────────────────────────────────────────────────
...
저 세미콜론 (semicolon)이 바로 이 연습의 핵심이다. 당신이 문장을 타이핑하면 속도를 확인할 수 있고, 왜 세미콜론은 그 두 절을 연결할 수 있는데 쉼표 (comma)는 안 되는지에 대해 두세 문장의 설명을 듣게 된다. 코퍼스 (corpus) 내의 모든 문장은 하나의 패턴을 전달하기 위해 존재한다. 즉, 지나가는 길에 명사를 정의하는 동격 (appositive), 현수 수식어 (dangling modifier), 그리고 fewer와 less의 차이 같은 것들이다.
틀린 글자는 거부되는 대신 빨간색으로 화면에 남아 있다. 틀린 키를 거부하는 트레이너는 키가 제대로 눌릴 때까지 두드리도록 가르치며, 보고서에서 실수를 조용히 숨겨버린다. 하지만 여기서는 실수가 발생한 지점을 볼 수 있으며, 다시 돌아가서 수정할지 직접 결정할 수 있다. 수정하더라도 이미 실수가 발생했기 때문에 정확도 (accuracy) 측면에서는 여전히 손해를 본다.
그다음은 내가 실제로 이 도구를 만든 목적인 또 다른 모드가 있다. 이 모드는 당신에게 짧은 지시 사항 (brief)을 주고, 당신이 직접 문장을 작성하게 한다.
score ▓▓▓▓▓▓▓▓▓▓▓░░░░░ 2/3 checks
yours the outage was caused by an expired certificate
...
이 과정에는 모델 (model)이 개입하지 않는다. 단 한 번의 호출 (call)도, 단 하나의 토큰 (token)도 사용되지 않는다. 각 검사 (check)는 당신이 직접 열어보고 읽을 수 있는 JSON 파일에 담긴 규칙이다. '이 패턴이 나타나야 함', '이 패턴은 나타나지 않아야 함', '12단어 이내로 유지할 것', '이 단어를 사용할 것' 같은 규칙들 말이다. 이는 인간 편집자(human editor)에 비하면 한참 못 미치는 수준이지만, 내가 포기하고 싶지 않았던 세 가지를 보장해 준다. 판정은 키를 누르는 것과 동일한 프레임 내에서 즉각적으로 도착한다. 판정은 매번 동일하므로, 어제 통과하지 못한 규칙은 오늘도 똑같은 방식으로 통과하지 못한다. 그리고 이 도구는 기차 안에서도 작동한다.
채점은 의도적으로 두 부분으로 나뉜다. 메카닉스 (mechanics)는 문장 맨 앞의 대문자나 끝의 마침표처럼 당신이 쓰는 모든 것에 적용되는 규칙이다. 체크 (checks)가 실제 학습 내용이며, 각 체크는 당신이 무엇을 틀렸는지 대신 무엇을 해야 하는지를 알려주는 힌트와 함께 실패를 알린다. "여전히 수동태입니다. 행위자를 동사 앞으로 배치하세요"라는 피드백은 유용하지만, "부정확함"이라는 피드백은 유용하지 않다.
이해하기 (Getting it)
npm install -g wordwright
wordwright
Node 20.11 이상 버전이 필요하며, 별도의 런타임 의존성(runtime dependencies)이나 설정할 것이 없습니다. 아무것도 설치하고 싶지 않다면, npx wordwright를 통해 한 번만 실행하고 흔적을 남기지 않을 수 있습니다.
wordwright 레벨과 모드를 선택하여 연습하세요
wordwright drill 문장을 타이핑하며 분당 단어 수(WPM)를 측정합니다
wordwright compose 지시 사항에 따라 글을 쓰며 문법과 의도를 평가받습니다
...
단순히 wordwright만 실행하면 레벨과 모드를 묻고 8개의 연습 문제를 실행하며, 이는 약 2분 정도 소요됩니다. --count 3을 사용하면 더 짧게 진행할 수 있습니다. --level advanced는 첫 번째 메뉴를 건너뜁니다. Escape 키를 누르면 언제든 종료할 수 있으며, 완료한 내용은 모두 유지됩니다.
세 가지 레벨이 있습니다. Beginner(초급)는 기초가 되는 단계로, its와 it's의 구분, 주어와 동사의 일치(subject and verb agreement), and 앞의 콤마 사용 등을 다룹니다. Intermediate(중급)는 문장 연결 요소인 세미콜론(semicolons), 콤마 결합(comma splices), 능동태(active voice), 병렬 구조(parallel structure)를 다룹니다. Advanced(고급)는 리듬과 정밀함을 다루며, 동격(appositives), 긴 문장 뒤에 배치하는 짧은 문장, 불필요한 수식어 제거(cutting the hedges), 그리고 절 전체를 하나의 단어로 압축하는 표현 등을 포함합니다.
사용자의 기록은 ~/.wordwright/progress.json에 단일 파일로 저장됩니다. 도구가 보여주는 모든 수치는 요청 시 이 파일로부터 도출되므로 데이터가 오래되어 쓸모없어지는 일이 없으며, 보낼 곳이 없기 때문에 데이터가 어디론가 전송되지도 않습니다.
다음에 선택되는 항목 (What it picks next)
무작위 문장을 제공하는 트레이너는 당신이 이미 잘하는 것을 훈련시킵니다.
모든 연습 문제에는 포커스 태그(focus tags)가 포함되어 있으며, 전체 코퍼스(corpus)에 걸쳐 semicolon, active-voice, its-vs-its, rhythm 등 84개의 태그가 있습니다. 완료한 각 시도(attempt)는 접촉한 태그들에 점수를 매기며, 최근의 시도가 오래된 시도보다 더 높은 가중치를 갖도록 설계되었습니다. 따라서 다음 세션은 당신이 가장 취약한 태그와 한동안 보지 못했던 연습 문제 위주로 구성됩니다.
두 명의 가드(guard)가 이것이 처벌의 루프(punishment loop)가 되는 것을 방지합니다. 지난 한 시간 동안 수행한 연습 문제는 우선순위가 크게 낮아지며, 모든 우선순위에 약간의 지터(jitter)를 추가하여 당신의 가장 취약한 세 문장이 다시 싫어질 때까지 계속해서 반복되지 않도록 합니다. 징벌이 아닌 연습을 위한 것입니다.
인터페이스가 구성되는 방식
이 부분이 흥미로운 지점이며, 터미널을 그리는 작업이 아닙니다.
규칙은 단 하나입니다: 터미널이 존재한다는 사실을 알 수 있는 파일은 정확히 하나뿐이어야 합니다. 그 외의 모든 것은 순수 함수 (pure function)입니다.
flowchart LR
subgraph impure["app.ts, 유일한 불순수(impure) 파일"]
T["Terminal: raw mode, alternate screen, the clock"]
...
타이핑 엔진은 불변 상태 (immutable state)를 유지하며 시계 (clock)를 절대 읽지 않습니다. 현재 시간은 시간이 필요한 모든 함수에 인자 (argument)로 전달되며, 이것이 타이밍 테스트가 불안정하지 않은(flaky) 유일한 이유입니다. 테스트는 세 개의 키 입력과 가짜 스톱워치를 전달하고, 대기 시간이나 허용 오차 범위 없이 분당 단어 수 (words per minute)를 검증 (assert)합니다.
키 파서 (key parser)는 문자열을 받아 키 입력 (key presses)을 반환하며, 이는 빠르게 타이핑하는 것이 보기보다 더 복잡하기 때문에 존재합니다. 손이 움직일 때 여러 문자가 단일 청크 (chunk)로 들어옵니다. 화살표 키는 3바이트로 들어오며, 누군가 괄호를 타이핑하는 것으로 읽혀서는 안 됩니다. 순수 함수 (pure function)이기 때문에, 테스트는 어디에도 터미널을 연결하지 않고도 문자열을 입력함으로써 전체 세션을 구동할 수 있습니다.
렌더러 (renderers)는 상태 (state)를 받아 라인 배열을 반환합니다. 이들은 표준 출력 (standard output)에 쓰지 않고, 시계 (clock)를 읽지 않으며, 창의 너비는 누군가가 전달해 준 숫자로서만 알고 있습니다. 따라서 테스트는 당신이 보게 될 내용을 검증 (assert)하며, 타이핑 트레이너에게 있어 이는 검증할 가치가 있는 대부분의 내용입니다. 모든 색상은 plain 플래그를 받는 하나의 paint 함수를 거치므로, 모든 화면은 색상이 없는 쌍둥이를 가집니다. 이것이 --plain 옵션이 제공하는 것이며, 테스트가 읽는 방식이기도 합니다.
불순수 (impure) 파일에 포함된 두 가지 세부 사항이 그 자리를 차지했습니다.
첫 번째는 커서를 홈(home) 위치로 이동시키고 다시 그리는 방식으로 프레임(frame)을 그리는 것이며, 이동하면서 각 줄을 지우고 그 아래에 남은 모든 것을 지웁니다. 명백한 버전은 화면을 지운 다음 글자를 쓰는데, 이 명백한 버전은 깜빡임(flicker)이 발생합니다. 왜냐하면 한 프레임 동안에는 실제로 아무것도 없는 상태가 되기 때문입니다. 아무도 빠르게 타이핑하기 전까지는 이를 눈치채지 못합니다.
두 번째는 복구(restore)가 화면에 진입한 후가 아니라, 진입하기 전에 등록된다는 점입니다. 로우 모드(Raw mode)와 대체 화면(alternate screen)은 누군가의 터미널에서 빌려오는 것들입니다. 만약 빌린 것과 돌려주는 것 사이에 프로세스가 중단되면, 사용자는 자신이 입력하는 내용이 에코(echo)되지 않는 터미널을 갖게 되며, 유일한 방법은 탭을 닫는 것뿐입니다. 따라서 종료(exit), 인터럽트(interrupt), 종료(terminate) 핸들러가 가장 먼저 등록되며, 이들은 모두 동일한 복구 로직을 실행합니다. 그리고 복구 로직은 두 번 호출되더라도 해롭지 않도록 보호되어 있습니다.
전체 과정에는 단 하나의 타이머가 있습니다. 드릴(drill)이 실행되는 동안 120밀리초(ms)마다 다시 그리기(repaint)를 수행하며, 이는 단 하나의 이유를 위해 존재합니다. 즉, 사용자의 손이 움직이지 않을 때도 경과된 초(elapsed seconds)는 계속 흘러가야 하기 때문입니다. 키 입력(Keystrokes)은 자체적인 프레임을 그립니다.
그 결과 3,476줄의 TypeScript 코드가 만들어졌으며, 그중 1,134줄은 테스트(test)입니다. 프레임워크나 의존성(dependency) 없이 Node의 자체 테스트 러너(test runner)를 사용하는 127개의 테스트가 있으며, 약 130밀리초(ms) 만에 실행됩니다. 이 테스트 중 하나는 콘텐츠를 배포하는 모든 프로젝트에서 가져다 쓸 만한 가치가 있습니다. 배포된 모든 팩(pack)의 모든 모델 답변은 자체 검사를 통과해야 합니다. 자신의 정답이 오답으로 표시되는 연습 문제는 버그이며, 이는 사용자에게 도달하기 훨씬 전에 포착됩니다.
나를 물었던 것
이 리포지토리(repository)는 빌드 단계 없이 TypeScript로 바로 실행됩니다. 이제 Node가 타입을 제거(strip)해 주기 때문입니다. 이는 정말 좋은 작업 방식이지만, 누군가 당신의 패키지를 설치하는 순간 작동을 멈춥니다. Node는 node_modules 아래에 있는 것에 대해서는 타입 제거를 거부하기 때문입니다. 제가 패키징한 첫 번째 버전은 이를 설치하는 모든 머신에서 실패했을 것입니다.
따라서 빌드(build) 결과물은 JavaScript로 컴파일되며, 지속적 통합 (CI) 과정에서 Linux 및 macOS 환경의 Node 20, 22, 24에 패키징된 tarball을 설치하고, 무언가가 게시되기 전에 실제로 명령어를 실행합니다. 타입 체크 (Type checking)를 통해 코드가 컴파일됨을 증명합니다. 하지만 낯선 사람이 설치하는 방식으로 설치해 보는 것만이 코드가 실제로 작동함을 증명합니다.
이것이 하지 않는 것
이것은 당신의 문장이 좋은지 아닌지는 알지 못합니다. 문장이 수동태인지, 특정 단어를 사용했는지, 12단어 이내로 유지되었는지, 그리고 문법적 구조 (mechanics)가 유지되는지는 압니다. 만약 당신이 키보드를 한 번도 만져본 적이 없다면, 이것은 타이핑을 가르쳐주지 않을 것이니, 다른 곳에서 기본 자리 (home row)를 익히고 다시 돌아오십시오.
그리고 코퍼스 (corpus)는 81개의 연습문제로 구성되어 있습니다. 이는 몇 주간의 매일 연습하는 분량이며, 영원히 충분하기에는 턱없이 부족합니다. 바로 그렇기 때문에 팩 (pack) 형식이 README에서 가장 먼저 문서화되는 것입니다. 팩은 ~/.wordwright/packs/에 넣는 JSON 파일이며, wordwright template은 스켈레톤 (skeleton)을 출력하고, wordwright add는 팩이 삽입되기 전에 이를 검증합니다. 당신이 실제로 반복하는 실수들을 위해 팩을 작성한다면, 꼭 보고 싶군요.
코드는 github.com/juliantellez/wordwright에 있으며, MIT 라이선스이고, npm에 등록되어 있습니다.
이제 가서 당신의 에이전트에게 느릿느릿한 작업 하나를 맡겨보세요.
이곳의 모든 것이 그렇듯, 처음부터 직접 만들었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기