메인 콘텐츠로 건너뛰기
failproofai는 JSON 설정 파일을 사용하여 어떤 정책이 활성화되는지, 동작 방식, 그리고 커스텀 정책을 어디서 로드하는지를 제어합니다. 설정은 팀과 쉽게 공유할 수 있도록 설계되어 있습니다 — 저장소에 커밋하면 모든 개발자가 동일한 에이전트 안전망을 사용할 수 있습니다.

설정 범위

우선순위 순서대로 평가되는 세 가지 설정 범위가 있습니다:
범위파일 경로용도
project.failproofai/policies-config.json버전 관리에 커밋되는 저장소별 설정
local.failproofai/policies-config.local.jsongitignore 처리되는 개인 저장소별 재정의
global~/.failproofai/policies-config.json모든 프로젝트에 적용되는 사용자 수준 기본값
failproofai가 훅 이벤트를 받으면 현재 작업 디렉토리에 존재하는 세 파일을 모두 로드하고 병합합니다.

병합 규칙

enabledPolicies — 세 범위의 합집합입니다. 어느 수준에서든 활성화된 정책은 적용됩니다.
project:  ["block-sudo"]
local:    ["block-rm-rf"]
global:   ["block-sudo", "sanitize-api-keys"]

resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"]  ← 중복 제거된 합집합
policyParams — 특정 정책의 파라미터를 처음 정의한 범위가 전체 우선권을 가집니다. 정책 파라미터 내의 값은 깊은 병합을 수행하지 않습니다.
project:  block-sudo → { allowPatterns: ["sudo apt-get update"] }
global:   block-sudo → { allowPatterns: ["sudo systemctl status"] }

resolved: { allowPatterns: ["sudo apt-get update"] }   ← project 우선, global 무시
project:  (block-sudo 항목 없음)
local:    (block-sudo 항목 없음)
global:   block-sudo → { allowPatterns: ["sudo systemctl status"] }

resolved: { allowPatterns: ["sudo systemctl status"] }  ← global까지 전달됨
customPoliciesPath — 처음 정의한 범위가 우선권을 가집니다. llm — 처음 정의한 범위가 우선권을 가집니다.

설정 파일 형식

{
  "enabledPolicies": [
    "block-sudo",
    "block-rm-rf",
    "block-push-master",
    "sanitize-api-keys",
    "sanitize-jwt",
    "block-env-files",
    "block-read-outside-cwd"
  ],
  "policyParams": {
    "block-sudo": {
      "allowPatterns": ["sudo systemctl status", "sudo journalctl"]
    },
    "block-push-master": {
      "protectedBranches": ["main", "release", "prod"]
    },
    "block-rm-rf": {
      "allowPaths": ["/tmp"]
    },
    "block-read-outside-cwd": {
      "allowPaths": ["/shared/data", "/opt/company"]
    },
    "sanitize-api-keys": {
      "additionalPatterns": [
        { "regex": "myco_[A-Za-z0-9]{32}", "label": "MyCo API key" }
      ]
    },
    "warn-large-file-write": {
      "thresholdKb": 512
    }
  },
  "customPoliciesPath": "/home/alice/myproject/my-policies.js"
}

필드 참조

enabledPolicies

타입: string[] 활성화할 정책 이름 목록입니다. 이름은 failproofai policies가 표시하는 정책 식별자와 정확히 일치해야 합니다. 전체 목록은 기본 제공 정책을 참고하세요. enabledPolicies에 없는 정책은 policyParams에 항목이 있더라도 비활성화됩니다.

policyParams

타입: Record<string, Record<string, unknown>> 정책별 파라미터 재정의입니다. 외부 키는 정책 이름이고, 내부 키는 정책별로 다릅니다. 각 정책의 사용 가능한 파라미터는 기본 제공 정책에서 확인할 수 있습니다. 파라미터가 있는 정책에 파라미터를 지정하지 않으면 정책의 기본값이 사용됩니다. policyParams를 전혀 설정하지 않은 사용자는 이전 버전과 동일하게 동작합니다. 정책 파라미터 블록 내의 알 수 없는 키는 훅 실행 시 조용히 무시되지만, failproofai policies를 실행하면 경고로 표시됩니다.

hint (공통 옵션)

타입: string (선택 사항) 정책이 deny 또는 instruct를 반환할 때 이유에 추가되는 메시지입니다. 정책 자체를 수정하지 않고도 Claude에게 실행 가능한 지침을 제공하는 데 사용합니다. 기본 제공, 커스텀(custom/), 프로젝트 규칙(.failproofai-project/), 사용자 규칙(.failproofai-user/) 등 모든 정책 유형에서 사용할 수 있습니다.
{
  "policyParams": {
    "block-force-push": {
      "hint": "Try creating a fresh branch instead."
    },
    "block-sudo": {
      "allowPatterns": ["sudo apt-get"],
      "hint": "Use apt-get directly without sudo."
    },
    "custom/my-policy": {
      "hint": "Ask the user for approval first."
    }
  }
}
block-force-push가 차단하면 Claude는 다음과 같이 확인합니다: “Force-pushing is blocked. Try creating a fresh branch instead.” 문자열이 아닌 값과 빈 문자열은 조용히 무시됩니다. hint가 설정되지 않으면 동작이 변경되지 않습니다 (하위 호환 유지).

customPoliciesPath

타입: string (절대 경로) 커스텀 훅 정책이 포함된 JavaScript 파일의 경로입니다. failproofai policies --install --custom <path>를 사용하면 자동으로 설정됩니다 (경로는 저장 전에 절대 경로로 변환됩니다). 이 파일은 매 훅 이벤트마다 새로 로드됩니다 — 캐싱이 없습니다. 작성 방법은 커스텀 정책을 참고하세요.

규칙 기반 정책

명시적인 customPoliciesPath 외에도 failproofai는 .failproofai/policies/ 디렉토리에서 정책 파일을 자동으로 검색하고 로드합니다:
수준디렉토리범위
프로젝트.failproofai/policies/버전 관리를 통해 팀과 공유
사용자~/.failproofai/policies/개인용, 모든 프로젝트에 적용
파일 매칭: *policies.{js,mjs,ts} 패턴에 맞는 파일만 로드됩니다 (예: security-policies.mjs, workflow-policies.js). 디렉토리의 다른 파일은 무시됩니다. 설정 불필요: 규칙 기반 정책은 policies-config.json에 항목이 필요하지 않습니다. 디렉토리에 파일을 넣기만 하면 다음 훅 이벤트에서 자동으로 로드됩니다. 통합 로드: 프로젝트와 사용자 규칙 디렉토리가 모두 스캔됩니다. 두 수준의 모든 매칭 파일이 로드됩니다 (첫 번째 범위가 우선권을 갖는 customPoliciesPath와 다릅니다). 자세한 내용과 예시는 커스텀 정책을 참고하세요.

llm

타입: object (선택 사항) AI 호출을 수행하는 정책을 위한 LLM 클라이언트 설정입니다. 대부분의 경우 필요하지 않습니다.
{
  "llm": {
    "model": "claude-sonnet-4-6",
    "apiKey": "sk-ant-..."
  }
}

CLI에서 설정 관리

policies --installpolicies --uninstall 명령은 에이전트 CLI의 훅 설정 파일(훅 진입점)에 씁니다. policies-config.json은 직접 관리하는 파일로, 두 가지는 분리되어 있습니다:
  • 에이전트 CLI 설정 — 에이전트가 각 도구 사용 시 failproofai --hook <event>를 호출하도록 지시합니다:
    • Claude Code: ~/.claude/settings.json (사용자), <cwd>/.claude/settings.json (프로젝트), <cwd>/.claude/settings.local.json (로컬)
    • OpenAI Codex: ~/.codex/hooks.json (사용자), <cwd>/.codex/hooks.json (프로젝트) — Codex에는 local 범위가 없습니다
    • GitHub Copilot CLI (베타): ~/.copilot/hooks/failproofai.json (사용자), <cwd>/.github/hooks/failproofai.json (프로젝트) — Copilot에는 local 범위가 없습니다. 훅 항목은 Copilot의 OS별 bash/powershell 명령 필드와 timeoutSec을 사용하며, 파일에는 최상위 version: 1 마커가 있습니다. Copilot CLI 지원은 events.jsonl 레코드 스키마(공개 문서에 명시되지 않음)를 더 많은 실제 세션에서 검증하는 동안 베타 상태입니다.
    • Cursor Agent (베타): ~/.cursor/hooks.json (사용자), <cwd>/.cursor/hooks.json (프로젝트) — Cursor에는 local 범위가 없습니다. 훅 항목은 Claude 형식의 {type, command, timeout} 형태를 사용하지만, Cursor의 hooks 스키마에 따라 camelCase 이벤트 키(preToolUse, beforeSubmitPrompt, …) 아래의 플랫 배열에 저장됩니다. 파일에는 최상위 version: 1 마커가 있습니다. 핸들러는 CURSOR_EVENT_MAP을 통해 camelCase를 PascalCase로 정규화하므로 기존 기본 정책이 변경 없이 실행됩니다. Cursor Agent 지원은 Cursor의 전사본 온디스크 형식(공개 문서에 명시되지 않음)을 더 많은 실제 설치 환경에서 검증하는 동안 베타 상태입니다.
    • OpenCode (베타): ~/.config/opencode/opencode.json + ~/.config/opencode/plugins/failproofai.mjs (사용자), <cwd>/.opencode/opencode.json + <cwd>/.opencode/plugins/failproofai.mjs (프로젝트) — OpenCode에는 local 범위가 없습니다. 다른 여섯 CLI와 달리 OpenCode에는 외부 명령 훅 시스템이 없습니다: opencode.jsonplugin: [] 배열을 통해 명시적으로 등록된 인프로세스 JS/TS 플러그인을 로드합니다 (.opencode/plugins/에서의 자동 검색은 opencode v1.14.33에서 플러그인이 로드되는 방식이 아닙니다). 설치 시 failproofai 바이너리를 서브프로세스로 호출하고 바이너리의 Claude 형식 JSON 응답을 플러그인 시맨틱으로 변환하는 소형 생성 플러그인 심(shim)을 생성합니다: 도구 이벤트 deny에는 throw new Error() (도구 호출 취소), instruct 및 Stop/SubagentStop deny에는 client.session.prompt(...) (deny 이유를 다음 사용자 메시지로 제출 — session.idle은 알림 전용이고 throw는 무작동이므로 이 채널이 유일한 강제 재시도 채널), allow에는 무작동. 심은 도구 이름(소문자 → OPENCODE_TOOL_MAP을 통한 PascalCase)과 도구 입력 인수 키(Read/Write/Edit에 대해 OPENCODE_TOOL_INPUT_MAP을 통한 camelCase → snake_case, 예: filePathfile_path, oldStringold_string)를 정규화한 후 바이너리로 전달하므로, block-read-outside-cwd, block-env-files, block-secrets-write와 같은 경로 확인 기본 정책이 OpenCode 도구 호출에서 변경 없이 실행됩니다. 세션은 ~/.local/share/opencode/opencode.db의 opencode SQLite DB에 저장되며, 대시보드의 세션 뷰어는 opencode db --format jsonopencode export <id>를 통해 읽습니다. OpenCode 지원은 버전 간 동작과 더 많은 실제 세션을 검증하는 동안 베타 상태입니다. OpenCode 플러그인 문서를 참고하세요.
    • Pi (베타): ~/.pi/agent/settings.json (사용자), <cwd>/.pi/settings.json (프로젝트) — Pi에는 local 범위가 없습니다. Pi는 시작 시 TypeScript 확장 패키지를 로드하며, 설정 파일은 플랫 문자열 배열 {"packages": ["./relative/path", …]}입니다. failproofai는 번들된 pi-extension/ 디렉토리를 가리키는 단일 packages 배열 항목을 씁니다. 확장은 내부적으로 Pi의 tool_call/user_bash/input/session_start 이벤트를 구독하고 failproofai --hook <Event> --cli pi를 쉘 아웃합니다. 핸들러는 PI_EVENT_MAP을 통해 underscore_lower_snake_case를 PascalCase로 정규화하므로 기존 기본 정책이 변경 없이 실행됩니다. 도구 입력 인수도 PI_TOOL_INPUT_MAP을 통해 정규화됩니다 (Pi의 Read/Write/Edit는 file_path 대신 path를 전달하며, 최상위 키를 매핑하면 block-env-filesblock-secrets-write가 실행됩니다 — block-read-outside-cwd는 이미 path 폴백을 가지고 있었습니다). Pi 지원은 Pi의 확장 API와 세션 로그 레이아웃이 안정화되는 동안 베타 상태입니다.
    • Gemini CLI (베타): ~/.gemini/settings.json (사용자), <cwd>/.gemini/settings.json (프로젝트) — Gemini에는 local 범위가 없습니다 (failproofai가 노출하지 않는 /etc/gemini-cli/settings.jsonsystem 범위를 문서화하고 있습니다). 훅 항목은 기본적으로 matcher: "*"를 사용하는 Gemini의 {matcher, hooks: [...]} 매처 스키마로 래핑된 Claude의 {type, command, timeout} 형태를 사용합니다. 이벤트는 PascalCase(SessionStart, BeforeAgent, AfterAgent, BeforeModel, AfterModel, BeforeToolSelection, BeforeTool, AfterTool, PreCompress, Notification, SessionEnd)이며, 핸들러는 GEMINI_EVENT_MAP을 통해 Claude 표준 이름으로 매핑합니다. 도구 이름은 snake_case(run_shell_command, read_file, write_file, replace, …)이며, 핸들러는 GEMINI_TOOL_MAP을 통해 정규화하므로 기존 기본 정책이 변경 없이 실행됩니다. 정책 평가기는 Gemini의 플랫 {decision: "deny", reason} 형태 (Gemini의 “Golden Rule” exit-0 계약에 따른 선호 형식), BeforeAgent/AfterTool/SessionStart에서의 컨텍스트 주입을 위한 {hookSpecificOutput: {hookEventName, additionalContext}}, 그리고 강제 재시도 시맨틱을 위한 AfterAgent의 {decision: "block", reason}을 반환합니다. Gemini CLI 지원은 실제 환경 커버리지를 넓히는 동안 베타 상태입니다. Gemini CLI 훅 문서를 참고하세요.
  • policies-config.json — failproofai에게 어떤 정책을 평가할지, 어떤 파라미터로 평가할지 알려줍니다 (모든 에이전트 CLI에서 공유)
특정 에이전트를 대상으로 하려면 --cli claude|codex|copilot|cursor|opencode|pi|gemini를 전달하세요 (공백으로 구분하거나 반복 사용으로 부분 집합 선택):
failproofai policies --install --cli codex --scope project
failproofai policies --install --cli copilot --scope project
failproofai policies --install --cli cursor --scope project
failproofai policies --install --cli opencode --scope project
failproofai policies --install --cli pi --scope project
failproofai policies --install --cli gemini --scope project
failproofai policies --install --cli claude codex copilot cursor opencode pi gemini
--cli를 생략하면 failproofai는 설치된 에이전트 CLI를 자동 감지합니다 (which claude/which codex/which copilot/which cursor-agent/which opencode/which pi/which gemini):
  • 하나의 CLI 감지됨 — 확인 없이 해당 CLI를 자동 선택합니다.
  • 여러 CLI가 대화형 터미널에서 감지됨Detected (N) 섹션(개별 감지된 CLI와 Install for all N detected 집계 행 포함) 및 Not installed (M) · install hooks ahead of time 섹션(감지되지 않은 지원 CLI를 사전 설치 옵션으로 표시)이 있는 화살표 키 단일 선택 프롬프트를 표시합니다 (↑↓로 이동, Enter로 선택, ^C로 종료). 제거 흐름에는 Detected 섹션만 표시됩니다.
  • 여러 CLI가 비대화형 실행에서 감지됨 (CI, TTY 없음) — 확인 없이 감지된 모든 CLI에 설치합니다.
  • 감지된 CLI 없음 — PATH에서 에이전트 바이너리를 찾을 수 없다는 경고와 함께 claude로 폴백합니다. 훅 명령은 여전히 작성되므로 에이전트를 설치하는 즉시 활성화됩니다.
policies-config.json은 언제든지 직접 편집할 수 있으며, 다음 훅 이벤트에서 즉시 적용됩니다 — 재시작이 필요 없습니다.

예시: 팀 기본값이 포함된 프로젝트 수준 설정

저장소에 .failproofai/policies-config.json을 커밋하세요:
{
  "enabledPolicies": [
    "block-sudo",
    "block-rm-rf",
    "block-push-master",
    "sanitize-api-keys",
    "block-env-files"
  ],
  "policyParams": {
    "block-push-master": {
      "protectedBranches": ["main", "release", "hotfix"]
    }
  }
}
각 개발자는 팀원에게 영향을 주지 않고 개인 재정의를 위해 .failproofai/policies-config.local.json (gitignore 처리)을 생성할 수 있습니다.