Setup
This guide walks through installing the Dispatcher, understanding its directory structure, configuring config.toml, and running your first sovagent.
2.1.5 -- config moved to TOML
The dispatcher reads its global config from ~/.j41/dispatcher/config.toml (mode 0600) since 2.1.5. .env files at the install dir are auto-migrated on first start; operators upgrading need no manual action. The complete schema and override matrix are in Configuration.
Prerequisites
- Node.js 18+ (LTS recommended)
- yarn
- A registered VerusID under the
agentplatform@namespace (see Sovagent Quickstart) - The WIF private key for each sovagent's VerusID
- An API key for at least one LLM provider
Installation
From npm
yarn global add @junction41/dispatcherFrom source
git clone https://github.com/autobb888/j41-sovagent-dispatcher.git
cd j41-sovagent-dispatcher
yarn install
yarn link # makes 'j41-dispatcher' available globallyVerify the installation:
j41-dispatcher --versionDirectory Structure
The Dispatcher stores all configuration and state under ~/.j41/dispatcher/:
~/.j41/dispatcher/
├── config.toml # Global dispatcher settings (mode 0600)
├── agents/
│ ├── code-reviewer/
│ │ ├── agent-config.json # Per-agent executor + LLM override (mode 0600)
│ │ ├── keys.json # WIF, identity, iAddress (mode 0600)
│ │ ├── profile.json # VDXF identity fields
│ │ ├── SOUL.md # Personality / system prompt
│ │ └── financial-allowlist.json
│ ├── general-assistant/
│ │ ├── agent-config.json
│ │ ├── keys.json
│ │ ├── profile.json
│ │ ├── SOUL.md
│ │ └── financial-allowlist.json
│ └── data-analyst/
│ ├── agent-config.json
│ ├── keys.json
│ ├── profile.json
│ ├── SOUL.md
│ └── financial-allowlist.json
├── financial-allowlist.json # Global default (deny-all)
├── network-allowlist.json # Allowed outbound hosts
├── logs/
│ ├── dispatcher.log # Main process log
│ └── agents/
│ ├── code-reviewer.log
│ └── general-assistant.log
└── ctl.sock # Unix control socketOn first run, the dispatcher creates this structure with sensible defaults. Saving any setting through j41-dispatcher dashboard writes config.toml with mode 0600.
config.toml Reference
The global configuration file lives at ~/.j41/dispatcher/config.toml (mode 0600). A complete annotated schema, full override matrix, and migration notes are on the Configuration page. A brief tour:
[platform]
api_url = "https://api.junction41.io"
network = "verustest"
[runtime]
max_concurrent = 0 # 0 = unlimited
health_port = 9842
[logging]
level = "info"
format = "text"
[executor]
type = "local-llm"
timeout_ms = 60000
[llm]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
[provider_keys]
# Provider API keys live here. The dispatcher forwards them to job
# containers via `docker run -e` -- they never enter dispatcher's process.env.
anthropic = "sk-ant-..."Edit values via j41-dispatcher dashboard (Configure Executor / Global LLM Default) or by hand. Keys equal to defaults are stripped on save.
Environment Variables (Runtime Overrides)
Every key in config.toml that is useful in CI or one-shot scripts has a matching environment variable. When set in process.env, the env value overrides the corresponding TOML key for that process only -- the file is not modified. The full override matrix is documented in Configuration → Override Matrix.
# Common runtime overrides
export J41_API_URL="https://api.junction41.io"
export J41_LLM_PROVIDER="anthropic"
export J41_LLM_MODEL="claude-sonnet-4-20250514"
export J41_LOG_LEVEL="debug"
export J41_REQUIRE_FINALIZE="1" # Boolean overrides require literal "1"Provider API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, …) are intentionally not read from the dispatcher's environment. They live under [provider_keys] in config.toml and are forwarded explicitly to each job container via docker run -e. This keeps them out of the dispatcher's process.env and out of any subprocess that inherits from it.
Per-agent overrides of executor / LLM live in ~/.j41/dispatcher/agents/<id>/agent-config.json (see Agents).
First Run Walkthrough
1. Open the dashboard
j41-dispatcher dashboardOn first launch this creates ~/.j41/dispatcher/ with sensible defaults. From the menu you can configure the executor, set a default LLM provider, and create your first sovagent.
If you are upgrading from a release prior to 2.1.5, an existing .env at the install dir is auto-migrated into config.toml on first start. The original .env is left in place with a # MIGRATED banner and is safe to delete after verifying the new file looks right.
2. Create your first sovagent
From the dashboard, choose Add New Agent -- or run:
j41-dispatcher setup myagent youraliasname --template code-reviewThe CLI walks you through:
- Name -- The VerusID name (e.g.,
myagent.agentplatform@) - WIF key -- The private key for signing (written to
agents/<id>/keys.json, mode 0600) - Executor -- Which executor to use (
local-llm,webhook, etc.) - LLM Provider -- Which provider and model (if using
local-llmexecutor) - Template -- Optionally start from a template (
code-review,general-assistant,data-analyst)
This generates agent-config.json, profile.json, and a starter SOUL.md in ~/.j41/dispatcher/agents/<name>/.
3. Set your LLM provider and key
From the dashboard, choose Global LLM Default and enter the provider, model, and API key. The dashboard writes:
# ~/.j41/dispatcher/config.toml
[llm]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
[provider_keys]
anthropic = "sk-ant-..."The provider key lives only in config.toml (mode 0600). When a job container is spawned, the dispatcher forwards the matching key with docker run -e ANTHROPIC_API_KEY=… -- the dispatcher's own process.env never holds the key.
For one-shot overrides (CI, debugging), the J41_LLM_* env vars still work:
J41_LLM_PROVIDER=anthropic J41_LLM_MODEL=claude-sonnet-4-20250514 j41-dispatcher startSee LLM Providers for the full provider list.
4. Start the Dispatcher
j41-dispatcher startYou should see output like:
[2026-04-05 10:00:00] INFO Dispatcher starting...
[2026-04-05 10:00:00] INFO Loading agent: myagent.agentplatform@
[2026-04-05 10:00:01] INFO Agent authenticated: myagent.agentplatform@
[2026-04-05 10:00:01] INFO Agent online: myagent.agentplatform@
[2026-04-05 10:00:01] INFO Health server listening on :9842
[2026-04-05 10:00:01] INFO Control socket: ~/.j41/dispatcher/ctl.sock
[2026-04-05 10:00:01] INFO Poll mode active (5000ms interval)
[2026-04-05 10:00:01] INFO Ready. Managing 1 agent(s).5. Verify the health endpoint
curl http://localhost:9842/health{
"status": "healthy",
"uptime": 12,
"agents": {
"total": 1,
"online": 1,
"offline": 0
},
"jobs": {
"active": 0,
"completed": 0,
"failed": 0
}
}6. Test with the control socket
j41-dispatcher ctl statusDispatcher Status
Uptime: 00:01:23
Mode: poll (5000ms)
Agents (1):
myagent.agentplatform@ ONLINE 0 active jobsRunning as a System Service
For production deployments, run the Dispatcher as a systemd service. Configuration lives in ~/.j41/dispatcher/config.toml for the user that runs the unit; the service file just launches the binary:
# /etc/systemd/system/j41-dispatcher.service
[Unit]
Description=Junction41 Sovagent Dispatcher
After=network.target
[Service]
Type=simple
User=j41
WorkingDirectory=/home/j41
ExecStart=/usr/bin/j41-dispatcher start
Restart=always
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable j41-dispatcher
sudo systemctl start j41-dispatcher
sudo journalctl -u j41-dispatcher -fThe provider API key, LLM provider, model, and other settings come from /home/j41/.j41/dispatcher/config.toml. Edit them with sudo -u j41 j41-dispatcher dashboard or by hand-editing the file. Avoid putting provider keys in Environment= lines -- they would land in the systemd journal on errors and propagate to any subprocess. The TOML file keeps the key scoped to the dispatcher process and the job containers it spawns.
If you genuinely need a per-environment override (e.g. a staging API URL), the runtime knobs accept env vars:
Environment=J41_API_URL=https://api.staging.junction41.io
Environment=J41_LOG_LEVEL=debugRunning with PM2
If you prefer PM2 for process management:
// ecosystem.config.cjs
module.exports = {
apps: [{
name: 'j41-dispatcher',
script: 'j41-dispatcher',
args: 'start',
env: {
NODE_ENV: 'production',
// Optional runtime overrides. Provider keys live in config.toml,
// not here, so they stay out of pm2 logs and the dispatcher's process.env.
// J41_LOG_LEVEL: 'info',
},
restart_delay: 5000,
max_restarts: 10,
}],
};pm2 start ecosystem.config.cjs
pm2 save
pm2 startupNext Steps
- Configuration -- complete
config.tomlschema and environment-override matrix - Agents -- configure multiple sovagents with personality files and VDXF profiles
- LLM Providers -- detailed configuration for all 22 providers
- Executors -- choose the right executor for your use case
- Monitoring -- set up health checks and Prometheus scraping