> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gorules.io/llms.txt
> Use this file to discover all available pages before exploring further.

# GoRules CLI

> Bridge your GoRules BRMS projects to local development, AI tooling, and CI/CD pipelines.

The GoRules CLI (`@gorules/cli`) is an open-source command-line tool for [GoRules BRMS](https://gorules.io). It exposes an MCP (Model Context Protocol) server so AI-powered editors like Claude Code, Cursor, and Windsurf can read, evaluate, and interact with your decision logic directly, and it ships rules from BRMS into your own infrastructure with [`gorules pull`](#pulling-rules-into-a-pipeline).

**npm:** [@gorules/cli](https://www.npmjs.com/package/@gorules/cli)

## Installation

```bash theme={null}
# npm
npm install -g @gorules/cli

# Or run directly with npx
npx @gorules/cli mcp start
```

## Quick start

Start the MCP bridge:

```bash theme={null}
gorules mcp start
```

This launches a local server on port 41919 that:

1. Exposes an MCP endpoint for AI tools to discover and call GoRules tools
2. Exposes REST endpoints for evaluating decisions and fetching decision files
3. Opens a WebSocket connection that the GoRules browser editor connects to

Once running, open your GoRules project in the browser and click **Connect MCP** to link the editor to your local CLI.

## Commands

### `gorules mcp start`

Start the MCP bridge server.

| Flag | Alias | Default | Description |
| - | - | - | - |
| `--port` | `-p` | `41919` | Server port |
| `--host` | `-h` | `localhost` | Server host |
| `--url` | `-u` | - | GoRules server URL |
| `--open` | - | `false` | Open browser on start |

### `gorules pull`

Download the rules artifact for a project target. See [Pulling rules into a pipeline](#pulling-rules-into-a-pipeline).

| Flag | Alias | Env | Description |
| - | - | - | - |
| `--project` | `-p` | `GORULES_PROJECT` | Project key or ID |
| `--target` | `-t` | `GORULES_TARGET` | Target to resolve (default `main`) |
| `--out` | `-o` | - | Output directory (default `.`) |
| `--unpack` | - | - | Extract the archive instead of writing the zip |
| `--delete` | - | - | With `--unpack`: delete files not in the artifact so the directory mirrors the target exactly |
| `--name` | - | - | Output file name (zip) or sub-directory name (`--unpack`); defaults to the project key with no extension |
| `--current` | - | - | Release or commit ID you already hold; exits `3` when unchanged |
| `--url` | `-u` | `GORULES_URL` | BRMS URL |
| `--token` | - | `GORULES_TOKEN` | Project access token |
| `--json` | - | - | Print the result as JSON on stdout |

## Pulling rules into a pipeline

`gorules pull` resolves a target in BRMS through the Rules Sync API and downloads the matching rules artifact. It is the building block for shipping rules from BRMS into your own infrastructure: a CI job pulls the artifact and uploads it wherever your runtime - typically the [Agent](/developers/deployment/agent/overview) - reads it from.

For end-to-end pipelines - BRMS webhook to object storage, with environment routing - see the CI/CD integration guides for [GitHub Actions](/developers/cicd/github-actions), [GitLab CI](/developers/cicd/gitlab-ci), and [Azure DevOps](/developers/cicd/azure-devops).

```bash theme={null}
export GORULES_URL=https://acme.us1.gorules.io
export GORULES_TOKEN=...            # project access token, read scope is enough

gorules pull --project pricing --target env:production --out ./dist
aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive
```

Run it in a pipeline with npx:

```bash theme={null}
npx @gorules/cli@latest pull --project pricing --target env:production
```

For reproducible production pipelines, pin a released version (`@gorules/cli@<version>`, action/template tag `cli-v<version>`) instead of tracking latest.

### Targets

| Target | Resolves to |
| - | - |
| `main` (default) | Latest commit on the default branch |
| `branch:<branchId>` | Latest commit on that branch |
| `commit:<commitId>` | That exact commit, pinned |
| `release:<version>` | That release, by semantic version or ID |
| `env:<key>` | Whichever release is deployed to that environment |

### Naming the output

By default the artifact is written as `<project-key>` with **no** `.zip` suffix, because the Agent's S3, GCS, and Azure Blob providers use the object name verbatim as the project key. The Agent's local `zip` provider is the opposite - it reads `<root>/<project>.zip` and strips the suffix itself - so that destination needs `--name pricing.zip`.

With `--unpack`, `--name` is the sub-directory to extract into (default: the project key, the layout the Agent's `filesystem` provider expects). Pass `--name .` to extract straight into `--out`, which is what you want when baking rules into a container image:

```bash theme={null}
gorules pull --project pricing --target release:1.4.2 --out ./rules --unpack --name .
```

Extraction behaves like `aws s3 sync`: byte-identical files are left untouched, changed files are written atomically, and files the artifact does not carry are preserved. Add `--delete` for `s3 sync --delete` semantics, so rules deleted in BRMS are deleted on disk too. As a guard against wiping a directory it does not own, `--delete` refuses a non-empty destination without a `.config/project.json` from a previous pull.

### Exit codes

Pipelines branch on the exit code:

| Code | Meaning |
| - | - |
| `0` | Artifact downloaded |
| `1` | Error |
| `2` | Usage error (missing or invalid arguments) |
| `3` | Nothing to do (`--current` matched what is deployed) |
| `4` | No release is deployed to the target |

### GitHub Actions

A composite action lives in the [gorules/cli](https://github.com/gorules/cli) repository, so the tag you pin is the CLI version you get. A `payload` sent by a BRMS [webhook](/brms/setup/webhooks) via `workflow_dispatch` is picked up automatically.

```yaml theme={null}
jobs:
  rules:
    runs-on: ubuntu-latest
    steps:
      # Pin to the latest release tag (cli-vX.Y.Z) rather than @main in production
      - uses: gorules/cli/actions/pull@main
        id: rules
        with:
          url: https://acme.us1.gorules.io
          token: ${{ secrets.GORULES_TOKEN }}
          # no project/target: a BRMS-triggered run supplies both via the payload
          out: ./dist

      - name: Deploy to S3
        env:
          PROJECT: ${{ steps.rules.outputs.project }}
          TARGET: ${{ steps.rules.outputs.target }}
        run: |
          case "$TARGET" in
            env:production) BUCKET=acme-rules-prod ;;
            env:dev)        BUCKET=acme-rules-dev ;;
            *) echo "Refusing to deploy target '$TARGET'" >&2; exit 1 ;;
          esac
          aws s3 cp "./dist/$PROJECT" "s3://$BUCKET/rules/$PROJECT"
```

The action outputs `project`, `target` (payload-aware), `changed`, `release`, `version`, `commit`, `sha256`, and `files`, so the workflow routes on what was actually pulled and a scheduled workflow can skip the upload when nothing moved.

### GitLab CI

`templates/gitlab-ci-pull.yml` defines a hidden job you extend. `GORULES_URL` and `GORULES_TOKEN` are CI/CD variables; mask and protect the token.

```yaml theme={null}
include:
  # Pin to the latest release tag (cli-vX.Y.Z) rather than main in production
  - remote: 'https://raw.githubusercontent.com/gorules/cli/main/templates/gitlab-ci-pull.yml'

pull:rules:
  extends: .gorules-pull
  # no project/target: a BRMS-triggered run supplies both via GRL_PAYLOAD

publish:rules:
  needs: ['pull:rules']
  script:
    # rules: cannot see dotenv variables (evaluated before jobs run) - guard in script
    - if [ "$RULES_CHANGED" != "true" ]; then exit 0; fi
    - |
      case "$RULES_TARGET" in
        env:production) BUCKET=acme-rules-prod ;;
        env:dev)        BUCKET=acme-rules-dev ;;
        *) echo "No destination for '$RULES_TARGET'"; exit 1 ;;
      esac
    - aws s3 cp "dist/$RULES_PROJECT" "s3://$BUCKET/rules/$RULES_PROJECT"
```

The job publishes `RULES_CHANGED`, `RULES_PROJECT`, `RULES_TARGET`, `RULES_VERSION`, `RULES_RELEASE`, and `RULES_SHA256` as a dotenv report, so later jobs read them as ordinary variables.

### Azure Pipelines

`templates/azure-pipelines-pull.yml` is a steps template: it pulls the artifact and sets result variables, and you append your own publish step in the same job. `GORULES_TOKEN` must exist as a secret pipeline variable or in a linked variable group.

```yaml theme={null}
resources:
  repositories:
    - repository: gorules
      type: github
      name: gorules/cli
      ref: refs/heads/main # pin to the latest release tag (cli-vX.Y.Z) in production
      endpoint: <your GitHub service connection>

jobs:
  - job: deploy_rules
    pool:
      vmImage: ubuntu-latest
    steps:
      - template: templates/azure-pipelines-pull.yml@gorules
        parameters:
          url: https://acme.us1.gorules.io
          # no project/target: a BRMS-triggered run supplies both via GRL_PAYLOAD

      - script: |
          case "$(rulesTarget)" in
            env:production) BUCKET=acme-rules-prod ;;
            env:dev)        BUCKET=acme-rules-dev ;;
            *) echo "Refusing to deploy target '$(rulesTarget)'"; exit 1 ;;
          esac
          aws s3 cp "$(Build.ArtifactStagingDirectory)/rules/$(rulesProject)" "s3://$BUCKET/rules/$(rulesProject)"
        displayName: Deploy to S3
```

The template sets `rulesChanged`, `rulesProject`, `rulesTarget` (payload-aware), `rulesVersion`, `rulesRelease`, and `rulesSha256` for the steps that follow.

<Note>
  For BRMS-triggered runs, the pipeline must accept the `GRL_PAYLOAD` variable at queue time: add a pipeline variable named `GRL_PAYLOAD` with "Let users override this value when running this pipeline" checked. Organizations with "Limit variables that can be set at queue time" enabled reject the queue request otherwise.
</Note>

## REST API

When the bridge is running, it exposes HTTP endpoints for local development.

### Evaluate a decision

```bash theme={null}
POST http://localhost:41919/evaluate/{filePath}
```

```json theme={null}
{
  "context": {
    "customer": { "tier": "premium" },
    "orderTotal": 150
  },
  "trace": false
}
```

Response:

```json theme={null}
{
  "result": { "discount": 0.15, "freeShipping": true }
}
```

Optional body fields: `trace` (boolean), `maxDepth` (number).

### Retrieve a decision file

```bash theme={null}
GET http://localhost:41919/file/{filePath}
```

Returns the raw decision graph JSON. You can use this as a loader for the ZEN Engine:

```javascript theme={null}
import { ZenEngine } from "@gorules/zen-engine";

const engine = new ZenEngine({
  loader: async (key) => {
    const res = await fetch(`http://localhost:41919/file/${key}`);
    return res.json();
  },
});

const result = await engine.evaluate("my-decision", {
  customer: { tier: "premium" },
  orderTotal: 150,
});
```

## How it works

The CLI acts as a bridge between AI tools and the GoRules browser editor:

```mermaid theme={null}
graph TD
    A[AI Tool - Claude, Cursor, etc.] -->|MCP Protocol| B[GoRules CLI - localhost:41919]
    B -->|WebSocket| C[GoRules Browser Editor]
    C -->|API| D[GoRules BRMS Platform]
```

1. The CLI starts and generates a connection token
2. The GoRules browser editor connects via WebSocket using the token
3. The editor sends a tool manifest - the list of available tools for that project
4. AI tools discover these tools via MCP and invoke them
5. The CLI forwards tool calls to the browser, which executes them and returns results

The CLI is stateless - it doesn't store credentials or project data. All tool execution happens in the browser editor, which has an authenticated session with the GoRules platform.

## License

MIT


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