SOP 참조: 구문, 트리거, 실행
SOP.toml 메타데이터, SOP.md 단계, SOP CLI, MQTT/웹훅/크론/주변장치/수동 트리거, LLM을 사용하지 않는 결정론적 모드를 포함한 실행 모드, 실행 수명 주기, 동시성/쿨다운, 감사 기록에 대한 완전한 참조 문서입니다.
**SOP(표준 운영 절차)**는 타입이 지정된 트리거, 승인 게이트, 그리고 감사 가능한 실행 레코드를 갖춘 결정론적 이벤트 기반 절차입니다. SOP는 디스크 상의 SOP.toml + SOP.md 파일로 정의되며 Rust SopEngine이 실행합니다. Kumiho에 저장되고 operator-mcp 백엔드가 실행하는 YAML 워크플로우와는 구별됩니다. 외부 신호(MQTT 메시지, 웹훅, 크론 틱, 하드웨어 핀)가 정의되고 게이트 처리된 감사 절차를 안정적으로 실행해야 할 때 SOP를 사용하세요 — 순수한 기계적 시퀀스를 위한 LLM 없는 결정론적 모드도 포함됩니다.
이 페이지는 SOP 파일 구문, 트리거 타입, 실행 모드, 실행 수명 주기, 그리고 실행을 구동하는 CLI 및 에이전트 도구에 대한 완전한 참조입니다. SOP와 워크플로우의 개념적 비교는 워크플로우 & SOP 개요를 참고하세요. 관련 YAML 워크플로우 엔진은 첫 번째 워크플로우를 참고하세요.
SOP 시스템 개요
섹션 제목: “SOP 시스템 개요”SOP는 설정된 sops_dir 아래에 있는 자체 디렉터리에 위치합니다. 각 디렉터리에는 필수 SOP.toml(메타데이터 + 트리거)과 선택적 SOP.md(번호가 매겨진 절차 단계)가 포함됩니다. 엔진은 시작 시 모든 SOP를 로드하고, 각 SOP의 트리거에 대해 들어오는 이벤트를 매칭하며, 매칭마다 **실행(run)**을 시작합니다. 실행은 에이전트 루프를 통해 진행되며 승인 게이트와 결정론적 체크포인트에서 일시 정지하고, 감사 로거가 모든 시작, 단계, 승인을 기록합니다.
~/.revka/workspace/sops/ deploy-prod/ SOP.toml # metadata + triggers (required) SOP.md # numbered procedure steps (optional, but a run with no steps fails validation)MQTT, 웹훅, 크론, 주변장치 등 모든 이벤트 소스는 단일 통합 디스패처(dispatch_sop_event)를 통해 처리되므로, 실행이 어떻게 시작되더라도 트리거 매칭, 실행 시작 감사, 헤드리스 안전 동작이 동일하게 적용됩니다.
Event sources unified dispatcher MQTT message (topic match) │ POST /sop/* or /webhook (path match) │ Scheduler (window check) ─────┼──▶ dispatch_sop_event ──▶ SopEngine ──▶ SOP Run ──▶ Action Peripheral signal (board/signal) │ │ sop_execute tool (manual) │ ┌────────────────────────┴───────────┐ ExecuteStep WaitApproval │ │ ▼ ▼ Agent loop Operator │ sop_approve ▼ SOP Run (resumes)SOP 서브시스템 활성화
섹션 제목: “SOP 서브시스템 활성화”SOP는 ~/.revka/config.toml에서 활성화하기 전까지 비활성 상태입니다:
[sop]enabled = truesops_dir = "sops" # relative to the workspace; defaults to <workspace>/sopsdefault_execution_mode = "supervised"| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
enabled | bool | false | SOP 엔진의 마스터 스위치. |
sops_dir | string | <workspace>/sops | SOP 서브디렉터리를 검색하는 디렉터리. |
default_execution_mode | string | supervised | 자체 execution_mode를 설정하지 않은 SOP에 적용되는 모드. |
max_concurrent_total | int | 10 | 모든 SOP에 걸친 동시 실행의 전역 상한. |
approval_timeout_secs | int | 3600 | 승인 게이트에서 타임아웃 처리 전까지 대기하는 시간(초) (0 = 무기한 대기). |
SOP 정의 — SOP.toml
섹션 제목: “SOP 정의 — SOP.toml”SOP.toml은 매니페스트입니다: 식별 정보, 우선순위, 실행 정책, 동시성/쿨다운 제한, 그리고 하나 이상의 [[triggers]]를 포함합니다.
[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 = 1deterministic = false # true forces execution_mode = deterministic
[[triggers]]type = "webhook"path = "/sop/deploy"
[[triggers]]type = "manual"| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
name | string | — (필수) | sop_execute 및 CLI에서 사용하는 고유 SOP 식별자. |
description | string | — (필수) | 사람이 읽을 수 있는 목적 설명. |
version | string | "0.1.0" | 절차의 시맨틱 버전. |
priority | string | normal | low, normal, high, critical 중 하나. priority_based 모드와 승인 타임아웃 에스컬레이션에 사용. |
execution_mode | string | ([sop].default_execution_mode) | auto, supervised, step_by_step, priority_based, deterministic 중 하나. 실행 모드를 참고하세요. |
cooldown_secs | int | 0 | 이 SOP의 실행 간 최소 대기 시간(초) (0 = 쿨다운 없음). |
max_concurrent | int | 1 | 이 SOP의 최대 동시 실행 수. |
deterministic | bool | false | true이면 execution_mode를 deterministic으로 재정의. |
각 [[triggers]] 블록은 하나의 트리거를 선언하며, 하나의 SOP에 여러 트리거를 설정할 수 있습니다. 각 type이 허용하는 필드는 트리거 타입을 참고하세요.
SOP 정의 — SOP.md 단계
섹션 제목: “SOP 정의 — SOP.md 단계”SOP.md는 순서가 있는 절차를 정의합니다. 단계는 ## Steps 섹션에서 번호 목록으로 파싱됩니다. 각 항목의 앞부분 굵은 텍스트가 단계 제목이며, 나머지는 본문입니다. 하위 글머리는 메타데이터를 첨부합니다.
## Steps
1. **Check readings** — Read sensor data and confirm it is within range. - tools: gpio_read, kumiho_memory_store
2. **Close valve** — Set GPIO pin 5 LOW. - tools: gpio_write - requires_confirmation: true
3. **Review** — Human review before proceeding. - kind: checkpoint파서 동작:
- 번호 항목(
1.,2., …)은 단계 순서를 정의합니다. 번호 갭이 있으면 검증 경고가 발생합니다. - 앞부분 굵은 텍스트(
**제목**)가 단계 제목이 되고,—뒤의 텍스트가 단계 본문입니다. - tools:는 단계의suggested_tools에 매핑되는 쉼표로 구분된 목록입니다(에이전트에 대한 힌트이며 강제 허용 목록이 아님).- requires_confirmation: true는 해당 단계에 대해 승인 게이트를 강제하며, 해당 단계에 한해 실행 모드를 재정의합니다.- kind: checkpoint(기본값인- kind: execute와 반대)는 단계를 결정론적 체크포인트로 표시합니다 — SOP가 결정론적 모드로 실행될 때 승인을 위해 일시 정지합니다.
SOP 실행 모드
섹션 제목: “SOP 실행 모드”실행 모드는 단계 간 에이전트의 자율성 수준을 제어합니다. 단계별 requires_confirmation: true는 항상 해당 단계에 대해 모드를 재정의합니다.
| 모드 | 동작 |
|---|---|
auto | 승인 프롬프트 없이 모든 단계를 실행합니다. |
supervised | 첫 번째 단계 전에만 승인을 요구합니다. |
step_by_step | 모든 단계 전에 승인을 요구합니다. |
priority_based | critical / high SOP는 auto로 실행되고, normal / low는 supervised로 실행됩니다. |
deterministic | LLM 호출 없음. 단계가 순차적으로 실행되며, 각 단계의 출력이 다음 단계의 입력으로 전달됩니다. checkpoint 단계는 승인을 위해 일시 정지합니다. |
SOP CLI 명령어
섹션 제목: “SOP CLI 명령어”revka sop 서브커맨드는 정의를 관리합니다 — 실행을 시작하지 않습니다. (실행은 트리거 또는 sop_execute 에이전트 도구로 시작됩니다.)
revka sop list # list all loaded SOPs with triggers and moderevka sop validate # validate all SOPs (warnings on empty fields, missing triggers/steps, numbering gaps)revka sop validate <name> # validate a single SOPrevka sop show <name> # detailed view of one SOP| 명령어 | 목적 |
|---|---|
revka sop list | 버전, 우선순위, 모드, 단계 수, 트리거, 쿨다운과 함께 로드된 모든 SOP를 나열합니다. |
revka sop validate [name] | 모든 SOP 또는 이름으로 지정한 SOP 하나를 검증합니다. 빈 name/description, 누락된 트리거, 누락된 단계, 단계 번호 갭에 대해 경고합니다. |
revka sop show <name> | 단일 SOP의 전체 상세 정보를 표시합니다. |
revka sop list 출력 예시:
SOPs (3): deploy-prod v1.0.0 [high] — Deploy service to production Mode: supervised Steps: 4 Triggers: webhook:/sop/deploy, manual Cooldown: 300s[sop] 설정
섹션 제목: “[sop] 설정”~/.revka/config.toml의 [sop] 섹션은 엔진을 전역적으로 제어하며, SOP.toml의 SOP별 필드는 단일 절차의 동작을 세부 조정합니다.
[sop]enabled = truesops_dir = "sops"default_execution_mode = "supervised"max_concurrent_total = 10 # global limit across all SOPsapproval_timeout_secs = 3600 # 1 hour before approval-timeout handlingMQTT 트리거에 피드를 제공하는 MQTT 브로커는 [channels_config.mqtt] 아래에 별도로 설정합니다 — MQTT 트리거를 참고하세요.
SOP 트리거 타입
섹션 제목: “SOP 트리거 타입”SOP는 들어오는 이벤트가 [[triggers]] 중 하나와 매칭될 때 실행됩니다. 다섯 가지 type 값이 지원됩니다.
[[triggers]]type = "mqtt"topic = "sensors/pressure"condition = "$.value > 85" # optional JSONPath condition
[[triggers]]type = "webhook"path = "/sop/deploy" # exact path match
[[triggers]]type = "cron"expression = "0 */5 * * *" # 5/6/7-field crontab
[[triggers]]type = "peripheral"board = "nucleo-f401re-0"signal = "pin_3"condition = "> 0" # optional numeric comparison
[[triggers]]type = "manual" # started via the sop_execute tool| 타입 | 필드 | 비고 |
|---|---|---|
manual | 없음 | sop_execute 도구로 시작됩니다(CLI run 명령어 없음). |
webhook | path | 요청 경로(/sop/... 또는 /webhook)에 대한 완전 일치. |
mqtt | topic, 선택적 condition | topic은 +(단일 레벨) 및 #(다중 레벨) MQTT 와일드카드를 지원합니다. |
cron | expression | 5, 6, 또는 7개 필드; 5필드 표현식은 내부적으로 초 필드가 앞에 추가됩니다. |
peripheral | board, signal, 선택적 condition | 신호 키 "{board}/{signal}"에 매칭됩니다. |
조건 구문
섹션 제목: “조건 구문”mqtt 및 peripheral 트리거의 condition은 실패 폐쇄 방식으로 평가됩니다: 잘못된 조건이나 누락/파싱 불가한 페이로드는 매칭이 아닌 매칭 실패를 반환합니다.
- JSONPath 비교 (MQTT JSON 페이로드에 주로 사용):
$.value > 85,$.status == "critical" - 직접 숫자 비교 (단순 주변장치 신호에 주로 사용):
> 0,== 1 - 연산자:
==,!=,>,<,>=,<=
MQTT (SOP 이벤트 트리거)
섹션 제목: “MQTT (SOP 이벤트 트리거)”MQTT는 기본 IoT/자동화 팬인(fan-in)입니다. MQTT 구독자는 채팅 채널이 아닙니다 — 에이전트 채팅 루프가 아닌 SOP 엔진으로 브로커 메시지를 직접 라우팅합니다. [channels_config.mqtt] 아래에서 브로커를 설정하세요:
[channels_config.mqtt]broker_url = "mqtts://broker.example.com:8883" # use mqtt:// for plaintextclient_id = "revka-agent-1"topics = ["sensors/alert", "ops/deploy/#"]qos = 1 # 0 | 1 | 2keep_alive_secs = 60username = "mqtt-user" # optionalpassword = "mqtt-password" # optionaluse_tls = true # must match the scheme (mqtts:// => true)| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
broker_url | string | — (필수) | 브로커 URL; mqtts://는 TLS를, mqtt://는 평문 연결을 선택합니다. |
client_id | string | — (필수) | MQTT 클라이언트 식별자. |
topics | list | — | 구독 목록; + 및 # 와일드카드 지원. |
qos | int | 1 | 서비스 품질: 0 최대 한 번, 1 최소 한 번, 2 정확히 한 번. |
keep_alive_secs | int | 60 | 킵얼라이브 간격. |
username / password | string | — | 선택적 브로커 인증. |
use_tls | bool | false | TLS 활성화; broker_url 스킴과 일치해야 합니다. |
MQTT 페이로드는 SOP 이벤트 페이로드(event.payload)로 전달되어 단계 컨텍스트에서 사용 가능하므로, SOP 단계에서 트리거 메시지를 읽을 수 있습니다. $.severity >= 2와 같은 트리거 condition으로 매칭하세요.
SOP 웹훅 엔드포인트
섹션 제목: “SOP 웹훅 엔드포인트”HTTP를 통해 SOP 실행을 시작할 수 있는 두 가지 게이트웨이 라우트:
| 메서드 + 경로 | 동작 |
|---|---|
POST /sop/{*rest} | SOP 전용. 웹훅 트리거에 대해 요청 경로를 매칭합니다. 매칭되는 SOP가 없으면 404를 반환합니다 — LLM 폴백이 없습니다. |
POST /webhook | SOP 우선 디스패치가 있는 채팅 엔드포인트. SOP 매칭을 먼저 시도하고, 매칭되는 항목이 없으면 일반 LLM 흐름으로 폴백합니다. |
경로 매칭은 설정된 트리거 path에 대해 완전 일치합니다. path = "/sop/deploy" 트리거는 POST /sop/deploy와 매칭됩니다.
페어링이 활성화된 경우(기본값), 페어링 베어러 토큰을 제공하세요. 웹훅 시크릿이 설정된 경우 두 번째 레이어가 추가됩니다:
POST /sop/deployAuthorization: Bearer <token>X-Webhook-Secret: <secret>X-Idempotency-Key: <unique-key>Content-Type: application/jsonAuthorization: Bearer <token>—POST /pair에서 발급된 페어링 토큰 (페어링 & 인증 참고).X-Webhook-Secret: <secret>— 선택적; 웹훅 시크릿이 설정된 경우에만 필요합니다.X-Idempotency-Key: <key>— 선택적 중복 제거 키. 기본 TTL 300초; 해당 창 내의 중복 요청은"status": "duplicate"와 함께200 OK를 반환합니다. 키는 엔드포인트별로 네임스페이스됩니다(/webhookvs/sop/*).
웹훅 라우트는 클라이언트당 속도 제한이 적용됩니다(webhook_rate_limit_per_minute, 기본값 60).
요청 및 응답 예시
섹션 제목: “요청 및 응답 예시”curl -X POST http://127.0.0.1:42617/sop/deploy \ -H "Authorization: Bearer <token>" \ -H "X-Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"message":"deploy-service-a"}'{ "status": "accepted", "matched_sops": ["deploy-pipeline"], "source": "sop_webhook", "path": "/sop/deploy"}전체 웹훅 인그레스 세부 사항은 웹훅 인그레스를 참고하세요.
크론 트리거 평가
섹션 제목: “크론 트리거 평가”스케줄러는 캐시된 크론 트리거를 (last_check, now] 구간의 윈도우 기반 검사로 평가하므로, 폴링 경계를 넘어도 실행 시점을 놓치지 않으며, 하나의 윈도우에 여러 실행 시점이 포함되더라도 주어진 표현식은 틱당 최대 한 번 디스패치됩니다. 잘못된 크론 표현식은 캐시 빌드 시 실패 폐쇄됩니다. 크론 트리거는 데몬(revka daemon)이 실행 중이어야 합니다. 표현식 구문 및 시간대는 크론 개요 & 표현식을 참고하세요.
팬인 라우팅
섹션 제목: “팬인 라우팅”MQTT, 웹훅, 크론, 주변장치, sop_execute 도구 등 모든 소스가 단일 디스패처 dispatch_sop_event로 수렴하여 시스템에 세 가지 일관된 보장을 제공합니다:
- 단일 매처 경로. 소스에 관계없이 트리거 매칭이 동일하므로, 동일한
condition및 경로/토픽 규칙이 모든 곳에 적용됩니다. - 실행 시작 감사. 시작된 모든 실행은 실행이 진행되기 전에 감사 로거가 기록합니다(감사 로거 참고).
- 헤드리스 안전성. 에이전트 루프 컨텍스트가 없는 경우(예: 활성 에이전트 턴 없이 웹훅이 도착),
ExecuteStep액션은 자동으로 실행되지 않고 보류(pending) 상태로 로그됩니다.ExecuteStep단계를 처리하려면 에이전트 루프를 실행하거나, 승인에서 일시 정지하도록 SOP를 설계하세요.
단일 인바운드 이벤트가 여러 SOP와 매칭될 수 있으며, 응답의 matched_sops에 시작된 각 SOP가 나열됩니다.
SOP 실행 수명 주기 & 상태
섹션 제목: “SOP 실행 수명 주기 & 상태”각 실행은 최대 7가지 상태를 거칩니다:
| 상태 | 설명 |
|---|---|
pending | 생성되었지만 아직 시작되지 않음. |
running | 활성 실행 중. |
waiting_approval | 승인 게이트에서 일시 정지됨. |
paused_checkpoint | 결정론적 체크포인트에서 일시 정지됨. |
completed | 모든 단계가 성공적으로 완료됨. |
failed | 단계 실패. |
cancelled | 사용자 또는 시스템에 의해 취소됨. |
실행은 pending에서 시작하여 running으로 이동하고, 운영자가 sop_approve로 해결할 때까지 waiting_approval(모드/단계 게이트) 또는 paused_checkpoint(결정론적 체크포인트)에서 일시 정지됩니다. sop_status 도구로 라이브 상태를 조회하세요.
SOP 동시성, 쿨다운, 승인 타임아웃
섹션 제목: “SOP 동시성, 쿨다운, 승인 타임아웃”세 가지 독립적인 제한이 SOP의 과도한 실행을 방지합니다:
# Global, in config.toml[sop]max_concurrent_total = 10 # across all SOPsapproval_timeout_secs = 3600 # wait at an approval gate before timeout handling (0 = forever)# Per-SOP, in SOP.tomlcooldown_secs = 300 # minimum seconds between runs of this SOP (0 = none)max_concurrent = 1 # max simultaneous runs of this SOP| 범위 | 필드 | 기본값 | 설명 |
|---|---|---|---|
| 전역 | max_concurrent_total | 10 | 모든 SOP에 걸친 최대 동시 실행 수. |
| 전역 | approval_timeout_secs | 3600 | 타임아웃 처리 전까지 승인 게이트에서 대기하는 시간(초) (0 = 타임아웃 없음). |
| SOP별 | cooldown_secs | 0 | 하나의 SOP 실행 간 최소 대기 시간(초). |
| SOP별 | max_concurrent | 1 | 하나의 SOP의 최대 동시 실행 수. |
승인 타임아웃 동작은 우선순위를 인식합니다. 게이트가 approval_timeout_secs를 초과하면:
critical/high우선순위 SOP는 자동 승인되어 계속 진행됩니다(자동 승인은 감사 추적에 기록됩니다).normal/low우선순위 SOP는 수동 결정을 위해 무기한 대기합니다.
SOP 결정론적 모드
섹션 제목: “SOP 결정론적 모드”결정론적 모드는 LLM 호출 없이 SOP를 순수한 파이프라인으로 실행합니다: 단계가 순차적으로 실행되고 각 단계의 출력이 다음 단계의 입력으로 전달됩니다. 모든 단계가 완전히 명세되어 있고 속도, 반복성, 토큰 비용 제로를 원하는 기계적 시퀀스(하드웨어 액추에이션, 고정 데이터 변환)에 이상적입니다.
SOP.toml에서 deterministic = true 또는 execution_mode = "deterministic"으로 활성화한 다음, SOP.md에서 사람 검토 지점을 체크포인트로 표시하세요:
[sop]name = "valve-shutdown"description = "Mechanical valve shutdown sequence"version = "1.0.0"priority = "critical"deterministic = true # forces deterministic mode
[[triggers]]type = "peripheral"board = "nucleo-f401re-0"signal = "pin_3"condition = "> 0"## Steps
1. **Read pressure** — Sample the pressure sensor. - tools: gpio_read
2. **Confirm shutdown** — Operator review before actuation. - kind: checkpoint
3. **Close valve** — Drive the valve closed. - tools: gpio_writecheckpoint 단계에서 실행이 일시 정지(paused_checkpoint)되고 상태가 JSON 파일({sop_dir}/{run_id}.state.json 또는 시스템 임시 디렉터리)에 저장됩니다. 검토 후 sop_approve 도구로 재개하세요. 각 실행은 llm_calls_saved를 보고하며, 엔진은 모든 결정론적 실행에 걸친 누적 합계를 유지합니다.
SOP 감사 로거
섹션 제목: “SOP 감사 로거”모든 실행 시작은 SopAuditLogger에 의해 Memory 백엔드의 sop 카테고리에 기록되어, 어떤 SOP가 언제 어떤 이벤트 소스에서 실행되었는지에 대한 감사 추적을 제공합니다. 일반적인 키 패턴:
| 키 패턴 | 기록 내용 |
|---|---|
sop_run_{run_id} | 실행 스냅샷 (시작 및 완료 업데이트). |
sop_step_{run_id}_{step_number} | 단계별 결과. |
sop_approval_{run_id}_{step_number} | 운영자 승인 기록. |
sop_timeout_approve_{run_id}_{step_number} | 타임아웃 자동 승인 기록 (우선순위 에스컬레이션). |
CLI로 정의를 검사하고(revka sop list / show), sop_status 도구로 라이브 실행 상태를 확인하세요. [observability] backend = "prometheus"인 경우, GET /metrics에서 revka_* 런타임 메트릭 패밀리가 노출됩니다. SOP별 집계는 include_metrics: true와 함께 sop_status를 통해 사용 가능합니다. 더 넓은 감사 및 메트릭 표면은 감사 로그 및 관찰 가능성 & 트레이싱을 참고하세요.
SOP 에이전트 도구
섹션 제목: “SOP 에이전트 도구”에이전트 세션 내에서 네 가지 MCP 도구가 SOP 실행을 시작하고 구동합니다:
| 도구 | 목적 |
|---|---|
sop_execute <name> | 이름으로 SOP를 수동으로 트리거합니다(manual 트리거를 충족). |
sop_status <run_id> | 현재 실행 상태 및 단계 결과를 가져옵니다. 신뢰 단계/게이트 평가기 상태는 include_gate_status: true로, SOP 메트릭 집계는 include_metrics: true로 전달하세요. |
sop_approve <run_id> | 승인 게이트 또는 결정론적 체크포인트에서 일시 정지된 실행을 승인합니다. |
sop_advance <run_id> <result> | 단계 결과를 보고하고 실행을 다음 단계로 진행합니다. |
이 도구들은 에이전트의 나머지 스케줄링 및 오케스트레이션 도구들과 함께 스케줄링 & SOP 도구에 문서화되어 있습니다.