> 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
