Headlong: 셸이 다시 컴퓨팅의 중심으로 돌아왔다

다시, 셸

Laude Institute 팀이 공개한 Headlong의 철학 문서(philosophy.md)를 읽었다. 제목부터가 선언적이다. “The Shell is Back at the Center of Computing.” 1971년 켄 톰슨이 만든 최초의 유닉스 셸은 한 줄을 읽고, 프로그램을 찾고, 실행하고, 기다리는 얇은 루프였다. 그게 전부였고, 그걸로 충분했다.

그 후 GUI가 이겼고 웹이 이겼다. 터미널은 git push를 하거나 도커 컨테이너를 재시작할 때 마지못해 들르는 곳이 되었다. 그런데 LLM이 그 판을 되돌리고 있다는 게 이 글의 주장이다.

셸은 AI 에이전트에게 단지 좋은 환경이 아니라 올바른 환경이다. 결국 이기게 될 환경이다.

왜 LLM과 셸이 잘 맞는가

글이 짚는 구조적 정렬이 설득력 있다. LLM은 본질적으로 텍스트를 읽고 텍스트를 쓰는 존재다. 그리고 유닉스 셸은 모든 것이 텍스트인 환경이다. stdin, stdout, stderr, 환경변수, 파일, 파이프 — 보편 인터페이스가 바이트 스트림이고, 실질적으로는 텍스트 스트림이다.

이걸 지금의 지배적 패러다임과 비교해 보자. 손으로 짠 함수 스키마, JSON 인자 마샬링, 도구마다 붙는 어댑터. 함수 호출 방식은 LLM을 큐레이션된 메뉴에서 고르는 디스패처로 취급한다. 반면 셸은 LLM을 오퍼레이터로 취급한다. 터미널 앞에 앉아 시스템 전체에 접근할 수 있는 사람으로.

열거가 아니라 조합

개인적으로 이 글에서 가장 중요한 대목은 “열거 문제(enumeration problem)”라고 생각한다. 함수 호출 방식은 search_web, read_file, run_sql처럼 도구를 미리 나열한다. 목록에 없으면 못 한다.

셸은 이걸 뒤집는다. 능력을 열거하는 대신 조합 가능한 환경을 주고 모델이 알아서 하게 한다. 웹페이지를 받아 링크를 뽑고 도메인으로 걸러 세는 일은 curl | grep | grep | wc -l 한 줄이다. 아무도 count_links_by_domain이라는 도구를 정의하지 않았다. 능력이 조합에서 창발한 것이다.

모델은 모든 도구를 미리 알 필요가 없다. 조합의 문법을 알면 충분하다.

이건 더그 매킬로이의 유닉스 철학 — 한 가지를 잘하는 작은 도구들을 파이프로 연결하라 — 이 그가 예상하지 못한 매체에서 실현된 것에 가깝다. “텍스트 스트림이라는 보편 인터페이스”가 하필 LLM의 모국어였다는 얘기다.

shellm: bash 안에서 사는 LLM

그 생각의 결과물이 shellm이다. 루프는 단순하다.

  1. “bash 코드를 써라”는 시스템 프롬프트와 함께 컨텍스트를 LLM에 보낸다
  2. 모델이 bash 코드 블록으로 답한다
  3. 코드를 실행한다 (도커가 있으면 컨테이너 안에서, 없으면 로컬에서)
  4. 출력을 다음 메시지로 되돌려준다
  5. FINAL="답"이 설정되거나 반복 한도에 걸릴 때까지 반복

전체가 하나의 bash 스크립트다. 의존성은 bash, jq, curl뿐. 프레임워크도, package.json도, 가상환경도 없다. 셸 도구로 만든 셸 도구다. 그리고 생성된 코드 안에서 다시 shellm "prompt"를 부를 수 있다. 재귀다. 오케스트레이션 프레임워크가 따로 없는 이유는 간단하다 — 셸의 프로세스 모델이 곧 오케스트레이션 프레임워크이기 때문이다.

도구에서 에이전트로

shellm은 강력한 원시 도구지만 상태가 없다. 매번 새로 시작하고 아무것도 기억하지 못한다. 도구지 에이전트가 아니다. 그래서 저자는 도구를 더 만들었고, 그 방식이 일관돼서 좋았다.

  • mem — 메모리를 YAML 프론트매터가 붙은 개별 마크다운 파일로 저장한다. 데이터베이스도, 벡터 스토어도 없다. 그냥 디렉터리 안의 파일들이다. grep으로도 검색된다.
  • skills — Agent Skills 표준을 따르는 SKILL.md 디렉터리. 스킬의 “실행 엔진”은 그냥 LLM이 지시를 읽고 코드를 생성하는 능력이다. 플러그인 API도, SDK도, 등록 절차도 없다.
  • traj / context — 에이전트의 궤적을 append-only JSONL로 기록하고(포크와 머지로 DAG를 이룬다), 그걸 다음 호출의 메시지 배열로 투영한다. 오래된 것은 지워지는 게 아니라 지수적으로 해상도가 낮아지며 요약되고, 그 계층이 그대로 원본을 되짚는 인덱스가 된다.
  • thinkers — 디스패처가 궤적을 지켜보다가 작은 사고 프로세스를 깨운다. 각 깨어남이 또 하나의 shellm 실행이다.

Headlong의 진짜 차별점, 멈추지 않는 마음

Headlong의 정의적 특징으로 저자가 꼽는 건 지속적 행위성(persistent agency)이다. 이 부분이 가장 흥미로웠다.

사람에게 말을 거는 이가 없어도 내적 독백이 계속되듯, 에이전트는 외부 상호작용 사이에도 스스로 생각을 이어간다. 사람의 메시지는 세션을 시작시키지 않는다. 그것은 사고 흐름에 하나의 관찰로 도착할 뿐이고, 응답 여부와 시점은 에이전트가 결정한다.

대부분의 에이전트는 “요청 → 처리 → 종료”의 리퀘스트-리스폰스 모델이다. 메시지를 하나의 관찰로 강등시키고 루프를 계속 돌린다는 발상은 확실히 다른 축의 설계다. 그리고 정체성(identity)이 그냥 디렉터리라는 점 — 페르소나 마크다운, 메모리 폴더, 스킬 폴더, 궤적 JSONL — 도 이 철학의 일관성을 잘 보여준다. 에이전트의 이름이 곧 커맨드가 된다(ada hello!, ada stop, ada dash).

톰슨 테스트

글 후반의 “Thompson test”는 에이전트 아키텍처를 평가하는 체크리스트로 두고두고 쓸 만하다.

  1. 오후 한나절에 모든 컴포넌트를 이해할 수 있는가? 코어 전체가 1만 줄 미만, 가장 큰 shellm도 3천 줄 미만이다.
  2. 저자가 예상하지 못한 방식으로 조합할 수 있는가? mem은 그냥 파일을 관리하는 CLI라 출력을 아무 데나 파이프할 수 있다. 이런 조합 패턴은 “설계된” 게 아니라 유닉스 인터페이스에서 저절로 떨어져 나온다.
  3. 상태를 들여다볼 수 있는가? 모든 상태가 디스크 위의 텍스트 파일이다. 숨겨진 DB도, 바이너리 직렬화도 없다.
  4. 아무 컴포넌트나 교체할 수 있는가? 결합 메커니즘이 파일시스템과 환경변수이기 때문이다. 컴퓨팅에서 가장 오래되고 가장 많이 검증된 통합 프로토콜.

저자는 대부분의 현대 에이전트 프레임워크가 이 테스트를 통과하지 못한다고 말한다. “바자회가 필요한 곳에 성당을 짓고 있다”는 표현이 뼈아프다.

남는 생각

다만 나는 이 글이 스스로 그은 선도 눈여겨봐야 한다고 본다. 저자도 “모든 에이전트가 bash 스크립트여야 한다고 주장하는 게 아니다”라고 명시한다. 핵심은 구현체가 아니라 설계 원칙이다. 작고 조합 가능한 도구, 보편 인터페이스로서의 텍스트, 상태 계층으로서의 파일시스템, 일급 속성으로서의 투명성. 그리고 그 원칙을 지키는 가장 쉬운 방법이 마침 그 원칙을 체현한 시스템을 실제로 쓰는 것이라는 얘기다.

또 하나 마음에 든 건 투명성이다. 매 반복마다 LLM이 어떤 bash를 썼고 무엇을 돌려받았고 어떻게 적응했는지가 그대로 보인다. 이건 AI 에이전트를 디버깅한다기보다 동료의 작업을 리뷰하는 감각에 가깝다. 블랙박스가 없다는 건 생각보다 큰 가치다.

톰슨의 셸은 얇은 루프였다. 읽고, 찾고, 실행하고, 기다린다. shellm도 얇은 루프다. 메시지를 읽고, LLM에 묻고, 코드를 돌리고, 반복한다. Headlong은 그 루프를 결코 멈추지 않는 마음으로 감쌌다. 55년이 지나도 그 패턴은 여전히 작동한다. 다만 새로운 종류의 사용자가 필요했을 뿐이다.

셸이 돌아왔다. 이번엔 에이전트 런타임으로서.

참고: Laude Institute 팀의 philosophy.md — github.com/laude-institute/headlong

Show CommentsClose Comments

Leave a comment