How to configure GolemCore Bot.
There are three main configuration surfaces:
- Storage workspace (filesystem) controlled by Spring properties.
- Runtime config (editable at runtime, persisted to workspace).
- User preferences (editable at runtime, persisted to workspace).
The bot stores all state under a base path:
- Spring property:
bot.storage.local.base-path - Docker/JAR env var (via Spring):
STORAGE_PATH
In Docker, you almost always want this mounted:
docker run -d \
-e STORAGE_PATH=/app/workspace \
-v golemcore-bot-data:/app/workspace \
-p 8080:8080 \
golemcore-bot:latestThe easiest way to configure the bot is via the dashboard:
http://localhost:8080/dashboard
See: Dashboard Guide
Runtime config is persisted to the workspace:
- Files:
preferences/*.json(one JSON file per section, for examplellm.json,turn.json,hive.json) - Dashboard API:
GET /api/settings/runtime,PUT /api/settings/runtime
Some runtime-adjacent operational state also lives under preferences/, but outside the editable runtime-config surface. Examples: hive-session.json, hive-control-inbox.json, hive-policy-state.json.
Secrets (API keys) can be provided as plain strings in JSON; they are wrapped as Secret internally.
Notable runtime sections:
telegram.jsonmodel-router.jsonllm.jsontools.jsonvoice.jsonmemory.jsonskills.jsontool-loop.jsonturn.jsonusage.jsonmcp.jsonplan.jsonhive.jsonself-evolving.json
Repeat guard settings live in preferences/tool-loop.json under the toolLoop section. The guard prevents the
same tool call with the same canonical arguments from being executed indefinitely when no state changes.
Default runtime shape:
{
"toolLoop": {
"maxLlmCalls": 20,
"maxToolExecutions": 80,
"stopOnToolFailure": false,
"stopOnConfirmationDenied": true,
"stopOnToolPolicyDenied": true,
"repeatGuardEnabled": true,
"repeatGuardShadowMode": false,
"repeatGuardMaxSameObservePerTurn": 2,
"repeatGuardMaxSameUnknownPerTurn": 2,
"repeatGuardMaxBlockedRepeatsPerTurn": 4,
"repeatGuardMinPollIntervalSeconds": 60,
"repeatGuardAutoLedgerTtlMinutes": 120
}
}Field notes:
repeatGuardEnabled: enables pre-execution repeat protection. When disabled, the guard is a hard kill switch and does not accumulate future-blocking ledger state.repeatGuardShadowMode: records warning telemetry and model-visible hints for would-block decisions while still allowing execution.repeatGuardMaxSameObservePerTurn: successful identical observe calls allowed in the current verified state before blocking.repeatGuardMaxSameUnknownPerTurn: successful identical unknown execution calls, including shell, allowed before blocking in the current verified state. Unknown executions do not by themselves prove that workspace or remote state changed, but verified filesystem mutations reset the repeat window for local shell-style commands such as repeated test runs.repeatGuardMaxBlockedRepeatsPerTurn: stops a turn after repeated ignored guard hints.repeatGuardMinPollIntervalSeconds: minimum backoff before repeating the same polling call, independent of unrelated local environment changes.repeatGuardAutoLedgerTtlMinutes: TTL for autonomous task/goal repeat ledgers underauto/tool-ledgers/; applies to observations, polling, unknown executions and guard-blocked synthetic records.
The persisted auto ledger stores fingerprints, output digests and state-domain environment versions only. It is capped to the newest
bounded records per work item, and it does not persist per-turn warning/block counters, full tool outputs or raw
secret-like arguments. Policy denials, confirmation denials and guard synthetic records may be retained for diagnostics,
but they are not counted as successful prior executions for repeat-block decisions.
The durable ledger currently writes schema version 3; schema versions 1 and 2 are still readable for branch-local
upgrade compatibility. Output-digest progress is opt-in per tool semantic. Deterministic local/read-model observations
such as filesystem, memory, plan, skill, goal and scheduling reads may use changed output digest as progress for that
fingerprint. Dynamic remote observations such as datetime, weather, browser/search/scrape, Perplexity and read-only
mail checks do not use digest changes as progress, because their rendered output can change without agent progress.
When a tool result supplies semanticOutputDigest or semanticDigest in structured data, repeat guard uses that value;
otherwise it falls back to the model-visible tool result content. The digest is not computed from hidden raw adapter
payloads.
Unknown executions keep stricter exact-repeat behavior because their output volatility is tool-specific and not safe to
interpret generically.
Ledger file paths use readable sanitized prefixes with short hash suffixes, which prevents sanitized id collisions while
keeping storage inspectable. Readable path prefixes are length-bounded; the hash suffix carries the full work-item identity.
Repeat windows are scoped by state domain, not one global state bit. Filesystem writes invalidate WORKSPACE
observations and local shell repeats, memory writes invalidate MEMORY observations, goal/diary updates invalidate
AUTONOMY_PROGRESS, Hive writes invalidate HIVE_REMOTE, delayed-action changes invalidate SCHEDULING, plan edits
invalidate PLAN, skill changes invalidate SKILLS, tier/skill-transition changes invalidate SESSION_CONTROL, web
tools observe WEB_REMOTE, weather observes WEATHER, datetime observes TIME, and mail tools use MAIL.
Unrelated progress writes do not re-allow the same workspace read, search or shell command.
Repeat warning hints are appended only after all tool results for the current assistant tool-call batch have been
written, and stale warning hints are suppressed when a later tool in the same batch invalidates the warning's observed
state domain. This keeps strict provider tool-call adjacency intact while still giving the model guidance before the next
LLM call. Fingerprinting is fail-open for model-generated invalid paths/workdirs: invalid path strings are replaced with
a deterministic hash placeholder instead of throwing before normal tool validation can run. Shell fingerprints include
normalized cwd, workdir and workingDirectory values, so equivalent relative
working directories do not bypass the repeat guard. Missing shell workdir is treated as the workspace root; conflicting
workdir aliases are preserved in the fingerprint rather than collapsed to an arbitrary alias. Documented
read-only filesystem operations (read_file, list_directory, file_info) and memory operations (memory_search,
memory_read, memory_expand_section) are classified as observations, so they do not reset any verified state domain.
First-party goal_management, schedule_session_action, plan, skill, session-control and Hive tools use explicit
operation/name semantics instead of generic string matching. plan_exit remains an unconditional safe exit path, while
set_tier and skill_transition are bounded idempotent SESSION_CONTROL mutations. Official plugin observation tools such as browse,
brave_search, tavily_search, firecrawl_scrape, perplexity_ask, weather, datetime and read-only imap calls
are classified as observations in their own remote/time/mail domains; smtp and send_voice are treated as
non-idempotent mutations. Successful mutation
records are retained until the per-work-item ledger cap rather than the observation TTL; this keeps idempotent duplicate
write protection durable while synthetic repeat-guard records still expire by TTL.
Repeat guard decisions are exposed in TOOL_FINISHED payloads with repeatGuardDecision, repeatFingerprint,
repeatCategory and repeatTool fields. Synthetic blocked results carry the same stable repeat fingerprint in
ToolResult.data, so recovery telemetry can aggregate by semantic fingerprint instead of transient tool-call id.
Malformed or unreadable durable ledgers fail open to an empty in-turn ledger and emit a warning with the ledger path and
exception class.
SelfEvolving is the native observe, judge, evolve, and promote runtime plane for the bot.
Configuration lives in preferences/self-evolving.json and is also available in the dashboard under Settings -> SelfEvolving.
Important behaviors:
SelfEvolvingis disabled by default.enabled=trueturns on theSelfEvolvingpipeline in post-run analysis.- When enabled,
SelfEvolvingforces trace payload capture for evaluation-relevant spans even if normal trace payload logging is reduced. - Judge model selection is tier-based, not model-id based:
judge.primaryTierjudge.tiebreakerTierjudge.evolutionTier
- Promotion policy defaults to
approval_gate. - Promotion policy can be relaxed to automatic rollout modes through runtime config.
- Benchmark harvesting can promote production runs into offline regression suites.
- Tactic search is disabled by default and stays separate from the curated
skillsregistry. - Tactic search always keeps
BM25available; embeddings are optional and degrade toBM25-onlywhen disabled, misconfigured, or temporarily unavailable. - All non-embedding search models resolve through tiers. Cross-encoder reranking is configured via
tactics.search.rerank.tier, not a direct model id.
Default runtime shape:
{
"selfEvolving": {
"enabled": false,
"tracePayloadOverride": true,
"tactics": {
"enabled": false,
"search": {
"mode": "bm25",
"bm25": {
"enabled": true
},
"embeddings": {
"enabled": false,
"autoFallbackToBm25": true,
"local": {
"autoInstall": false,
"pullOnStart": false,
"requireHealthyRuntime": true,
"failOpen": true
}
},
"rerank": {
"crossEncoder": true,
"tier": "deep"
},
"personalization": {
"enabled": true
},
"negativeMemory": {
"enabled": true
}
}
}
}
}Runtime operators can still enable the full judge/evolve/promote loop after startup:
{
"selfEvolving": {
"enabled": true,
"tracePayloadOverride": true,
"judge": {
"enabled": true,
"primaryTier": "balanced",
"tiebreakerTier": "deep",
"evolutionTier": "deep",
"requireEvidenceAnchors": true
},
"promotion": {
"mode": "approval_gate",
"shadowRequired": true,
"canaryRequired": true,
"hiveApprovalPreferred": true
},
"benchmark": {
"enabled": true,
"harvestProductionRuns": true,
"autoCreateRegressionCases": true
}
}
}Runtime preferences remain editable in preferences/self-evolving.json, but startup overrides can force effective values without mutating persisted settings.
Common overrides:
bot.self-evolving.bootstrap.enabledbot.self-evolving.bootstrap.trace-payload-overridebot.self-evolving.bootstrap.tactics.enabledbot.self-evolving.bootstrap.tactics.search.modebot.self-evolving.bootstrap.tactics.search.rerank.cross-encoderbot.self-evolving.bootstrap.tactics.search.rerank.tierbot.self-evolving.bootstrap.tactics.search.personalization.enabledbot.self-evolving.bootstrap.tactics.search.negative-memory.enabledbot.self-evolving.bootstrap.tactics.search.embeddings.enabledbot.self-evolving.bootstrap.tactics.search.embeddings.providerbot.self-evolving.bootstrap.tactics.search.embeddings.base-urlbot.self-evolving.bootstrap.tactics.search.embeddings.api-keybot.self-evolving.bootstrap.tactics.search.embeddings.modelbot.self-evolving.bootstrap.tactics.search.embeddings.dimensionsbot.self-evolving.bootstrap.tactics.search.embeddings.batch-sizebot.self-evolving.bootstrap.tactics.search.embeddings.timeout-msbot.self-evolving.bootstrap.tactics.search.embeddings.auto-fallback-to-bm25bot.self-evolving.bootstrap.tactics.search.embeddings.local.auto-installbot.self-evolving.bootstrap.tactics.search.embeddings.local.pull-on-startbot.self-evolving.bootstrap.tactics.search.embeddings.local.require-healthy-runtimebot.self-evolving.bootstrap.tactics.search.embeddings.local.fail-open
Example bot.properties:
bot.self-evolving.bootstrap.enabled=true
bot.self-evolving.bootstrap.trace-payload-override=true
bot.self-evolving.bootstrap.tactics.enabled=true
bot.self-evolving.bootstrap.tactics.search.mode=hybrid
bot.self-evolving.bootstrap.tactics.search.rerank.cross-encoder=true
bot.self-evolving.bootstrap.tactics.search.rerank.tier=deep
bot.self-evolving.bootstrap.tactics.search.personalization.enabled=true
bot.self-evolving.bootstrap.tactics.search.negative-memory.enabled=true
bot.self-evolving.bootstrap.tactics.search.embeddings.enabled=true
bot.self-evolving.bootstrap.tactics.search.embeddings.provider=ollama
bot.self-evolving.bootstrap.tactics.search.embeddings.base-url=http://127.0.0.1:11434
bot.self-evolving.bootstrap.tactics.search.embeddings.model=qwen3-embedding:0.6b
bot.self-evolving.bootstrap.tactics.search.embeddings.dimensions=1024
bot.self-evolving.bootstrap.tactics.search.embeddings.batch-size=32
bot.self-evolving.bootstrap.tactics.search.embeddings.timeout-ms=10000
bot.self-evolving.bootstrap.tactics.search.embeddings.auto-fallback-to-bm25=true
bot.self-evolving.bootstrap.tactics.search.embeddings.local.auto-install=true
bot.self-evolving.bootstrap.tactics.search.embeddings.local.pull-on-start=true
bot.self-evolving.bootstrap.tactics.search.embeddings.local.require-healthy-runtime=true
bot.self-evolving.bootstrap.tactics.search.embeddings.local.fail-open=trueThe preferred local path is a lightweight embedding runtime, not a bundled inference stack.
Recommended flow:
- Make sure a local
ollamaruntime is installed. - Configure the embedding provider through
bot.self-evolving.bootstrap.tactics.search.embeddings.*. - Enable local embeddings and choose the embedding model in
Settings -> Self-Evolving -> Tactics. - Let the bot manage readiness and degraded fallback; install the embedding model only after the runtime is ready.
Managed local runtime behavior:
- If embeddings are enabled with local
ollama, the bot checkshttp://127.0.0.1:11434during startup. - If an external
ollamaruntime is already ready there, the bot uses it without taking ownership. - If no runtime is ready, the bot tries to start its own managed
ollamaprocess and waits up to5sfor readiness. - If readiness is not reached within
5s, the bot still finishes startup and stays healthy, butSelf-Evolvingembeddings remain in a degraded state untilollamabecomes ready. - If the bot owns the runtime and it crashes later, the bot retries with exponential backoff and exposes restart attempts and next retry time in the UI.
- If the bot is using an external runtime and that runtime disappears later, the bot does not take it over retroactively; embeddings simply degrade.
- On shutdown, the bot stops only the
ollamaprocess that it started itself.
Notes:
- The
golemcore-bot-baseimage now bundles theollamabinary. - Bundling the binary in the base image does not install or update
ollamaon the host machine. - The dashboard
Settings -> Self-Evolving -> Tacticspage shows explicit diagnostics for:ollamanot installedollamainstalled but not running- selected embedding model missing from
ollama
- Bundling the binary in the base image does not guarantee a ready runtime. If diagnostics say the runtime is not running, start it with
ollama serveinside the container or your preferred service manager outside it. - The bot never installs or updates
ollamaitself. It only diagnoses missing/outdated runtime states and can pull the selected embedding model into an already available runtime. - Outdated
ollamaversions are surfaced as degraded diagnostics; the operator must update them manually.
Recommended local model:
qwen3-embedding:0.6b
Configure provider credentials under llm.providers.
- Provider key is the model prefix in
provider/model(and should matchproviderinmodels/models.json). apiTypeselects the wire protocol used by the adapter.- Supported
apiTypevalues:openai(default),anthropic,gemini.
{
"llm": {
"providers": {
"openai": {
"apiKey": "sk-proj-...",
"apiType": "openai",
"baseUrl": null,
"requestTimeoutSeconds": 300
},
"anthropic": {
"apiKey": "sk-ant-...",
"apiType": "anthropic"
},
"google": {
"apiKey": "AIza...",
"apiType": "gemini"
}
}
}
}Notes:
- Use lowercase
apiTypevalues. baseUrlis optional; forgeminiit is typically left empty.- These same provider profiles are used by the dashboard
Model Catalogfor live model discovery via/api/models/discover/{provider}.
Model selection now has three layers:
llm.providersdefines provider profiles and credentials.models/models.jsondefines model capability metadata.modelRoutermaps routing/tier slots to concrete models.
Tier routing is configured in runtime config under modelRouter:
{
"modelRouter": {
"routingModel": "openai/gpt-5.2-codex",
"routingModelReasoning": "none",
"balancedModel": "openai/gpt-5.1",
"balancedModelReasoning": "none",
"smartModel": "openai/gpt-5.1",
"smartModelReasoning": "none",
"codingModel": "openai/gpt-5.2",
"codingModelReasoning": "none",
"deepModel": "openai/gpt-5.2",
"deepModelReasoning": "none",
"dynamicTierEnabled": true,
"temperature": 0.7
}
}Notes:
routingModelis used for internal routing/classification flows.*Reasoningvalues depend on the selected model entry frommodels/models.json.- In the dashboard, this is split across
LLM Providers,Model Catalog, andModel Router. /api/models/availablereturns models grouped by provider, filtered to provider profiles that are API-ready.- When a discovered model id conflicts across providers, the catalog can persist a provider-scoped id such as
provider/model.
Core tool enablement flags are in runtime-config.json under tools:
{
"tools": {
"filesystemEnabled": true,
"shellEnabled": true,
"skillManagementEnabled": true,
"skillTransitionEnabled": true,
"tierEnabled": true,
"goalManagementEnabled": true,
"shellEnvironmentVariables": []
}
}Official integrations that are loaded through the plugin runtime keep their
own configuration under preferences/plugins/<owner>/<plugin>.json. This
includes the first-party browser, Brave Search, Tavily Search, Firecrawl,
Perplexity Sonar, weather, mail, and LightRAG modules.
See: Tools Guide
The browse tool is provided by the official golemcore/browser plugin and
uses Playwright.
Configuration lives in preferences/plugins/golemcore/browser.json:
{
"enabled": true,
"headless": true,
"timeoutMs": 30000,
"userAgent": "..."
}Docker requirements (Chromium sandbox):
docker run -d \
--shm-size=256m \
--cap-add=SYS_ADMIN \
...The tavily_search tool is provided by the official
golemcore/tavily-search plugin.
Configuration lives in preferences/plugins/golemcore/tavily-search.json:
{
"enabled": true,
"apiKey": "tvly-...",
"defaultMaxResults": 5,
"defaultTopic": "general",
"defaultSearchDepth": "basic",
"includeAnswer": true,
"includeRawContent": false
}The firecrawl_scrape tool is provided by the official golemcore/firecrawl
plugin.
Configuration lives in preferences/plugins/golemcore/firecrawl.json:
{
"enabled": true,
"apiKey": "fc-...",
"defaultFormat": "markdown",
"onlyMainContent": true,
"maxAgeMs": 172800000,
"timeoutMs": 30000
}The perplexity_ask tool is provided by the official
golemcore/perplexity-sonar plugin and currently uses synchronous completions.
Configuration lives in preferences/plugins/golemcore/perplexity-sonar.json:
{
"enabled": true,
"apiKey": "pplx-...",
"defaultModel": "sonar",
"defaultSearchMode": "web",
"returnRelatedQuestions": false,
"returnImages": false
}Input and tool safety settings live in runtime config under security:
{
"security": {
"sanitizeInput": true,
"detectPromptInjection": true,
"detectCommandInjection": true,
"maxInputLength": 10000,
"allowlistEnabled": true,
"toolConfirmationEnabled": false,
"toolConfirmationTimeoutSeconds": 60
}
}Hive runtime settings live in preferences/hive.json and are also available in the dashboard under Settings -> Hive.
{
"hive": {
"enabled": true,
"serverUrl": "https://hive.example.com",
"displayName": "Build Runner",
"hostLabel": "builder-lab-a",
"autoConnect": true,
"managedByProperties": false
}
}Rules:
RuntimeConfig.HiveConfigis the effective UI/runtime configuration.bot.hive.*acts as a managed bootstrap override.- When managed bootstrap is active, the dashboard Hive tab becomes read-only and the backend rejects edits to the Hive section.
- Rotating machine auth state does not belong in
hive.json; it lives inpreferences/hive-session.json. - Buffered control channel commands live in
preferences/hive-control-inbox.json. - Hive-managed policy sync state lives in
preferences/hive-policy-state.json. - When a Hive policy group is active, the dashboard exposes
LLM Providers,Models, andModel Catalogas read-only and the backend rejects local writes for those managed sections.
See: Hive Integration
{
"rateLimit": {
"enabled": true,
"userRequestsPerMinute": 20,
"userRequestsPerHour": 100,
"userRequestsPerDay": 500,
"channelMessagesPerSecond": 30,
"llmRequestsPerMinute": 60
}
}Automatic history compaction (to prevent context overflow):
{
"compaction": {
"enabled": true,
"maxContextTokens": 50000,
"keepLastMessages": 20,
"preserveTurnBoundaries": true,
"detailsEnabled": true,
"detailsMaxItemsPerCategory": 50,
"summaryTimeoutMs": 15000
}
}Field notes:
preserveTurnBoundaries: keeps compaction split-safe so turns are not truncated mid exchange.detailsEnabled: persists structured compaction diagnostics in session metadata and summary metadata.detailsMaxItemsPerCategory: caps stored file/tool detail lists.summaryTimeoutMs: hard timeout for the LLM summarization phase.
Limits for a single user request (one internal tool loop run):
{
"turn": {
"maxLlmCalls": 200,
"maxToolExecutions": 500,
"deadline": "PT1H",
"autoRetryEnabled": true,
"autoRetryMaxAttempts": 2,
"autoRetryBaseDelayMs": 600,
"queueSteeringEnabled": true,
"queueSteeringMode": "one-at-a-time",
"queueFollowUpMode": "one-at-a-time"
}
}Field notes:
autoRetry*: resilient retries for transient LLM/tool-loop failures.queueSteeringEnabled: allows steering messages to bypass normal follow-up handling.queueSteeringMode:one-at-a-timeorall.queueFollowUpMode:one-at-a-timeorall.
Automatic cleanup of persisted chat sessions is configured under sessionRetention:
{
"sessionRetention": {
"enabled": true,
"maxAge": "P30D",
"cleanupInterval": "PT24H",
"protectActiveSessions": true,
"protectSessionsWithPlans": true,
"protectSessionsWithDelayedActions": true
}
}Field notes:
maxAge: ISO-8601 retention window before a session becomes eligible for deletion.cleanupInterval: how often the background cleanup job may run.protectActiveSessions: keeps sessions referenced by current web/Telegram active-session pointers.protectSessionsWithPlans: keeps sessions that still have collecting, ready, approved, or executing plan mode state.protectSessionsWithDelayedActions: keeps sessions referenced by pending delayed actions and reminders.
Recommended defaults:
enabled=truemaxAge=P30DcleanupInterval=PT24H- all protection flags enabled
This cleanup targets the sessions/ directory, which is usually the fastest-growing durable state for long-running chat usage.
Memory behavior is configured under memory:
{
"memory": {
"enabled": true,
"softPromptBudgetTokens": 1800,
"maxPromptBudgetTokens": 3500,
"workingTopK": 6,
"episodicTopK": 8,
"semanticTopK": 6,
"proceduralTopK": 4,
"promotionEnabled": true,
"promotionMinConfidence": 0.75,
"decayEnabled": true,
"decayDays": 30,
"retrievalLookbackDays": 21,
"codeAwareExtractionEnabled": true,
"disclosure": {
"mode": "summary",
"promptStyle": "balanced",
"toolExpansionEnabled": true,
"disclosureHintsEnabled": true,
"detailMinScore": 0.80
},
"reranking": {
"enabled": true,
"profile": "balanced"
},
"diagnostics": {
"verbosity": "basic"
}
}
}Field notes:
softPromptBudgetTokens/maxPromptBudgetTokens: target and hard limit for prompt memory budget.*TopK: per-layer recall limits before budget trimming.promotion*: controls promotion from episodic records into semantic/procedural stores.decay*: stale item pruning window for stored memory.retrievalLookbackDays: episodic retrieval window.disclosure.*: controls progressive disclosure. This decides whether memory is shown as a tiny index, a compact summary, or selective raw detail.reranking.*: second-pass candidate reordering after normal scoring. Useful when recall is relevant but not precise enough.diagnostics.verbosity: how much memory telemetry is exposed for tuning/debugging.
Quick guidance:
summaryis the recommended default for most coding sessions.selective_detailis better for long autonomous or deep-focus work.indexkeeps chat lightweight.full_packis mostly for debugging or compatibility.
For a fuller explanation of these fields and the built-in presets, see Memory Guide.
Telegram channel settings are stored in runtime config under telegram:
{
"telegram": {
"enabled": false,
"token": "123456:ABC-DEF...",
"authMode": "invite_only",
"allowedUsers": []
}
}{
"voice": {
"enabled": false,
"telegramRespondWithVoice": false,
"telegramTranscribeIncoming": false,
"sttProvider": "golemcore/elevenlabs",
"ttsProvider": "golemcore/elevenlabs"
}
}Notes:
- The
voicesection now primarily routes STT/TTS providers and Telegram voice behavior. - Provider-specific secrets and endpoints live in plugin settings, for example:
preferences/plugins/golemcore/elevenlabs.jsonpreferences/plugins/golemcore/whisper.json
- The dashboard resolves available providers from
/api/plugins/voice/providers.
{
"autoMode": {
"enabled": false,
"tickIntervalSeconds": 1,
"taskTimeLimitMinutes": 10,
"autoStart": true,
"maxGoals": 3,
"modelTier": "default",
"notifyMilestones": true
}
}Notes:
- Auto mode is schedule-driven; goals/tasks are only executed automatically when a cron schedule exists.
tickIntervalSecondsremains in runtime config, but the backend currently polls due schedules every second.- Schedules themselves are stored separately in
auto/schedules.json.
RAG is configured through the official golemcore/lightrag plugin rather than
the core runtime schema.
{
"enabled": false,
"url": "http://localhost:9621",
"apiKey": "",
"queryMode": "hybrid",
"timeoutSeconds": 10,
"indexMinLength": 50
}Store this in preferences/plugins/golemcore/lightrag.json or configure it
from the dashboard plugin settings UI.
{
"mcp": {
"enabled": true,
"defaultStartupTimeout": 30,
"defaultIdleTimeout": 5
}
}See: MCP Integration
User preferences are stored separately:
- File:
preferences/settings.json
This includes language/timezone/notifications and per-user tier/model overrides.
Webhooks configuration also lives here. See: Webhooks Guide
Model capabilities are stored in the workspace at:
models/models.json
On first run, the bot copies a bundled models.json into the workspace. The dashboard Model Catalog can edit, reload, and enrich this file with live provider discovery.
Important behavior:
- model ids may be plain (
gpt-5.1) or provider-scoped (openai/gpt-5.1) - provider-scoped ids are useful when the same raw id exists under multiple provider profiles
/api/models/discover/{provider}reads live models from the configured provider API and helps seed catalog entries
See: Model Routing Guide
Some settings are still controlled via Spring properties (application config), typically using env vars in Docker:
- Workspace paths:
STORAGE_PATH,TOOLS_WORKSPACE - Dashboard toggle:
DASHBOARD_ENABLED - Plugin runtime:
BOT_PLUGINS_ENABLED,BOT_PLUGINS_DIRECTORY,BOT_PLUGINS_AUTO_START,BOT_PLUGINS_AUTO_RELOAD,BOT_PLUGINS_POLL_INTERVAL - Skills marketplace source defaults:
BOT_SKILLS_MARKETPLACE_REPOSITORY_DIRECTORY,BOT_SKILLS_MARKETPLACE_REPOSITORY_URL,BOT_SKILLS_MARKETPLACE_BRANCH - Skills marketplace HTTP fallback:
BOT_SKILLS_MARKETPLACE_API_BASE_URL,BOT_SKILLS_MARKETPLACE_RAW_BASE_URL,BOT_SKILLS_MARKETPLACE_REMOTE_CACHE_TTL - Plugin marketplace source:
BOT_PLUGINS_MARKETPLACE_REPOSITORY_DIRECTORY,BOT_PLUGINS_MARKETPLACE_REPOSITORY_URL,BOT_PLUGINS_MARKETPLACE_BRANCH - Plugin marketplace HTTP fallback:
BOT_PLUGINS_MARKETPLACE_API_BASE_URL,BOT_PLUGINS_MARKETPLACE_RAW_BASE_URL,BOT_PLUGINS_MARKETPLACE_REMOTE_CACHE_TTL - SelfEvolving bootstrap overrides:
bot.self-evolving.bootstrap.* - Self-update controls:
BOT_UPDATE_ENABLED,UPDATE_PATH,BOT_UPDATE_MAX_KEPT_VERSIONS,BOT_UPDATE_CHECK_INTERVAL - Local bundle runtime override:
GOLEMCORE_BUNDLED_JAR,golemcore.launcher.bundled-jar - Allowed providers in model picker:
BOT_MODEL_SELECTION_ALLOWED_PROVIDERS - Tool result truncation:
bot.auto-compact.max-tool-result-chars - Plan mode feature flag:
bot.plan.enabled
The plugin runtime and marketplace are controlled by bot.plugins.*.
Important properties:
bot.plugins.enabled/BOT_PLUGINS_ENABLEDbot.plugins.directory/BOT_PLUGINS_DIRECTORYbot.plugins.auto-start/BOT_PLUGINS_AUTO_STARTbot.plugins.auto-reload/BOT_PLUGINS_AUTO_RELOADbot.plugins.poll-interval/BOT_PLUGINS_POLL_INTERVALbot.plugins.marketplace.repository-directory/BOT_PLUGINS_MARKETPLACE_REPOSITORY_DIRECTORYbot.plugins.marketplace.repository-url/BOT_PLUGINS_MARKETPLACE_REPOSITORY_URLbot.plugins.marketplace.branch/BOT_PLUGINS_MARKETPLACE_BRANCHbot.plugins.marketplace.api-base-url/BOT_PLUGINS_MARKETPLACE_API_BASE_URLbot.plugins.marketplace.raw-base-url/BOT_PLUGINS_MARKETPLACE_RAW_BASE_URLbot.plugins.marketplace.remote-cache-ttl/BOT_PLUGINS_MARKETPLACE_REMOTE_CACHE_TTL
Behavior:
- If
repository-directoryis configured and present, marketplace metadata/artifacts are read from that repository checkout. - Otherwise the backend falls back to the configured remote repository and GitHub HTTP sources.
- Installed marketplace artifacts are written into the plugin runtime directory and then reloaded into the running bot.
Core skill loading is split between:
- workspace storage under
skills/ - runtime config under
skills - marketplace source defaults under
bot.skills.marketplace.*
Important properties:
bot.skills.marketplace-enabled/BOT_SKILLS_MARKETPLACE_ENABLEDbot.skills.marketplace-repository-directory/BOT_SKILLS_MARKETPLACE_REPOSITORY_DIRECTORYbot.skills.marketplace-sandbox-path/BOT_SKILLS_MARKETPLACE_SANDBOX_PATHbot.skills.marketplace-repository-url/BOT_SKILLS_MARKETPLACE_REPOSITORY_URLbot.skills.marketplace-branch/BOT_SKILLS_MARKETPLACE_BRANCHbot.skills.marketplace-api-base-url/BOT_SKILLS_MARKETPLACE_API_BASE_URLbot.skills.marketplace-raw-base-url/BOT_SKILLS_MARKETPLACE_RAW_BASE_URLbot.skills.marketplace-remote-cache-ttl/BOT_SKILLS_MARKETPLACE_REMOTE_CACHE_TTL
Runtime config fields exposed in the dashboard:
{
"skills": {
"enabled": true,
"progressiveLoading": true,
"marketplaceSourceType": "repository",
"marketplaceRepositoryDirectory": null,
"marketplaceSandboxPath": null,
"marketplaceRepositoryUrl": "https://github.com/alexk-dev/golemcore-skills",
"marketplaceBranch": "main"
}
}Behavior:
- The dashboard
Skills -> Marketplacepage can switch the source betweenrepository,directory, andsandbox. - Runtime config values take precedence over Spring defaults when present.
- If source type is
directory, the configured path may point either to the repository root or directly to itsregistry/directory. - If source type is
directoryand the configured path points at a validgolemcore-skillscheckout, metadata is loaded from disk. - If source type is
sandbox, the configured path is resolved relative to the configured tool workspace and must stay inside that sandbox. - If source type is
sandbox, the configured path may point either to the repository root or directly to itsregistry/directory. - Otherwise the backend reads the configured remote repository through the GitHub tree/raw endpoints.
- Remote repository mode currently expects a GitHub repository URL such as
https://github.com/alexk-dev/golemcore-skills. - Installed skill artifacts are written into
skills/marketplace/<maintainer>/<artifact>/...and then the skill registry is reloaded. - Standalone marketplace artifacts install one runtime skill; pack artifacts install multiple runtime skills with namespaced runtime ids.
- The registry format is manifest-driven:
registry/<maintainer>/maintainer.yamlplusregistry/<maintainer>/<artifact>/artifact.yaml.
Core self-update is controlled by Spring properties under bot.update.*.
bot.update.enableddefaults totrue(disable withBOT_UPDATE_ENABLED=false).- Release repository is fixed in code:
alexk-dev/golemcore-bot. - GitHub token is not required (public repository).
- Release asset glob is fixed in code:
bot-*-exec.jar.
Configurable properties:
bot.update.updates-path(UPDATE_PATH, default${STORAGE_PATH}/updates; ifSTORAGE_PATHis unset, it followsbot.storage.local.base-path)bot.update.max-kept-versions(BOT_UPDATE_MAX_KEPT_VERSIONS, default3)bot.update.check-interval(BOT_UPDATE_CHECK_INTERVAL, defaultPT1H)
When the app starts through the native app-image launcher, the CLI launcher can also use:
GOLEMCORE_BUNDLED_JARgolemcore.launcher.bundled-jar
These point to the bundled runtime jar inside the local app-image.
The native launcher itself is picocli-based and documents its launcher-only options via --help.
Launcher-specific options:
webstarts the spawned runtimeweb --port=<port>forwards-Dserver.port=<port>to the spawned runtimeweb --hostname=<address>forwards-Dserver.address=<address>to the spawned runtime--storage-path=<path>orweb --storage-path=<path>forwards-Dbot.storage.local.base-path=<path>--updates-path=<path>orweb --updates-path=<path>forwards-Dbot.update.updates-path=<path>--bundled-jar=<path>overrides the bundled runtime jar pathweb -J=<jvm-option>/web --java-option=<jvm-option>forwards extra JVM options
The native package starts the Spring runtime with the prod profile by default.
Unknown arguments are passed through to Spring Boot, so both of these remain valid:
golemcore-bot web --port=9090
golemcore-bot web --spring.main.banner-mode=offThe launcher priority is:
- staged update selected by
updates/current.txt, unless the bundled runtime jar is newer - bundled runtime jar
- legacy Jib classpath fallback
This preserves the existing self-update model for local distributions while allowing a newer native bundle to take over from an older persisted runtime.
Default (macOS/Linux): ~/.golemcore/workspace
workspace/
├── auto/ # auto mode + plan mode state
├── memory/ # structured memory items (JSONL)
├── models/ # models.json (capabilities)
├── preferences/ # settings.json, sectioned runtime config, admin.json, hive-session.json
├── sessions/ # conversation sessions
├── skills/ # manual skills + marketplace-installed artifacts
└── usage/ # usage logs
Example skills layout:
workspace/skills/
├── greeting/
│ └── SKILL.md
└── marketplace/
└── golemcore/
└── devops-pack/
├── .marketplace-install.json
└── skills/
├── deploy-review/SKILL.md
└── incident-triage/SKILL.md
- Health:
GET /api/system/health - Config flags:
GET /api/system/config - Diagnostics:
GET /api/system/diagnostics