Search

260719_2022_grok-build 진행

grok-build
xai-org

요약

SpaceXAI의 터미널 기반 AI 코딩 에이전트 즉 클로드 코드와 같은 것으로, Grok Build를 구성하는 Rust 소스와 에이전트 런타임이 공개됐으며, 저장소는 SpaceXAI 모노레포에서 주기적으로 동기화될 예정이라고 한다.
전체 화면 TUI에서 코드베이스 이해, 파일 수정, 셸 명령 실행, 웹 검색, 장기 작업 관리를 지원하고 대화형·헤드리스·Agent Client Protocol(ACP) 연동 방식으로 실행할 수 있는 형태로, 이제 MCP가 아닌 ACP 형태의 진화가 오픈소스로 배포가 되었다.
macOS·Linux·Windows용 사전 빌드 바이너리를 제공하며, 소스 빌드는 Rust와 protoc가 필요하고 macOS·Linux만 정식 빌드 호스트로 지원한다고, 한다.
코드는 TUI, 에이전트 런타임, 도구 구현, 호스트 파일 시스템·VCS·실행·체크포인트를 각각 담당하는 Rust 크레이트로 나뉘어 있는데, 맨 아래 cargo.toml은 공개해놓도록 하겠다.
자체 코드는 Apache License 2.0으로 배포되지만 외부 기여는 받지 않으며, 서드파티 및 벤더링 코드는 기존 라이선스를 유지한다고 한다.

Grok Build (grok)

SpaceXAI의 터미널 기반 AI 코딩 에이전트

한줄 요약

Rust로 작성된 CLI/TUI + 에이전트 런타임
코드베이스 이해, 파일 편집, 셸 실행, 웹 검색, 장기 작업 관리를 터미널에서 수행
SpaceXAI 모노레포에서 주기적으로 동기화되며, SOURCE_REV에 원본 커밋 SHA 기록
공식 바이너리 이름은 grok, 소스 빌드 산출물은 xai-grok-pager

핵심 기능

코드베이스 이해
파일 편집
셸 명령 실행
웹 검색
장기 실행 작업 관리
확장: MCP, 스킬/플러그인, 훅, 테마, 샌드박싱

실행 방식 (3가지)

대화형 TUI — 전체 화면, 마우스 인터랙션
헤드리스 — 스크립트/CI용
ACP(Agent Client Protocol) — 편집기 임베드

설치

macOS / Linux / Git Bash
curl -fsSL <https://x.ai/cli/install.sh> | bash
Windows PowerShell
irm <https://x.ai/cli/install.ps1> | iex
확인: grok --version
첫 실행 시 브라우저로 인증

소스 빌드 조건

필요: Rust(rust-toolchain.toml 고정), DotSlash, protoc
지원 빌드 호스트: macOS, Linux
Windows 소스 빌드는 best-effort, 이 트리에서는 미테스트
프로토 생성: bin/protoc(DotSlash) 우선, 없으면 PATH/$PROTOC

주요 빌드 명령

cargo run -p xai-grok-pager-bin — 빌드 + TUI 실행
cargo build -p xai-grok-pager-bin --release — target/release/xai-grok-pager
cargo check -p xai-grok-pager-bin — 빠른 검증
전체 워크스페이스 빌드는 느리므로 크레이트 단위로 check/test/clippy 권장

저장소 구조

xai-grok-pager-bin — 바이너리 구성 루트
xai-grok-pager — TUI (스크롤백, 프롬프트, 모달, 렌더링)
xai-grok-shell — 에이전트 런타임, leader/stdio/헤드리스 진입점
xai-grok-tools — 터미널/파일편집/검색 등 도구 구현
xai-grok-workspace — 파일시스템, VCS, 실행, 체크포인트
기타 codegen 크레이트 — config, MCP, markdown, sandbox 등
crates/common, crates/build, prod/mc — 공유 리프 크레이트
third_party — Mermaid 다이어그램 스택 벤더링
루트 Cargo.toml은 생성 파일이므로 읽기 전용, 수정은 크레이트별 Cargo.toml

사용자 가이드 범위

위치: crates/codegen/xai-grok-pager/docs/user-guide/
시작하기, 단축키, 슬래시 명령, 설정/테마
MCP, 스킬/플러그인, 훅, 헤드리스, 샌드박싱

라이선스 / 기여

자체 코드: Apache-2.0
외부 기여 받지 않음 (CONTRIBUTING.md)
서드파티/벤더링은 원 라이선스 유지
도구 구현에 openai/codex, sst/opencode 포트 포함
Mermaid 관련 독립형 터미널 렌더러도 포함

커뮤니티 반응 (GeekNews / HN 요지)

오픈소스 직후 프라이버시 포크, 멀티 프로바이더 CLI, 데스크톱 GUI 등 파생 프로젝트가 빠르게 등장
코드량이 크고 Codex/OpenCode 계열 도구 포트를 포함한 에이전트 하네스로 평가됨
성능·가격 호평과 데이터/평판 이슈에 대한 경계가 동시에 존재
Grok Build보다 Pi 등 다른 오픈 에이전트를 권하는 의견도 있음

Cargo.toml

# Auto-generated workspace root. Prefer editing per-crate Cargo.toml files. [workspace] resolver = "2" members = [ "crates/build/xai-proto-build", "crates/codegen/ptyctl", "crates/codegen/ptyctl-cli", "crates/codegen/xai-acp-lib", "crates/codegen/xai-agent-lifecycle", "crates/codegen/xai-chat-state", "crates/codegen/xai-codebase-graph", "crates/codegen/xai-crash-handler", "crates/codegen/xai-fast-worktree", "crates/codegen/xai-file-utils", "crates/codegen/xai-fsnotify", "crates/codegen/xai-gix-status", "crates/codegen/xai-grok-agent", "crates/codegen/xai-grok-announcements", "crates/codegen/xai-grok-auth", "crates/codegen/xai-grok-config", "crates/codegen/xai-grok-config-types", "crates/codegen/xai-grok-env", "crates/codegen/xai-grok-hooks", "crates/codegen/xai-grok-http", "crates/codegen/xai-grok-markdown", "crates/codegen/xai-grok-markdown-core", "crates/codegen/xai-grok-mcp", "crates/codegen/xai-grok-memory", "crates/codegen/xai-grok-mermaid", "crates/codegen/xai-grok-models", "crates/codegen/xai-grok-pager", "crates/codegen/xai-grok-pager-bin", "crates/codegen/xai-grok-pager-minimal", "crates/codegen/xai-grok-pager-pty-harness", "crates/codegen/xai-grok-pager-render", "crates/codegen/xai-grok-paths", "crates/codegen/xai-grok-plugin-marketplace", "crates/codegen/xai-grok-sampler", "crates/codegen/xai-grok-sampling-types", "crates/codegen/xai-grok-sandbox", "crates/codegen/xai-grok-secrets", "crates/codegen/xai-grok-shared", "crates/codegen/xai-grok-shell", "crates/codegen/xai-grok-shell-base", "crates/codegen/xai-grok-shell-session-support", "crates/codegen/xai-grok-subagent-resolution", "crates/codegen/xai-grok-telemetry", "crates/codegen/xai-grok-test-support", "crates/codegen/xai-grok-tools", "crates/codegen/xai-grok-tools-api", "crates/codegen/xai-grok-update", "crates/codegen/xai-grok-version", "crates/codegen/xai-grok-voice", "crates/codegen/xai-grok-workspace", "crates/codegen/xai-grok-workspace-client", "crates/codegen/xai-grok-workspace-types", "crates/codegen/xai-hooks-plugins-types", "crates/codegen/xai-hunk-tracker", "crates/codegen/xai-mixpanel", "crates/codegen/xai-prompt-queue", "crates/codegen/xai-ratatui-inline", "crates/codegen/xai-ratatui-textarea", "crates/codegen/xai-sqlite-journal", "crates/codegen/xai-system-power", "crates/codegen/xai-token-estimation", "crates/codegen/xai-tracing-macros", "crates/codegen/xai-tty-utils", "crates/common/xai-circuit-breaker", "crates/common/xai-computer-hub-core", "crates/common/xai-computer-hub-mcp-adapter", "crates/common/xai-computer-hub-sdk", "crates/common/xai-grok-compaction", "crates/common/xai-interjection-core", "crates/common/xai-test-utils", "crates/common/xai-tool-protocol", "crates/common/xai-tool-runtime", "crates/common/xai-tool-types", "crates/common/xai-tracing", "prod/mc/cli-chat-proxy-types", "third_party/dagre_rust", "third_party/graphlib_rust", "third_party/mermaid-to-svg", "third_party/ordered_hashmap", ] [workspace.package] edition = "2024" license = "Apache-2.0" [workspace.dependencies] agent-client-protocol = { version = "0.10.4", features = ["unstable"] } alacritty_terminal = "0.26.0" ansi-to-tui = "7.0.0" ansi-width = "0.1" anstyle = "1.0" anstyle-lossy = "1.1.4" anstyle-parse = "0.2" anstyle-syntect = "1.0.4" anyhow = { version = "1", features = ["backtrace"] } arboard = "3.6" arc-swap = "1.7" assert_matches = "1.5.0" async-compression = { version = "0.4.17", default-features = false, features = ["gzip", "zstd", "tokio"] } async-lsp = { version = "0.2.3", features = ["tokio", "tracing"] } async-openai = { version = "0.33.0", features = ["responses"] } async-stream = "0.3" async-trait = "0.1" axum = { version = "0.8", features = ["macros", "ws"] } backon = { version = "1.6" } backtrace = "0.3" base64 = "0.22" blake3 = "1" bytes = { version = "1", features = ["serde"] } camino = "1.1.10" chrono = "0.4" clap = { version = "4", features = ["derive", "env"] } clap_complete = { version = "4" } colored_json = "5" core-foundation = "0.10" crc32fast = "1.4" criterion = "0.6" crossbeam = "0.8" crossterm = "0.28" cryptify = "3.2" dashmap = "6" derive_more = { version = "2", features = ["add", "add_assign", "debug", "deref", "deref_mut", "display", "from", "from_str", "into", "into_iterator", "try_into"] } dhat = "0.3" dirs = "5.0" documented = "0.9" dunce = "1" educe = "0.6.0" enum_delegate = "0.2" env_logger = "0.11" eventsource-stream = "0.2" fastrace = { version = "0.7" } fastrace-opentelemetry = { version = "0.18" } fastrace-reqwest = { version = "0.2" } fastrace-tonic = { version = "0.1" } fastrand = "2" filetime = "0.2.25" flate2 = { version = "1", default-features = false, features = ["zlib-rs"] } fontdb = "0.23" fs2 = "0.4" futures = "0.3" futures-util = "0.3" fuzzy-matcher = "0.3.7" gcloud-storage = { version = "1.3.0", default-features = false, features = ["auth", "jwt-aws-lc-rs", "external-account"] } gethostname = "1" gix = { version = "0.83", default-features = false, features = ["sha1"] } glob = "0.3" globset = "0.4" htmd = "0.5.4" html-escape = "0.2" http = "1" http-body-util = "0.1" humantime-serde = "1" ignore = "0.4" image = { version = "0.25.9", default-features = false } indexmap = { version = "2", features = ["serde"] } indicatif = "0.18" infer = "0.19.0" insta = "1" itertools = "0.14" jsonschema = "0.30.0" libc = "0.2" linkify = "0.10" lipsum = "0.9" log = { version = "0.4", features = ["kv", "kv_unstable"] } md5 = "0.8" mermaid-to-svg = { path = "third_party/mermaid-to-svg" } minijinja = "2.9" mockito = "1" moka = "0.12" nix = { version = "0.30", features = ["poll", "process", "signal", "sched", "term", "mount", "fs", "ioctl", "mman", "reboot", "user"] } notify = "8" notify-debouncer-mini = "0.6" nucleo = { git = "https://github.com/helix-editor/nucleo.git", rev = "5b74652" } num_cpus = "1" oauth2 = "5" obfstr = "0.4" once_cell = "1" opentelemetry = "0.32" opentelemetry-http = { version = "0.32", features = ["reqwest-blocking"] } opentelemetry-otlp = { version = "0.32", features = ["grpc-tonic", "reqwest-blocking-client", "tls-roots"] } opentelemetry-proto = { version = "0.32", features = ["gen-tonic"] } opentelemetry_sdk = { version = "0.32.1", features = ["spec_unstable_metrics_views"] } parking_lot = "0.12.4" pbjson-build = "0.9" pdf_oxide = { version = "0.3.43", features = ["rendering"] } petgraph = { version = "0.6.5", default-features = false, features = ["serde-1", "stable_graph"] } portable-pty = "0.9" pprof = "0.15" pretty_assertions = "1" prometheus = { version = "0.14", features = ["process"] } prost = "0.14" prost-build = "0.14" pulldown-cmark = "0.13" quick-xml = "0.38" rand = "0.9" ratatui = { version = "0.29" } ratatui-core = "0.1" rayon = "1" reflink-copy = "0.1" regex = "1" reqwest = { version = "0.12", features = ["rustls-tls", "stream", "json", "multipart", "http2", "blocking", "socks"], default-features = false } reqwest-middleware = { version = "0.4.1", features = ["json", "multipart"] } resvg = { version = "0.47", default-features = false, features = ["text"] } ring = "0.17" rsa = "0.9" runfiles = "0.1" rustc-hash = "2" schemars = "1" scraper = "0.23" semver = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_path_to_error = "0.1" serde_yaml = "0.9" serial_test = "3" sha2 = { version = "0.10", features = ["force-soft"] } shlex = "1" signal-hook = "0.3" similar = "2.7" siphasher = "1" smallvec = "1" strip-ansi-escapes = "0.2.1" strum = { version = "0.27", features = ["derive"] } supports-color = "3.0" syntect = "5.3" tar = "0.4" tempfile = "3" terminput = "0.3" termwiz = { version = "0.23", default-features = false } textwrap = "0.16" thiserror = "2" tikv-jemalloc-ctl = "0.6" tikv-jemalloc-sys = "0.6" tikv-jemallocator = { version = "0.6", features = ["profiling", "unprefixed_malloc_on_supported_platforms"] } time = "0.3" tiny-skia = "0.12" tokio = { version = "1", features = ["full"] } tokio-retry = "0.3" tokio-stream = "0.1" tokio-tungstenite = "0.27" tokio-util = { version = "0.7", features = ["rt"] } toml = "0.9" toml_edit = "0.22" tonic = { version = "0.14", features = ["tls-aws-lc", "gzip", "deflate", "zstd"] } tonic-prost = "0.14" tonic-prost-build = "0.14" tower = "0.5" tower-http = "0.6" tracing = "0.1" tracing-opentelemetry = "0.33" tracing-subscriber = { version = "0.3.23", default-features = false, features = ["env-filter", "smallvec", "tracing-log", "std", "ansi"] } ts-rs = "12.0" tui-scrollbar = "0.2" two-face = { version = "0.4", default-features = false, features = ["syntect-fancy"] } unicode-segmentation = "1.12.0" unicode-width = "0.2" url = "2" urlencoding = "2" uuid = { version = "1", features = ["serde", "v4", "v5"] } vte = "0.15.0" wait-timeout = "0.2" walkdir = "2" webbrowser = { version = "1.0.4" } which = "8" whoami = "1.4" windows = { version = "0.61", features = ["Win32_Security", "Win32_Security_Authorization", "Win32_Foundation", "Win32_System_Threading", "Win32_System_JobObjects", "Win32_System_Console", "Win32_System_Pipes"] } wiremock = "0.6" wl-clipboard-rs = "0.9" xai-acp-lib = { path = "crates/codegen/xai-acp-lib" } xai-agent-lifecycle = { path = "crates/codegen/xai-agent-lifecycle" } xai-circuit-breaker = { path = "crates/common/xai-circuit-breaker" } xai-computer-hub-core = { path = "crates/common/xai-computer-hub-core" } xai-computer-hub-sdk = { path = "crates/common/xai-computer-hub-sdk" } xai-gix-status = { path = "crates/codegen/xai-gix-status" } xai-grok-agent = { path = "crates/codegen/xai-grok-agent" } xai-grok-announcements = { path = "crates/codegen/xai-grok-announcements" } xai-grok-auth = { path = "crates/codegen/xai-grok-auth" } xai-grok-config = { path = "crates/codegen/xai-grok-config" } xai-grok-config-types = { path = "crates/codegen/xai-grok-config-types" } xai-grok-env = { path = "crates/codegen/xai-grok-env" } xai-grok-http = { path = "crates/codegen/xai-grok-http" } xai-grok-markdown = { path = "crates/codegen/xai-grok-markdown" } xai-grok-markdown-core = { path = "crates/codegen/xai-grok-markdown-core" } xai-grok-mcp = { path = "crates/codegen/xai-grok-mcp" } xai-grok-memory = { path = "crates/codegen/xai-grok-memory" } xai-grok-mermaid = { path = "crates/codegen/xai-grok-mermaid" } xai-grok-models = { path = "crates/codegen/xai-grok-models" } xai-grok-sampler = { path = "crates/codegen/xai-grok-sampler" } xai-grok-secrets = { path = "crates/codegen/xai-grok-secrets" } xai-grok-shared = { path = "crates/codegen/xai-grok-shared" } xai-grok-shell = { path = "crates/codegen/xai-grok-shell" } xai-grok-shell-base = { path = "crates/codegen/xai-grok-shell-base" } xai-grok-shell-session-support = { path = "crates/codegen/xai-grok-shell-session-support" } xai-grok-telemetry = { path = "crates/codegen/xai-grok-telemetry" } xai-grok-test-support = { path = "crates/codegen/xai-grok-test-support" } xai-grok-tools = { path = "crates/codegen/xai-grok-tools" } xai-grok-tools-api = { path = "crates/codegen/xai-grok-tools-api" } xai-grok-version = { path = "crates/codegen/xai-grok-version" } xai-grok-workspace = { path = "crates/codegen/xai-grok-workspace" } xai-grok-workspace-types = { path = "crates/codegen/xai-grok-workspace-types" } xai-hooks-plugins-types = { path = "crates/codegen/xai-hooks-plugins-types" } xai-interjection-core = { path = "crates/common/xai-interjection-core" } xai-mixpanel = { path = "crates/codegen/xai-mixpanel" } xai-prompt-queue = { path = "crates/codegen/xai-prompt-queue" } xai-proto-build = { path = "crates/build/xai-proto-build" } xai-ratatui-inline = { path = "crates/codegen/xai-ratatui-inline" } xai-ratatui-textarea = { path = "crates/codegen/xai-ratatui-textarea" } xai-sqlite-journal = { path = "crates/codegen/xai-sqlite-journal" } xai-system-power = { path = "crates/codegen/xai-system-power" } xai-test-utils = { path = "crates/common/xai-test-utils" } xai-token-estimation = { path = "crates/codegen/xai-token-estimation" } xai-tool-protocol = { path = "crates/common/xai-tool-protocol" } xai-tool-runtime = { path = "crates/common/xai-tool-runtime" } xai-tool-types = { path = "crates/common/xai-tool-types" } xai-tracing = { path = "crates/common/xai-tracing" } xai-tty-utils = { path = "crates/codegen/xai-tty-utils" } zbus = { version = "5" } zstd = "0.13" [profile.release] incremental = true panic = "abort" # Hardened release profile for shipping to end users (alpha + stable). # Use `cargo build --profile release-dist` for distribution builds. # Not used by default `--release` to avoid slowing down local dev builds (~2.2x). # # Hardening: thin LTO for cross-crate optimization with reasonable link times, # codegen-units=1 maximizes optimization (whole-program analysis, no CGU boundaries). # debug=1 emits line-tables DWARF; strip=false keeps symbols so CI can extract # .debug sidecars (Linux) or .dSYM bundles (macOS) before stripping post-build. # Linker flags (RELRO, NX stack) are set per-target in .cargo/config.toml. [profile.release-dist] inherits = "release" lto = "thin" codegen-units = 1 strip = false debug = 1 split-debuginfo = "off" # Production profile for latency-sensitive x-product services (VF, home-mixer). # Thin LTO gives ~90% of full LTO benefit at significantly faster link time. # Keeps symbols + line tables for prod debuggability (perf, flamegraph, stack traces). [profile.x-prod] inherits = "release" lto = "thin" strip = false codegen-units = 1 debug = "line-tables-only" panic = "unwind" # Desktop release profile. Functionally identical to release-dist — kept as a # named alias so the desktop workflow can reference it without coupling to the # CLI pipeline's profile name. Alpha and stable share a single release-dist # profile so that stable promotion can pointer-swap the alpha binary without # rebuilding. [profile.release-dist-jemalloc] inherits = "release-dist" # All settings now match the parent — this is an intentional alias. [profile.dev] panic = "abort" split-debuginfo = "unpacked" codegen-units = 128 debug = "line-tables-only" opt-level = 0 lto = false incremental = true [profile.bench] debug = true [workspace.lints.clippy] # prost 0.14 renders proto doc-comment bullet lists in a way that trips this # lint on generated code. Kept in sync with bazel/lint/linters.bzl. doc_lazy_continuation = "allow" doc_overindented_list_items = "allow" needless_lifetimes = "allow" single_range_in_vec_init = "allow" too_many_arguments = "allow" # Allow uninlined_format_args lint to prevent main from breaking after merges # When older branches (created before this lint was added to CI) get merged, # they pass their own CI because their CI config doesn't include this lint check. # However, once merged to main, the code violates main's lint rules, causing: # 1. Main's CI to fail # 2. All new branches based off main to fail CI # 3. Developers having to fix lint violations from other people's merged code # Without a merge-queue that runs main's CI checks on the PR branch, # these violations slip through and break the build for everyone. # TODO: -> "deny" once/if merge queue enabled uninlined_format_args = "allow" # The `fastrace::trace(properties = { … })` proc-macro expands `"{param}"` # into `format!("{}", param)`, which clippy flags as useless_format. # Suppressed until the upstream crate fixes its codegen (fixed in 0.7.16+). useless_format = "allow"
TOML
복사

안녕하세요

관련 기술 문의와 R&D 공동 연구 사업 관련 문의는 “glory@keti.re.kr”로 연락 부탁드립니다.

Hello

For technical and business inquiries, please contact me at “glory@keti.re.kr”