> For the complete documentation index, see [llms.txt](https://govplane.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://govplane.gitbook.io/docs/documentation/getting-started/quickstart.md).

# Quickstart

Govplane allows you to replace your hard-coded `if` statements that govern your application with a **signed policy bundle** your code evaluates locally.

In about five minutes you will write a policy, build and sign a bundle, prove it behaves, and evaluate it from an application. **Everything below runs on your machine** — no account, no server, no network.

**You need:** Node.js 20.19 or later.

### 1. Install

```bash
npm install --global @govplane/cli @govplane/cli-toolkit
govplane version
```

Two packages, one `govplane` command:

* **`@govplane/cli`** reads and verifies — `validate`, `inspect`. Zero dependencies, never touches the network.
* **`@govplane/cli-toolkit`** writes — `policies`, `build`, `sign`, `simulate`, `analyze`. Free.

```bash
govplane activate # It's free, you can also skip it for 30 days.
```

Activation is free and asks for an email address in your browser, nothing else. Once activated the toolkit never contacts Govplane again. **You can skip it for now** — the toolkit works for 30 days first, which is plenty for this quickstart. See Licensing.

### 2. Write a policy

The example: lock an account after five failed logins.

```bash
mkdir govplane-quickstart && cd govplane-quickstart
govplane policies create-file
govplane policies add-policy --policy-key login-protection --defaults-effect allow
```

```
Policy added: login-protection

Active version: 1
Defaults effect: allow
```

The policy allows by default. Now the exception — save this as `deny-retries.json`:

```json
{
  "id": "deny-after-five-failures",
  "status": "active",
  "priority": 100,
  "target": { "service": "auth", "resource": "login", "action": "authenticate" },
  "when": { "op": "gte", "path": "failedAttempts", "value": 5 },
  "effect": { "type": "deny" }
}
```

```bash
govplane policies add-rule --policy-key login-protection --rule-file ./deny-retries.json
```

```
Rule added to login-protection: deny-after-five-failures

Priority: 100
Effect: deny
```

The `5` now lives in a reviewable document instead of your source.

### 3. Check it

This is the basic CLI — it only reads.

```bash
govplane validate
```

```
✓ policy-drafts.json is valid

Type:     draft
Policies: 1
Rules:    1
Schema:   1.0
```

```bash
govplane inspect --policies
```

```
KEY               TARGET                       RULES  STATUS
login-protection  auth / login / authenticate  1      complete
```

### 4. Build a signed bundle

```bash
export GOVPLANE_HMAC_SECRET=$(openssl rand -hex 32)

govplane build --signed \
  --signing-algorithm HMAC_SHA256 \
  --hmac-secret-env GOVPLANE_HMAC_SECRET
```

```
Output:
  Bundle: policy-bundle.json
  Schema: 1
  Env: prod
  Bundle version: 1

Integrity:
  Checksum: sha256:ed3e1bc3165968d34ba07c63895b05e66a6a8533ad92a541f6789e054e75ef44

Signature:
  Enabled: yes
  Algorithm: HMAC_SHA256
  Key ID: local-key-01
```

`policy-bundle.json` is the artifact you ship. It is deterministic — the same draft always produces the same bytes.

{% hint style="info" %}
HMAC keeps this quickstart to one command. For a bundle you distribute, use `ECDSA_SHA_256` instead: the public half verifies it, so consumers never hold the signing key. See Configuring the Toolkit.

The build also warns that `orgId` and `projectId` are unset. For a local bundle that is fine — they only matter for Govplane Cloud.
{% endhint %}

### 5. Prove it behaves

```bash
govplane simulate --service auth --resource login --action authenticate \
  --context '{"failedAttempts":6}'
```

```
Decision:
  decision: deny
  reason: rule

Match:
  Policy: login-protection
  Rule: deny-after-five-failures
```

And below the threshold:

```bash
govplane simulate --service auth --resource login --action authenticate \
  --context '{"failedAttempts":2}' --trace full
```

```
Decision:
  decision: allow
  reason: default

Evaluation trace:
  Rules considered:
    login-protection / deny-after-five-failures  priority 100  skipped (when_false)

  Selected:
    login-protection / __default__ (priority -1, effect allow)
```

`simulate` runs the **same engine** your application will, so this is not an approximation.

### 6. Evaluate it from your application

{% hint style="warning" %}
**This step is Node.js.** `@govplane/runtime-sdk` is the reference SDK and the only one currently rebuilt on this architecture. **Java, Python and PHP SDKs are coming.** Steps 1–5 are language-neutral — the bundle you just built is a plain JSON document that every SDK will evaluate identically.
{% endhint %}

```bash
npm init -y
npm install @govplane/runtime-sdk
```

```js
// policy-check.mjs
import { createLocalClient } from '@govplane/runtime-sdk';

const govplane = await createLocalClient({
  bundlePath: './policy-bundle.json',
  verify: { algorithm: 'HMAC_SHA256', secret: process.env.GOVPLANE_HMAC_SECRET },
});

const target = { service: 'auth', resource: 'login', action: 'authenticate' };

console.log(govplane.status().signature);
console.log(JSON.stringify(govplane.evaluate({ target, context: { failedAttempts: 6 } })));
console.log(JSON.stringify(govplane.evaluate({ target, context: { failedAttempts: 2 } })));

govplane.close();
```

```bash
node policy-check.mjs
```

```
{ status: 'verified', algorithm: 'HMAC_SHA256', keyId: 'local-key-01' }
{"decision":"deny","reason":"rule","policyKey":"login-protection","ruleId":"deny-after-five-failures"}
{"decision":"allow","reason":"default","policyKey":"login-protection"}
```

The first line is the one that matters: **`status: 'verified'`** means the bundle's signature was checked before a single decision was made.

{% hint style="warning" %}
`GOVPLANE_HMAC_SECRET` lives in your shell, so a new terminal loses it and the check fails with:

```
BundleSignatureError: The bundle signature is not valid — it may have been modified after signing.
```

Set the same secret again, or rebuild. This is the right behaviour — the SDK refuses to evaluate a bundle it cannot verify — but it catches everyone once.
{% endhint %}

The same answers `simulate` gave. In real code:

```js
const decision = govplane.evaluate({
  target: { service: 'auth', resource: 'login', action: 'authenticate' },
  context: { failedAttempts },
});

if (decision.decision === 'deny') return lockAccount();
```

Evaluation is synchronous, in-process and offline. No network call, ever.

### What just happened

|                      |                                                          |
| -------------------- | -------------------------------------------------------- |
| `policy-drafts.json` | What you **edit** — reviewed like code                   |
| `policy-bundle.json` | What you **ship** — deterministic, checksummed, signed   |
| The SDK              | **Evaluates** it, locally, verifying the signature first |

Changing the threshold from 5 to 3 is now a rebuilt bundle, not a code release. Nothing in this loop depends on Govplane being reachable — which is the point.

### Next

* Policies and Rules — the concepts, properly
* A Practical Example, Start to End — this again, but thorough, starting from `govplane analyze` on real source
* CLI Overview · SDK Overview
* Effects — beyond allow and deny: throttle, kill switch, custom


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://govplane.gitbook.io/docs/documentation/getting-started/quickstart.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
