Command-line tool for GoRules — a business rules management system (BRMS) for decision tables, decision graphs, and expressions.
npm install -g @gorules/cliOr run directly with npx (e.g. mcp start):
npx @gorules/cli mcp startgorules pull resolves a target in BRMS 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 reads it from.
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| 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 |
| Flag | Env | Description |
|---|---|---|
-p, --project |
GORULES_PROJECT |
Project key or id |
-t, --target |
GORULES_TARGET |
Target to resolve (default main) |
-o, --out |
Output directory (default .) |
|
--unpack |
Extract the archive instead of writing it | |
--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 (dir); defaults to the project key with no extension | |
--current |
Release or commit id you already hold; exits 3 when unchanged |
|
-u, --url |
GORULES_URL |
BRMS URL |
--token |
GORULES_TOKEN |
Access token |
--json |
Print the result as JSON on stdout |
The default writes <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: upload pricing.zip and the agent
serves a project literally called pricing.zip.
The agent's local zip provider is the opposite -- it reads <root>/<project>.zip and strips the
suffix itself -- so that destination needs it back:
gorules pull --project pricing --name pricing.zip --out ./rulesWith --unpack, --name is the sub-directory to extract into (default: the project key, which is
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.
Extraction behaves like aws s3 sync: byte-identical files are left untouched, changed files are
written atomically (temp file + rename, so a concurrent reader never sees a partial write), and
files the artifact does not carry are preserved. Add --delete for s3 sync --delete semantics:
the directory mirrors the target exactly, 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 that
has no .config/project.json from a previous pull, and deletions only run after every new file has
been written.
Object storage that the agent watches -- one archive per project, no extension:
gorules pull --project pricing --target env:production --out ./dist
aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursiveA volume the agent reads with its filesystem provider -- unpacked, one directory per project:
gorules pull --project pricing --target env:production --out /srv/rules --unpack
# /srv/rules/pricing/...Baked into a container image, pinned to an exact release so the build is reproducible:
gorules pull --project pricing --target release:1.4.2 --out ./rules --unpack --name .
# ./rules/*.json + ./rules/.config/project.json, ready for COPYScheduled job that does nothing when production has not moved:
gorules pull --project pricing --target env:production --current "$LAST_RELEASE_ID" --out ./dist
case $? in
0) aws s3 cp ./dist/ s3://my-bucket/rules/live/ --recursive ;;
3) echo "unchanged" ;;
*) exit 1 ;;
esac| 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 |
Pin the version in a pipeline rather than tracking latest:
npx @gorules/cli@0.3.3 pull --project pricing --target env:production # x-release-please-versionComposite actions live under actions/, in this repository, so the tag you pin is the CLI version
you get.
on:
workflow_dispatch:
inputs:
payload:
description: Set by BRMS when a webhook triggers the run; the action picks it up automatically
required: false
type: string
jobs:
rules:
runs-on: ubuntu-latest
steps:
- uses: gorules/cli/actions/pull@cli-v0.3.3 # x-release-please-version
id: rules
with:
url: https://acme.us1.gorules.io
token: ${{ secrets.GORULES_TOKEN }}
# project and target normally arrive in the BRMS payload; set them
# only for runs that have none (manual without payload, schedules)
out: ./dist
- name: Deploy
env:
PROJECT: ${{ steps.rules.outputs.project }}
run: aws s3 cp "./dist/$PROJECT" "s3://my-bucket/rules/$PROJECT"| Input | Required | Description |
|---|---|---|
url |
yes | BRMS URL |
token |
yes | Access token; pass a secret |
project |
yes* | Project key or id; optional when payload is set |
target |
Target to resolve (default main) |
|
out |
Output directory (default .) |
|
name |
Output file or sub-directory name | |
unpack |
true to extract the archive |
|
delete |
With unpack, mirror the target exactly (delete stale files) |
|
current |
Release or commit id already held | |
payload |
BRMS event payload; auto-detected from workflow_dispatch, set only to override |
|
cli-version |
Version of @gorules/cli to run |
| Output | Description |
|---|---|
project / target |
What was pulled, payload-aware |
changed |
false when current still matched, so nothing was downloaded |
release / version / commit |
What the target resolved to |
sha256 |
Checksum of the downloaded artifact |
files |
JSON array of paths written |
The token is passed to the CLI as an environment variable rather than an argument, and masked in the
log. changed exists so a scheduled workflow can skip the upload when production has not moved.
templates/gitlab-ci-pull.yml defines a hidden job you extend:
include:
- remote: 'https://raw.githubusercontent.com/gorules/cli/cli-v0.3.3/templates/gitlab-ci-pull.yml' # x-release-please-version
pull:rules:
extends: .gorules-pull
# project and target normally arrive in the BRMS payload (GRL_PAYLOAD);
# set GORULES_PROJECT / GORULES_TARGET only for runs that have none
publish:rules:
needs: ['pull:rules']
script:
# dotenv variables are not visible in rules: (evaluated before jobs run) -
# gate in script when using scheduled pulls with GORULES_CURRENT
- aws s3 cp "dist/$RULES_PROJECT" "s3://my-bucket/rules/$RULES_PROJECT"GORULES_URL and GORULES_TOKEN are CI/CD variables; mask and protect the token. GitLab puts them
in the environment automatically, so nothing else is needed to wire them up. Optional job variables:
GORULES_OUT (default dist), GORULES_NAME, GORULES_CURRENT, GORULES_UNPACK and
GORULES_DELETE (both 'false' by default), and GORULES_CLI_VERSION.
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 — a deploy job can route on the target (e.g. per-environment buckets) without parsing
anything.
templates/azure-pipelines-pull.yml is a steps template: it pulls the artifact and sets result
variables (rulesChanged, rulesProject, rulesTarget, rulesVersion, rulesRelease,
rulesSha256), and you append your own publish step in the same job:
resources:
repositories:
- repository: gorules
type: github
name: gorules/cli
ref: refs/tags/cli-v0.3.3 # x-release-please-version
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
# project and target normally arrive in the BRMS payload (GRL_PAYLOAD)
- script: aws s3 cp "$(Build.ArtifactStagingDirectory)/rules/$(rulesProject)" "s3://my-bucket/rules/$(rulesProject)"
displayName: DeployGORULES_TOKEN must exist as a secret pipeline variable or in a linked variable group. Azure
DevOps does not map secret variables into the environment automatically, which the template handles
by declaring it explicitly under env:.
The job sets rulesChanged and rulesVersion as pipeline variables for later stages to read.
All three templates read GRL_PAYLOAD when it is present, which is what BRMS sends when a webhook
triggers the pipeline. The project and target then come from the event rather than from static
configuration, so one pipeline handles every project and environment:
| System | How the payload arrives |
|---|---|
| GitHub Actions | inputs.payload on workflow_dispatch |
| GitLab CI | GRL_PAYLOAD pipeline variable |
| Azure Pipelines | GRL_PAYLOAD run variable |
Without it, the configured GORULES_PROJECT and GORULES_TARGET are used, so the same file also
works for a manual or scheduled run.
2 The CLI includes an MCP (Model Context Protocol) bridge that connects AI tools like Claude, Cursor, and Windsurf to the GoRules decision graph editor.
gorules mcp startThis starts a local server on localhost:41919 that:
- Exposes an MCP endpoint (
/mcp) for AI tool integration - Connects to the GoRules editor via WebSocket
- Provides REST endpoints for evaluating decisions and fetching files
| Flag | Description | Default |
|---|---|---|
-p, --port |
Server port | 41919 |
-h, --host |
Server host | localhost |
-u, --url |
GoRules server URL | — |
--open |
Open browser on start | false |
- Run
gorules mcp start - Open the GoRules editor and click Connect MCP
- Enter the connection token displayed in your terminal
The bridge exposes REST endpoints for local development:
Evaluate a decision graph:
curl -X POST http://localhost:41919/evaluate/my-decision \
-H "Content-Type: application/json" \
-d '{"context": {"customer": {"tier": "premium"}, "orderTotal": 150}}'Retrieve a decision file:
curl http://localhost:41919/file/my-decisionThese endpoints can also be used as a loader for ZenEngine:
const engine = new ZenEngine({
loader: async (key) => {
const res = await fetch(`http://localhost:41919/file/${key}`);
return res.json();
},
});Add the MCP server to your AI tool's configuration:
Claude Desktop / Claude Code:
{
"mcpServers": {
"gorules": {
"command": "gorules",
"args": ["mcp", "start"]
}
}
}pnpm install
pnpm dev # Build and run
pnpm build # Production build
pnpm lint # Lint
pnpm format:fix # Format