개요
failproofai는 두 개의 독립적인 서브시스템으로 구성됩니다:- 훅 핸들러 - 에이전트의 모든 도구 호출 시 Claude Code가 실행하는 빠른 CLI 서브프로세스입니다. 정책을 평가하고 결정을 반환합니다.
- 에이전트 모니터 (대시보드) - 에이전트 세션 모니터링 및 정책 관리를 위한 Next.js 웹 애플리케이션입니다.
~/.failproofai/와 프로젝트의 .failproofai/ 디렉터리에 있는 설정 파일을 공유하지만, 별도의 프로세스로 실행되며 파일 시스템을 통해서만 통신합니다.
훅 핸들러
Claude Code와의 통합
failproofai policies --install을 실행하면 ~/.claude/settings.json에 다음과 같은 항목이 작성됩니다:
failproofai --hook PreToolUse를 서브프로세스로 실행하고, stdin으로 JSON 페이로드를 전달합니다.
페이로드 형식
PostToolUse 이벤트의 페이로드에는 도구의 출력이 담긴 tool_result도 포함됩니다.
핸들러는 stdin을 1MB로 제한합니다. 이 크기를 초과하는 페이로드는 무시되며, 모든 정책은 암묵적으로 허용됩니다.
응답 형식
거부 (PreToolUse):- 종료 코드:
2 - 이유는 stdout이 아닌 stderr에 기록됨
- 종료 코드:
0 - stdout 비어 있음
allow(message)는 작업이 허용될 때도 정책이 Claude에게 정보성 컨텍스트를 전달할 수 있게 합니다. 훅 핸들러는 다음 JSON을 stdout에 작성합니다(설정 파일이 아니라 위의 거부/지시 응답과 마찬가지로 Claude Code에 대한 핸들러의 응답입니다):
- 종료 코드:
0(작업 허용됨) - 여러 정책이 메시지와 함께
allow를 반환하면, 해당 메시지들이 줄바꿈으로 연결되어 하나의additionalContext문자열로 합쳐짐 - 어떤 정책도 메시지를 제공하지 않으면 stdout은 비어 있음 (이전과 동일)
처리 파이프라인
src/hooks/handler.ts가 전체 파이프라인을 구현합니다:
설정 로딩
src/hooks/hooks-config.ts가 세 가지 범위의 설정 로딩을 구현합니다.
enabledPolicies- 세 파일 전체에서 중복 제거 후 합집합policyParams- 정책별 키, 먼저 정의한 파일이 전적으로 우선customPoliciesPath- 먼저 정의한 파일이 우선llm- 먼저 정의한 파일이 우선
readHooksConfig()(전역만)를 사용합니다.
정책 평가
src/hooks/policy-evaluator.ts가 정책을 순서대로 실행합니다.
각 정책에 대해:
- 정책의
params스키마를 조회합니다(있는 경우). - 병합된 설정에서
policyParams[policy.name]을 읽습니다. - 사용자가 제공한 값을 스키마 기본값에 덮어씌워
ctx.params를 생성합니다. - 확인된 컨텍스트로
policy.fn(ctx)를 호출합니다. - 결과가
deny이면 즉시 중단하고 해당 결정을 반환합니다. - 결과가
instruct이면 메시지를 누적하고 계속 진행합니다. - 결과가
allow이면 다음 정책으로 계속 진행합니다.
deny가 반환된 경우 거부 응답을 내보냅니다.instruct반환이 수집된 경우 모든 메시지를 합쳐 단일 지시 응답을 내보냅니다.- 그 외의 경우 허용 응답을 내보냅니다(stdout 비어 있음, 종료 코드 0).
빌트인 정책
src/hooks/builtin-policies.ts는 39개의 빌트인 정책을 BuiltinPolicyDefinition 객체로 정의합니다:
params를 허용하는 정책은 각 파라미터의 타입과 기본값을 포함하는 PolicyParamsSchema를 선언합니다. 정책 평가기는 fn 호출 전에 확인된 값을 ctx.params에 주입합니다. 기본값이 항상 먼저 적용되므로 정책 함수는 null 검사 없이 ctx.params를 읽을 수 있습니다.
정책 내부의 패턴 매칭은 원시 문자열 매칭이 아닌 파싱된 명령 토큰(argv)을 사용합니다. 이를 통해 셸 연산자 주입을 통한 우회를 방지합니다(예: sudo systemctl status * 패턴은 명령에 ; rm -rf /를 덧붙여도 우회할 수 없습니다).
커스텀 정책
src/hooks/custom-hooks-registry.ts는 globalThis 기반 레지스트리를 구현합니다:
src/hooks/custom-hooks-loader.ts는 사용자의 정책 파일을 로드합니다:
- 설정에서
customPoliciesPath를 읽습니다. 없으면 건너뜁니다. - 절대 경로로 변환하고 파일 존재 여부를 확인합니다.
customPolicies가 동일한globalThis레지스트리로 확인될 수 있도록 모든from "failproofai"임포트를 실제 dist 경로로 재작성합니다.- ESM 호환성을 위해 로컬 임포트의 전이적 의존성도 재귀적으로 재작성합니다.
- 임시
.mjs파일을 작성하고 엔트리 파일을import()합니다. getCustomHooks()를 호출하여 등록된 훅을 가져옵니다.finally블록에서 모든 임시 파일을 정리합니다.
~/.failproofai/hook.log에 기록되고 로더는 빈 배열을 반환합니다. 빌트인 정책은 영향을 받지 않습니다.
커스텀 정책은 모든 빌트인 정책 이후에 평가됩니다. 커스텀 정책의 deny는 이후 커스텀 정책의 실행을 중단시키지만, 모든 빌트인은 이미 실행된 상태입니다.
활동 로깅
각 훅 이벤트 이후 핸들러는~/.failproofai/hook-activity.jsonl에 JSONL 줄을 추가합니다:
대시보드 아키텍처
대시보드는 App Router와 React 서버 컴포넌트 및 서버 액션을 사용하는 Next.js 16 애플리케이션입니다.- 페이지 컴포넌트는
lib/projects.ts와lib/log-entries.ts를 호출하여 파일 시스템에서 직접 프로젝트/세션 데이터를 읽습니다(읽기에 별도 API 레이어 없음). - Policies 페이지는 모든 변경(토글, 파라미터 업데이트, 설치/제거)에 서버 액션을 사용합니다.
- 세션 뷰어는 Claude의 JSONL 트랜스크립트 형식을 파싱하고 메시지 및 도구 호출 타임라인을 렌더링합니다.
- 데이터베이스 없음 - 모든 영구 상태는 일반 파일(
~/.failproofai/,~/.claude/projects/)에 저장됩니다. - 변경에 서버 액션 사용 - CRUD 작업에 REST API가 필요하지 않습니다.
- 읽기 페이지에 React 서버 컴포넌트 사용 - 초기 로딩이 빠르고 데이터 페칭을 위한 클라이언트 번들이 필요 없습니다.
- 클라이언트 컴포넌트는 상호작용이 필요한 곳에만 사용(정책 토글, 활동 검색, 로그 뷰어).

