워크플로우 및 SOP 개요
두 가지 오케스트레이션 기본 요소인 선언적 YAML 워크플로우와 이벤트 기반 SOP의 개념과 각각의 활용 시점을 설명합니다.
Revka는 다단계 작업을 실행하기 위한 두 가지 오케스트레이션 기본 요소를 제공하며, 각각 스택의 서로 다른 레이어에 위치합니다. 워크플로우는 선언적 YAML 파이프라인으로, 대시보드 또는 Gateway API에서 작성하고 Kumiho에 저장하며 Python Operator MCP 서버가 실행하는 타입이 지정된 단계(LLM 에이전트, 셸, Python, 조건 분기, 병렬 팬아웃, 사람 승인)로 구성된 DAG입니다. SOP(표준 운영 절차)는 디스크의 SOP.toml + SOP.md 파일로 정의되는 이벤트 기반 절차로, Rust SopEngine이 실행하며 MQTT, 웹훅, cron, 주변 장치 신호, 또는 수동 호출로 트리거됩니다.
먼저 이 페이지를 읽고 어느 쪽을 사용할지 결정하십시오. 두 시스템 모두 감사 우선 원칙(사람 승인 게이트, 체크포인트 상태, Kumiho 기반 감사 기록)을 공유하지만, 정의가 저장되는 위치, 실행 주체, 시작 방법에서 차이가 있습니다. 이미 필요한 것을 알고 있다면 첫 번째 워크플로우 또는 SOP 레퍼런스로 바로 이동하십시오.
각각의 활용 시점
섹션 제목: “각각의 활용 시점”한눈에 보는 비교
섹션 제목: “한눈에 보는 비교”| 항목 | YAML 워크플로우 | SOP |
|---|---|---|
| 정의 형식 | YAML | SOP.toml (메타데이터 + 트리거) + SOP.md (단계) |
| 저장 위치 | Kumiho (Revka/Workflows 스페이스) + 디스크 YAML | 디스크의 <workspace>/sops/<name>/ 하위 |
| 실행기 | Operator MCP (Python) | SopEngine (Rust) |
| 작성 도구 | 대시보드 에디터, Gateway API, MCP 도구 | 텍스트 에디터 + revka sop CLI |
| 실행 시작 방법 | 수동 실행, cron 트리거, 엔티티 이벤트 트리거 | MQTT, 웹훅, cron, 주변 장치, 또는 수동 |
| 단계 모델 | 분기, 병렬, 루프를 포함한 타입 지정 DAG | 번호가 매겨진 순차적 단계 |
| 승인 모델 | human_approval / human_input 단계 | 실행 모드 + 단계별 requires_confirmation |
| LLM 없는 모드 | — (단계가 에이전트/도구를 구동) | deterministic = true (LLM 호출 없음) |
| 유효성 검사 | 저장/실행 시 6단계 검사기 | revka sop validate |
| 감사 | 실행 이력이 Kumiho에 저장(Revka/WorkflowRuns) | sop 카테고리의 메모리 백엔드 |
YAML 워크플로우
섹션 제목: “YAML 워크플로우”워크플로우는 타입이 지정된 입력, 순서가 있는 단계, 선택적 트리거, 명명된 출력을 포함하는 YAML 문서입니다. 가장 단순한 워크플로우는 단일 에이전트 단계로 실행됩니다.
name: hello-world # unique slug (required)version: "1.0" # semantic version (required)description: Say hello to a topic.inputs: - name: topic type: string # string | number | boolean | list required: true default: ""steps: - id: greet type: agent agent: agent_type: claude # claude or codex role: researcher prompt: "Say hello about ${inputs.topic}."outputs: - name: result source: "${greet.output}"단계는 ${...} 변수 보간과 depends_on 엣지를 통해 서로를 참조하며, 이를 통해 실행 DAG가 형성됩니다. 단계 유형의 전체 목록에는 agent, shell, python, email, notify, resolve, conditional, parallel, goto, output, human_approval, human_input, a2a와 고수준 오케스트레이션 단계인 map_reduce, supervisor, group_chat, handoff가 포함됩니다. 각 단계 유형은 단계 유형 레퍼런스를, 전체 스키마는 YAML 레퍼런스를 참조하십시오.
워크플로우 정의의 저장 위치
섹션 제목: “워크플로우 정의의 저장 위치”오퍼레이터는 우선순위가 낮은 것부터 높은 것 순으로 최대 네 곳에서 워크플로우 YAML을 탐색하며, 나중에 발견된 소스가 slug 기준으로 이전 소스를 덮어씁니다.
| 우선순위 | 경로 | 용도 |
|---|---|---|
| 3 (최고) | .revka/workflows/ | 프로젝트 로컬 오버라이드 |
| 2 | ~/.revka/workflows/ | 사용자 전역 워크플로우 |
| 1 (최저) | .revka/operator_mcp/workflow/builtins/ | 제공된 기본 내장 워크플로우 |
| 폴백 | Kumiho 스페이스 Revka/Workflows | 클라우드 관리 정의 |
대시보드에서 워크플로우를 저장하면 YAML이 ~/.revka/workflows/{slug}.r{N}.yaml 경로의 디스크에 저장되고 Kumiho 아티팩트가 등록됩니다. 디렉터리 스캐너가 로드하는 파일은 기본 {slug}.yaml입니다. 정의는 workflow 종류의 Kumiho 아이템으로 저장되며, YAML은 크기 제한을 피하기 위해 인라인 메타데이터가 아닌 workflow.yaml 아티팩트 파일로 보관됩니다.
트리거
섹션 제목: “트리거”워크플로우는 스케줄 또는 업스트림 엔티티 이벤트에 반응하여 자동으로 실행될 수 있습니다.
triggers: - cron: "0 9 * * 1" # every Monday 9am timezone: "America/Los_Angeles" # optional IANA timezone - on_kind: "qs-arc-plan" # Kumiho entity kind (required) on_tag: "ready" # revision tag (default: "ready") input_map: arc_kref: "${trigger.entity_kref}"cron 트리거가 있는 워크플로우를 Kumiho에 저장하면, 게이트웨이가 자동으로 Revka cron 스토어에 cron 작업을 등록합니다. 워크플로우를 더 이상 사용하지 않거나 삭제하면 해당 작업도 제거됩니다. 엔티티 이벤트 트리거는 output 단계에서 발행하는 revision.tagged 이벤트를 감시하여 한 워크플로우가 다음 워크플로우로 연결될 수 있게 합니다. 변수, 표현식 및 트리거를 참조하십시오.
실행, 유효성 검사, 승인
섹션 제목: “실행, 유효성 검사, 승인”정의를 저장하거나 실행하기 전에 오퍼레이터는 6단계 검사기(중복 단계 ID, 의존성 참조, 사이클 감지, 단계별 설정, 변수 참조, 트리거 유효성 검사)를 실행합니다. 대시보드는 저장 시 유효성을 검사하고 인라인으로 오류를 표시하며, API는 유효하지 않은 정의를 HTTP 400으로 거부합니다. 워크플로우 상태는 각 단계 이후 ~/.revka/workflow_checkpoints/{run_id}.json에 체크포인트로 저장되므로, 실패한 실행을 첫 번째 실패 단계부터 재시도할 수 있습니다. 실행 상태는 pending, running, paused, completed, failed, cancelled, stale입니다. 실행, 승인 및 체크포인트를 참조하십시오.
SOP
섹션 제목: “SOP”SOP는 TOML 매니페스트와 선택적 Markdown 단계 목록을 포함하는 디렉터리입니다. config.toml에서 하위 시스템을 활성화하십시오.
[sop]enabled = truesops_dir = "sops" # defaults to <workspace>/sopsdefault_execution_mode = "supervised"~/.revka/workspace/sops/ deploy-prod/ SOP.toml # metadata + triggers (required) SOP.md # procedure steps (optional)SOP.toml은 식별 정보, 실행 동작, 트리거를 선언하고, SOP.md는 제안 도구와 단계별 플래그를 포함한 번호가 매겨진 단계를 나열합니다.
[sop]name = "deploy-prod"description = "Deploy service to production"version = "1.0.0"priority = "high" # low | normal | high | criticalexecution_mode = "supervised" # auto | supervised | step_by_step | priority_based | deterministiccooldown_secs = 300max_concurrent = 1
[[triggers]]type = "webhook"path = "/sop/deploy"
[[triggers]]type = "manual"## Steps
1. **Check readings** — Read sensor data and confirm. - tools: gpio_read, kumiho_memory_store
2. **Close valve** — Set GPIO pin 5 LOW. - tools: gpio_write - requires_confirmation: true트리거와 실행 모드
섹션 제목: “트리거와 실행 모드”SOP는 mqtt, webhook, cron, peripheral, manual의 다섯 가지 이벤트 소스에서 트리거될 수 있으며, 실행 모드는 에이전트가 단계별로 가지는 자율성 수준을 제어합니다.
| 모드 | 동작 |
|---|---|
auto | 승인 없이 모든 단계 실행 |
supervised | 첫 번째 단계 전에만 승인 필요 |
step_by_step | 모든 단계 전에 승인 필요 |
priority_based | Critical/High → 자동; Normal/Low → 감독 |
deterministic | LLM 호출 없음; 각 단계의 출력이 다음 단계로 파이프됨; 체크포인트 단계에서 일시 정지 |
deterministic = true를 설정하면 execution_mode에 관계없이 결정적 모드가 강제 적용되며, 엔진은 해당 실행에 대해 llm_calls_saved 지표를 추적합니다. 단계별 requires_confirmation: true는 모드를 재정의하여 해당 단계에 대한 승인을 강제합니다. 실행 상태는 pending, running, waiting_approval, paused_checkpoint, completed, failed, cancelled입니다. SOP 레퍼런스를 참조하십시오.
CLI에서 SOP 관리
섹션 제목: “CLI에서 SOP 관리”revka sop 하위 명령은 정의만 관리하며, revka sop run은 존재하지 않습니다. 실행은 이벤트 소스 또는 에이전트 내 sop_execute 도구에서 시작됩니다.
revka sop list # list all loaded SOPs with triggers and moderevka sop validate # validate all SOPsrevka sop validate <name> # validate a specific SOPrevka sop show <name> # detailed view of a single SOP에이전트 내 도구로 실행을 제어할 수 있습니다. sop_execute <name>으로 실행을 시작하고, sop_status <run_id>로 상태를 확인하고, sop_approve <run_id>로 승인 게이트를 해제하고, sop_advance <run_id> <result>로 단계 결과를 보고합니다. SOP 실행 시작 기록은 sop 카테고리의 구성된 메모리 백엔드에 저장됩니다.
Operator MCP 실행
섹션 제목: “Operator MCP 실행”YAML 워크플로우는 Rust 게이트웨이 내부에서 실행되지 않고 Operator MCP 서버에서 실행됩니다. Operator MCP는 데몬이 에이전트 채팅 세션별로 생성하는 Python 3.11+ MCP 사이드카입니다. 오퍼레이터는 워크플로우를 검증, 실행, 저장하며, 에이전트가 직접 호출할 수 있는 MCP 도구로도 노출합니다.
| 도구 | 용도 |
|---|---|
run_workflow(workflow, inputs, cwd, run_id?, max_cost_usd?) | 이름 또는 인라인 정의로 워크플로우 실행 |
validate_workflow(...) | 6단계 검사기 실행; {valid, errors, warnings} 반환 |
dry_run_workflow(...) | 실행 순서, 단계 수, 비용 추정치 미리보기 |
get_workflow_status(run_id, include_outputs?) | 실행의 단계별 결과 조회 |
resume_workflow(run_id, approved?, cwd?) | human_approval 단계 이후 재개 |
retry_workflow(run_id, cwd?) | 첫 번째 실패 단계부터 재시도 |
cancel_workflow(run_id) | 실행 중이거나 일시 정지된 워크플로우 취소 |
Gateway API는 이에 대한 얇은 프런트엔드입니다. POST /api/workflows/run/{name}을 디스패치하면 Kumiho에 지속적인 workflow-run-request 아이템을 기록하고 빠른 시작을 위해 오퍼레이터의 run_workflow MCP 도구를 즉시 호출하며, 직접 호출이 실패하면 Kumiho 아이템으로 폴백합니다. 실행에 max_cost_usd 한도를 설정하면 초과 시 중단됩니다. 전체 도구 목록과 설치 단계는 Operator MCP를 참조하십시오.
아키텍처
섹션 제목: “아키텍처”두 오케스트레이터는 서로 다른 레이어에 위치하지만 스토리지와 감사를 공유합니다.
| 항목 | YAML 워크플로우 경로 | SOP 경로 |
|---|---|---|
| 작성 | 대시보드 / Gateway API / MCP 도구 | 에디터 + revka sop CLI |
| 정의 | Kumiho + 디스크의 YAML | 디스크의 SOP.toml + SOP.md |
| 트리거 | 수동 실행, cron, 엔티티 이벤트 | MQTT, 웹훅, cron, 주변 장치, 수동 |
| 실행 | DAG 위의 Operator MCP (Python) | SopEngine (Rust), 순차 |
| 일시 정지 | human_approval / human_input 단계 | 승인 게이트 / 결정적 체크포인트 |
| 저장 | 디스크의 체크포인트; Kumiho의 실행 이력 | 메모리 백엔드의 실행 상태 + 감사 |
게이트웨이는 Kumiho 메타데이터 위에 로컬 체크포인트와 잠금 파일을 덮어씌워 실시간 실행 상태를 보고합니다. SOP 웹훅 수신에는 두 가지 경로가 있습니다. POST /sop/{*rest}는 SOP만 매칭하며(LLM 폴백 없음), POST /webhook은 SOP를 먼저 시도하고 일치하는 것이 없으면 LLM 에이전트로 폴백합니다. 엔드투엔드 런타임 구조는 Revka의 작동 방식과 게이트웨이 워크플로우 및 아키텍트 API를 참조하십시오.
노드 간 전송 (HMAC)
섹션 제목: “노드 간 전송 (HMAC)”Revka 인스턴스가 여러 머신에 걸쳐 조정할 때 노드 전송을 통해 통신합니다. 이는 포트 443에서 HMAC-SHA256으로 인증하는 표준 HTTPS로, 특이한 프로토콜 없이 기업 프록시, 방화벽, IT 감사 요구 사항을 통과할 수 있도록 의도적으로 선택되었습니다. 피어의 /api/node-control/{endpoint}로 나가는 모든 요청에는 세 가지 헤더가 포함됩니다.
| 헤더 | 값 |
|---|---|
X-Revka-Timestamp | Unix 에포크 초 |
X-Revka-Nonce | 무작위 UUID v4 |
X-Revka-Signature | 요청의 HMAC-SHA256 16진수 다이제스트 |
서명은 리틀엔디안 타임스탬프 바이트, 논스 바이트, 페이로드 바이트를 공유 비밀 키로 계산합니다. 수신측은 다이제스트를 재계산하여 타이밍 공격에 대응하기 위해 상수 시간으로 비교하며, 타임스탬프가 300초 재전송 방지 윈도우를 벗어난 요청은 거부합니다. 비밀 키는 공유되며 전송되지 않으므로, 변조된 페이로드, 잘못된 키, 오래된 타임스탬프는 모두 검증에 실패합니다.