← 에세이 /Post · 17 of 21 · Embedded Dev

임베디드에서 AI Agents: 전체 파이프라인

AI 에이전트 기반 임베디드 개발의 완전한 프로젝트 해부. i.MX8M Plus 센서 드라이버의 폴더 구조, 스펙, property-based 테스트, 리뷰 에이전트, 피드백 루프.

·7 min read · · · #ai-agents#embedded-linux#developer-workflow#testing#yocto
임베디드에서 AI Agents: 전체 파이프라인
On this page

첫 번째 포스트에서 스펙 기반 피드백 루프를 만들었다. 마크다운에 인수 기준을 적고, JSON을 뱉는 테스트 래퍼를 두고, 그 구조화된 결과를 보고 에이전트가 반복하는 구조다. 두 번째 포스트에선 컨텍스트를 세 층으로 쌓았다. 하드웨어 제약을 담은 CLAUDE.md, 리뷰 전담 서브에이전트, 그리고 컴파일러를 루프에 넣은 피드백.

두 글 다 각 조각이 필요한지를 설명한다. 그런데 폴더를 실제로 열었을 때 프로젝트가 어떻게 생겼는지는 안 보여줬다. 이 글이 그 빈칸을 메운다. 프로젝트 하나. 파일 전부. 그게 어떻게 맞물리는지.

대상은 i.MX8M Plus용 IMU 센서 드라이버다. SPI에 DMA를 쓰고, Yocto scarthgap으로 빌드하고, Raspberry Pi 4에서 돌려 테스트했다. 개발은 처음부터 끝까지 Claude Code로 했다. 앞선 두 글에서 예제로 계속 끌고 온 그 드라이버다. 이번엔 통째로 뜯어본다.

프로젝트 트리

sensor-driver/
├── CLAUDE.md
├── .claude/
│   ├── rules/
│   │   ├── kernel.md
│   │   ├── dts.md
│   │   └── test.md
│   └── agents/
│       ├── supervisor.md
│       ├── concurrency-reviewer.md
│       ├── register-contract-reviewer.md
│       ├── side-effect-reviewer.md
│       ├── coding-standard-reviewer.md
│       └── test-coverage-reviewer.md
├── specs/
│   └── imu-driver.md
├── tests/
│   ├── conftest.py
│   ├── inventory.yaml
│   ├── test_imu_driver.py
│   ├── test_imu_properties.py
│   ├── test_imu_hil.py
│   └── fuzz/
│       ├── corpus/
│       └── harness_spi_parser.c
├── scripts/
│   ├── run_target_tests.sh
│   └── static_analysis.sh
├── docs/
│   └── hardware/
│       └── imu-register-map.md
├── drivers/
│   └── imu/
│       ├── imu_core.c
│       ├── imu_dma.c
│       ├── imu_spi.c
│       └── imu.h
└── meta-sensor/
    └── recipes-kernel/
        └── linux-imx/
            └── sensor-driver.bbappend

디렉토리마다 파이프라인에서 맡는 역할이 다르다. 보통의 개발 사이클에서 에이전트가 마주치는 순서로 훑는다.

CLAUDE.md — 에이전트가 매 세션 읽는 20줄쯤. 하드웨어 제약과 학습된 수정만 담는다. 프로젝트 구조 설명은 안 넣는다. 그건 에이전트가 저장소를 보고 알아서 추론한다. 자세한 건 컨텍스트 엔지니어링 포스트에서 다뤘다.

.claude/rules/ — 매칭되는 파일을 편집할 때만 로드되는 범위 지정 컨텍스트. kernel.mddrivers/**/*.c에, dts.md*.dts*.dtsi에, test.mdtests/**/*.py에 걸린다. CLAUDE.md에 다 몰아넣는 대신, 컨텍스트를 잘게 쪼개 집중시킨다.

.claude/agents/ — 특화 리뷰어 5개와 감독자의 시스템 프롬프트. 파일 하나가 에이전트 하나의 역할과 체크리스트를, 딱 거기까지만 정의한다. 동시성과 레지스터 계약 리뷰어는 중복 확인을 위해 인스턴스를 각각 2개씩 병렬로 띄운다. 나머지 3개는 하나씩만 돈다. 감독자가 모든 인스턴스 결과를 모은다.

specs/ — 마크다운 테이블로 적은 인수 기준. 드라이버나 모듈 하나에 파일 하나. 에이전트가 이걸 근거로 테스트를 만든다.

tests/ — 테스트 네 종류가 여기 모여 있다. test_imu_driver.py는 스펙 기반 예제 테스트, test_imu_properties.py는 property-based 테스트(Hypothesis + CFFI), fuzz/는 AFL++ 하네스. conftest.pyinventory.yaml은 타겟에 접근하려고 labgrid를 설정해 둔 것이다.

scripts/ — 래퍼 스크립트 두 개. run_target_tests.sh는 모듈 배포하고 pytest 돌리고 JSON을 돌려준다. static_analysis.sh는 cppcheck에 clang-tidy를 돌린 뒤 JSON으로 뱉는다.

docs/hardware/ — 데이터시트에서 뽑아낸 레지스터 맵, 에라타 노트, 핀아웃 다이어그램. 레지스터 계약 리뷰어가 리뷰할 때 여길 참조한다.

drivers/imu/ — 진짜 드라이버 소스. 관심사별로 갈라놨다. 코어 로직, DMA 처리, SPI 통신.

meta-sensor/ — Yocto 레이어. .bbappend가 드라이버를 BSP 빌드에 끼워 넣는다.

스펙

전부 여기서 시작한다. 에이전트가 드라이버 코드를 한 줄 쓰기도 전에, 이 파일이 먼저 있다:

# IMU Sensor Driver (ICM-42688-P) Acceptance Criteria

## Target
- SoC: i.MX8M Plus (Cortex-A53)
- Interface: SPI (mode 3, 10MHz)
- DMA: SDMA channel, 64-byte aligned buffers
- Test board: Raspberry Pi 4 (Yocto scarthgap, kernel 6.1 LTS)
IDCriterionMetricMethod
AC-1Sampling rate 1kHz within 1% tolerancesample count per secondsysfs counter over 10s
AC-2Data integrity after 10K DMA transfersCRC32 match rate = 100%CRC on raw buffer vs parsed
AC-3RSS memory < 2MB after 1hr soak/proc/meminfo deltastress-ng + periodic sample
AC-4Recovery within 3s after SPI bus errortime to first valid readunbind/rebind SPI device
AC-5IRQ-to-userspace latency < 500us (p99)timestamp deltacyclictest-style measurement
AC-6No data loss under CPU stresssample gap detectionstress-ng —cpu 4 + counter
## Constraints
- Kernel 6.1 LTS: no spi-fault-inject module available
- DMA buffers: 64-byte aligned (L1 cache line on Cortex-A53)
- SPI mode 3 (CPOL=1, CPHA=1) for ICM-42688-P
- CTRL_REG1 at 0x4E (not 0x11 as in MPU-6050)

제약 사항 섹션은 기준만큼 중요하다. 없는 도구를 쓰거나 하드웨어를 잘못 설정하는 테스트를 에이전트가 만들어내는 걸 막아준다. 제약 하나하나가 개발하다 실제로 깨진 데서 나왔다.

네 개의 테스트 계층

스펙은 예제 기반 테스트를 굴린다. 하지만 예제 기반 테스트는 내가 콕 집어 적어둔 시나리오만 커버한다. 그래서 네 계층이 갈수록 깊은 데서 버그를 잡는다.

계층 1: Property-Based 테스트 (밀리초, 호스트)

호스트 머신에서, 공유 라이브러리로 컴파일한 C 코드를 상대로 돈다. 타겟 하드웨어는 필요 없다. CFFI는 C 함수를 파이썬에서 바로 부르는 외부 함수 인터페이스인데, 컴파일된 C를 곧장 로드한다. 그러면 Hypothesis가 입력을 수천 개씩 만들어 던지고, 실패를 최소 케이스로 줄인다. 설치는 pip install cffi hypothesis 한 줄이면 된다.

# tests/test_imu_properties.py
from hypothesis import given, strategies as st, settings
import cffi

ffi = cffi.FFI()
ffi.cdef("""
    typedef struct {
        int16_t accel[3];
        int16_t gyro[3];
        uint32_t timestamp;
        uint8_t  status;
    } imu_sample_t;

    int parse_imu_frame(const uint8_t *buf, int len, imu_sample_t *out);
    int build_imu_frame(const imu_sample_t *sample, uint8_t *buf, int max_len);
""")
lib = ffi.dlopen("./build/libimu_host.so")

@given(data=st.binary(min_size=1, max_size=64))
def test_parser_never_crashes(data):
    """No input -- valid, truncated, or garbage -- should crash the parser."""
    buf = ffi.new("uint8_t[]", data)
    sample = ffi.new("imu_sample_t *")
    ret = lib.parse_imu_frame(buf, len(data), sample)
    assert ret in (0, -1)

@given(
    accel=st.tuples(*[st.integers(-32768, 32767)] * 3),
    gyro=st.tuples(*[st.integers(-32768, 32767)] * 3),
    ts=st.integers(0, 2**32 - 1),
)
def test_roundtrip_preserves_values(accel, gyro, ts):
    """Encode then decode must recover the original values."""
    sample_in = ffi.new("imu_sample_t *")
    for i in range(3):
        sample_in.accel[i] = accel[i]
        sample_in.gyro[i] = gyro[i]
    sample_in.timestamp = ts
    buf = ffi.new("uint8_t[64]")
    n = lib.build_imu_frame(sample_in, buf, 64)
    assert n > 0
    sample_out = ffi.new("imu_sample_t *")
    assert lib.parse_imu_frame(buf, n, sample_out) == 0
    assert tuple(sample_out.accel) == accel
    assert tuple(sample_out.gyro) == gyro
    assert sample_out.timestamp == ts

@given(data=st.binary(min_size=1, max_size=15))
@settings(max_examples=10000)
def test_short_frames_rejected(data):
    """Frames shorter than minimum valid length must return -1."""
    buf = ffi.new("uint8_t[]", data)
    sample = ffi.new("imu_sample_t *")
    # minimum frame: header(2) + payload(12) + crc(2) = 16 bytes
    assert lib.parse_imu_frame(buf, len(data), sample) == -1

3주 동안 못 잡던 버그를 10초 만에 찾았다. 프레임 헤더엔 맞는데 페이로드가 잘린 특정 7바이트 시퀀스였다. 파서가 버퍼 경계를 넘어 읽고 있었다. Hypothesis가 알아서 최소 케이스까지 줄여줬다.

잡히는 것: 버퍼 오버플로, off-by-one, 인코딩과 디코딩 불일치, 프로토콜 파싱의 엣지 케이스. 전기 노이즈 때문에 SPI로 쓰레기 값이 흘러들 때 문제가 되는데, 정작 사람은 테스트 케이스로 떠올리지도 못하는 것들이다.

계층 2: 스펙 기반 테스트 (초, 타겟)

labgrid를 거쳐 진짜 Raspberry Pi 4에서 돈다. 인수 기준 하나에 테스트 함수 하나씩이다.

# tests/test_imu_driver.py
import time

def test_sampling_rate_1khz(target):
    """AC-1: Sampling rate 1kHz within 1% tolerance."""
    target.run("echo 1000 > /sys/class/imu/imu0/sampling_rate")
    target.run("echo 0 > /sys/class/imu/imu0/sample_count")
    time.sleep(10)
    count = int(target.run("cat /sys/class/imu/imu0/sample_count"))
    rate = count / 10.0
    assert 990 <= rate <= 1010, f"Rate {rate} Hz outside 1% of 1000 Hz"

def test_dma_data_integrity(target):
    """AC-2: Data integrity after 10K DMA transfers."""
    result = target.run("imu_integrity_test --transfers 10000 --verify crc32")
    # imu_integrity_test is a small C program deployed to the target
    lines = result.strip().split('\n')
    last = lines[-1]  # "PASS: 10000/10000 CRC match" or "FAIL: 9153/10000"
    assert last.startswith("PASS"), f"Integrity check: {last}"

def test_spi_error_recovery(target):
    """AC-4: Recovery within 3s after SPI bus error."""
    # Driver exposes force_error sysfs since spi-fault-inject is unavailable on kernel 6.1
    target.run("echo 1 > /sys/class/imu/imu0/force_error")
    time.sleep(0.5)
    start = time.time()
    for _ in range(30):
        data = target.run("cat /sys/class/imu/imu0/data")
        if "error" not in data.lower():
            elapsed = time.time() - start
            assert elapsed < 3.0, f"Recovery took {elapsed:.1f}s, limit 3s"
            return
        time.sleep(0.1)
    raise AssertionError("Driver did not recover within 3s")

run_target_tests.sh 래퍼가 모듈을 올리고, 테스트를 전부 돌리고, JSON을 돌려준다. 에이전트는 SSH를 직접 만질 일이 없다.

잡히는 것: 인수 기준에 대한 회귀, 타겟 특유의 타이밍 이슈, 진짜 하드웨어에 진짜 주변장치를 붙여야만 드러나는 통합 문제.

계층 3: 퍼징 (시간, 호스트)

SPI 프레임 파서용 퍼즈 하네스다. AFL++ 인스트루먼테이션으로 컴파일한다:

/* tests/fuzz/harness_spi_parser.c */
#include <stdint.h>
#include <stdlib.h>
#include "imu.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size > 256) return 0;  /* limit input size */
    imu_sample_t sample;
    parse_imu_frame(data, (int)size, &sample);
    return 0;
}
# Build and run
afl-clang-fast -o fuzz_parser tests/fuzz/harness_spi_parser.c drivers/imu/imu_spi.c -I drivers/imu/
afl-fuzz -i tests/fuzz/corpus -o findings -- ./fuzz_parser

코퍼스에는 정상 프레임, 잘린 프레임, 알려진 불량 시퀀스를 시드로 깔아둔다. AFL++는 CI에서 밤새 돈다. 첫 주에만 버그를 두 개 잡았다. 타임스탬프 파싱의 정수 오버플로, 그리고 특정 프레임 길이에서 CRC 체크가 실패할 때 터지는 use-after-free다.

잡히는 것: 메모리 안전 버그, 정의되지 않은 동작, 크래시를 부르는 입력. 스펙 기반 테스트로는 안 보인다. 사람 손으로는 안 나올 특정 바이트 패턴이 있어야 터진다.

계층 4: Hardware-in-the-Loop (분, 실제 하드웨어)

labgrid가 실제 하드웨어 테스트를 지휘한다. CPU 스트레스를 걸어둔 채로 DMA, 전원 사이클 복구, 열 부하 아래 지속 샘플링. 느리긴 한데 타이밍과 주변장치 상호작용 버그를 잡아낸다.

# tests/test_imu_hil.py (runs via labgrid with power control)
def test_dma_under_cpu_stress(target, power):
    """AC-6: No data loss under CPU stress."""
    target.run("stress-ng --cpu 4 --timeout 30 &")
    target.run("echo 0 > /sys/class/imu/imu0/sample_count")
    time.sleep(30)
    count = int(target.run("cat /sys/class/imu/imu0/sample_count"))
    expected = 30 * 1000  # 30s at 1kHz
    loss = expected - count
    assert loss == 0, f"Lost {loss} samples under stress ({count}/{expected})"

잡히는 것: 스트레스 아래 타이밍과 주변장치 상호작용 버그, 전원 사이클 복구 동작, 유닛 테스트나 스펙 테스트가 흘려보내는 열적 영향.

네 계층은 피라미드를 이룬다. 계층 1은 코드가 바뀔 때마다 밀리초 단위로 돈다. 계층 2는 테스트 사이클마다 초 단위로. 계층 3은 밤새, 계층 4는 필요할 때나 주 단위로. 버그 대부분은 계층 1과 2에서 죽는다. 비싼 계층은 거기서 새어나간 놈들을 줍는다.

CLAUDE.md: 남기는 것, 버리는 것

덩치 큰 CLAUDE.md는 결과를 나아지게 하지도 못하면서 토큰만 태운다(컨텍스트 엔지니어링 포스트에서 이유를 다뤘다). 추론으로는 못 얻는 내용만 자리값을 한다.

처음 CLAUDE.md가 어땠고, 정리하고 나서 어떻게 됐는지 보자:

Before (58줄, 낭비):

## Project Structure
sensor-driver/ contains the IMU driver source code...
tests/ contains pytest-based tests using labgrid...
meta-sensor/ is the Yocto layer...

## Build
Uses meson build system. Cross-compile with:
  meson setup build --cross-file cross-aarch64.ini
  ninja -C build

## Testing
Run tests with: ./scripts/run_target_tests.sh build/imu_sensor.ko

에이전트는 이걸 전부 meson.buildinventory.yaml, 폴더 구조에서 추론한다. 30줄 넘게가 그냥 놀고 있는 셈이다.

After (22줄, 집중):

## Hardware
- SoC: i.MX8M Plus (Cortex-A53), SPI IMU: ICM-42688-P
- CTRL_REG1 = 0x4E (not 0x11). SPI mode 3 (CPOL=1, CPHA=1)
- DMA buffers: 64-byte aligned (L1 cache line)

## Learned Corrections
- 2026-01-15: ICM-42688-P CTRL_REG1 is 0x4E, not 0x11
- 2026-01-18: DMA buffers must be 64-byte aligned on Cortex-A53
- 2026-02-03: SPI mode 3 for ICM-42688-P, not mode 0
- 2026-02-22: Kernel 6.1 LTS lacks spi-fault-inject module
- 2026-03-01: spin_lock_bh() in process context, spin_lock() in softirq

## Never Do This
- kmalloc(GFP_KERNEL) or msleep under spin_lock
- CPU access to DMA buffer without dma_sync_single_for_cpu
- Assume register addresses from generic datasheets -- always check ICM-42688-P

줄마다 실제 버그가 출처다. 에이전트가 새 실수를 저지르면 파일이 늘고, 린터나 범위 규칙이 그 제약을 대신 강제하기 시작하면 그만큼 줄어든다.

리뷰 에이전트

리뷰어가 전부 매 변경에 도는 건 아니다. 에이전트마다 시작할 때 파일 glob을 확인해서, 볼 게 있는지부터 따진다:

ReviewerTriggers onInstances
Concurrencydrivers/**/*.c, drivers/**/*.h2 (parallel)
Register contractdrivers/**/*.c, *.dts, *.dtsi2 (parallel)
Side-effectany non-test file1
Coding standarddrivers/**/*.c, drivers/**/*.h1
Test coveragetests/**/*.py, specs/**/*.md1

동시성과 레지스터 계약 리뷰어를 각각 2개씩 돌리는 이유는 컨텍스트 엔지니어링 포스트에서 짚었다. LLM이 한 번 훑고 지나가면 놓치는 걸, 같은 모델이 두 번째엔 잡아내는 경우가 있어서다.

테스트만 손댄 커밋은 테스트 커버리지 리뷰어 하나만 깨운다. 디바이스 트리를 바꾸면 레지스터 계약 리뷰어가 뜨고 동시성은 건너뛴다. 대부분의 커밋은 드라이버 코드를 건드리니까, 리뷰어 3개에서 4개에 인스턴스 5개에서 6개가 돈다. 결과는 감독자가 다 모은다:

리뷰 에이전트 아키텍처: 5개 특화 리뷰어(동시성과 레지스터 계약은 각각 2개 병렬 인스턴스, 부작용, 코딩 표준, 테스트 커버리지는 단일 인스턴스)가 감독자에게 결과를 전달하고, 감독자가 중복 제거와 순위 매김을 거쳐 보고서를 생성. 높은 확신 이슈는 자동 수정, 중간 확신은 사람 리뷰로 플래그

리뷰어 시스템 프롬프트는 죄다 같은 틀이다. 범위를 못 박는 한 문장, 확인할 항목 체크리스트, 그리고 범위 밖은 무시하라는 못 박기.

동시성 리뷰어의 핵심 프롬프트다:

You review ONLY concurrent execution safety. Ignore style, naming, performance.

## Checklist
- [ ] No spinlock held in sleepable context
- [ ] Correct lock variant for execution context
- [ ] DMA buffers synced before CPU access
- [ ] No shared state accessed without protection
- [ ] Lock ordering consistent across all paths

레지스터 계약 리뷰어는 이렇다:

You verify ONLY that hardware register accesses match the datasheet.
Reference: docs/hardware/imu-register-map.md

## Checklist
- [ ] Register addresses match ICM-42688-P datasheet
- [ ] Bit field masks and shifts correct
- [ ] Read/write direction matches register type
- [ ] Initialization sequence follows datasheet power-on requirements
- [ ] SPI mode, clock speed, and CS polarity correct

감독자 규칙은 단순하다. 인스턴스든 리뷰어든 2개 이상이 같은 이슈를 집으면 높은 확신이고, 에이전트가 알아서 고친다. 1개만 집으면 중간 확신이라, 사람 리뷰로 넘기는 플래그만 달고 보고서엔 넣되 자동 수정은 안 한다. 인스턴스 2개를 돌리는 핵심 리뷰어라면, 두 인스턴스가 같은 소리를 하는 순간 이미 높은 확신이다.

리뷰 패스마다 그 전에 scripts/static_analysis.sh가 cppcheck와 clang-tidy를 돌려 JSON을 뽑는다. 이 JSON이 각 리뷰어 프롬프트에 추가 컨텍스트로 들어간다. 정적 분석 결과에 LLM 리뷰를 얹으면, 둘 중 하나만 쓸 때보다 더 많이 걸린다.

전체 루프

완전한 AI 에이전트 임베디드 개발 파이프라인: spec.md가 에이전트 코드 생성에 입력되고, 크로스 컴파일, JSON 출력 정적 분석, 호스트 property-based 테스트, labgrid 통한 타겟 스펙 기반 테스트까지 구조화된 결과가 모두 에이전트에 피드백. 수정 후 5개 특화 리뷰어가 병렬 실행, 감독자가 결과 집계, 사이클이 반복되거나 출시

사이클 한 번이 어떻게 굴러가는지, 내 환경에서 잰 타이밍이다. 호스트는 M2 MacBook Air, 타겟은 RPi4, 이더넷으로 물렸다:

StepActionTime
1에이전트가 스펙 읽고 드라이버 코드 생성/수정~30s
2크로스 컴파일 (aarch64, meson + ninja)~15s
3정적 분석 (cppcheck + clang-tidy to JSON)~10s
4Property-based 테스트 (Hypothesis, 1000 examples)~3s
5배포 + 타겟 테스트 (run_target_tests.sh to JSON)~240s
6에이전트가 모든 결과 읽고 실패 수정~30s
Total~5.5min

3, 4단계는 호스트에서, 5단계는 타겟에서 돈다. Property-based 테스트나 정적 분석이 버그를 먼저 잡으면, 에이전트는 4분짜리 타겟 배포를 날리기 전에 고친다. 이 순서가 핵심이다. 빨리 실패하고, 싸게 실패하는 것.

에이전트 수정이 테스트를 다 통과하면 그제야 리뷰어가 돈다(동시 API 호출로 통틀어 45초쯤). 어떤 리뷰어가 뜨는지는 바뀐 파일이 정한다. 드라이버 코드를 건드리면 핵심 리뷰어 둘(각 2인스턴스)에 부작용, 코딩 표준까지 붙는다. 테스트만 바꾸면 테스트 커버리지 리뷰어 하나로 끝난다. 감독자가 보고서를 낸다. 높은 확신 이슈는 자동으로 고치고 다시 테스트한다. 중간 확신 이슈는 플래그만. 보통 첫 패스에서 이슈 1개에서 2개가 걸리는데, 대개 락킹 규율이나 빠진 DMA 동기화다. 두 번째 반복쯤이면 대부분 깨끗하게 나간다.

루프 전체, 그러니까 “자 스펙이다”에서 “테스트 다 통과, 리뷰어 다 클리어”까지는, 보통 드라이버 기능 하나에 2번에서 3번 반복해서 15분에서 20분이 든다. 첫 번째 포스트의 수동 워크플로와 대보면, 그쪽은 반복 한 번에 30분에서 60분, 그걸 3번에서 5번, 그러고도 정상 경로만 커버한다.

이 파이프라인이 깨지는 지점

파이프라인은 설계된 케이스는 처리한다. 여기부턴 그 범위 밖이다.

형식 검증. Martin Kleppmann은 몇 년 안에 AI가 형식 검증을 주류로 끌어올릴 거라고 예측한다. 아직은 범용 임베디드 드라이버에 쓰기엔 도구가 덜 여물었다. 지금 실용적으로 제일 가까운 근사가 Property-based testing이다.

물리적 디버깅. 로직 분석기에 SPI 클럭이 10MHz 대신 8MHz로 찍히거나, DMA 전송은 끝났는데 인터럽트가 안 뜰 때, 파이프라인은 손을 못 쓴다. 이건 오실로스코프의 영역이다. 파이프라인이 책임지는 건 “코드가 스펙대로 맞다”까지다. 그 스펙이 물리 현실이랑 맞는지는 여전히 사람 몫이다.

보안 회귀, 컨텍스트 저하, 스펙 품질컨텍스트 엔지니어링 포스트에서 길게 다뤘다. 요약하면 이렇다. 반복 개선이 취약점을 슬쩍 심을 수 있고(서브에이전트 리뷰어가 안전망 역할을 한다), 에이전트는 2시간을 넘기면 표류하기 시작하고(/clear로 끊어준다), 파이프라인은 결국 스펙만큼만 좋다(정확한 인수 기준을 쓰는 게 사람이 하는 가장 큰 투자다. TDD 포스트 참고).

시작하기

이걸 한꺼번에 다 갖출 필요는 없다. 계층마다 잡는 버그가 다르고, 어느 지점에서 멈춰도 된다.

StepActionReference
15개 인수 기준이 담긴 specs/<driver>.mdPost 1
2테스트 래퍼 스크립트 (배포 + 테스트 + JSON)Post 1
3하드웨어 제약이 담긴 CLAUDE.mdPost 2
4리뷰어 에이전트 하나 (동시성 또는 레지스터)Post 2
5Property-based 테스트 + 정적 분석을 CI에이 포스트

핵심은 에이전트가 아니다. 핵심은 피드백 루프다. 에이전트는 그 루프를 실제로 굴릴 수 있을 만큼 싸게 만들어줄 뿐이다.

ecro
글쓴이 ecro

LLM 펌웨어 벤치마크를 만들었습니다. EmbedEval →

프로젝트에 맞는 Claude Code / Cursor / Codex 하네스를 생성하는 도구를 만듭니다. harness-maker →

Datasheet을 읽는 터미널을 만들고 있습니다. NeuroTerm →

댓글

댓글 불러오는 중...