diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index b42e1cb275..38978b602f 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -16,6 +16,16 @@
- [Write a mutation policy](./writing-policies/rust/05-mutation-policy.md)
- [Logging](./writing-policies/rust/06-logging.md)
- [Build and distribute](./writing-policies/rust/07-build-and-distribute.md)
+ - [Rego](./writing-policies/rego/01-intro.md)
+ - [Open Policy Agent](./writing-policies/rego/open-policy-agent/01-intro.md)
+ - [Create a new policy](./writing-policies/rego/open-policy-agent/02-create-policy.md)
+ - [Build and run](./writing-policies/rego/open-policy-agent/03-build-and-run.md)
+ - [Distribute](./writing-policies/rego/open-policy-agent/04-distribute.md)
+ - [Gatekeeper](./writing-policies/rego/gatekeeper/01-intro.md)
+ - [Create a new policy](./writing-policies/rego/gatekeeper/02-create-policy.md)
+ - [Build and run](./writing-policies/rego/gatekeeper/03-build-and-run.md)
+ - [Distribute](./writing-policies/rego/gatekeeper/04-distribute.md)
+ - [Builtin support](./writing-policies/rego/02-builtin-support.md)
- [Go](./writing-policies/go/01-intro.md)
- [Create a new policy](./writing-policies/go/02-scaffold.md)
- [Define policy settings](./writing-policies/go/03-policy-settings.md)
diff --git a/src/writing-policies/rego/01-intro.md b/src/writing-policies/rego/01-intro.md
new file mode 100644
index 0000000000..4a51e7b09c
--- /dev/null
+++ b/src/writing-policies/rego/01-intro.md
@@ -0,0 +1,47 @@
+# Rego
+
+The Rego language is a tailor made language designed to embrace
+policies as code. Rego is a language inspired by Datalog.
+
+There are two ways of writing Rego policies as of today in order to
+implement policies as code in Kubernetes: Open Policy Agent and
+Gatekeeper.
+
+## One language. Two frameworks
+
+### Open Policy Agent
+
+Open Policy Agent is a project that allows you to implement policies
+as code in any project. You can rely on Open Policy Agent for any
+policy based check that you might require in your own application,
+that will in turn execute the required Rego policies.
+
+In this context, writing policies for Kubernetes is just another way
+of exercising Open Policy Agent. By using Kubernetes admission
+webhooks, it's possible leverage Kubernetes' admission webhooks to
+evaluate requests using Open Policy Agent, that will in turn execute
+the policies written in Rego.
+
+Open Policy Agent has some optional integration with Kubernetes
+through its `kube-mgmt` sidecar. When deployed on top of Kubernetes
+and next to the Open Policy Agent server evaluating the Rego policies,
+it is able to replicate the configured Kubernetes resources into Rego
+-- so those Kubernetes resources are visible to all policies. It aalso
+lets you define policies inside Kubernetes' configmaps. You can read
+more about it on [its project
+page](https://github.com/open-policy-agent/kube-mgmt).
+
+### Gatekeeper
+
+Gatekeeper is very different from Open Policy Agent in this regard. It
+is focused exclusively to be used in Kubernetes, and takes advantage
+of that as much as it can, making some Kubernetes workflows easier
+than Open Policy Agent in many cases.
+
+## Looking at the differences
+
+Both Open Policy Agent and Gatekeeper policies use Rego to describe
+their policies as code. However, this is only one part of the
+puzzle. Each solution has differences when it comes to writing real
+policies in Rego, and we are going to look at those differences in the
+next sections.
diff --git a/src/writing-policies/rego/02-builtin-support.md b/src/writing-policies/rego/02-builtin-support.md
new file mode 100644
index 0000000000..4c91393123
--- /dev/null
+++ b/src/writing-policies/rego/02-builtin-support.md
@@ -0,0 +1,102 @@
+# Builtin support
+
+Building a policy for the `wasm` target is only half of the problem,
+it needs to be executed.
+
+The Open Policy Agent team has a dedicated page you can check in order
+to [find out the built-in support
+level](https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions).
+
+Every green check in this table means that those built-ins are
+implemented regardless of the runtime: they are built on top of other
+functions and are implemented already on the policy you have built.
+
+The built-ins marked as `SDK-dependent` are the ones that the host has
+to implement -- in this case, Kubewarden. Open Policy Agent may use
+them in order to build the rest of the built-ins. In any case, this
+built-ins are exposed to the policy and any new or existing policy
+could depend on them.
+
+This is the built-ins implemented up until now in Kubewarden:
+
+
+| Category | Built-in | Status |
+|--------------------|---------------------------------------------|-------------|
+| Numbers | `rand.intn` | - |
+|
| | |
+| Objects | `json.patch` | - |
+|
| | |
+| Strings | `sprintf` | Implemented |
+|
| | |
+| Regex | `regex.split` | - |
+| | `regex.globs_match` | - |
+| | `regex.template_match` | - |
+| | `regex.find_n` | - |
+|
| | |
+| Glob | `glob.quote_meta` | - |
+|
| | |
+| Units | `units.parse_bytes` | - |
+|
| | |
+| Encoding | `base64url.encode_no_pad` | - |
+| | `urlquery.encode` | - |
+| | `urlquery.encode_object` | - |
+| | `urlquery.decode` | - |
+| | `urlquery.decode_object` | - |
+| | `json.is_valid` | - |
+| | `yaml.marshal` | - |
+| | `yaml.unmarshal` | - |
+| | `yaml.is_valid` | - |
+| | `hex.encode` | - |
+| | `hex.decode` | - |
+|
| | |
+| Token Signing | `io.jwt.encode_sign_raw` | - |
+| | `io.jwt.encode_sign` | - |
+|
| | |
+| Token Verification | `io.jwt.verify_rs256` | - |
+| | `io.jwt.verify_rs384` | - |
+| | `io.jwt.verify_rs512` | - |
+| | `io.jwt.verify_ps256` | - |
+| | `io.jwt.verify_ps384` | - |
+| | `io.jwt.verify_ps512` | - |
+| | `io.jwt.verify_es256` | - |
+| | `io.jwt.verify_es384` | - |
+| | `io.jwt.verify_es512` | - |
+| | `io.jwt.verify_hs256` | - |
+| | `io.jwt.verify_hs384` | - |
+| | `io.jwt.verify_hs512` | - |
+| | `io.jwt.decode` | - |
+| | `io.jwt.decode_verify` | - |
+|
| | |
+| Time | `time.now_ns` | - |
+| | `time.parse_ns` | - |
+| | `time.parse_rfc3339_ns` | - |
+| | `time.parse_duration_ns` | - |
+| | `time.date` | - |
+| | `time.clock` | - |
+| | `time.weekday` | - |
+| | `time.add_date` | - |
+| | `time.diff` | - |
+|
| | |
+| Cryptography | `crypto.x509.parse_certificates` | - |
+| | `crypto.x509.parse_and_verify_certificates` | - |
+| | `crypto.x509.parse_certificate_request` | - |
+| | `crypto.md5` | - |
+| | `crypto.sha1` | - |
+| | `crypto.sha256` | - |
+|
| | |
+| HTTP | `http.send` | - |
+|
| | |
+| Net | `net.cidr_contains_matches` | - |
+| | `net.cidr_expand` | - |
+| | `net.cidr_merge` | - |
+|
| | |
+| UUID | `uuid.rfc4122` | - |
+|
| | |
+| Semantic Versions | `semver.is_valid` | - |
+| | `semver.compare` | - |
+|
| | |
+| Rego | `rego.parse_module` | - |
+|
| | |
+| OPA | `opa.runtime` | - |
+|
| | |
+| Debugging | `trace` | - |
diff --git a/src/writing-policies/rego/gatekeeper/01-intro.md b/src/writing-policies/rego/gatekeeper/01-intro.md
new file mode 100644
index 0000000000..3db2b4dd0f
--- /dev/null
+++ b/src/writing-policies/rego/gatekeeper/01-intro.md
@@ -0,0 +1,19 @@
+# Gatekeeper
+
+Gatekeeper is a project targeting Kubernetes, and as such, has some
+features that are thought out of the box for being integrated with it.
+
+## Compatibility with existing policies
+
+All Gatekeeper policies that you have written already should be
+compatible with Kubewarden as we will explain during this chapter.
+
+> **Note**: if this is not the case, please report it to us and we
+> will do our best to make sure your policy runs flawlessly in
+> Kubewarden.
+
+They have to be recompiled with the `opa` CLI to the `wasm` target.
+
+In terms of policy execution, you can read more about the [Open Policy
+Agent built-in support that is implemented in
+Kubewarden](../02-builtin-support.md).
diff --git a/src/writing-policies/rego/gatekeeper/02-create-policy.md b/src/writing-policies/rego/gatekeeper/02-create-policy.md
new file mode 100644
index 0000000000..d53ee92379
--- /dev/null
+++ b/src/writing-policies/rego/gatekeeper/02-create-policy.md
@@ -0,0 +1,48 @@
+# Create a new policy
+
+Let's implement the same policy that [we wrote with Open Policy
+Agent](../open-policy-agent/02-create-policy.md): a policy that
+rejects a resource if it's targeting the `default` namespace.
+
+## Requirements
+
+As in the previous section, we will require the following tools:
+
+- `opa`
+- `kwctl`
+
+## The policy
+
+Since Gatekeeper is targeting Kubernetes, it has the freedom to be
+more handy in what the policy has to return.
+
+With Open Policy Agent we had to construct a whole `AdmissionReview`
+object as the response of our policy. With Gatekeeper, we only have to
+return none or more violations from our policy entrypoint.
+
+If none violations were reported, the request will be accepted. If
+one, or more violations were reported, the request will be rejected.
+
+We create a new folder, named `rego-policy`. Inside of it, we create a
+`policy.rego` file with contents:
+
+```rego
+package policy
+
+violation[{"msg": msg}] {
+ input.review.object.metadata.namespace == "default"
+ msg := "it is forbidden to use the default namespace"
+}
+```
+
+In this case, our entrypoint is `policy/violation`, and because of how
+Rego works, it can either have 1 violation: if the object to be
+reviewed is targeting the `default` namespace, or 0 violations
+otherwise.
+
+Take a moment to compare this policy with the one we wrote in the Open
+Policy Agent section. That one had to build the whole
+`AdmissionReview` response, and the inputs were slightly
+different. In the Gatekeeper mode, the `AdmissionRequest` object is
+provided at the `input.review` attribute. All attributes of the
+`AdmissionRequest` are readable along with `object`.
diff --git a/src/writing-policies/rego/gatekeeper/03-build-and-run.md b/src/writing-policies/rego/gatekeeper/03-build-and-run.md
new file mode 100644
index 0000000000..4c9a4ab879
--- /dev/null
+++ b/src/writing-policies/rego/gatekeeper/03-build-and-run.md
@@ -0,0 +1,82 @@
+# Build and run
+
+Building and running the policy is done exactly the same as a Rego
+policy targeting Open Policy Agent. The structure is like:
+
+```
+.
+├── data
+│ ├── default-ns.json
+│ └── other-ns.json
+└── policy.rego
+
+1 directory, 3 files
+```
+
+## Build
+
+Let's build our policy by running the following `opa` command:
+
+```shell
+~/gatekeeper-policy » opa build -t wasm -e policy/violation policy.rego
+```
+
+What this does is build the rego policy, with:
+
+- `target`: `wasm`. We want to build the policy for the `wasm` target.
+- `entrypoint`: `policy/main`. The entry point is the `main` rule
+inside the `policy` package.
+- `policy.rego`: build and include the `policy.rego` file.
+- `request.rego`: build and include the `request.rego` file.
+
+After the build is complete, `opa build` will have generated a
+`bundle.tar.gz` file. You can extract it:
+
+```shell
+gatekeeper-policy » tar -xf bundle.tar.gz /policy.wasm
+```
+
+The tree looks like:
+
+```
+.
+├── bundle.tar.gz
+├── data
+│ ├── default-ns.json
+│ └── other-ns.json
+├── policy.rego
+└── policy.wasm
+
+1 directory, 5 files
+```
+
+We can now execute our policy!
+
+## Run
+
+Let's use `kwctl` to run our policy as follows:
+
+```
+gatekeeper-policy » kwctl run -e gatekeeper --request-path data/other-ns.json policy.wasm | jq
+{
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "allowed": true
+}
+```
+
+Given that this is our resource created in the namespace called
+`other`, this resource is accepted, as expected. Now let's execute a
+request that will be rejected by the policy:
+
+```
+gatekeeper-policy » kwctl run -e gatekeeper --request-path data/default-ns.json policy.wasm | jq
+{
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "allowed": false,
+ "status": {
+ "message": "it is forbidden to use the default namespace"
+ }
+}
+```
+
+As you can see, our Gatekeeper policy rejected this resource as expected.
diff --git a/src/writing-policies/rego/gatekeeper/04-distribute.md b/src/writing-policies/rego/gatekeeper/04-distribute.md
new file mode 100644
index 0000000000..36b909fbcd
--- /dev/null
+++ b/src/writing-policies/rego/gatekeeper/04-distribute.md
@@ -0,0 +1,99 @@
+# Distribute
+
+Policies have to be annotated for them to be pushed, and eventually
+executed in the `policy-server` in a Kubernetes cluster.
+
+Annotating and distributing our gatekeeper policy is very similar to
+distribute an Open Policy Agent one. Let's go through it.
+
+## Annotating the policy
+
+We are going to write a `metadata.yaml` file in our policy directory
+with contents:
+
+```yaml
+rules:
+- apiGroups: [""]
+ apiVersions: ["*"]
+ resources: ["*"]
+ operations: ["CREATE"]
+mutating: false
+contextAware: false
+executionMode: gatekeeper
+annotations:
+ io.kubewarden.policy.title: no-default-namespace
+ io.kubewarden.policy.description: This policy will reject any resource created inside the default namespace
+ io.kubewarden.policy.author: The Kubewarden Authors
+ io.kubewarden.policy.url: https://github.com/kubewarden/some-policy
+ io.kubewarden.policy.source: https://github.com/kubewarden/some-policy
+ io.kubewarden.policy.license: Apache-2.0
+ io.kubewarden.policy.usage: |
+ This policy is just an example.
+
+ You can write interesting descriptions about the policy here.
+```
+
+As you can see, everything is the same as the Open Policy Agent
+version metadata, except for the `executionMode: gatekeeper` bit.
+
+Let's go ahead and annotate the policy:
+
+```console
+gatekeeper-policy » kwctl annotate policy.wasm --metadata-path metadata.yaml --output-path annotated-policy.wasm
+```
+
+## Pushing the policy
+
+Let's push our policy to an OCI registry:
+
+```console
+gatekeeper-policy » kwctl push annotated-policy.wasm registry.my-company.com/kubewarden/no-default-namespace-gatekeeper:v0.0.1
+Policy successfully pushed
+```
+
+## Creating a scaffold manifest
+
+We have to pull our policy to our `kwctl` local store first:
+
+```console
+» kwctl pull registry://registry.my-company.com/kubewarden/no-default-namespace-gatekeeper:v0.0.1
+pulling policy...
+```
+
+Now, we can check that the policy is listed as expected:
+
+```console
+» kwctl policies
++--------------------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+| Policy | Mutating | Context aware | SHA-256 | Size |
++--------------------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+| registry://registry.my-company.com/kubewarden/no-default-namespace-gatekeeper:v0.0.1 | no | no | 0e34c374db2e | 112.99 kB |
++--------------------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+```
+
+We can now create a scaffold `ClusterAdmissionPolicy` resource:
+
+```console
+» kwctl manifest registry://registry.my-company.com/kubewarden/no-default-namespace-gatekeeper:v0.0.1 --type ClusterAdmissionPolicy
+---
+apiVersion: policies.kubewarden.io/v1alpha2
+kind: ClusterAdmissionPolicy
+metadata:
+ name: generated-policy
+spec:
+ module: "registry://registry.my-company.com/kubewarden/no-default-namespace-gatekeeper:v0.0.1"
+ settings: {}
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - "*"
+ resources:
+ - "*"
+ operations:
+ - CREATE
+ mutating: false
+```
+
+We could now use this `ClusterAdmissionPolicy` resource to deploy our
+policy to a Kubernetes cluster.
diff --git a/src/writing-policies/rego/open-policy-agent/01-intro.md b/src/writing-policies/rego/open-policy-agent/01-intro.md
new file mode 100644
index 0000000000..9bc3995f84
--- /dev/null
+++ b/src/writing-policies/rego/open-policy-agent/01-intro.md
@@ -0,0 +1,28 @@
+# Open Policy Agent
+
+Open Policy Agent is a general purpose policy framework. This is the
+reason why we can use regular Rego policies with Open Policy Agent
+when targeting Kubernetes as if it was any other application taking
+advantage of it.
+
+## Introduction
+
+Rego policies work by receiving an input to evaluate, and produce an
+output as a response. In this sense, Open Policy Agent has no specific
+tooling for targeting writing policies for Kubernetes.
+
+Specifically, policies in Open Policy Agent receive a JSON input and
+produce a JSON output. When the Open Policy Agent server is set up to
+receive admission review requests from Kubernetes, policies will
+receive a Kubernetes `AdmissionReview` object in JSON format with the
+object to evaluate, and it has to produce a valid `AdmissionReview`
+object in return with the evaluation results.
+
+## Compatibility with existing policies
+
+All policies can be compiled to the `wasm` target (WebAssembly) with
+the official `opa` CLI tool.
+
+In terms of policy execution, you can read more about the [Open Policy
+Agent built-in support that is implemented in
+Kubewarden](../02-builtin-support.md).
diff --git a/src/writing-policies/rego/open-policy-agent/02-create-policy.md b/src/writing-policies/rego/open-policy-agent/02-create-policy.md
new file mode 100644
index 0000000000..b82d08b0d9
--- /dev/null
+++ b/src/writing-policies/rego/open-policy-agent/02-create-policy.md
@@ -0,0 +1,162 @@
+# Create a new policy
+
+Let's create a sample policy that will help us go through some
+important concepts. Let's start!
+
+## Requirements
+
+We will write, compile and execute the policy on this section. You
+need some tools in order to complete this tutorial:
+
+- [`opa`](https://github.com/open-policy-agent/opa/releases): we
+will use the `opa` CLI to build our policy to a `wasm` target.
+
+- [`kwctl`](https://github.com/kubewarden/kwctl/releases): we will use
+`kwctl` to execute our built policy.
+
+## The policy
+
+We are going to create a policy that is going to evaluate any kind of
+namespaced resource. Its goal is to forbid the creation of any
+resource if the target namespace is `default`. Otherwise, the request
+will be accepted. Let's start by creating a folder called
+`opa-policy`.
+
+We are going to create a folder named `data` inside of the
+`opa-policy` folder. This folder will contain the recorded
+`AdmissionReview` objects from the Kubernetes API server. I reduced
+them greatly in purpose for the sake of simplicity for the exercise,
+so we can focus on the bits that matter.
+
+I first create a `default-ns.json` file with contents inside the
+`data` directory:
+
+```json
+{
+ "apiVersion": "admission.k8s.io/v1",
+ "kind": "AdmissionReview",
+ "request": {
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "operation": "CREATE",
+ "object": {
+ "kind": "Pod",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "nginx",
+ "namespace": "default",
+ "uid": "04dc7a5e-e1f1-4e34-8d65-2c9337a43e64"
+ }
+ }
+ }
+}
+```
+
+This simulates a pod operation creation inside the `default`
+namespace. Now, let's create another request example in
+`other-ns.json` inside the `data` directory:
+
+```json
+{
+ "apiVersion": "admission.k8s.io/v1",
+ "kind": "AdmissionReview",
+ "request": {
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "operation": "CREATE",
+ "object": {
+ "kind": "Pod",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "nginx",
+ "namespace": "other",
+ "uid": "04dc7a5e-e1f1-4e34-8d65-2c9337a43e64"
+ }
+ }
+ }
+}
+```
+
+As you can see, this simulates another pod creation request, this time
+under a namespace called `other`.
+
+Let's go back to our `opa-policy` folder and start writing our Rego policy.
+
+Inside this folder, we create a file named `request.rego` inside the
+`opa-policy` folder. The name can be anything, but we'll use that one
+for this exercise. As the name suggests, this is a Rego file that has
+some utility code regarding the request/response itself: in
+particular, it allows us to simplify our policy code itself and reuse
+this common bit across different policies if desired. The contents
+are:
+
+```rego
+package policy
+
+import data.kubernetes.admission
+
+main = {
+ "apiVersion": "admission.k8s.io/v1",
+ "kind": "AdmissionReview",
+ "response": response,
+}
+
+response = {
+ "uid": input.request.uid,
+ "allowed": false,
+ "status": {"message": reason},
+} {
+ reason = concat(", ", admission.deny)
+ reason != ""
+} else = {
+ "uid": input.request.uid,
+ "allowed": true,
+} {
+ true
+}
+```
+
+We will not go too deep into the Rego code itself. You can learn about
+it in depth in its website and y reading its documentation.
+
+Suffice to say that in this case, it will return either `allowed:
+true` or `allowed: false` depending on whether other package
+(`data.kubernetes.admission`) has any `deny` statement that evaluates
+to `true`.
+
+If any `data.kubernetes.admission.deny` evaluates to `true`, the
+`response` here will evaluate to the first block. Otherwise, it will
+evaluate to the second block -- leading to acceptance, because no
+`deny` block evaluated to `true`, this means we are accepting the
+request.
+
+Now, this is just the shell of the policy, the utility. Now, we create
+another file, called, for example `policy.rego` inside our
+`opa-policy` folder with the following contents:
+
+```rego
+package kubernetes.admission
+
+deny[msg] {
+ input.request.object.metadata.namespace == "default"
+ msg := "it is forbidden to use the default namespace"
+}
+```
+
+This is our policy. The important part. `deny` will evaluate to true
+if all statements within it evaluate to true. In this case, is only
+one statement: checking if the namespace is `default`.
+
+By Open Policy Agent design, `input` contains the queriable object
+with the `AdmissionReview` object, so we can inspect it quite easily.
+
+If everything went well, our tree should look like the following:
+
+```
+.
+├── data
+│ ├── default-ns.json
+│ └── other-ns.json
+├── policy.rego
+└── request.rego
+
+1 directory, 4 files
+```
diff --git a/src/writing-policies/rego/open-policy-agent/03-build-and-run.md b/src/writing-policies/rego/open-policy-agent/03-build-and-run.md
new file mode 100644
index 0000000000..9c40459512
--- /dev/null
+++ b/src/writing-policies/rego/open-policy-agent/03-build-and-run.md
@@ -0,0 +1,102 @@
+# Build and run
+
+In the previous section we have written our Rego policy. The structure
+looks as the following:
+
+```
+.
+├── data
+│ ├── default-ns.json
+│ └── other-ns.json
+├── policy.rego
+└── request.rego
+
+1 directory, 4 files
+```
+
+## Build
+
+We have our policy, now let's go ahead and build it. We do:
+
+```shell
+~/opa-policy » opa build -t wasm -e policy/main policy.rego request.rego
+```
+
+What this does is build the rego policy, with:
+
+- `target`: `wasm`. We want to build the policy for the `wasm` target.
+- `entrypoint`: `policy/main`. The entry point is the `main` rule
+inside the `policy` package.
+- `policy.rego`: build and include the `policy.rego` file.
+- `request.rego`: build and include the `request.rego` file.
+
+After the build is complete, `opa build` will have generated a
+`bundle.tar.gz` file. You can extract it:
+
+```shell
+opa-policy » tar -xf bundle.tar.gz /policy.wasm
+```
+
+Now the tree looks like the following:
+
+```shell
+.
+├── bundle.tar.gz
+├── data
+│ ├── default-ns.json
+│ └── other-ns.json
+├── policy.rego
+├── policy.wasm
+└── request.rego
+
+1 directory, 6 file
+```
+
+We have our precious `policy.wasm` file:
+
+```shell
+opa-policy » file policy.wasm
+policy.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)
+```
+
+Now it's time to execute it! Let's go on.
+
+## Run
+
+We are going to use `kwctl` in order to run the policy:
+
+```
+opa-policy » kwctl run -e opa --request-path data/other-ns.json policy.wasm | jq
+{
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "allowed": true
+}
+```
+
+This request is accepted by the policy, since this is the request
+pointing to the `other` namespace.
+
+- `execution-mode`: `opa`. Rego policies can be targeting Open Policy
+ Agent or Gatekeeper: we must tell `kwctl` what kind of policy we are
+ running.
+
+
+- `request-path`: the location of the recorded request `kwctl` will
+ send to the policy to evaluate.
+
+Now let's try to evaluate the request that creates the pod inside the
+`default` namespace:
+
+```
+opa-policy » kwctl run -e opa --request-path data/default-ns.json policy.wasm | jq
+{
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "allowed": false,
+ "status": {
+ "message": "it is forbidden to use the default namespace"
+ }
+}
+```
+
+In this case, the policy is rejecting the request, and giving a reason
+back to the API server that will be returned to the user or API consumer.
diff --git a/src/writing-policies/rego/open-policy-agent/04-distribute.md b/src/writing-policies/rego/open-policy-agent/04-distribute.md
new file mode 100644
index 0000000000..339f4f0ffe
--- /dev/null
+++ b/src/writing-policies/rego/open-policy-agent/04-distribute.md
@@ -0,0 +1,139 @@
+# Distribute
+
+We have written, built and run our Rego policy. Now it's time to
+distribute the policy.
+
+Policies have to be annotated in order for them to be executed in the
+`policy-server`, the component that executes the policies when running
+in a Kubernets cluster.
+
+Also, the command we used to execute from the previous section also
+signals a limitation:
+
+```
+opa-policy » kwctl run -e opa --request-path data/default-ns.json policy.wasm | jq
+{
+ "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
+ "allowed": false,
+ "status": {
+ "message": "it is forbidden to use the default namespace"
+ }
+}
+```
+
+As you can see, we had to provide the execution mode. When executing
+an unannotated policy written in Rego is not trivial to determine
+whether the target framework is Open Policy Agent or Gatekeeper. This
+is why when executing an unannotated policy built with `opa build`
+`kwctl` cannot know what is the target.
+
+## Annotating the policy
+
+In order to get rid of this limitations, we will annotate the
+policy. This is not only useful for what we have already described,
+but also because the annotation of the policy contains valuable
+information that always travels with the policy.
+
+Let's write a simple `metadata.yaml` file:
+
+```yaml
+rules:
+- apiGroups: [""]
+ apiVersions: ["*"]
+ resources: ["*"]
+ operations: ["CREATE"]
+mutating: false
+contextAware: false
+executionMode: opa
+annotations:
+ io.kubewarden.policy.title: no-default-namespace
+ io.kubewarden.policy.description: This policy will reject any resource created inside the default namespace
+ io.kubewarden.policy.author: The Kubewarden Authors
+ io.kubewarden.policy.url: https://github.com/kubewarden/some-policy
+ io.kubewarden.policy.source: https://github.com/kubewarden/some-policy
+ io.kubewarden.policy.license: Apache-2.0
+ io.kubewarden.policy.usage: |
+ This policy is just an example.
+
+ You can write interesting descriptions about the policy here.
+```
+
+In this case, you can see several details:
+
+- Rules: what resources this policy is targeting
+- Mutating: whether this policy is mutating. In this case, is just
+validating.
+- Context aware: whether this policy requires context from the
+cluster in order to evaluate the request.
+- Execution mode: since this is a Rego policy it is mandatory to
+specify what execution mode it expects: `opa` or `gatekeeper`. This
+policy is written in the `opa` style: returning a whole
+`AdmissionReview` object.
+- Annotations: metadata stored into the policy itself.
+
+Let's go ahead and annotate our policy:
+
+```console
+opa-policy » kwctl annotate policy.wasm --metadata-path metadata.yaml --output-path annotated-policy.wasm
+```
+
+Now you can `inspect` the policy if you will by running `kwctl inspect annotated-policy.wasm`.
+
+## Pushing the policy
+
+Now that the policy is annotated we can push it to an OCI
+registry. Let's do that:
+
+```console
+opa-policy » kwctl push annotated-policy.wasm registry.my-company.com/kubewarden/no-default-namespace:v0.0.1
+Policy successfully pushed
+```
+
+Now our Rego policy targeting the OPA framework has everything it
+needs to be deployed in production by creating a
+`ClusterAdmissionPolicy`. Let's prepare that too. First, we have to
+pull the policy into the `kwctl` local store:
+
+```console
+» kwctl pull registry://registry.my-company.com/kubewarden/no-default-namespace:v0.0.1
+pulling policy...
+```
+
+Now, we can check that the policy is listed as expected:
+
+```console
+» kwctl policies
++---------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+| Policy | Mutating | Context aware | SHA-256 | Size |
++---------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+| registry://registry.my-company.com/kubewarden/no-default-namespace:v0.0.1 | no | no | 55290dc1ba87 | 114.66 kB |
++---------------------------------------------------------------------------+----------+---------------+--------------+-----------+
+```
+
+Now, let's create a `ClusterAdmissionPolicy` out of it. This operation
+will take into account the metadata it has about the policy:
+
+```console
+» kwctl manifest registry://registry.my-company.com/kubewarden/no-default-namespace:v0.0.1 --type ClusterAdmissionPolicy
+---
+apiVersion: policies.kubewarden.io/v1alpha2
+kind: ClusterAdmissionPolicy
+metadata:
+ name: generated-policy
+spec:
+ module: "registry://registry.my-company.com/kubewarden/no-default-namespace:v0.0.1"
+ settings: {}
+ rules:
+ - apiGroups:
+ - ""
+ apiVersions:
+ - "*"
+ resources:
+ - "*"
+ operations:
+ - CREATE
+ mutating: false
+```
+
+You can now use this `ClusterAdmissionPolicy` as a base to target the
+resources that you want, or deploy to Kubernetes as is.