# Author a Policy

> Build deterministic executable authorization logic and test allow, deny, and constraint behavior before attachment.

## Before you begin {#before-you-begin}

Write down the exact action and CRN patterns the Policy should govern, the normalized identity evidence it may use, and the constraints it should add. Executable Policy code is deterministic: it has no network, secret, storage, clock, or random authority. Use request input only.

## Steps {#steps}

1. Create an ESM package and install the SDK with `npm install @constal/sdk`.
2. Export a Policy definition:

   ```ts src/index.ts
   import { hashValue, policy, type PolicyWorkerResult } from "@constal/sdk";

   export default policy({
     id: "ticket-read-boundary",
     version: "1.0.0",
     async evaluate(request): Promise<PolicyWorkerResult> {
       const isRead = request.input.context?.["resource.operation"] === "ticket.read";
       const decision = isRead
         ? { kind: "allow" as const, explicitDeny: false, constraints: [
             { kind: "context" as const, equals: { "resource.operation": "ticket.read" } },
           ] }
         : { kind: "deny" as const, explicitDeny: true, constraints: [], reason: "read only" };
       return { inputHash: request.inputHash, outputHash: await hashValue(decision), decision };
     },
   });
   ```

3. Add `constal.policy.json` with the same id and version, its entrypoint, namespace, and expected current deployment revision.
4. Unit test allowed, denied, missing, malformed, and boundary inputs. Assert a deterministic output hash for each fixture.
5. Upload the archive through the common deployment workflow.

## Verify {#verify}

Call `POST /v1/namespaces/:namespace/policies/:id/evaluate` with a representative action, Resource, and optional context. Confirm both the returned decision and Policy hash. Test a denied case before attaching the Policy to production Resources.

## Next steps {#next-steps}

Continue with [Operate Policies](/docs/policies/operate.md) to attach and inspect it. See [Policies and analytics](/docs/sdk/policies-and-analytics.md) for the SDK boundary and [Deploy an Agent](/docs/agents/deploy.md) for the shared package upload model.
