본문으로 건너뛰기
5분 AI.
GITHUB TRENDING GO MONTHLY #1 딥다이브 · 2026-10-23 분석

ax 딥다이브
— 에이전트에게 작업실을 빌려주는 실행 플랫폼

실행 플랫폼

빠른 판단

무엇
에이전트 작업의 공간·자원·명령을 YAML로 선언해 격리 실행·중단·재개를 관리하는 Go 플랫폼
이럴 때
여러 에이전트용 실행 환경을 공통 규칙으로 준비하고 작업 상태·자원 한도·재개 흐름을 운영할 때
입력
작업 공간·실행 명령·자원·인증을 정의한 YAML
결과
격리 작업 실행과 중단·재개 상태
AI가 코드를 쓰게 만드는 일과, 그 AI 수천 개를 안전하게 실행하고 멈추고 다시 깨우는 일은 다른 문제입니다. Google의 Agent Executor(AX)는 두 번째 문제를 다룹니다. Go로 만든 CLI·제어 서버·작업 실행기를 따라가며 선언형 API, Redis 분산 잠금, 샌드박스, 프로세스 수명주기를 배웁니다. 2026-10-23 GitHub 기준 스타 14,049 · 포크 732 · Apache-2.0. 소스 설명은 커밋 0f085aa 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

에이전트의 생각보다, 에이전트가 일할 실행 환경을 관리한다

ax는 에이전트 작업을 YAML로 선언하면, 필요한 작업 공간을 준비하고 격리된 환경에서 실행·중단·재개하도록 조정하는 플랫폼입니다. AX의 핵심은 모델에게 무엇을 말할지가 아니라, 에이전트가 어디서 어떤 자원으로 일하게 할지를 관리하는 데 있습니다.

예를 들어 코드 검사 에이전트 100개를 실행한다고 해 봅시다. 각 에이전트에는 저장소, 실행 명령, 메모리 한도, API 인증 정보가 필요합니다. 문제가 생기면 내부를 들여다봐야 하고, 오래 쉬는 작업은 멈췄다가 다시 이어가고 싶습니다. AX는 이 운영 문제를 세 가지 자원으로 나눕니다.

자원쉬운 뜻실제 선언 내용
Task한 에이전트의 작업 주문서이미지, 명령, 환경변수, CPU·메모리 한도, Workspace 참조, 디버그 허용 여부
Workspace작업실 준비 목록Git 저장소, 파일 내용, MCP 설정, 스킬 설정
Model모델 접속 설정표제공자, 모델 식별자, 생성 매개변수, Kubernetes Secret 참조

이 구조의 원본은 pkg/apis/v1alpha1/ax.proto입니다. 이름에 붙은 v1alpha1은 초기 단계 API임을 드러냅니다. 선언할 수 있는 필드와 실제 실행 경로에서 소비하는 필드는 구분해야 합니다. 특히 MCP·스킬의 구현 범위는 뒤에서 따로 확인합니다.

용어 풀이
오케스트레이션과 런타임
오케스트레이션은 여러 작업의 준비·실행·중단을 조정하는 일입니다. 런타임은 프로그램이 실제로 움직이는 실행 기반입니다. AX가 작업을 조정하고, Agent Substrate가 Actor라는 격리 실행 단위를 제공합니다. 언어 모델 자체를 학습하는 프로그램은 아닙니다.
전체 구조를 이해하는 비유

에이전트가 연구원이라면, AX는 연구실 운영 담당자입니다

Task는 연구 지시서, Workspace는 책상에 놓을 자료와 도구 목록, Model은 자문할 전문가의 연락처입니다. Agent Substrate는 방과 전기·출입 통제를 제공하는 건물에 가깝습니다.

연구원이 똑똑해도 방을 공유하다 서로의 파일을 지우거나, 자리를 비운 채 비용을 계속 쓰면 운영이 어렵습니다. AX를 읽는 이유는 연구원의 지능을 높이는 법보다, 여러 연구원이 함께 일할 기반을 만드는 법을 배우기 위해서입니다.

1-1. 사용자가 보는 흐름과 서버 안의 흐름

사용자: YAML 작성 → ax apply → ax resume → ax watch / ax ssh 서버: 검증 → Redis 저장 → Actor 준비 → 실행 활성화 → 준비 상태 확인 작업실: 명세 읽기 → 파일·Git 준비 → 선택적 초기화 → 사용자 명령 실행

실행 파일은 세 개입니다. cmd/ax가 사용자의 CLI, cmd/ax-server가 제어 서버, cmd/ax-task-runner가 각 샌드박스 안의 시작점입니다. 서버와 실행기를 분리한 덕분에 사용자는 실행기 이미지를 바꿀 수 있습니다.

읽고 나면 할 수 있는 일
YAML 한 장이 실제 프로세스가 되는 경로를 설명하기

입력 검증, RPC, 상태 저장, 분산 잠금, 격리 실행, 준비 상태 확인을 하나의 흐름으로 연결할 수 있습니다. 초보자에게는 거대한 저장소보다 경계가 분명한 작은 분산 시스템을 읽는 연습이 됩니다.

2왜 주목받는가

순위는 관심의 신호이고, 소스는 관심을 둘 이유를 보여 준다

2026-10-23 GitHub Trending Go Monthly 1위, 스타 14,049개, 포크 732개입니다. 이 수치만으로 인기의 원인을 입증할 수는 없습니다. 다만 Google의 공개 에이전트 실행 기반이라는 위치와 아래 설계 선택들은 개발자가 이 저장소에 주목할 이유로 해석할 수 있습니다.

2-1. 에이전트의 운영을 별도 문제로 다룬다

README는 에이전트가 상태를 쌓고, 모델 API와 도구 서버에 접근하며, 반복 실행으로 비용을 소모할 수 있다고 설명합니다. AX는 이 문제에 격리, 자원 한도, 작업 공간 준비, 명시적인 중단·재개라는 관리 단위를 제공합니다. 에이전트 로직이 바뀌어도 실행 환경을 관리하는 규칙은 재사용할 수 있다는 점이 이 설계의 학습 가치입니다.

2-2. 익숙한 Kubernetes 문법, 다른 상태 저장소

apiVersion·kind·metadata·spec 형태와 apply·get·watch 명령은 Kubernetes와 닮았습니다. 하지만 Task를 Kubernetes CRD로 등록하는 구조는 아닙니다. DESIGN.md는 수많은 짧은 작업이 Kubernetes의 etcd에 주는 부담을 피하려고 Redis를 선택했다고 설명합니다.

여기서 배울 것은 특정 DB가 언제나 더 빠르다는 결론이 아닙니다. 인프라 배포를 관리하는 데이터와 대량의 작업 상태 데이터를 같은 저장 경로로 보내야 하는지 묻는 제어 경계의 설계입니다.

2-3. 기존 선택지와 비교하면 어디에 놓이는가

선택지잘 맞는 문제AX를 선택할 이유와 비용
직접 만든 Go 실행기소수의 명령을 시작하고 결과 수집AX에는 자원 명세·상태 API·원격 점검 경로가 이미 있다. 대신 Redis와 Substrate 운영이 추가된다.
Kubernetes Job완료를 목표로 하는 배치 작업AX는 작업 공간과 중단·재개를 자체 API로 다룬다. 단, Job 생태계 전체를 대체한다는 뜻은 아니다.
에이전트 로직 프레임워크모델 호출·도구 선택·대화 흐름 구성AX의 중심은 격리 실행과 수명주기다. 실제 에이전트 로직은 작업 명령이나 사용자 이미지 안에 둔다.
Agent Substrate 직접 사용Actor와 실행 기반을 직접 제어AX는 그 위에 Task·Workspace·Model과 CLI를 올린다. 대신 Substrate API의 모든 기능을 노출하지는 않는다.

비교의 기준은 역할과 구조입니다. AX가 다른 도구보다 빠르거나 저렴하다는 실측 비교는 아닙니다. 특히 에이전트의 사고 흐름과 실행 인프라는 함께 조합할 수 있는 서로 다른 층입니다.

2-4. 작은 코드에서 분산 시스템의 현실을 만난다

자동 생성 코드를 제외한 Go 구현은 7,237줄이고, Go 테스트는 6,751줄입니다. internal/lock/lock.go에는 잠금 갱신 실패의 한계까지 주석으로 적혀 있습니다. runner/runner.go에는 자식 프로세스 종료, 종료 신호 전파, 정리 시간 제한이 한 파일에 모여 있습니다.

목표와 검증은 다르다
“수십억 작업”은 README의 설계 목표입니다

README는 클러스터당 수십억 작업을 목표로 내세웁니다. 이 소스에서 확인되는 E2E 테스트는 기능과 수명주기를 검증하는 구성입니다. 처리량·동시 실행 수·장애 복구 시간을 입증하는 대규모 벤치마크 수치로 읽으면 안 됩니다.

자동 유휴 감지, 상태를 가진 작업의 분기, SPIFFE 기반 작업 신원, 원격 측정 확장은 docs/roadmap.md에 계획으로 적혀 있습니다. 이미 완성된 기능 목록과 구분하세요.

3기술 스택 전체 지도

의존성 선언, 사용자 접점, 배포 구성을 나눠 읽기

3-1. 백엔드: Go 표준 라이브러리 위에 얇은 의존성

go.mod의 Go 지시문은 go 1.27.1입니다. docs/development.md는 Go 1.27 이상이라고 안내하지만, 실제 빌드 기준을 볼 때는 더 구체적인 모듈 선언을 먼저 읽습니다.

의존성실제 선언 버전역할과 확인할 파일
Agent Substratev0.5.0Actor·템플릿·중단·재개 API. internal/substrate/client.go
Agent envv0.0.11-0.20260912052224-4468a200b170게스트의 프로세스·파일 서비스. internal/guest/client.go
go-redis/v9v9.22.0상태 저장, 정렬 집합, Pub/Sub, Lua 잠금
gRPCv1.83.2CLI↔제어 서버, 서버↔Substrate 통신
Protobufv1.36.12공유 자원 모델, RPC 타입, JSON 직렬화
yaml.v3v3.0.1여러 YAML 문서 읽기와 YAML 노드 변환
backoff/v5v5.0.3일시적 Substrate 오류의 지수 백오프

날짜와 커밋 식별자가 붙은 긴 Agent env 버전은 의사 버전입니다. 날짜·시간과 커밋 식별자를 포함해 특정 소스를 가리킵니다. 보기 편한 릴리스 이름이 없어도 의존성을 재현 가능한 위치에 고정하는 Go 모듈의 방법입니다.

// go.mod의 직접 의존성 중 일부
go 1.27.1
require (
    github.com/agent-substrate/substrate v0.5.0
    github.com/redis/go-redis/v9 v9.22.0
    google.golang.org/grpc v1.83.2
    google.golang.org/protobuf v1.36.12
    gopkg.in/yaml.v3 v3.0.1
)

net/http, flag, log/slog, os/exec 같은 Go 표준 패키지도 중요합니다. 별도의 웹 프레임워크나 Cobra 없이 서버와 CLI를 구성합니다. cmd/ax/main.go의 parseGlobalArgs()·runApply()를 읽으면 명령 처리의 기본을 직접 볼 수 있습니다.

3-2. 프론트엔드: 웹 화면 대신 CLI와 YAML

이 커밋에는 package.json과 React·Vue 같은 웹 앱이 없습니다. 사용자 접점은 ax CLI이며, cmd/ax/main.go 한 파일이 1,219줄입니다. 입력은 YAML, 요청은 gRPC, 출력은 표·상세 텍스트·YAML·상태 스트림입니다.

접점구현초보자가 볼 부분
선언 입력runApply()·applyDocument()YAML의 kind에 따라 다른 RPC로 분기
실시간 상태runWatch()·WatchTask()요청 한 번으로 응답을 계속 받는 서버 스트리밍
클러스터 연결internal/tunnel/kube context를 읽고 제어 서버 연결 경로 준비
원격 작업 점검runSSH()·internal/guest/SSH와 닮은 명령 뒤의 게스트 gRPC 서비스
용어 풀이
gRPC와 Protocol Buffers
gRPC는 다른 프로세스의 함수를 호출하듯 통신하게 하는 체계입니다. Protocol Buffers는 주고받을 데이터와 서비스의 모양을 정의합니다. AX에서는 pkg/apis/v1alpha1/ax.proto가 계약서이고, pkg/apis/v1alpha1/ax.pb.go·pkg/apis/v1alpha1/ax_grpc.pb.go가 그 계약서에서 만들어진 Go 코드입니다.

3-3. 실행 이미지와 모델 초기화

Dockerfile.task-runner는 python:3.12-slim을 기반으로 Git·curl·bash 등을 설치하고, Go 실행기와 cmd/ax-task-runner/antigravity_bootstrap.py를 넣습니다. Python은 129줄의 초기화 연결 코드에 사용됩니다.

google-antigravity는 pip install에 버전 고정 없이 선언되어 있습니다. Python 패키지용 pyproject.toml이나 잠금 파일은 없습니다. 따라서 Go 모듈 버전이 고정되었다고 해서 실행 이미지 전체의 의존성이 같은 수준으로 고정된 것은 아닙니다.

3-4. 인프라·빌드·CI

영역실제 설정해석
제어 서버·DBdeploy/ax-server.yaml, redis:7-alpineKubernetes Deployment·Service로 배치. Redis의 세부 패치 버전은 고정하지 않음
Go 이미지.ko.yaml, CGO_ENABLED=0, -trimpathko 사용. 서버 기본 이미지는 cgr.dev/chainguard/static:latest
작업 이미지Makefile의 build-task-runnerLinux amd64로 교차 컴파일한 뒤 Dockerfile로 Python 포함 이미지 생성
단위 테스트 CI.github/workflows/go.yml모듈 정리 차이 검사, 바이너리 세 개 빌드, go test -v ./...
통합 테스트 CI.github/workflows/e2e.ymlKind·Substrate·gVisor 환경. PR은 go.mod 버전, 야간 작업은 Substrate main을 대상으로 구성

기술 스택을 읽을 때는 라이브러리 이름뿐 아니라 버전이 고정되는 경계와 실제 배포 경로까지 함께 확인해야 합니다. .ko.yaml의 실행기 기반은 alpine/git:latest로, Python을 포함하는 Dockerfile 경로와 다릅니다. 목표 기반 초기화에 필요한 도구가 어느 이미지에 들어가는지 구분해서 읽으세요.

4아키텍처 심화 분석

네 가지 설계 패턴으로, 입력부터 프로세스 종료까지 추적하기

4-1. 시스템 구조도: 제어 서버 밖에서 실행되는 작업

[개발자] | | YAML: Task / Workspace / Model v [ax CLI] -- gRPC ---------------------> [ax-server :8080] | | | | kube context / tunnel | +-- /healthz | v | [Redis :6379] | - 자원 JSON | - 정렬 집합 인덱스 | - 잠금과 Pub/Sub | ^ | | 저장 / 상태 갱신 | [TaskReconciler.Reconcile] | | | | Substrate Control API | v | [Agent Substrate] | Atespace / ActorTemplate | | | v | [gVisor Actor 샌드박스] | ax-task-runner | | | +-- 파일 / Git / 선택적 초기화 | +-- 사용자 명령 (자식 프로세스) | +-- 작업 디렉터리 /workspace | +-- 내부 메타데이터 127.0.0.1:8099 | +-- probe / guest :80 | +-- ax ssh -- 직접 연결 또는 atenet router --> guest gRPC (debug=true일 때) 별도 기반: Kubernetes가 제어 구성요소를 배치하고, Substrate가 Actor 실행·작업자 배정·스냅샷을 담당한다.

AX가 직접 가상화 엔진을 구현하는 것은 아닙니다. internal/substrate/client.go의 BuildActorTemplate()는 샌드박스 클래스를 GVisor, 설정 이름을 gvisor-default로 지정합니다. 격리의 실제 동작과 지원 환경은 Substrate 쪽 구현·설정에도 달려 있습니다.

4-2. 패턴 ① 하나의 데이터 계약, 경계마다 다른 검증

pkg/apis/v1alpha1/ax.proto에 자원과 RPC를 함께 정의합니다. YAML은 pkg/apis/v1alpha1/types.go의 unmarshalYAMLWith()에서 일반 데이터로 읽은 뒤 JSON으로 변환하고, 마지막에 protojson으로 해석합니다. YAML과 RPC의 필드 이름·타입이 같은 계약을 따르게 하는 설계입니다.

// pkg/apis/v1alpha1/types.go의 옵션
protoUnmarshal = protojson.UnmarshalOptions{}
protoUnmarshalLenient = protojson.UnmarshalOptions{
    DiscardUnknown: true,
}

// 사용자 YAML: unmarshalYAML() → 엄격하게 해석
// 실행기 입력: UnmarshalYAMLLenient() → 모르는 필드는 무시

사용자가 memory를 memroy로 쓰면 빠르게 오류를 알려야 합니다. 반대로 새 서버가 추가한 필드를 오래된 실행기가 모른다는 이유로 작업 전체가 멈추면 업데이트가 어려워집니다. cmd/ax-task-runner/main.go의 loadSpec()가 관대한 해석을 사용하는 이유입니다.

비유

주문을 받는 창구에서는 메뉴 이름의 오타를 잡습니다. 주방에 전달된 주문서에 새 관리 항목이 추가됐다고 해서 예전 조리 기계가 모든 주문을 거절하게 하지는 않습니다. 같은 문서도 어느 경계를 지나는지에 따라 검증 목적이 달라집니다.

커밋 0f085aa는 바로 이 실행기 호환성을 보완합니다. cmd/ax-task-runner/main_test.go의 TestLoadSpec_IgnoresUnknownFields()와 TestLoadSpec_WorkspaceIgnoresUnknownFields()가 그 의도를 보여 줍니다. 다만 모르는 필드를 무시한다는 것은 그 필드의 기능까지 구현한다는 뜻은 아닙니다.

4-3. 패턴 ② 인터페이스로 분리한 저장소와 직접 조정

internal/store/store.go의 Store는 저장·조회·삭제·감시 계약입니다. 실제 Redis 구현은 internal/store/redis/store.go, 테스트에 쓰기 쉬운 메모리 구현은 internal/store/memory/store.go에 있습니다. API 서버는 구체적인 Redis 명령 대신 이 인터페이스를 호출합니다.

internal/server/server.go의 CreateTask()는 검증과 잠금 획득 후 Task를 저장하고, 같은 요청 안에서 Reconcile()를 호출합니다. 이름이 controller라고 해서 별도 백그라운드 작업 큐가 모든 상태를 계속 재조정한다고 가정하면 안 됩니다.

CreateTask 요청 → ValidateTask → 자원별 잠금 → 중복·불변성 확인 → phase = Suspended 로 저장 → Reconcile → EnsureAtespace → EnsureActorTemplateWithImage → EnsureActor → SuspendActor → 상태 갱신 후 응답 ResumeTask 요청 → phase = Running 의도로 Reconcile → ResumeActor → WorkspaceReady가 아직 참이 아니면 /readyz 확인 → Running + WorkspaceReady / Ready 조건 저장

README와 다른 중요한 지점: 빠른 시작의 출력은 apply 뒤 Running을 보여 주지만, 이 커밋의 생성 경로는 Suspended입니다. applyDocument()에도 자동 재개 호출이 없습니다. TestE2E_TaskLifecycleAndSubstrateSync() 역시 생성 후 별도의 ax resume task를 호출합니다.

Task의 명세는 생성 후 불변입니다. 이미 존재하는 Task를 다시 적용하면 보통 거절하며, Pending 상태에서 동일 명세로 생성 요청을 다시 보내는 복구 경로는 허용합니다. Workspace·Model의 생성 또는 갱신과 Task의 생성을 같은 동작으로 이해하지 마세요.

taskTemplateName()는 이미지와 환경변수를 정렬된 순서로 해시해 템플릿 이름에 넣습니다. 실행용 Task 복사본에서 Status를 제거하므로, 단순한 상태 변화가 새로운 시작 템플릿을 만들지 않습니다. 설정과 관측 상태를 분리하는 구체적인 예입니다.

Redis는 문서 저장·목록 조회·알림을 나누어 맡는다

SaveTask()는 TxPipeline()으로 자원 JSON 저장, 두 개의 정렬 집합 갱신, Pub/Sub 발행을 묶습니다. 기본 키는 ax:task:default:hello처럼 만들어집니다. 서버 시작 시 저장소 옵션은 비어 있어 Task 레코드 TTL은 기본적으로 설정되지 않습니다.

// internal/store/redis/store.go, SaveTask()의 핵심
pipe := s.client.TxPipeline()
pipe.Set(ctx, s.taskKey(atespace, name), data, s.opts.TTL)
pipe.ZAdd(ctx, s.taskIndexKey(), redis.Z{Score: score, Member: member})
pipe.ZAdd(ctx, s.taskAtespaceIndexKey(atespace), redis.Z{Score: score, Member: name})
pipe.Publish(ctx, s.taskPubSubChannel(atespace, name), data)
_, err = pipe.Exec(ctx)

WatchTask()는 먼저 구독을 준비하고 현재 값을 INITIAL로 보낸 뒤, 이후 알림을 MODIFIED로 전달합니다. Redis Pub/Sub는 과거 알림을 재생하는 영속 로그가 아닙니다. 연결이 끊긴 동안의 모든 변화를 보장하는 이벤트 저장소로 해석하면 안 됩니다.

4-4. 패턴 ③ 자원별 잠금과 갱신 가능한 임대

두 서버가 같은 Task를 동시에 중단·재개하면 상태가 꼬일 수 있습니다. internal/lock/lock.go의 RedisLocker.Lock()는 자원의 종류·atespace·이름을 키로 만들어 같은 자원에 대한 변경을 직렬화합니다. 서로 다른 Task 전체를 하나의 전역 잠금으로 묶지는 않습니다.

장치실제 값·구현해결하는 문제
획득SetNX + 임의 토큰키가 비어 있을 때 한 요청만 소유
임대 시간기본 30초소유 프로세스가 죽었을 때 잠금이 영구히 남지 않게 함
갱신renew(), TTL/3마다정상적인 긴 작업이 30초를 넘겨도 잠금 유지 시도
해제·알림Lua에서 토큰 확인 후 삭제·발행다른 소유자의 잠금을 지우지 않고 대기자 깨우기
알림 누락 대비기본 1초 재시도Pub/Sub 알림 없이 만료된 키도 다시 획득
용어 풀이
TTL, 임대, 펜싱 토큰
TTL은 키의 남은 유효 시간입니다. 임대는 시간이 지나면 소유권이 끝나는 잠금입니다. 펜싱 토큰은 예전 소유자의 뒤늦은 쓰기를 실행 대상이 거절하도록 붙이는 증가 번호입니다. AX의 임의 소유 토큰은 잠금 키 확인용이며, 외부 실행 대상까지 지키는 펜싱 토큰과 역할이 다릅니다.
소스가 밝히는 한계
잠금 갱신 실패는 기존 작업을 강제로 멈추지 않습니다

코드 주석은 펜싱 토큰이 없고 갱신이 최선 노력 방식임을 명시합니다. Redis 장애가 TTL보다 길면 기존 요청이 계속 실행되는 중에 다른 요청이 잠금을 얻을 수 있습니다. “분산 잠금이 있으니 모든 중복 실행이 불가능하다”는 보장은 아닙니다.

4-5. 패턴 ④ 실행기 수명주기와 상태 신호의 분리

runner/runner.go의 Run()은 메타데이터 서버를 시작하고 작업 공간을 준비한 뒤, 사용자 명령을 별도 프로세스 그룹으로 실행합니다. 명령 종료를 감지해도 실행기는 취소 신호를 기다리며 살아 있습니다. 사용자 명령의 종료, 샌드박스의 생존, 작업 공간의 준비 상태는 서로 다른 사실로 관리됩니다.

// runner/runner.go, Run()에서 발췌
exited := make(chan error, 1)
go func() { exited <- cmd.Wait() }()

select {
case err := <-exited:
    reportExit(cfg, cmd, err)
    // 명령이 끝나도 점검할 수 있도록 실행기를 유지한다.
    <-ctx.Done()
case <-ctx.Done():
    reportExit(cfg, cmd, stopCommand(cmd, exited))
}

stopCommand()는 프로세스 그룹에 SIGTERM을 보내고 10초를 기다린 뒤, 끝나지 않으면 SIGKILL을 보냅니다. 자식이 만든 하위 프로세스까지 함께 정리하려고 Setpgid: true와 음수 PID를 사용합니다.

OnCommandExit 훅은 있지만 기본 실행기의 main()은 이를 서버 상태 갱신에 연결하지 않습니다. 그러므로 명령이 정상 종료했다고 Task가 자동으로 Completed가 된다고 가정하면 안 됩니다. TestRun_KeepsServingAfterCommandExits()는 실행기를 계속 유지하려는 의도를 보여 줍니다.

신호·접점구현상 의미보장하지 않는 것
서버 /healthz제어 서버 HTTP 핸들러가 응답Redis·Substrate까지 정상이라는 종합 확인
실행기 /readyz내부 workspaceReady 값이 참모든 Git·초기화 작업의 실제 성공
RunningActor 재개 후의 단계 요약작업 공간 준비 완료, 명령의 성공 종료
Ready 조건Actor 재개 성공과 WorkspaceReady 조건을 조합매번 작업 공간을 새로 확인하거나 이후 상태를 계속 감시한다는 보장

특히 SetupWorkspace()는 Git 실패를 기록하고 초기화 마커 생성을 생략해도 nil 오류를 반환합니다. Run()은 오류가 없으면 준비 상태를 참으로 만들고 SetupResult의 세부 결과를 확인하지 않습니다. 초기화 에이전트의 실패·건너뛰기도 치명적 오류가 아닙니다. 조정기는 한 번 참이 된 WorkspaceReady 조건을 중단·재개 후에도 재사용합니다. 준비 상태와 실제 준비 품질 사이의 차이를 읽는 연습이 됩니다.

메타데이터는 127.0.0.1:8099, 외부 준비 확인과 게스트 서비스는 기본 :80으로 분리합니다. internal/metadata/server.go의 NewServer()는 spec.debug가 참일 때만 프로세스 실행·파일 접근 게스트 서비스를 등록합니다. 사용 가능한 기능에 따라 노출 면적을 줄이는 설계입니다.

5디렉토리 구조 해부

폴더를 기능 목록보다 호출 경로로 기억하기
ax/ |-- cmd/ | |-- ax/ CLI와 명령별 처리 | |-- ax-server/ 서버 의존성 조립과 시작 | `-- ax-task-runner/ 명세 로딩과 Python 초기화 연결 |-- internal/ | |-- controller/ Task를 Substrate Actor로 조정 | |-- server/ AX gRPC 핸들러 | |-- store/ | | |-- memory/ 메모리 저장소 | | `-- redis/ Redis 저장·조회·알림 | |-- lock/ 메모리·Redis 잠금 | |-- substrate/ 외부 실행 기반 연결 | |-- workspace/ 파일·Git·스킬 경로·초기화 | |-- model/ 모델 설정과 생성 API 클라이언트 | |-- metadata/ 준비 확인·내부 메타데이터 서버 | |-- guest/ 프로세스·파일 서비스 연결 | `-- tunnel/ Kubernetes context와 연결 터널 |-- pkg/apis/v1alpha1/ proto, 생성 코드, YAML 변환·검증 |-- runner/ 사용자 이미지도 호출할 공개 실행기 |-- deploy/ 제어 서버·Redis 배포 예시 |-- examples/ Task·Workspace·Model 선언 예시 |-- test/e2e/ 실제 구성요소 연결 테스트 |-- hack/ Kind 준비·실행·정리 스크립트 |-- docs/ 개념·명세·실행기·로드맵 |-- .github/workflows/ 빌드·테스트 CI |-- Dockerfile.task-runner Python 포함 작업 이미지 |-- .ko.yaml Go 이미지 빌드 설정 `-- go.mod Go와 라이브러리 버전

cmd/는 각 실행 파일의 입구입니다. 실제 동작 대부분은 internal/과 runner/에 있습니다. Go의 internal 경로는 바깥 프로젝트의 임의 가져오기를 제한합니다. 반면 공개 runner 패키지는 사용자 이미지가 runner.Run()을 호출하도록 제공하는 확장 지점입니다.

읽기 순서파일·함수답할 질문
1. 계약pkg/apis/v1alpha1/ax.proto, ValidateTask()사용자가 무엇을 선언할 수 있는가?
2. 접수cmd/ax/main.go, applyDocument()YAML은 어떤 요청이 되는가?
3. 조정Server.CreateTask(), TaskReconciler.Reconcile()언제 저장하고 언제 실제 실행 기반을 부르는가?
4. 실행runner.Run(), SetupWorkspace()샌드박스 안에서 어떤 순서로 준비하는가?
5. 의도*_test.go, test/e2e/어떤 동작을 유지하려고 테스트하는가?

5-1. 코드 규모를 분리해서 보기

커밋 0f085aa의 확장자별 물리적 줄 수입니다. 빈 줄·주석을 포함하며 Git 내부 파일은 제외합니다. 자동 생성 코드를 분리해야 실제로 읽어야 할 구현 규모가 보입니다.

언어·분류파일 수줄 수
Go 구현207,237
Go 테스트196,751
Go 생성 코드23,458
Go 합계4117,446
Python1129
Protocol Buffers1304
Shell5560
YAML / YML12723
Markdown13995

생성 코드를 뺀 Go 13,988줄 중 테스트는 약 48.3%입니다. 이는 줄 수의 비중이며 코드 커버리지 수치가 아닙니다. 초보자는 생성 코드 3,458줄부터 읽기보다, 계약을 정의한 proto와 테스트가 설명하는 동작부터 읽는 편이 좋습니다.

6학습 포인트 (기술별)

기술 이름을 외우는 대신, 그 기술이 해결하는 실패를 찾아보기

6-1. Go 인터페이스: 저장소를 바꿀 수 있게 만들기

store.Store, lock.Locker, server.Reconciler는 구현 교체 경계입니다. 서버가 Redis 클라이언트를 직접 받는 대신 저장소 계약을 받으면, 빠른 테스트에는 메모리 구현을 넣을 수 있습니다. server.NewServer()가 Options로 잠금과 조정기를 주입받는 부분을 함께 읽으세요.

실습 아이디어: CreateTask()가 실제로 사용하는 인터페이스 메서드만 표시한 의존성 표를 그려 보세요. “인터페이스가 있으면 좋다”를 넘어, 외부 서비스를 어느 지점에서 대체할 수 있는지 설명하는 것이 목표입니다.

6-2. YAML과 Protobuf: 직렬화도 제품의 계약이다

pkg/apis/v1alpha1/types.go의 YAML→JSON→Protobuf 변환은 필드 명명 규칙을 한곳에 모읍니다. pkg/apis/v1alpha1/ax.proto의 worker_ip에는 json_name = "workerIP"를 명시해 기존 표기를 유지합니다. 내부 언어의 관례와 외부 사용자에게 약속한 이름을 구분하는 예입니다.

실습 아이디어: 정상 YAML, 오타 필드가 있는 YAML, 새 필드가 추가된 YAML을 종이에 작성하고, CLI와 실행기가 각각 수락할지 예상해 보세요. pkg/apis/v1alpha1/types_test.go와 실행기 테스트에서 근거를 찾습니다.

6-3. Redis: 데이터와 알림은 역할이 다르다

Task의 현재 값은 문자열 키, 목록은 정렬 집합, 변화 알림은 Pub/Sub입니다. 같은 Redis를 사용하지만 자료구조마다 보장하는 동작은 다릅니다. GetTask()가 읽는 경로와 WatchTask()가 듣는 경로를 별도로 추적해 보세요.

실습 아이디어: watcher가 연결되지 않은 동안 상태가 두 번 변했다고 가정하세요. 다시 연결했을 때 현재 값으로 알 수 있는 사실과, 알림 기록 없이는 알 수 없는 사실을 두 열로 적어 봅니다.

6-4. 동시성과 취소: 일을 시작한 사람이 정리도 책임진다

context.Context는 시간 제한과 취소를 하위 동작에 전달합니다. Run()의 버퍼가 1인 종료 채널은 프로세스 종료 결과 하나를 전달하고, 잠금의 sync.Once는 해제 동작이 중복 호출돼도 한 번만 수행되게 합니다.

실습 아이디어: 명령이 먼저 끝나는 경우, 취소가 먼저 오는 경우, SIGTERM을 무시하는 경우를 각각 시간축으로 그리세요. 어느 goroutine이 무엇을 기다리고 누가 채널에 쓰는지 표시하면 됩니다.

6-5. 재시도: 일시적 실패와 잘못된 입력 구분하기

internal/substrate/client.go의 retryOnCodes()는 최대 10회, 초기 간격 200ms, 최대 간격 2초의 지수 백오프를 사용합니다. Git 준비는 최대 5회, 실패 사이 2초 간격으로 별도 구현합니다. 실패가 같아 보여도 상대 서비스와 작업 성격에 따라 재시도 정책이 다릅니다.

실습 아이디어: 네트워크 일시 단절, 잘못된 메모리 단위, 없는 이미지 이름을 분류해 보세요. IsTransientError()와 ValidateResources() 중 어느 경계가 먼저 책임져야 할지 설명합니다.

6-6. 준비 상태와 보안: 이름보다 실제 조건 읽기

internal/metadata/server.go는 메타데이터와 원격 실행 서비스를 다른 리스너로 나누고, 디버그 설정에 따라 게스트 서비스를 켭니다. cmd/ax-task-runner/antigravity_bootstrap.py는 파일 도구에 작업 디렉터리 정책을 적용하면서 명령 실행도 허용합니다. 이 정책과 OS 수준의 격리는 서로 다른 층입니다.

실습 아이디어: “Task가 Running이다”, “/readyz가 200이다”, “Git 준비가 성공했다”, “사용자 명령이 성공했다” 사이에 성립하는 관계만 화살표로 연결하세요. 소스에 없는 보장을 추가하지 않는 것이 핵심입니다.

공부 방법
정상 경로 하나와 실패 경로 하나를 묶어 읽기

함수마다 “성공하면 무엇이 저장되는가”, “실패하면 무엇이 남는가”, “다시 요청해도 안전한가”를 적어 보세요. API·저장소·실행기 중 어느 층이 그 질문에 답하는지 구분할 수 있으면, 다른 서버 프로젝트도 훨씬 읽기 쉬워집니다.

7하드웨어 / 시스템 요구사항

제어 서버의 자원 설정을 전체 시스템의 최소 사양으로 착각하지 않기

저장소에는 개발용 PC의 공식 최소 RAM·디스크 용량이나, 작업 수에 따른 용량 산정표가 없습니다. 필요 자원은 AX 제어 서버, Redis, Substrate 작업자, 실제 에이전트 작업의 몫을 나누어 계산해야 합니다. 아래 수치는 성능 측정값이 아니라 배포 예시의 설정값입니다.

대상확인되는 설정·요건해석
소스 학습텍스트 편집기와 파일 열람 도구클러스터·API 키·GPU 없이도 구조 학습 가능
Go 빌드go.mod의 Go 1.27.1CI는 go.mod를 기준으로 도구 버전 선택
제어 서버요청 100m / 128Mi, 한도 1000m / 1Gideploy/ax-server.yaml, 복제본 1개
Redis요청 100m / 128Mi, 한도 1000m / 1Gideploy/redis.yaml, 복제본 1개
실제 작업자Substrate와 gVisor 실행 환경제어 서버·Redis의 자원 설정에 포함되지 않음
배포 도구Kubernetes, kubectl, ko, 이미지 레지스트리작업 이미지에는 Docker 또는 Podman 경로도 사용
E2E 환경Kind, gVisor WorkerPool, 스냅샷 저장소hack/setup-e2e-kind.sh의 기본 작업자 복제본은 4개

100m은 CPU 0.1코어, 1000m은 1코어입니다. 두 제어 구성요소의 요청 합계는 CPU 0.2코어·메모리 256Mi이지만, Kubernetes 자체와 Substrate·실제 작업은 빠져 있으므로 노트북 전체의 최소 사양으로 사용할 수 없습니다.

7-1. Task의 자원 제한은 Kubernetes Pod와 다르다

pkg/apis/v1alpha1/resources.go의 ValidateResources()는 spec.resources.requests의 CPU나 메모리 값이 비어 있지 않으면 거절합니다. 스키마에 필드가 있어도 자원 크기 지정에 지원하는 설정은 limits뿐입니다. CPU·메모리는 양수여야 하고, CPU는 1,000코어 미만이어야 합니다. 생략하면 작업자 기본 설정을 따릅니다.

# Task.spec 안의 예시: Pod의 requests와 혼동하지 않는다.
resources:
  limits:
    cpu: "500m"
    memory: "512Mi"

이 값은 internal/substrate/client.go의 ResourceLimits()를 통해 ActorTemplate로 전달됩니다. 제한을 요청한 작업에 템플릿 생성이 실패했을 때, 다른 기본 템플릿으로 조용히 대체하지 않도록 제어 코드가 오류를 반환합니다.

7-2. GPU·모델·외부 연결

기본 배포에는 GPU 자원 요청이 없고, 모델 클라이언트는 외부 생성 API를 호출하는 구조입니다. 따라서 AX 제어 기능 자체를 배우기 위해 GPU가 필요하다는 근거는 없습니다. 다만 사용자가 실행할 이미지가 로컬 추론이나 무거운 빌드를 포함한다면 그 작업의 요구사항을 별도로 계산해야 합니다.

모델 기반 초기화에는 이미지 안의 초기화 스크립트와 GEMINI_API_KEY가 필요합니다. 기본 제한 시간은 10분이며 AX_BOOTSTRAP_TIMEOUT으로 조정합니다. Git 다운로드, 이미지 다운로드, 모델 API 호출, 스냅샷 저장소는 각각 네트워크 접근과 인증 구성이 필요할 수 있습니다.

실제 배포 전에 확인
예시 매니페스트는 운영 구성을 완성해 주지 않습니다

Redis 예시에는 영속 볼륨 선언이 없고 복제본도 1개입니다. 제어 서버의 /healthz는 의존 서비스의 상태를 확인하지 않습니다. 상태 보존·백업·장애 감지·인증 경계를 별도로 설계해야 합니다.

AX_SNAPSHOTS_BUCKET의 기본값과 배포 예시에는 특정 환경의 저장 위치가 들어 있습니다. 자신의 저장소와 권한으로 바꿔야 합니다. 기본 템플릿의 스냅샷 선호도는 SNAPSHOT_FIDELITY_VOLUMES이므로, 중단·재개를 곧바로 모든 메모리 상태의 완전 복원이라고 단정하지 마세요.

8직접 해볼 수 있는 실습 과제

읽기 과제에서 시작해, 독립된 학습용 환경의 실행 실험으로 확장하기

앞의 두 과제는 파일 열람만으로 끝낼 수 있습니다. 실행 실험은 Substrate가 준비된 별도의 학습용 클러스터를 전제로 합니다. 각 과제는 명령 실행 자체보다 예상한 상태와 실제 구현이 일치하는지 설명하는 것을 완료 기준으로 삼습니다.

과제 1 · 입문

YAML 한 필드의 여행 지도 파일 열람

문제: Task.spec.workspace.path가 어디에서 검증되고, 어디에서 사용자 명령의 작업 디렉터리가 되는지 찾아보세요.

  1. pkg/apis/v1alpha1/ax.proto에서 WorkspaceRef를 찾습니다.
  2. pkg/apis/v1alpha1/types.go에서 ValidateTask()와 WorkspacePath()를 읽습니다.
  3. runner.Run()의 cmd.Dir까지 연결합니다.

완료 기준: 생략 시 /workspace, 상대 경로 선언 시 검증 오류, 절대 경로 선언 시 실행기의 작업 디렉터리로 사용된다는 세 경우를 설명합니다. 단, 해당 경로가 실제로 영속 저장되는지는 볼륨 마운트를 별도로 확인해야 합니다.

과제 2 · 입문

엄격한 해석과 관대한 해석 비교 파일 열람

문제: spec.fieldFromTheFuture라는 알 수 없는 필드를 추가했다고 가정합니다. 같은 입력을 CLI와 실행기에 넣으면 어떤 차이가 날지 예상해 보세요.

힌트: UnmarshalYAML() 경로와 UnmarshalYAMLLenient() 경로, cmd/ax-task-runner/main_test.go를 나란히 읽습니다.

완료 기준: “오타를 막는 사용자 경계”와 “서버·이미지 버전 차이를 견디는 내부 경계”를 설명하고, 필드 무시가 새로운 기능의 지원을 의미하지 않는 이유를 적습니다.

과제 3 · 중급

작은 파일을 읽는 Task의 수명주기 관찰 학습용 클러스터

준비: 접근 가능한 AX·Substrate와 작업 이미지가 필요합니다. 서버의 --default-task-image 또는 AX_DEFAULT_TASK_IMAGE에 준비한 이미지를 지정합니다. 아래 선언은 모델 호출이나 목표 기반 초기화 없이 인라인 파일과 명령만 사용합니다. Workspace를 Task보다 먼저 선언합니다.

apiVersion: ax.io/v1alpha1
kind: Workspace
metadata:
  name: study-ws
spec:
  files:
    - path: message.txt
      content: "AX 학습용 파일"
---
apiVersion: ax.io/v1alpha1
kind: Task
metadata:
  name: study-task
spec:
  workspace:
    name: study-ws
  debug: true
  resources:
    limits:
      cpu: "500m"
      memory: "512Mi"
  command: ["sh", "-c", "pwd; cat message.txt"]
# study.yaml로 저장한 뒤, 준비된 학습용 클러스터에서 관찰
ax apply -f study.yaml
ax get task study-task
# 생성 직후 예상 단계: Suspended

ax resume task study-task
ax describe task study-task
ax ssh study-task -- cat /workspace/message.txt

ax suspend task study-task
ax resume task study-task
ax delete task study-task
ax delete workspace study-ws

완료 기준: 생성 직후 Suspended, 재개 후 단계와 조건, 사용자 명령이 끝난 뒤에도 내부 파일 점검이 가능한 이유를 설명합니다. ax watch는 상태 변화를 보는 명령이며 사용자 명령의 표준출력 로그를 대신하지 않습니다.

과제 4 · 고급

“준비 완료”의 정의를 다시 설계하기 설계·테스트 계획

문제: Git 준비 실패 시 마커는 남지 않지만, 실행기가 준비 상태를 참으로 만드는 경로가 있습니다. SetupResult와 Run() 사이의 계약을 어떻게 바꿀지 설계해 보세요.

완료 기준: 성공·일부 실패·재시작의 표를 만들고, 각각 반환값·마커·준비 응답·명령 실행 여부를 정합니다. 기존의 실패 허용 정책을 바꾸는 호환성 영향도 한 문단으로 설명합니다.

과제 5 · 고급

잠금 임대가 사라지는 순간 그려 보기 장애 시나리오 분석

문제: 서버 A가 작업을 진행하는 동안 Redis 연결이 30초 넘게 끊기고, 서버 B가 새 임대를 얻었다고 가정합니다. 실제 장애를 일으키지 않고 두 서버와 Redis의 시간축을 그리세요.

읽을 코드: RedisLocker.Lock()·renew(), releaseAndNotifyScript, Server.ResumeTask().

완료 기준: 토큰 비교가 막는 잘못된 잠금 해제와, 현재 구조가 막지 못하는 외부 작업 중첩을 구분합니다. 펜싱이나 임대 상실 시 취소를 도입하려면 어느 구성요소가 협력해야 하는지도 제안합니다.

9관련 기술 심화 학습 로드맵

6주 동안 작은 계약에서 분산 실행의 한계까지 넓혀 가기

Go 문법을 막 배웠다면 하루 30~60분의 읽기·메모를 기준으로 다음 순서를 활용할 수 있습니다. 일정은 학습용 제안이며, 각 주의 결과물을 설명할 수 있을 때 다음 단계로 넘어가세요.

주차주제와 읽을 코드남길 결과물
1주차Go 구조체·인터페이스·오류. Store, ValidateTask()세 자원의 필드 표와 입력 오류 사례 5개
2주차YAML·JSON·Protobuf·gRPC. pkg/apis/v1alpha1/types.go, applyDocument()YAML부터 CreateTask까지의 변환 지도
3주차Redis 자료구조·트랜잭션·Pub/Sub. SaveTask(), WatchTask()현재 값·목록·알림의 키와 보장 비교표
4주차context·goroutine·프로세스 신호. Run(), stopCommand()정상 종료·취소·강제 종료의 시간축
5주차Kubernetes 배포·gVisor·Substrate. BuildActorTemplate(), deploy/제어 서버와 실제 작업의 책임·자원 경계도
6주차임대·멱등성·장애 복구. internal/lock/lock.go, internal/controller/reconciler.go, E2E 테스트중복 요청·연결 단절·초기화 실패 설계 검토서

학습의 다음 단계는 비슷한 도구를 더 외우는 것이 아니라, 한 동작의 성공·실패·재시도 계약을 끝까지 설명하는 것입니다. 예를 들어 “재개가 실패했다”는 한 문장을 요청 취소, Substrate 오류, 준비 확인 시간 초과, 사용자 명령 실패로 분해할 수 있다면 시스템을 층별로 읽기 시작한 것입니다.

9-1. 관심사별 다음 갈림길

공부의 기준점

자동차의 부품 이름을 다 외우는 것보다 브레이크를 밟았을 때 어느 부품이 어떤 순서로 작동하는지 설명하는 편이 유용합니다. AX에서도 먼저 Task 하나의 생성·재개·중단·삭제를 따라가고, 그 다음에 대량 실행을 생각하세요.

10핵심 키워드 사전

본문으로 돌아갈 때 사용할 짧은 길잡이
용어쉬운 설명
AXAgent Executor. 에이전트 작업의 환경과 수명주기를 선언형으로 관리하는 실행 플랫폼.
선언형절차를 하나씩 호출하기보다 원하는 설정을 문서로 적는 방식. AX에서도 생성·재개 같은 동작 구분은 필요하다.
Task격리된 작업 하나의 명세와 상태. 이미지·명령·한도·Workspace 참조를 담는다.
Workspace작업 전에 준비할 저장소·파일·도구 설정 목록. 이름이 같다고 여러 작업이 한 폴더를 자동 공유한다는 뜻은 아니다.
Model모델 제공자·식별자·매개변수·인증 정보 참조를 담는 자원.
ActorSubstrate가 관리하는 실행 단위. AX는 Task 이름을 Actor 이름으로 사용한다.
ActorTemplateActor의 이미지·환경변수·볼륨·자원·샌드박스 설정을 담는 실행 틀.
AtespaceAX·Substrate 자원의 이름 범위. 기본값은 default이며 Kubernetes namespace와 같은 개념으로 단정하지 않는다.
제어 평면무엇을 실행하고 어떤 상태로 관리할지 결정하는 서버 계층. 실제 사용자 명령의 실행 위치와 구분한다.
Reconcile선언과 실제 실행 기반을 맞추는 조정. 현재 AX에서는 주요 변경 요청 안에서 직접 호출한다.
Phase / ConditionPhase는 Running 같은 단계 요약, Condition은 WorkspaceReady 같은 세부 조건.
gRPC 스트리밍한 요청에 응답을 여러 번 보내는 통신 방식. ax watch가 상태 변화를 받는 데 사용한다.
직렬화메모리 안의 데이터를 YAML·JSON·Protobuf 같은 전달·저장 형식으로 바꾸는 일.
Pub/Sub발행자가 채널로 알림을 보내고 구독자가 받는 방식. AX의 알림은 영속적인 변경 이력과 다르다.
분산 잠금여러 프로세스가 같은 자원을 동시에 변경하지 않도록 조정하는 장치. 장애 조건의 한계도 함께 읽어야 한다.
임대 / TTL시간이 지나면 끝나는 소유권과 그 유효 시간. 정상 작업은 주기적으로 연장한다.
멱등성같은 요청을 반복해도 결과가 중복되지 않게 하는 성질. AX의 모든 명령이 같은 재요청 정책을 갖지는 않는다.
백오프실패 직후 무작정 반복하지 않고 간격을 두는 재시도 정책. 지수 백오프는 간격을 점차 늘린다.
샌드박스 / gVisor작업을 격리하는 환경과, AX 기본 템플릿이 선택하는 격리 실행 기술.
스냅샷나중에 복원하기 위한 상태 저장본. 파일·볼륨·메모리 중 무엇을 보존하는지 구성을 확인해야 한다.
MCP모델 기반 앱과 도구·데이터 제공자를 연결하는 프로토콜. AX의 설정 필드 존재와 자동 연결 구현은 구분한다.
스킬에이전트가 참고할 작업 지침·자원 묶음. 현재 기본 준비 코드는 지정한 디렉터리를 만드는 수준이다.
Secret 참조명세에 키 본문 대신 Kubernetes Secret의 이름과 키 항목을 기록하는 방법.
E2E 테스트CLI·서버·저장소·샌드박스를 연결해 사용자 동작 전체를 검증하는 테스트.
의사 버전Go 모듈에서 날짜·시간과 커밋 식별자를 포함해 특정 소스를 지정하는 버전 표기.

11참고 링크

주장과 코드를 다시 연결하는 공식 자료

11-1. 공식 저장소와 읽기 순서

11-2. 코드 근거 바로가기

11-3. 관련 기술의 공식 학습 자료

현재 상태 (2026-10-23 확인)

항목상태
선정 위치GitHub Trending Go Monthly #1, 2026-10-23 분석
공식 설명Google의 공개 에이전트 오케스트레이션 런타임인 Agent Executor(AX)
스타 / 포크14,049 / 732 — 2026-10-23 GitHub 기준
주 언어 / 생성일Go / 2026-03-30
최신 릴리스v0.3.1 — 2026-09-25
최근 push2026-10-22 — GitHub 저장소 활동 시각
분석 기준 커밋0f085aa — 2026-10-21, 제어 서버에서 받은 명세의 알 수 없는 필드를 실행기가 무시하도록 변경 (#506)
Go 코드 규모41파일 / 17,446줄. 구현 7,237 + 테스트 6,751 + 생성 코드 3,458
그 밖의 코드Python 129줄, Protobuf 304줄, Shell 560줄, YAML·YML 723줄
라이선스Apache-2.0
안정성 안내README는 활발한 개발과 안정 릴리스 이전의 큰 호환성 변경 가능성을 명시

최근 push 시각과 분석 기준 커밋의 날짜는 서로 다른 정보입니다. 최신 릴리스 v0.3.1의 코드와 이 글이 설명하는 0f085aa의 코드 역시 같다고 가정하지 마세요. 줄 수는 해당 커밋의 물리적 줄 수 집계입니다.

사용 전에 알아둘 한계
명세에 있는 기능, 실행되는 기능, 앞으로의 목표를 나누어 읽으세요

MCP·스킬: README와 개념 문서는 도구·스킬 준비를 강조하지만, 기본 SetupWorkspace()에는 MCP 서버 시작·연결이나 레지스트리 검색 경로가 없습니다. setupSkills()는 지정 디렉터리를 만들 뿐 스킬 패키지를 내려받지 않습니다.

환경 계획과 모델: Planner.PlanEnvironment()는 존재하지만 기본 서버·실행기의 호출 경로에 연결되어 있지 않습니다. 실제 목표 초기화는 Python 연결 코드를 사용합니다. Go 모델 클라이언트는 Google 제공자를 구현하며, API 키가 없으면 고정 형식 응답으로 대체하는 경로도 있으므로 계획 응답 자체를 실제 환경 준비의 증거로 보지 마세요.

상태와 복원: 생성은 기본 중단 상태이고, 명령 종료가 자동 완료 상태로 이어지지 않습니다. 준비 상태 확인에서는 일부 초기화 실패가 드러나지 않을 수 있으며, 기본 스냅샷 구성은 볼륨 보존을 선호합니다. 자동 유휴 중단·상태 분기·확장 관측 기능은 로드맵과 실제 구현을 대조해야 합니다.

운영 판단: README의 대규모 실행 목표는 처리량·지연시간·비용 효율의 측정 결과와 구분해야 합니다. E2E 테스트는 기능과 수명주기를 검증하는 구성이며, 대규모 성능을 입증하는 벤치마크는 아닙니다. v1alpha1의 변경 가능성과 Redis 영속성·인증·실행 권한 구성을 고려해 별도의 환경에서 평가하세요.