본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 16. 08:39

M31A 구축하기: 단순히 제안만 하는 것이 아니라 실제로 결과물을 만들어내는 터미널 네이티브 AI 코딩 에이전트

요약

M31A는 단순한 코드 제안을 넘어 초기화부터 배포까지 6단계 워크플로우를 수행하는 터미널 기반 자율 AI 코딩 에이전트입니다. Go 언어로 작성되었으며, 계획 수립, 실행, 검증, Git 커밋을 엔드 투 엔드로 처리하여 사용자의 개입을 최소화합니다.

핵심 포인트

  • 초기화부터 배포까지 이어지는 6단계 자율 워크플로우 제공
  • Go 언어 기반의 단일 정적 바이너리 및 POSIX 셸 호환성
  • 계획, 실행, 검증, Git 커밋을 포함한 엔드 투 엔드 프로세스
  • 관심사 분리를 적용한 6계층 아키텍처 설계

대부분의 AI 코딩 어시스턴트(AI coding assistants)는 강화된 자동 완성 기능에 불과합니다. 코드를 제안하거나 함수 한두 개를 작성할 수는 있지만, 테스트, 검증, 그리고 실제로 변경 사항을 배포(shipping)하는 단계에 이르면 결국 사용자가 모든 책임을 떠맡게 됩니다.

**M31A (M31 Autonomous)**는 다른 접근 방식을 취합니다. Go 언어로 작성된 터미널 기반 AI 코딩 에이전트(AI coding agent)로서, **6단계 워크플로우(six-phase workflow)를 엔드 투 엔드(end-to-end)**로 수행합니다: 초기화(Initialize) → 논의(Discuss) → 계획(Plan) → 실행(Execute) → 검증(Verify) → 배포(Ship). 모든 실행은 검증된 git 커밋(git commit)과 학습 장부(learning ledger) 기록으로 마무리됩니다. 단일 정적 바이너리(static binary), 텔레메트리(telemetry) 제로, 모든 POSIX 셸(shell)에서 작동합니다.

이 포스트에서는 이 오픈 소스(open-source) 프로젝트의 아키텍처(architecture), 설계 결정, 그리고 기술적 하이라이트를 설명하겠습니다.

문제점: 일을 끝마치지 못하는 AI 어시스턴트

대부분의 AI 코딩 도구를 사용할 때의 전형적인 워크플로우는 다음과 같습니다:

  1. AI에게 코드 작성을 요청함
  2. 제안된 코드를 에디터(editor)에 복사하여 붙여넣음
  3. 수동으로 테스트를 실행함
  4. 필연적으로 발생하는 문제들을 디버깅(debug)함
  5. 작동할 때까지 반복함
  6. 변경 사항을 직접 커밋(commit)함

AI는 1단계에서 "도움"을 주었지만, 여전히 사용자가 작업의 80%를 수행하고 있습니다. 만약 세 번의 커밋이 지난 후에 무언가 고장난다면? AI가 실제로 무엇을 변경했는지 알아내는 데 행운을 빌어야 할 것입니다.

M31A는 이 모델을 뒤집습니다. 단순한 제안 엔진이 아니라, 다음과 같은 기능을 갖춘 **자율 에이전트(autonomous agent)**입니다:

  • 계획을 세우기 전에 명확한 질문을 던짐
  • 구조화된 구현 계획을 생성함
  • 적절한 의존성 해결(dependency resolution)과 함께 작업을 실행함
  • 검증(테스트, 구문 체크)을 수행함
  • 검증된 변경 사항을 git에 커밋함
  • 향후 세션을 위해 학습한 내용을 기록함

아키텍처 개요

M31A는 깔끔한 6계층 아키텍처(six-layer architecture)로 구축되었습니다:

┌─────────────────────────────────────────────────────────────┐
│  TUI 계층 (Bubble Tea)                                     │
│  29개 화면, 키보드/마우스 핸들링, 스트리밍 디스플레이         │
...

핵심 통찰은 무엇일까요? 바로 **모든 수준에서의 관심사 분리 (Separation of concerns)**입니다. TUI는 LLM API에 대해 알지 못합니다. 워크플로 엔진 (Workflow engine)은 터미널 렌더링에 대해 알지 못합니다. 도구 (Tools)들은 워크플로 단계 (Workflow phases)에 대해 알지 못합니다.

6단계 워크플로 엔진 (The Six-Phase Workflow Engine)

M31A의 핵심은 internal/workflow/engine.go에 구현된 워크플로 엔진입니다. 각 단계를 자세히 살펴보겠습니다:

1단계: 초기화 (Initialize)

에이전트는 프로젝트 유형(Go, Python, Node 등)을 감지하고, 필요한 경우 git을 초기화하며, 다음과 같은 내용이 포함된 .m31a/ 계획 디렉토리를 생성합니다:

  • PROJECT.md — 프로젝트 메타데이터 (Project metadata)
  • STATE.md — 현재 워크플로 상태 (Current workflow state)
  • TASKS.md — 작업 목록 (Task list, 나중에 채워짐)
// internal/workflow/initialize.go 에서 발췌
func (e *Engine) runInitialize(ctx context.Context) error {
    // 프로젝트 유형, 프레임워크, 언어 감지
...

2단계: 논의 (Discuss)

코드로 바로 뛰어들기 전에, 에이전트는 LLM 스트리밍 (LLM streaming)을 통해 명확한 질문을 던집니다. 이는

// pkg/taskrunner/runner.go 에서 발췌
func (r *Runner) Schedule() ([][]int, error) {
    // 인접 리스트(adjacency list) 및 진입 차수(in-degree count) 구축
...

그룹 내의 태스크(Tasks)는 제한된 병렬성(bounded parallelism, 기본값: 세마포어(semaphore)를 통한 4개의 동시 태스크)으로 실행될 수 있습니다. 실행기(executor)에는 복구 가능한 실패에 대해 최대 2회까지 재시도하는 **자가 치유 루프 (self-heal loop)**가 포함되어 있습니다.

단계 5: 검증 (Verify)

에이전트는 다음과 같은 검증 체크를 수행합니다:

  • 파일 존재 여부 확인 (File existence validation)
  • 구문 검사 (Syntax checking, 언어별 특화)
  • 테스트 실행 (Test execution)
  • LLM 컨텍스트를 위한 스마트 파일 절단 (Smart file truncation)

검증에 실패할 경우, 에이전트는 git-bisect 통합 기능을 사용하여 커밋 체인(commit chain)을 롤백(rollback)할 수 있습니다.

단계 6: 배포 (Ship)

마지막 단계입니다:

  1. 검증된 모든 변경 사항을 포함하는 git 커밋 생성
  2. 원장 항목(ledger entry, 세션 간 학습 기록) 작성
  3. 세션 아카이브(Archive)
  4. 데모 요약 생성

프로바이더 시스템: 자동 폴백(Fallback) 기능이 포함된 멀티 LLM

M31A는 기본적으로 두 가지 LLM 프로바이더(provider)를 지원합니다:

  • OpenRouter — Claude, GPT-4 등에 접근할 수 있는 기본 게이트웨이
  • Zen — 보조 프로바이더 (OpenCode Zen)

프로바이더 레이어(internal/provider/)에는 몇 가지 영리한 엔지니어링이 포함되어 있습니다:

자동 폴백 (Automatic Fallback)

프로바이더의 성능이 저하될 때(429 rate limit, 503 service unavailable), M31A는 자동으로 정상적인 프로바이더로 전환합니다. 폴백 로직은 지연 시간(latency)을 최소화하기 위해 **병렬 상태 확인 (parallel health checks)**을 사용합니다:

// internal/provider/fallback.go 에서 발췌
func FindFallbackProvider(registry *Registry, current string) (string, *FallbackEvent, error) {
    // 후보 프로바이더 수집
...

모델 차익 거래 (Model Arbitrage)

M31A에는 태스크의 역량 임계값(capability threshold)을 충족하면서 가장 저렴한 모델로 자동 전환하는 모델 차익 거래 시스템 (model arbitrage system)(pkg/arbitrage/)이 포함되어 있습니다:

// pkg/arbitrage/arbitrage.go 에서 발췌
func (s *Scorer) Score(task Task) (ComplexityLevel, int) {
    level := classifyText(task.Action, task.Description)
...

Scorer(점수 산정기)는 키워드 분석을 사용하여 작업을 simple(단순), moderate(보통), 또는 complex(복잡)로 분류한 다음, 해당 복잡도 수준을 처리할 수 있는 가장 저렴한 모델을 추천합니다.

도구 시스템: 의도적으로 작고, 공격적으로 샌드박스화됨

M31A는 5가지 핵심 도구를 제공합니다:

  1. Bash — 셸 명령 실행
  2. FileRead — 크기 제한(최대 50MB) 내 파일 읽기
  3. FileWrite — 원자적(atomic) 파일 쓰기 (임시 파일 생성 + 이름 변경)
  4. Glob — 파일 패턴 매칭 (doublestar, 결과 1,000개 제한)
  5. Grep — 콘텐츠 검색 (사용 가능 시 ripgrep, 불가 시 pure-Go 폴백)

도구의 노출 범위(surface area)는 의도적으로 작게 유지됩니다. 각 도구는 다음과 같은 방식으로 공격적으로 샌드박스(sandboxed) 처리됩니다:

권한 게이팅 (Permission Gating)

모든 도구 호출은 설정 가능한 타임아웃(기본 300초)을 가진 권한 모달(permission modal)에 의해 제어됩니다:

// From internal/tools/permissions.go
type PermissionMode string

...

보안 가드 (Security Guards)

  • 경로 탐색 방지(Path traversal guards): 심볼릭 링크(symlink) 해석 + 작업 디렉토리(workDir) 접두사 확인
  • 출력 제한(Output capping): MaxToolOutputChars (10,000) / BashOutputLimit (50,000)
  • SSRF 보호: DNS 피닝(pinning), TOCTOU(Time-of-Check to Time-of-Use) 방지, 리다이렉트 확인 (WebFetch)
  • 프로세스 생명주기(Process lifecycle): SIGINT/SIGKILL 유예 기간, 파이프(pipe) 정리

위험 수준 (Risk Levels)

각 도구는 자신의 위험 수준을 선언합니다:

type RiskLevel string

const (
...

Bash는 dangerous(위험), FileWrite는 medium(중간), FileRead는 safe(안전)입니다. 권한 시스템은 이러한 수준을 사용하여 사용자에게 확인 프롬프트를 띄울지 여부를 결정합니다.

교차 세션 학습 원장 (Cross-Session Learning Ledger)

M31A의 가장 흥미로운 기능 중 하나는 교차 세션 학습 원장 (cross-session learning ledger) (pkg/ledger/)입니다. 모든 세션은 마크다운(markdown) 파일에 구조화된 기록을 작성합니다:

| Session | Model | Tasks | Failed | Cost | Duration | Framework |
|---------|-------|-------|--------|------|----------|-----------|
| a1b2c3d4 | claude-3.5-sonnet | 5 | 1 | $0.12 | 8min | react |
...

원장은 다음 사항을 추적합니다:

  • 세션 ID 및 타임스탬프 (Session ID and timestamp)
  • 사용된 모델 및 제공자 (Model and provider used)
  • 작업 횟수 및 실패 횟수 (Task count and failures)
  • 예상 비용 (Cost estimate)
  • 소요 시간 (Duration)
  • 프로젝트 유형 및 프레임워크 (Project type and framework)
  • 목표 키워드 (불용어 필터링 포함) (Goal keywords (with stop-word filtering))

시간이 지남에 따라, 에이전트는 원장 (ledger)을 조회하여 과거 세션으로부터 학습할 수 있습니다:

// From pkg/ledger/ledger.go
type LedgerStats struct {
    TotalSessions      int
...

이를 통해 에이전트가 시간이 지날수록 더 정교해지는 피드백 루프 (feedback loop)가 생성됩니다. 어떤 프레임워크가 흔히 사용되는지, 어떤 유형의 작업이 실패하는지, 그리고 작업이 보통 얼마나 걸리는지를 학습하게 됩니다.

AutoDream: 컨텍스트 윈도우 통합 (Context Window Consolidation)

긴 대화는 컨텍스트 윈도우 (context window)를 과도하게 사용합니다. M31A는 자동 컨텍스트 통합 시스템인 AutoDream (pkg/autodream/)을 통해 이 문제를 해결합니다:

// From pkg/autodream/autodream.go
func (c *Consolidator) Consolidate() (ConsolidationResult, error) {
    // Protect system prompts and recent messages
...

AutoDream은 기본적으로 컨텍스트 사용량이 60%에 도달하면 트리거됩니다. 이는 역할 샘플링 요약 (role-sampled summarization) 방식을 사용하며 (시스템 프롬프트는 절대 압축되지 않음), 연속성을 위해 최근 메시지들을 보존합니다.

TUI: Bubble Tea로 구축된 29개의 화면

터미널 UI (TUI)는 Elm 아키텍처 (Elm architecture)를 따르는 Bubble Tea로 구축되었습니다. 화면 라우팅 (Screen routing)은 열거형 (enum) 기반의 디스패처 (dispatcher)를 사용합니다:

// From internal/tui/app_state.go
type Screen int

...

TUI에는 다음과 같은 유용한 기능들이 포함되어 있습니다:

  • 토큰당 비용 비교 기능이 포함된 퍼지 모델 선택기 (Fuzzy model selector)
  • 키보드 단축키를 지원하는 권한 모달 (Permission modals) (허용/항상 허용/거부/종료를 위한 y/a/n/e)
  • 실시간 LLM 출력을 위한 스트리밍 디스플레이 (Streaming display)
  • 자동 모드를 지원하는 다크/라이트 테마 (Dark/light themes)
  • 윈도우 사용량 80% 도달 시 나타나는 컨텍스트 경고 배너 (Context warning banner)

커밋 롤백 체인 (Commit Rollback Chain)

검증이 실패하면, M31A는 git-bisect 통합 기능(pkg/bisect/)을 사용하여 커밋 체인을 롤백 (rollback)할 수 있습니다:

// From pkg/rollback/rollback.go
func (r *Rollback) HardReset(commit string) error {
    // Create backup branch before destructive operation
...

롤백 시스템은 soft/hard/safe reset 옵션을 갖춘 커밋 체인 (commit chain)을 유지합니다. Safe reset은 파괴적인 작업 (destructive operation)을 수행하기 전에 백업 브랜치 (backup branches)를 생성합니다.

OS-Native 보안 키 저장소 (Secure Key Storage)

API 키는 OS-native 키체인 백엔드 (pkg/keychain/)를 사용하여 저장됩니다:

  • Linux: D-Bus Secret Service + pass CLI 폴백 (fallback)
  • macOS: /usr/bin/security CLI
  • Windows: Windows 자격 증명 관리자 (Windows Credential Manager)
// From pkg/keychain/keychain.go
type Keychain interface {
    Get(service string) (string, error)
...

키체인 추상화 (keychain abstraction)는 빌드 태그 (build tags)를 사용하여 컴파일 타임 (compile time)에 플랫폼별 구현을 선택합니다. 서비스 이름은 m31a/openrouter, m31a/zen 패턴을 따릅니다.

키 확인 순서 (Key resolution order):

  1. 환경 변수 (Environment variable): M31A_OPENROUTER_API_KEY
  2. 표준 폴백 (Standard fallback): OPENROUTER_API_KEY
  3. OS 키체인 (OS keychain): m31a/openrouter
  4. 설정 파일 (Config file): provider.openrouter.api_key

키체인을 사용할 수 있는 경우, 키는 절대 평문 (plaintext)으로 디스크에 기록되지 않습니다.

정적 바이너리, 제로 텔레메트리 (Static Binary, Zero Telemetry)

M31A는 CGO_ENABLED=0으로 컴파일되어, C 의존성이 없는 완전한 정적 바이너리 (static binary)를 생성합니다:

# From Makefile
build:
    CGO_ENABLED=0 go build -ldflags "-s -w \
...

바이너리 크기는 일반적으로 15-20MB입니다 (-s -w ldflags로 스트립 (stripped) 처리됨). 교차 컴파일 (Cross-compilation) 대상에는 linux/darwin/windows × amd64/arm64가 포함됩니다.

제로 텔레메트리 (Zero telemetry): 분석 (analytics), 충돌 보고 (crash reporting), 사용량 핑 (usage pings)이 전혀 없습니다. 귀하의 코드는 추론 (inference)을 위해 LLM 제공업체로 전송될 때를 제외하고는 절대 기기를 떠나지 않습니다.

세션 지속성 및 복구 (Session Persistence and Recovery)

세션은 <workDir>/.m31a/session.json에 지속되며, 다음을 포함합니다:

  • 워크플로 상태 (workflow state) (목표, 단계, 질문)
  • 메시지 기록 (message history) (messages.json 별도 저장)
  • 체크포인트 (checkpoints) (실행 취소/롤백을 위해 최대 2개)

Ctrl+C를 누르거나, 네트워크를 잃거나, 노트북 전원이 꺼지더라도 워크플로 중간부터 재개할 수 있습니다:

$ m31a --resume
# 최근 세션이 포함된 세션 브라우저를 표시합니다
# 워크플로 상태를 복구하고 마지막 체크포인트부터 계속합니다

테스트 전략 (Testing Strategy)

M31A는 외부 모킹 프레임워크 (mocking frameworks) 없이 Go의 표준 testing 패키지를 사용합니다:

  • 단위 테스트 (Unit tests): 개별 함수/메서드
  • 통합 테스트 (Integration tests): 실제 git 저장소, 임시 디렉토리, HTTP 테스트 서버
  • 보안 테스트 (Security tests): SSRF 방지, 타임아웃 강제 적용, 경로 탐색 (path traversal)
  • 테이블 기반 테스트 (Table-driven tests): t.Parallel()을 사용하는 익명 구조체

커버리지 (Coverage) 목표:

  • 전체: 75% (현재 ~74.7%)
  • 핵심 패키지: 90% — pkg/taskrunner (89.9%), pkg/bisect (91.3%), pkg/rollback (89.1%)

테스트 스위트에는 몇 가지 흥미로운 패턴이 포함되어 있습니다:

// SSRF 방지를 위한 보안 테스트
func TestWebFetch_BlocksPrivateIPs(t *testing.T) {
    tests := []struct {
...

시작하기 (Getting Started)

설치는 한 줄로 끝납니다:

# macOS (Homebrew)
brew install eshanized/tap/m31a

...

처음 실행할 때, M31A는 OpenRouter 또는 Zen API 키를 요청하며 이를 OS 키체인 (keychain)에 저장합니다.

기본 사용법:

$ m31a
# TUI가 실행됩니다
# 목표를 입력하세요: "refactor the auth middleware to use JWT with RS256"
...

슬래시 명령어 (Slash commands):

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0