콘텐츠로 이동

Cargo 기능 플래그 및 ADR

빌드 시점에 사용하는 모든 기능 플래그와 각 플래그가 활성화하는 기능, 그리고 승인된·제안된 아키텍처 결정 기록.

Revka는 단일 Rust 바이너리이지만, 모든 빌드에 모든 기능이 컴파일되는 것은 아닙니다. Matrix·Nostr 같은 채널, 하드웨어 서브시스템, PDF 텍스트 추출, 네이티브 브라우저 자동화, Prometheus·OpenTelemetry 익스포터, WASM 플러그인, WebAuthn, 그리고 OS 수준의 샌드박스 백엔드는 모두 Cargo 기능 플래그 뒤에 위치합니다 — 빌드 시점에 전달하는 옵트인 스위치입니다. 최소 빌드는 용량이 작고 의존성이 가벼우며, 필요한 기능만 선택적으로 활성화할 수 있습니다.

이 페이지는 Revka를 소스에서 빌드(cargo build, install.sh --force-source-build, 또는 Windows setup.bat/setup.ps1 모드)할 때 어떤 플래그가 어떤 기능을 활성화하는지 확인하거나, 툴·채널·엔드포인트가 사용 불가 상태를 보고하여 바이너리가 올바른 기능 없이 빌드되었다고 의심될 때 참고하세요. 이 페이지 후반부에는 Revka의 툴이 상태를 공유하는 방식과 오퍼레이터 런타임이 발전하는 방향을 규정하는 **아키텍처 결정 기록(ADR)**이 수록되어 있습니다.

기능 플래그활성화 대상런타임 설정 / 노출 지점
channel-matrixMatrix 채널 (matrix-sdk 기반 E2EE 룸)[channels_config.matrix]
channel-larkLark / Feishu 채널[channels_config.lark] / [channels_config.feishu]
channel-nostrNostr 채널 (NIP-04 / NIP-17)[channels_config.nostr]
whatsapp-webWhatsApp Web 네이티브 모드 (wa-rs)[channels_config.whatsapp] + session_path
voice-wake로컬 마이크 웨이크워드 채널[channels_config.voice_wake]
hardwareUSB/시리얼 보드 레지스트리 + Pico/Aardvark/GPIO 툴[hardware], [peripherals]
peripheral-rpi네이티브 Raspberry Pi GPIO 툴 (Linux)부팅 시 자동 감지
probeprobe-rs를 통한 STM32 실시간 칩 정보 / 메모리 읽기revka hardware info, hardware_memory_read
safetyRobot Kit SafetyMonitor + SafeDrive 래퍼crates/robot-kit robot.toml [safety]
rag-pdfPDF 텍스트 추출pdf_read 툴, PDF에 대한 file_read, 데이터시트 읽기
browser-nativerust_native 브라우저 자동화 백엔드[browser] backend = "native"
observability-prometheusPrometheus 메트릭 엔드포인트GET /metrics, [observability] backend = "prometheus"
observability-otelOpenTelemetry/OTLP 트레이스 익스포트[observability] backend = "otel"
plugins-wasmWASM 플러그인 툴 및 revka plugin CLI[plugins], ~/.revka/plugins/
webauthnFIDO2 / 패스키 게이트웨이 인증[security.webauthn], /api/webauthn/*
sandbox-bubblewrapBubblewrap 사용자 네임스페이스 샌드박스 백엔드[security.sandbox] backend
sandbox-landlockLandlock 커널 적용 파일시스템 샌드박스[security.sandbox] backend

인스톨러는 기능 플래그를 이름 있는 프로파일로 묶어 제공하므로 목록을 일일이 기억할 필요가 없습니다.

Terminal window
setup.bat --minimal :: 기본 Cargo 기능만 (~15분)
setup.bat --standard :: + channel-matrix, channel-lark (~20분)
setup.bat --full :: 아래 모든 기능 (~30분)
Terminal window
.\setup.ps1 -Mode Standard
.\setup.ps1 -Mode Full
  • --standard / -Mode Standardchannel-matrix,channel-lark를 추가합니다.
  • --full / -Mode Fullchannel-matrix,channel-lark,browser-native,hardware,rag-pdf,observability-otel을 추가합니다.

대부분의 채널(Telegram, Discord, Slack, Mattermost, Signal, WhatsApp Cloud API, IRC, 아시아권 플랫폼, 이메일, 웹훅, 음성 통화)은 항상 컴파일됩니다. 다음 네 가지는 무겁거나 플랫폼 특화된 의존성을 끌어오기 때문에 플래그로 제어합니다.

matrix-sdk 기반의 Matrix 채널을 활성화합니다. 암호화된 룸에 대한 투명한 종단간 암호화(E2EE), 별칭 해석, 드래프트 스트리밍(m.replace 편집), 음성 전사를 포함합니다. E2EE는 SDK가 세션을 복원할 수 있도록 올바른 device_id가 필요합니다.

[channels_config.matrix]
homeserver = "https://matrix.example.com"
access_token = "syt_..."
user_id = "@revka:matrix.example.com"
device_id = "DEVICEID123"
room_id = "!room:matrix.example.com"
allowed_users = ["*"]
stream_mode = "partial" # off | partial | multi_message
draft_update_interval_ms = 1500 # E2EE 재암호화 오버헤드로 다른 채널보다 높게 설정

Lark / Feishu 채널을 활성화합니다. Lark는 기본적으로 Open Platform WebSocket 장기 연결(receive_mode = "websocket", 인바운드 포트 불필요)을 사용하거나 HTTP 콜백(receive_mode = "webhook", 공개 HTTPS 필요)을 사용합니다. tenant_access_token은 캐시되고 자동 갱신되며, ACK 반응은 로케일(zh-CN, zh-TW, en, ja)을 인식합니다.

[channels_config.lark]
app_id = "cli_xxx"
app_secret = "xxx"
allowed_users = ["*"]
receive_mode = "websocket" # websocket | webhook
use_feishu = false

중국 배포 환경에서는 레거시 use_feishu = true 플래그 대신 전용 [channels_config.feishu] 블록을 사용하는 것을 권장합니다.

NIP-04(레거시 암호화 DM)와 NIP-17(선물 래핑 개인 메시지)을 지원하는 탈중앙화 프로토콜인 Nostr 채널을 활성화합니다. Revka는 발신자가 사용한 프로토콜로 응답하며, 자발적 전송은 기본적으로 NIP-17을 사용합니다.

[channels_config.nostr]
private_key = "nsec1..." # 고가치 비밀 — secrets.encrypt = true 유지 권장
relays = ["wss://relay.damus.io", "wss://nos.lol"]
allowed_pubkeys = ["hex-or-npub-key"] # 비어 있으면 전체 거부, "*"이면 전체 허용

wa-rs 크레이트를 통한 네이티브 WhatsApp Web 모드를 활성화합니다(Baileys와 동등: QR 또는 페어 코드 연결, Signal 프로토콜 E2EE, 그룹, 미디어, 반응, 음성 전사 및 TTS). WhatsApp 채널은 런타임에 모드를 협상합니다. session_path를 설정하면 Web 모드가 활성화되고, phone_number_id를 설정하면 Cloud API 모드가 활성화됩니다(Cloud API 모드는 기능 플래그가 필요 없습니다).

[channels_config.whatsapp]
session_path = "~/.revka/whatsapp-session.db" # 이 키가 있으면 Web 모드 선택
pair_phone = "15551234567" # QR 코드 연결 시 생략
allowed_numbers = ["*"]
mode = "business" # 또는 "personal"

로컬 마이크 웨이크워드 채널을 활성화합니다. 기본 오디오 장치에서 에너지 기반 음성 활동 감지(VAD)를 사용해 지속적으로 수신하고, 짧은 구간을 전사해 웨이크워드 여부를 확인한 뒤 전체 발화를 캡처하여 전달합니다. 크로스 플랫폼 캡처(macOS/Linux/Windows)에 cpal을 사용하며 출력 전용입니다 — send()는 no-op이므로 음성 응답을 원한다면 별도의 TTS 설정이 필요합니다.

[channels_config.voice_wake]
wake_word = "hey revka" # 대소문자 구분 없는 부분 문자열
silence_timeout_ms = 2000
energy_threshold = 0.01 # VAD용 RMS 하한값
max_capture_secs = 30
# STT 백엔드를 위한 [transcription] 섹션도 필요합니다.

하드웨어 서브시스템은 두 개의 레이어로 나뉘며, 둘 다 플래그로 제어됩니다. 전체 워크플로는 하드웨어 퀵스타트를 참고하세요.

USB/시리얼 장치 서브시스템의 마스터 플래그입니다. 컴파일되면 데몬이 시작 시 연결된 보드를 자동 탐색하고 안정적인 별칭(pico0, arduino0, nucleo0, aardvark0)을 할당하며, 감지된 장치에 따라 조건부로 툴을 로드합니다. 다음을 활성화합니다.

  • 항상 로드되는 GPIO/시리얼 툴 (아무것도 연결되지 않으면 “장치를 찾을 수 없음”을 정상적으로 보고): gpio_write, gpio_read, pico_flash, device_read_code, device_write_code, device_exec.
  • Aardvark 툴 (Total Phase Aardvark 어댑터가 감지될 때만): i2c_scan, i2c_read, i2c_write, spi_transfer, gpio_aardvark, datasheet.
  • 주변 보드 설정 시 보드 정보 툴: hardware_board_info, hardware_memory_map, hardware_capabilities.
  • CLI 명령어: revka hardware discover, revka hardware introspect <path>, revka peripheral add, revka peripheral list, revka peripheral flash.
Terminal window
cargo build --release --features hardware
revka hardware discover
[peripherals]
enabled = true
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial" # serial | native | bridge
path = "/dev/ttyACM0"
baud = 115200

Revka가 Pi에서 직접 실행될 때(Linux 전용) 네이티브 Raspberry Pi GPIO를 활성화합니다. 부팅 시 /proc/device-tree/model을 읽어 Pi(RPi 3B/3B+/4B/5/Zero 2W) 여부를 확인하고, config 항목 없이 GPIO 툴을 자동 등록하며, rpi0.md 장치 프로파일을 생성하고, 보드 모델·IP·RAM·CPU 온도·GPIO 사용 규칙을 시스템 프롬프트에 주입합니다. 추가되는 툴: gpio_rpi_write, gpio_rpi_read, gpio_rpi_blink, rpi_system_info.

Terminal window
cargo build --release --features hardware,peripheral-rpi

probe-rs를 통해 USB/SWD로 STM32 칩 실시간 인트로스펙션을 활성화합니다 — 대상 칩에 펌웨어가 없어도 됩니다. 이 기능 없이는 해당 툴이 빌드 지침과 함께 명확한 오류를 반환합니다. revka hardware info --chip nucleo-f401rehardware_memory_read 툴을 구동하며, Nucleo 보드에서 hardware_board_info / hardware_memory_map을 정적 데이터시트 데이터에서 실시간 읽기로 업그레이드합니다.

Terminal window
cargo build --release --features hardware,probe
cargo install probe-rs-tools --locked # CLI 크레이트 이름은 probe-rs-tools (probe-rs 아님)
revka hardware info --chip nucleo-f401re

실시간 읽기를 지원하는 보드: Nucleo-F401RE, Nucleo-F411RE (RAM 베이스 0x20000000).

독립 crates/robot-kit 툴킷의 기능 플래그입니다. 다섯 가지 안전 레이어(이동 전 장애물 확인, 능동 모니터링, 반응적 정지, 워치독 자동 정지, 하드웨어 비상 정지 오버라이드)를 통해 모든 이동 요청을 검사하는 SafetyMonitor 백그라운드 태스크와 SafeDrive 래퍼를 활성화합니다. 핵심 원칙은 “AI는 이동을 요청할 수 있지만, 허용은 SafetyMonitor가 한다”입니다.

Terminal window
cargo build --release --features safety # crates/robot-kit 내에서
crates/robot-kit/robot.toml
[safety]
min_obstacle_distance = 0.3 # 미터 — 이보다 가까우면 정지
max_drive_duration = 30 # 비활성 후 자동 정지
estop_pin = 17 # 물리적 비상 정지 버튼용 BCM GPIO (선택 사항)

전체 드라이브/감지/보기/듣기/말하기/표현 툴셋은 Robot Kit 페이지를 참고하세요.

PDF 텍스트 추출을 활성화합니다. 컴파일되면 pdf_read 툴이 워크스페이스 PDF에서 일반 텍스트를 추출하고, file_read 툴이 PDF를 받으면 인라인으로 텍스트를 추출하며, 하드웨어 datasheet 툴의 read 액션이 파일 경로 대신 추출된 텍스트를 반환합니다.

# pdf_read는 rag-pdf 컴파일 기능으로 config에서 제어됨
{ "path": "docs/spec.pdf" }

외부 agent-browser CLI 없이 작동하는 인-프로세스 자동화 백엔드인 browser 툴의 rust_native 백엔드를 활성화합니다. 런타임에 선택합니다.

[browser]
enabled = true
backend = "native" # agent_browser | native | computer_use
allowed_domains = ["*"]
native_headless = true

agent_browser(기본값)와 computer_use 백엔드는 이 플래그가 필요 없으며, rust_native만 필요합니다. 브라우저 자동화를 참고하세요.

Prometheus 메트릭 엔드포인트를 활성화합니다. 컴파일되고 [observability] backend = "prometheus"가 설정되면 게이트웨이가 텍스트 형식 메트릭(요청 수, 지연 시간, 비용 등)을 제공합니다.

GET /metrics
Content-Type: text/plain; version=0.0.4; charset=utf-8

/metrics에는 인증이 필요 없습니다. Prometheus가 활성화되지 않은 경우 엔드포인트는 메트릭 대신 힌트 주석을 반환합니다.

OpenTelemetry / OTLP 트레이스 익스포트를 활성화합니다. 기능이 컴파일되고 config가 설정되면 블로킹 익스포터를 통해 OTLP HTTP로 스팬이 익스포트됩니다(Tokio 컨텍스트 외부에서도 작동).

[observability]
backend = "otel" # none | noop | log | prometheus | otel/opentelemetry/otlp
otel_endpoint = "http://localhost:4318"
otel_service_name = "revka"

런타임 트레이스 저장 및 revka doctor traces를 통한 쿼리는 관찰 가능성 및 트레이싱을 참고하세요.

WASM 플러그인 시스템을 활성화합니다. 시작 시 WASM 플러그인 파일에서 로드되는 툴(각 매니페스트는 이름, 설명, 단일 input 문자열 파라미터를 정의)과 revka plugin CLI(list, install, remove, info)를 포함합니다.

[plugins]
enabled = true
plugins_dir = "~/.revka/plugins"
Terminal window
revka plugin list
revka plugin install <directory-or-url>

WASM 플러그인을 참고하세요.

게이트웨이에 대한 WebAuthn / FIDO2 하드웨어 키 및 패스키 인증을 활성화합니다. bearer 토큰의 대안 또는 추가 인증 수단으로 사용할 수 있습니다. 컴파일 기능과 [security.webauthn] enabled = true 모두 필요합니다. 등록된 자격 증명은 SecretStore에 암호화되어 저장됩니다.

[security.webauthn]
enabled = true
rp_id = "revka.example.com"
rp_origin = "https://revka.example.com"
rp_name = "Revka"
POST /api/webauthn/register/start # body: {"user_id":"...","user_name":"..."}
POST /api/webauthn/register/finish
POST /api/webauthn/auth/start
POST /api/webauthn/auth/finish
GET /api/webauthn/credentials?user_id=...
DELETE /api/webauthn/credentials/{id}

모든 /api/webauthn/* 엔드포인트는 bearer 인증이 필요합니다. TLS, 속도 제한 및 WebAuthn을 참고하세요.

이 두 플래그는 명령 실행을 래핑하는 OS 수준의 샌드박스 백엔드를 추가합니다. 백엔드는 런타임에 선택(또는 자동 감지)됩니다.

[security.sandbox]
enabled = true
backend = "auto" # auto | none | firejail | bubblewrap | landlock | sandbox-exec | docker
  • sandbox-bubblewrapBubblewrap 백엔드를 컴파일합니다(Linux/macOS 사용자 네임스페이스 컨테이너).
  • sandbox-landlockLandlock 백엔드를 컴파일합니다(Linux 커널 5.13+, 커널 적용 파일시스템 제한 — 가장 강력한 격리).

Firejail(Linux), sandbox-exec/Seatbelt(macOS), Docker 백엔드, 그리고 항상 사용 가능한 NoopSandbox 폴백은 기능 플래그가 필요 없습니다. 사용 불가한 백엔드를 요청하면 Revka는 경고와 함께 NoopSandbox로 폴백합니다.

ADR은 중요한 설계 결정을 기록하는 개발자 향 문서입니다. 최종 사용자 설정이 아니라 Revka 내부가 현재와 같이 동작하는 이유를 설명합니다. 여기에는 두 개가 수록되어 있습니다.

ADR-004: 툴 공유 상태 소유권 Accepted

섹션 제목: “ADR-004: 툴 공유 상태 소유권 ”

승인 · 2026-03-22 · 이슈 #4057

Revka는 단일 데몬으로 여러 클라이언트에 동시 서비스하며, 일부 툴은 이미 장기적인 공유 상태를 유지합니다 — DelegateParentToolsHandle(위임 에이전트의 부모 툴), ChannelMapHandle(reaction 툴이 사용하는 전역 채널 맵), CanvasStore(라이브 캔버스 프레임 저장소). 이들이 유기적으로 성장했기 때문에 ADR-004는 툴이 공유 상태를 소유·식별·격리·재로드하는 방식에 대한 계약을 정의합니다.

다섯 가지 결정:

  1. 소유권 — 툴은 장기적인 공유 상태를 유지할 수 있지만, 검증된 핸들 패턴을 통해서만 가능합니다: Arc<RwLock<T>>로 래핑하고, 이름 있는 복제 가능한 핸들 타입을 노출하며, 생성 시 핸들을 받고, 동시성 계약을 문서화합니다. 툴은 요청별 또는 클라이언트별 데이터에 정적 가변 상태(lazy_static!, 내부 가변성 있는 OnceCell)를 사용해서는 안 됩니다.
  2. 식별데몬이 식별자를 할당합니다. 툴이 자체적으로 클라이언트 식별 키를 생성해서는 안 됩니다. 게이트웨이가 연결 시점에 생성하고 실행 컨텍스트를 통해 전달하는 새로운 불투명 ClientId(Clone + Eq + Hash + Send + Sync)가 현재의 IP 주소 방식(NAT이나 프록시 뒤에서 깨짐)을 대체합니다.
  3. 라이프사이클 — 네 가지 명시적 단계: 생성(I/O 없음), 등록(일회성 시작 유효성 검사 허용, 예: 자격 증명 확인), 실행(블로킹 재검증 없음; 캐시된 빠른 경로 사용), 종료(Drop 또는 명시적 메서드로 정리).
  4. 격리 — 보안 민감 상태(자격 증명, 할당량, 속도 제한 카운터, 클라이언트별 권한)와 사용자별 세션 데이터는 내부 맵을 ClientId로 키잉하여 클라이언트별로 격리해야 합니다. 브로드캐스트/디스플레이 상태(캔버스 프레임, 채널 맵)와 읽기 전용 참조 데이터는 선택적으로 {client_id}:{name} 네임스페이스 프리픽스를 사용하여 공유할 수 있습니다. 클라이언트별 비밀은 공유 구조체에 존재해서는 안 됩니다.
  5. 재로드 의미론 — 데몬은 툴 관련 config 섹션을 해시하고, 해시가 변경되면 영향받는 툴에 등록 단계 유효성 검사를 재실행하도록 신호를 보냅니다. 툴은 신호를 받으면 캐시된 유효성 검사를 오래된 것으로 처리해야 합니다. 자격 증명 교체는 툴별·클라이언트별 자격 증명 상태를 무효화하고, 툴 활성화/비활성화는 all_tools_with_runtime()을 통한 전체 레지스트리 재빌드를 트리거하며, 보안 정책·워크스페이스 디렉토리·공급자 변경은 각각 종속 상태를 무효화합니다.

이로 인해 기존 싱글톤(CanvasStore, ReactionTool)이 ClientId를 받도록 마이그레이션해야 하는 비용이 발생하지만, 일관성과 멀티테넌트 안전성을 확보합니다. 툴 레지스트리는 시작 후 불변으로 유지되며, SecurityPolicy는 에이전트별로 유지됩니다 — 클라이언트 격리는 에이전트 수준 정책과 직교합니다.

ADR-005: 오퍼레이터 활성 상태 및 Rust 마이그레이션 Proposed

섹션 제목: “ADR-005: 오퍼레이터 활성 상태 및 Rust 마이그레이션 ”

제안 · 2026-04-15

Operator MCP는 세 계층 스택을 통해 멀티 에이전트 워크플로를 조율합니다: Python 오퍼레이터(워크플로 실행기) → Node.js 세션 매니저(Unix 소켓을 통해) → Claude/Codex 에이전트 서브프로세스. ADR-005는 레이어 간에 에이전트 생존 여부에 대한 불일치로 발생하는 크로스 바운더리 상태 버그를 기록합니다 — 죽은 후에도 running으로 보고되는 좀비 에이전트, 복구 불투명성, 100% CPU 스핀 루프, 오퍼레이터와 서브 에이전트 MCP 간의 툴 표면 불일치, 속도 제한으로 인한 빈 출력을 성공으로 처리하는 문제. 임시 휴리스틱 패치(120초 좀비 감지 창, 빈 출력 실패 처리 등)가 2026-04-15에 배포되었지만, 근본 원인인 세션 매니저의 프로세스 활성 상태 미추적은 남아 있습니다.

이 제안은 Python 워크플로 실행기의 반복 속도를 유지하면서 에이전트 라이프사이클 관리를 Node.js에서 Rust 데몬으로 세 단계(선택적으로 네 단계)에 걸쳐 마이그레이션합니다.

  1. Phase 0 — Node.js에서 활성 상태 추적 (1~2일, 낮은 위험). processAlive/pumpAlive 플래그와 lastEventAt 타임스탬프를 세션 매니저에 추가하여 Python 오퍼레이터의 좀비 감지를 단순화합니다: lastEventAt가 오래되었고 상태가 running이면 에이전트는 죽은 것입니다. 추가적인 변경이며 마이그레이션 없습니다.
  2. Phase 1 — Rust 에이전트 프로세스 매니저 (1~2주, 중간 위험). 새로운 src/agent/process_manager.rstokio::process::Command로 Claude/Codex CLI를 생성하고, waitpid를 통해 폴링 없이 ~1초 내에 죽음을 감지하며, 출력을 통합된 AgentEvent로 파싱하고, Python 오퍼레이터가 이미 기대하는 동일한 HTTP API(/agents, /agents/:id, /agents/:id/events, …)를 제공합니다. Node.js 세션 매니저가 제거됩니다.
  3. Phase 2 — MCP 툴 표면 통합 (3~5일, 낮은 위험). 에이전트 라이프사이클 툴(create_agent, wait_for_agent, send_agent_prompt, get_agent_activity, list_agents)을 Rust 네이티브 툴로 이동하고, 워크플로 툴은 단일 슬림 MCP 서버 뒤의 Python에 유지하며, 서브 에이전트에 전체 라이프사이클 표면을 자동으로 제공합니다 — “run_workflowsubagent_mcp.py에 추가하는 것을 잊었다” 류의 버그를 제거합니다.
  4. Phase 3 — 선택적 Rust 실행기 (36주, 높은 위험). Phase 12가 안정화된 후에만: 워크플로 엔진(파싱, 순서 지정, 체크포인트, 복구)을 Rust로 포팅합니다. 워크플로 실행기가 자주 변경되지 않는 경우에만 권장됩니다 — 단계 유형이 아직 진화 중인 동안에는 컴파일 타임 안전성보다 Python의 빠른 반복이 더 가치 있습니다.

명시적 비목표도 중요합니다: 모든 것을 한 번에 재작성하지 않고, Kumiho 통합을 Rust로 성급히 이동하지 않으며, Python을 완전히 제거하지 않고, 프로세스 매니저를 과도하게 설계하지 않습니다(생성, 모니터링, 종료, HTTP API 제공, 이벤트 버퍼링만 수행합니다).