Run a Validator
GenVM Configuration

GenVM Configuration

You need to set up an LLM for your node to use to provide answers to natural language prompts. You can use any LLM you wish, however the quality of its answers will affect the performance of your node.

💡

GenLayer has partnered with multiple LLM providers to offer free credits for validators:

Heurist (opens in a new tab) - A Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network. GenLayer Validators can obtain free Heurist API credits (opens in a new tab) by using the referral code: "genlayer".

Comput3 (opens in a new tab) - A decentralized compute network providing access to various AI models. GenLayer Validators can use the Comput3.ai inferencing API with access to llama3, hermes3 and qwen3 models. Validators can obtain free Comput3 API credits (opens in a new tab) to get started with their validator setup.

io.net - A decentralized compute network providing GPU access for AI inference. GenLayer Validators can create an account at id.io.net (opens in a new tab) and obtain free credits by filling out this form (opens in a new tab).

Chutes - Serverless inference for open-source AI models running on decentralized GPU infrastructure. GenLayer Validators can create an account at chutes.ai (opens in a new tab) and generate an API key from their account settings.

Morpheus - A decentralized AI inference network where open-source model providers compete on a peer-to-peer marketplace. GenLayer Validators can obtain a Morpheus API key (opens in a new tab) to access models like DeepSeek, Llama, Qwen, and others through an OpenAI-compatible API.

The GenVM configuration files are located at third_party/genvm/config/

genvm-module-llm.yaml

This is the configuration file of the LLM module. In this file you can set up and configure various LLM providers, as well as the system prompts of your validator.

You should not need to modify this in general.

However, from here you can:

  • turn on and off various LLMs by setting the enabled field to false: By default they all come enabled for you to use. You will get warnings in the logs for each one that's enabled and not configured. Disabling non used LLM providers will hide those warnings

Note environment variable names for LLM API keys (e.g., HEURISTKEY, COMPUT3KEY, IOINTELLIGENCE_API_KEY, CHUTES_API_KEY, MORPHEUS_API_KEY). You will need to ensure the appropriate key is correctly set before running the node.

genvm-module-web.yaml

This is the configuration of webdriver module that enables the GenVM to access the internet. You should not need to modify this.

genvm-manager.yaml

This is the configuration of the GenVM manager. You should not need to modify this. However, if you are running the node on macos (natively), you may want to set permits to some large value, as auto-detection is not supported there yet, such as 32.

Greyboxing LLMs

Switch your GenLayer node from random LLM provider selection to deterministic ordered fallback via OpenRouter.

What is Greybox?

By default, the node picks a random LLM provider for each call. With greybox, the node uses a fixed priority chain configured via meta.greybox fields in the YAML config.

Default text chain: deepseek-v3.2 → qwen3-235b → claude-haiku-4.5 → kimi-k2 → glm-5 → llama-3.3 (heurist) → llama-3.3 (ionet)

Default image chain: gpt-5.1-mini → gemini-3-flash → claude-haiku-4.5

Chain order is determined by the meta.greybox priority numbers on each model in the YAML. Lower number = higher priority. You can change the order by editing these numbers — no Lua changes needed.

OpenRouter is the primary aggregator. If it fails, the node falls back to direct provider APIs (heurist, ionet).

Prerequisites

Step-by-Step Setup

1. Stop the node

sudo systemctl stop genlayer-node

2. Add OpenRouter API key to .env

# Find your active .env
ENV_FILE="/opt/genlayer-node/.env"
 
# Add the key (or edit the file manually)
echo "OPENROUTERKEY=sk-or-v1-your-key-here" >> ${ENV_FILE}

3. Apply the release LLM config

The tarball ships with a unified config that includes all backends (openrouter, morpheus, heurist, ionet, etc.).

VERSION=$(readlink /opt/genlayer-node/bin | sed 's|/bin||; s|.*/||')
 
cp /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-modules-llm-release.yaml \
   /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml

4. Switch to greybox strategy

sed -i 's/genvm-llm-default\.lua/genvm-llm-greybox.lua/' \
  /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml

5. Verify the config

# Check lua script path
grep lua_script_path /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml
# Expected: lua_script_path: ${exeDir}/../config/genvm-llm-greybox.lua
 
# Check openrouter is present
grep -A2 'openrouter:' /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml
# Expected: enabled: true
 
# Check the greybox Lua file exists
ls -la /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-llm-greybox.lua

6. Start the node

sudo systemctl start genlayer-node

7. Verify greybox is active

Wait for an LLM transaction to be processed, then check the logs:

sudo journalctl -u genlayer-node --no-hostname | grep "greybox"

You should see entries like:

greybox: using text chain    count: 5
greybox: success    provider: openrouter    model: deepseek/deepseek-v3.2    is_primary: true

Switching Back to Default

To revert to random provider selection:

sudo systemctl stop genlayer-node
 
sed -i 's/genvm-llm-greybox\.lua/genvm-llm-default.lua/' \
  /opt/genlayer-node/${VERSION}/third_party/genvm/config/genvm-module-llm.yaml
 
sudo systemctl start genlayer-node

Updating Greybox on a Running Node (No Full Restart)

If you need to update the Lua script or model config without stopping the whole node, you can restart just the LLM module on each GenVM instance:

# Find the GenVM manager port (check your config or active ports)
PORT=3999
 
# Stop the LLM module
curl -X POST "http://127.0.0.1:${PORT}/module/stop" \
  -H 'Content-Type: application/json' \
  -d '{"module_type": "Llm"}'
 
# Start the LLM module (reloads Lua script and config)
curl -X POST "http://127.0.0.1:${PORT}/module/start" \
  -H 'Content-Type: application/json' \
  -d '{"module_type": "Llm", "config": null}'

Repeat for each GenVM instance port. There is no atomic restart — each instance restarts independently.

Customizing the Chain Order

The greybox Lua script reads chain membership and priority from meta.greybox on each model in the YAML config. Example:

models:
  deepseek/deepseek-v3.2:
    supports_json: true
    meta:
      greybox: { text: 1 }        # text chain, priority 1 (primary)
  openai/gpt-5.1-mini:
    supports_json: true
    supports_image: true
    meta:
      greybox: { image: 1 }       # image chain, priority 1
  anthropic/claude-haiku-4.5:
    supports_json: true
    supports_image: true
    meta:
      greybox: { text: 3, image: 3 }  # both chains

Change model order: Edit the priority numbers. Lower number = tried first.

Add a model to the chain: Add meta: { greybox: { text: N } } to any model in any enabled backend.

Remove a model from the chain: Remove its meta.greybox field.

Disable an entire provider: Remove its API key from .env — all its models drop out automatically.

The YAML config must have meta.greybox fields on at least some models. If none are found, the LLM module will fail to start with an error.

After editing the YAML, restart the LLM module (see "Updating Greybox on a Running Node" above) or restart the node.

Troubleshooting

"module_failed_to_start" error:

  • Check that genvm-llm-greybox.lua exists in the config directory
  • Check that OPENROUTERKEY is set in .env and not empty
  • Check that the openrouter backend shows enabled: true in the YAML

No "greybox:" entries in logs:

  • The greybox Lua only logs when an LLM call happens. Run a transaction that uses an intelligent contract with LLM calls.
  • Verify lua_script_path points to genvm-llm-greybox.lua (not default)

All models exhausted error: