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

# Write a policy

> Let Failproof AI draft a policy from an audit finding, or write the source yourself, then review, test, and publish it.

There are two ways to write a policy: let Failproof AI draft it from an audit finding, or write the source yourself. Nothing is published or deployed until you choose to.

## Write a policy from an audit

An audit finds a failure; a policy stops it happening again. Failproof AI drafts the policy from the finding's own evidence.

### 1. Run an audit

[Run an audit](/audits/run) over the sessions where the failure happens. Each finding carries its evidence sessions, a root cause, and a suggested prevention path. Work from a finding with a **repeatable action pattern** — a policy can only stop what it can recognize in a hook event.

### 2. Generate the draft

<Tabs>
  <Tab title="Dashboard">
    1. Open the finding's issue under **Analyze → issues** and check its cited sessions, root cause, and recommendation.
    2. Select **generate policy**. Failproof AI first says whether a policy can express the problem at all. A **no policy** result means the fix is an alert, a workflow change, or a person — not a policy.
    3. Select **write this policy**. The issue title, finding, root cause, recommendation, and proposed enforcement intent become a draft in **Admin → policy editor**. Use **open the editor anyway** when you disagree with the candidacy check.

           <img src="https://mintcdn.com/exosphere/WgPwQzedeDNwJBTy/images/dashboard/policy-editor.png?fit=max&auto=format&n=WgPwQzedeDNwJBTy&q=85&s=7c01c862f4ec601d0535a6969eb619ce" alt="The Policy editor compose view with policy identity, AI-assisted drafting, source validation, and publishing controls." width="2938" height="1608" data-path="images/dashboard/policy-editor.png" />
  </Tab>

  <Tab title="CLI">
    Read the evidence, then draft with the assistant. `compose` prints source for you to review and publishes nothing:

    ```bash theme={null}
    fp issues show <issue-id>
    fp audits finding <finding-id>
    fp policies compose "Block git push --force on release branches"
    ```

    `compose` needs a signed-in session (`fp login`) whose role has `policies:write`; it refuses API keys.
  </Tab>
</Tabs>

### 3. Review the draft

A draft is a starting point, not a verdict. Before publishing, check that it:

1. Names the failure mode in operational language.
2. Matches only the hook events and tools that carry enough evidence to decide.
3. Uses the narrowest condition that catches the unsafe action.
4. Returns a reason that tells the agent what to do instead.
5. Uses `instruct` where the agent can safely correct course, and `deny` only where allowing the action is unacceptable or irreversible.

Validate the source in the editor and fix every reported error.

### 4. Test it, then publish

Run **backtest** under the source before you publish: it replays the draft against calls your fleet already made and counts the working calls it would have interrupted. [Test a policy](/policies/test) covers that and the other checks.

When it behaves, enter the policy identity and select **publish version**. Publishing mints an immutable version and deploys nothing: it sits unused until you [deploy it](/policies/deploy). From a terminal:

```bash theme={null}
fp policies publish checkout-guard ./checkout.policy.mjs --description "Block force-push"
```

`publish` parse-checks the source before sending it, so a syntax error surfaces here instead of on a machine at enforcement time.

## Write it yourself

A policy is JavaScript or TypeScript against the `failproofai` API:

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

customPolicies.add({
  name: "protect-production-paths",
  description: "Block writes to production configuration",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
    const path = String(ctx.toolInput?.file_path ?? "").replaceAll("\\", "/");
    if (path.split("/").includes("production")) {
      return deny("Writes to production configuration require approval.");
    }
    return allow();
  },
});
```

This matches `production/config.yml`, `/srv/production/config.yml`, `/srv/production`, and `C:\\production\\config.yml` for both `Write` and `Edit`, but not `production-backup`: `production` has to be a whole path segment. The context also carries the event type, normalized payload, session metadata, parameters, and source CLI when available — see the [policy SDK](/reference/policy-sdk).

To publish it as a version, paste the source into **compose** in **Admin → policy editor** and follow steps 3 and 4 above, or publish the file from a terminal with `fp policies publish`.

To run it on a machine without Cloud, save it under `.failproofai/policies/` with a name ending in `policies.js`, `policies.mjs` or `policies.ts` — those load automatically at project and user scope — or install it by path:

```bash theme={null}
failproofai policies --install --custom ./security.policies.ts --scope project
```

Give every policy a name that is unique across convention, custom, pack, and Cloud-managed policies.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.