> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 팩 게시하기

> 직접 만든 정책을 GitHub 릴리스로 배포하여 누구나 설치할 수 있게 합니다.

팩은 GitHub 릴리스에 첨부된 세 개의 파일로 구성됩니다. `failproofai pack build`를 실행하면 이미 가지고 있는 정책 파일로부터 세 파일 모두 생성됩니다.

## 1. 정책 작성하기

커스텀 정책과 동일한 API를 사용하는 파일 하나로 작성합니다. 팩에서 중요한 추가 필드가 두 가지 있습니다:

```js theme={null}
import { customPolicies, deny, allow } from "failproofai";

customPolicies.add({
  name: "block-refunds",
  description: "Refunds above the approved limit need a human",
  category: "Billing",        // groups it, and is what --category selects on
  defaultEnabled: true,       // switched on by a plain `pack add`
  match: { events: ["PreToolUse"], tools: ["Bash"] },
  fn: async (ctx) =>
    String(ctx.toolInput?.command ?? "").includes("refund")
      ? deny("Refunds need a human. Ask before running this.")
      : allow(),
});
```

`defaultEnabled`를 생략하면 기본값은 **false**입니다. `failproofai pack add`를 그냥 실행하면 표시해 둔 정책만 활성화됩니다. 처음 보는 사람의 모든 정책을 사용자 동의 없이 설치하는 건 설치 도구가 사용자 대신 결정할 일이 아닙니다.

<Warning>
  엔트리는 **완전히 독립된 하나의 파일**이어야 합니다. 다이제스트 핀은 엔트리 파일에만 적용되므로, 로컬 파일을 임포트하는 팩은 다이제스트가 실제 실행 코드를 보장한다고 말할 수 없습니다. 먼저 번들링(`esbuild`, `bun build`, `rollup`)한 뒤 번들로부터 팩을 빌드하세요 — `pack build`는 지킬 수 없는 약속을 배포하는 대신 로컬 임포트가 있으면 거부합니다.
</Warning>

## 2. 릴리스 에셋 빌드하기

```bash theme={null}
failproofai pack build ./policies.mjs \
  --id acme/support-agent \
  --version 1.0.0 \
  --out ./dist-pack
```

세 개의 파일을 생성하며, 모든 정책을 **로더 자체 규칙**으로 먼저 검증합니다. 따라서 설치가 절대 불가능한 팩은 여기서 실패하고, 수정할 기회가 생깁니다:

| 파일                      | 설명                                  |
| ----------------------- | ----------------------------------- |
| `failproofai-pack.json` | 매니페스트: id, 버전, effect, 정책별 항목 포함    |
| `failproofai-pack.mjs`  | 그대로 복사된 엔트리 파일                      |
| `SHA256SUMS`            | 나머지 두 파일에 대한 `<sha256>  <filename>` |

빌드 시 거부되는 경우: `publisher/name` 형식이 아닌 id, `/`가 포함된 정책 이름, `alwaysOn`을 선언하는 정책, `description`·`category`·`match` 누락, 아무것도 등록하지 않는 엔트리, 로컬 파일을 임포트하는 엔트리.

## 3. 릴리스에 파일 첨부하기

빌드 시 사용한 버전과 동일한 태그로 릴리스를 생성하고, 세 파일을 릴리스 에셋으로 첨부합니다:

```bash theme={null}
gh release create 1.0.0 \
  ./dist-pack/failproofai-pack.json \
  ./dist-pack/failproofai-pack.mjs \
  ./dist-pack/SHA256SUMS
```

이제 누구나 설치할 수 있습니다:

```bash theme={null}
failproofai pack add acme/support-agent
```

에셋 이름은 고정되어 있습니다 — API 호출이나 별도의 탐색 과정 없이 설치 CLI가 URL을 구성할 때 사용하는 이름이기 때문입니다.

## 새 버전 배포하기

새 `--version`으로 빌드하고, 새 릴리스에 태그를 달아 세 에셋을 다시 첨부하세요. 사용자는 동일한 `pack add` 명령으로 업그레이드하며, 이전에 선택한 정책 구성이 유지됩니다. 비활성화해 둔 정책은 업그레이드 후에도 비활성 상태를 유지합니다.

정책의 **이름**을 변경하는 것은 하위 호환성을 깨는 변경입니다. 해당 이름을 비활성화해 둔 머신은 이제 존재하지 않는 이름을 끄고 있는 셈이 되고, 새 이름은 `defaultEnabled` 설정에 따라 활성화 여부가 결정됩니다.

## 사용자가 신뢰하는 대상

`SHA256SUMS`는 아티팩트와 동일한 릴리스에 포함되어 있으므로, 게시한 바이트가 맞다는 것을 증명합니다 — 게시자가 누구인지는 증명하지 않습니다. 저장소에 쓰기 권한이 있는 사람은 두 파일 모두 수정할 수 있습니다. 사용자를 보호하는 것은 설치 시점에 다이제스트가 고정된다는 점입니다. 따라서 배포한 내용이 이후에 몰래 바뀌더라도 사용자에게는 영향을 미치지 않습니다.

쓰기 권한을 직접 관리하는 저장소에서 게시하고, 팩 릴리스를 패키지 배포와 동일하게 취급하세요.

## 적용 전 관찰하기

매니페스트에 `"effect": "observe"`를 선언할 수 있습니다. 해당 정책들은 실행되고 판정 결과가 **기록되지만 무시됩니다** — 아무것도 차단되지 않습니다. 누군가의 작업을 방해하기 전에 실제 트래픽을 기반으로 새 규칙을 측정하는 방법입니다.

```json theme={null}
{ "id": "acme/support-agent", "version": "1.1.0", "effect": "observe", "policies": [ ... ] }
```
