> ## 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.

# Políticas Personalizadas

> Escreva suas próprias políticas em JavaScript — aplique convenções, evite desvios, detecte falhas e integre com sistemas externos

As políticas personalizadas permitem que você escreva regras para qualquer comportamento do agente: aplique convenções do projeto, evite desvios, bloqueie operações destrutivas, detecte agentes travados ou integre com Slack, fluxos de aprovação e muito mais. Elas utilizam o mesmo sistema de eventos de hook e as decisões `allow`, `deny` e `instruct` das políticas integradas.

***

## Exemplo rápido

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

customPolicies.add({
  name: "no-production-writes",
  description: "Block writes to paths containing 'production'",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("production")) {
      return deny("Writes to production paths are blocked");
    }
    return allow();
  },
});
```

Instale:

```bash theme={null}
failproofai policies --install --custom ./my-policies.js
```

***

## Duas formas de carregar políticas personalizadas

### Opção 1: Por convenção (recomendado)

Coloque arquivos `*policies.{js,mjs,ts}` na pasta `.failproofai/policies/` e eles serão carregados automaticamente — sem flags ou alterações de configuração. Funciona como git hooks: basta adicionar o arquivo e ele já funciona.

```
# Nível do projeto — commitado no git, compartilhado com a equipe
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs

# Nível do usuário — pessoal, aplicado a todos os projetos
~/.failproofai/policies/my-policies.mjs
```

**Como funciona:**

* Os diretórios do projeto e do usuário são verificados (união — sem prioridade por escopo)
* Os arquivos são carregados em ordem alfabética dentro de cada diretório. Use o prefixo `01-`, `02-` para controlar a ordem
* Apenas arquivos que correspondem a `*policies.{js,mjs,ts}` são carregados; outros arquivos são ignorados
* Cada arquivo é carregado de forma independente (fail-open por arquivo)
* Funciona junto com `--custom` explícito e políticas integradas

<Tip>
  As políticas por convenção são a forma mais fácil de estabelecer um padrão de qualidade para sua organização. Faça commit de `.failproofai/policies/` no git e todos os membros da equipe recebem as mesmas regras automaticamente — sem configuração por desenvolvedor. Conforme sua equipe descobre novos tipos de falha, adicione uma política e faça push. Com o tempo, elas se tornam um padrão de qualidade vivo que melhora a cada contribuição.
</Tip>

### Opção 2: Caminho de arquivo explícito

```bash theme={null}
# Instalar com um arquivo de políticas personalizado
failproofai policies --install --custom ./my-policies.js

# Substituir o caminho do arquivo de políticas
failproofai policies --install --custom ./new-policies.js

# Remover o caminho de políticas personalizadas da configuração
failproofai policies --uninstall --custom
```

O caminho absoluto resolvido é armazenado em `policies-config.json` como `customPoliciesPath`. O arquivo é carregado novamente a cada evento de hook — não há cache entre eventos.

### Usando as duas opções juntas

As políticas por convenção e o arquivo `--custom` explícito podem coexistir. Ordem de carregamento:

1. Arquivo `customPoliciesPath` explícito (se configurado)
2. Arquivos de convenção do projeto (`{cwd}/.failproofai/policies/`, em ordem alfabética)
3. Arquivos de convenção do usuário (`~/.failproofai/policies/`, em ordem alfabética)

***

## API

### Importação

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

### `customPolicies.add(hook)`

Registra uma política. Chame quantas vezes precisar para múltiplas políticas no mesmo arquivo.

```ts theme={null}
customPolicies.add({
  name: string;                         // obrigatório - identificador único
  description?: string;                 // exibido na saída de `failproofai policies`
  match?: { events?: HookEventType[] }; // filtra por tipo de evento; omita para corresponder a todos
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
```

### Funções auxiliares de decisão

| Função              | Efeito                             | Use quando                                                      |
| ------------------- | ---------------------------------- | --------------------------------------------------------------- |
| `allow()`           | Permite a operação silenciosamente | A ação é segura, sem necessidade de mensagem                    |
| `deny(message)`     | Bloqueia a operação                | O agente não deve executar esta ação                            |
| `instruct(message)` | Adiciona contexto sem bloquear     | Forneça contexto extra ao agente para mantê-lo no caminho certo |

`deny(message)` — a mensagem aparece para Claude com o prefixo `"Blocked by failproofai:"`. Um único `deny` interrompe toda avaliação subsequente.

`instruct(message)` — a mensagem é anexada ao contexto de Claude para a chamada de ferramenta atual. Todas as mensagens `instruct` são acumuladas e entregues juntas.

<Tip>
  Você pode adicionar orientações extras a qualquer mensagem `deny` ou `instruct` incluindo um campo `hint` em `policyParams` — sem necessidade de alterar o código. Isso funciona também para políticas personalizadas (`custom/`), por convenção do projeto (`.failproofai-project/`) e por convenção do usuário (`.failproofai-user/`). Consulte [Configuração → hint](/pt-br/configuration#hint-cross-cutting) para mais detalhes.
</Tip>

### Mensagens allow informativas

`allow(message)` permite a operação **e** envia uma mensagem informativa para Claude. A mensagem é entregue como `additionalContext` na resposta stdout do hook handler — o mesmo mecanismo usado por `instruct`, mas semanticamente diferente: é uma atualização de status, não um aviso.

| Função           | Efeito                               | Use quando                                                            |
| ---------------- | ------------------------------------ | --------------------------------------------------------------------- |
| `allow(message)` | Permite e envia contexto para Claude | Confirme que uma verificação passou, ou explique por que foi ignorada |

Casos de uso:

* **Confirmações de status:** `allow("All CI checks passed.")` — informa Claude que tudo está ok
* **Explicações de fail-open:** `allow("GitHub CLI not installed, skipping CI check.")` — informa Claude por que uma verificação foi ignorada para que ele tenha contexto completo
* **Múltiplas mensagens são acumuladas:** se várias políticas retornarem `allow(message)`, todas as mensagens são unidas com quebras de linha e entregues juntas

```js theme={null}
customPolicies.add({
  name: "confirm-branch-status",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    const cwd = ctx.session?.cwd;
    if (!cwd) return allow("No working directory, skipping branch check.");

    // ... verificar status do branch ...
    if (allPushed) {
      return allow("Branch is up to date with remote.");
    }
    return deny("Unpushed changes detected.");
  },
});
```

### Campos de `PolicyContext`

| Campo       | Tipo                                   | Descrição                                                       |
| ----------- | -------------------------------------- | --------------------------------------------------------------- |
| `eventType` | `string`                               | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"`     |
| `toolName`  | `string \| undefined`                  | A ferramenta sendo chamada (ex.: `"Bash"`, `"Write"`, `"Read"`) |
| `toolInput` | `Record<string, unknown> \| undefined` | Os parâmetros de entrada da ferramenta                          |
| `payload`   | `Record<string, unknown>`              | Payload bruto completo do evento do Claude Code                 |
| `session`   | `SessionMetadata \| undefined`         | Contexto da sessão (veja abaixo)                                |

### Campos de `SessionMetadata`

| Campo            | Tipo     | Descrição                                             |
| ---------------- | -------- | ----------------------------------------------------- |
| `sessionId`      | `string` | Identificador da sessão do Claude Code                |
| `cwd`            | `string` | Diretório de trabalho da sessão do Claude Code        |
| `transcriptPath` | `string` | Caminho para o arquivo de transcrição JSONL da sessão |

### Tipos de evento

| Evento         | Quando dispara                          | Conteúdo de `toolInput`                                                                                                                                |
| -------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `PreToolUse`   | Antes de Claude executar uma ferramenta | A entrada da ferramenta (ex.: `{ command: "..." }` para Bash)                                                                                          |
| `PostToolUse`  | Após a conclusão de uma ferramenta      | A entrada da ferramenta + `tool_result` (a saída)                                                                                                      |
| `Notification` | Quando Claude envia uma notificação     | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - hooks devem sempre retornar `allow()`, não podem bloquear notificações |
| `Stop`         | Quando a sessão do Claude encerra       | Vazio                                                                                                                                                  |

***

## Ordem de avaliação

As políticas são avaliadas nesta ordem:

1. Políticas integradas (em ordem de definição)
2. Políticas personalizadas explícitas de `customPoliciesPath` (em ordem de `.add()`)
3. Políticas por convenção do projeto em `.failproofai/policies/` (arquivos em ordem alfabética, ordem de `.add()` internamente)
4. Políticas por convenção do usuário em `~/.failproofai/policies/` (arquivos em ordem alfabética, ordem de `.add()` internamente)

<Note>
  O primeiro `deny` interrompe todas as políticas subsequentes. Todas as mensagens `instruct` são acumuladas e entregues juntas.
</Note>

***

## Importações transitivas

Arquivos de políticas personalizadas podem importar módulos locais usando caminhos relativos:

```js theme={null}
// my-policies.js
import { isBlockedPath } from "./utils.js";
import { checkApproval } from "./approval-client.js";

customPolicies.add({
  name: "approval-gate",
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const approved = await checkApproval(ctx.toolInput?.command, ctx.session?.sessionId);
    return approved ? allow() : deny("Approval required for this command");
  },
});
```

Todas as importações relativas alcançáveis a partir do arquivo de entrada são resolvidas. Isso é implementado reescrevendo as importações de `from "failproofai"` para o caminho real do dist e criando arquivos `.mjs` temporários para garantir compatibilidade com ESM.

***

## Filtragem por tipo de evento

Use `match.events` para limitar quando uma política dispara:

```js theme={null}
customPolicies.add({
  name: "require-summary-on-stop",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    // Dispara apenas quando a sessão encerra
    // ctx.session.transcriptPath contém o log completo da sessão
    return allow();
  },
});
```

Omita `match` completamente para disparar em todos os tipos de evento.

***

## Tratamento de erros e modos de falha

As políticas personalizadas são **fail-open**: erros nunca bloqueiam as políticas integradas nem causam falha no hook handler.

| Falha                                  | Comportamento                                                                                                    |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `customPoliciesPath` não definido      | Nenhuma política personalizada explícita é executada; políticas por convenção e integradas continuam normalmente |
| Arquivo não encontrado                 | Aviso registrado em `~/.failproofai/hook.log`; políticas integradas continuam                                    |
| Erro de sintaxe/importação (explícito) | Erro registrado em `~/.failproofai/hook.log`; políticas personalizadas explícitas são ignoradas                  |
| Erro de sintaxe/importação (convenção) | Erro registrado; aquele arquivo é ignorado, outros arquivos de convenção ainda são carregados                    |
| `fn` lança erro em tempo de execução   | Erro registrado; aquele hook é tratado como `allow`; outros hooks continuam                                      |
| `fn` demora mais de 10s                | Timeout registrado; tratado como `allow`                                                                         |
| Diretório de convenção ausente         | Nenhuma política por convenção é executada; sem erro                                                             |

<Tip>
  Para depurar erros de políticas personalizadas, monitore o arquivo de log:

  ```bash theme={null}
  tail -f ~/.failproofai/hook.log
  ```
</Tip>

***

## Exemplo completo: múltiplas políticas

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

// Impede o agente de escrever no diretório secrets/
customPolicies.add({
  name: "block-secrets-dir",
  description: "Prevent agent from writing to secrets/ directory",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("secrets/")) return deny("Writing to secrets/ is not permitted");
    return allow();
  },
});

// Mantém o agente no caminho certo: verifica os testes antes de commitar
customPolicies.add({
  name: "remind-test-before-commit",
  description: "Keep the agent on track: verify tests pass before committing",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    if (/git\s+commit/.test(cmd)) {
      return instruct("Verify all tests pass before committing. Run `bun test` if you haven't already.");
    }
    return allow();
  },
});

// Impede mudanças de dependências não planejadas durante o período de freeze
customPolicies.add({
  name: "dependency-freeze",
  description: "Prevent unplanned dependency changes during freeze period",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    const isInstall = /^(npm install|yarn add|bun add|pnpm add)\s+\S/.test(cmd);
    if (isInstall && process.env.DEPENDENCY_FREEZE === "1") {
      return deny("Package installs are frozen. Unset DEPENDENCY_FREEZE to allow.");
    }
    return allow();
  },
});

export { customPolicies };
```

***

## Exemplos

O diretório `examples/` contém arquivos de políticas prontos para uso:

| Arquivo                                              | Conteúdo                                                                                                      |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `examples/policies-basic.js`                         | Cinco políticas iniciais cobrindo modos de falha comuns de agentes                                            |
| `examples/policies-advanced/index.js`                | Padrões avançados: importações transitivas, chamadas assíncronas, filtragem de saída e hooks de fim de sessão |
| `examples/convention-policies/security-policies.mjs` | Políticas de segurança por convenção (bloquear escrita em .env, impedir reescrita do histórico git)           |
| `examples/convention-policies/workflow-policies.mjs` | Políticas de fluxo de trabalho por convenção (lembretes de testes, auditoria de escritas em arquivos)         |

### Usando exemplos com arquivo explícito

```bash theme={null}
failproofai policies --install --custom ./examples/policies-basic.js
```

### Usando exemplos baseados em convenção

```bash theme={null}
# Copiar para o nível do projeto
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/

# Ou copiar para o nível do usuário
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
```

Nenhum comando de instalação é necessário — os arquivos são detectados automaticamente no próximo evento de hook.
