src / config.ts
src / config.ts
import { createConfigSchematics } from "@lmstudio/sdk";
export const configSchematics = createConfigSchematics()
.field(
"defaultWorkspacePath",
"string",
{
displayName: "Workspace path",
subtitle:
"Folder the tools work in. Wins over the empty folder LM Studio auto-creates per chat (working-directories/<id>); a folder you picked for the chat yourself still wins. Blank = the chat's folder.",
},
"",
)
.field(
"permissionMode",
"numeric",
{
int: true,
min: 0,
max: 2,
slider: { min: 0, max: 2, step: 1 },
displayName: "Permission mode",
subtitle:
"0 = Manual · 1 = Plan · 2 = Auto — Manual approves every action; Plan approves a plan once, then runs; Auto never asks. Reply /accept or /deny <reason> in chat.",
},
1,
)
.field(
"allowDestructiveEdits",
"boolean",
{
displayName: "Allow destructive commits",
subtitle: "Permit delete, move, and overwrite transactions to be committed.",
},
false,
)
.field(
"protectedPatterns",
"string",
{
displayName: "Paths the model may not write",
subtitle:
"Comma or newline separated globs. Blocks edits, not reads — keep secrets outside the workspace. `.git/**` and `.agentic/**` are always write-protected.",
},
".env,.env.*,**/*.pem,**/*.key",
)
.field(
"maxReadBytes",
"numeric",
{
int: true,
min: 1000,
max: 50000000,
displayName: "Maximum readable text file bytes",
subtitle: "Large or binary files are rejected by text tools.",
},
5000000,
)
.field(
"maxEditableBytes",
"numeric",
{
int: true,
min: 1000,
max: 20000000,
displayName: "Maximum editable file bytes",
subtitle: "Applies before and after a transaction.",
},
2000000,
)
.field(
"maxToolResultChars",
"numeric",
{
int: true,
min: 1000,
max: 100000,
displayName: "Maximum tool preview characters",
subtitle: "Full content is persisted as an artifact when a preview is truncated.",
},
14000,
)
.field(
"processExecutionEnabled",
"boolean",
{
displayName: "Allow process execution",
subtitle: "Enables structured executable + args command tools (allowlisted, no shell). Gated by the permission mode.",
},
true,
)
.field(
"inheritProcessEnvironment",
"boolean",
{
displayName: "Inherit full process environment",
subtitle: "Off by default to avoid exposing unrelated environment secrets to commands.",
},
false,
)
.field(
"allowedExecutables",
"string",
{
displayName: "Allowed executables",
subtitle: "Comma-separated bare executable names.",
},
"node,npm,npx,pnpm,python,python3,pytest,git,gh,tsc,deno,uv,ruff,eslint,prettier",
)
.field(
"maxCommandSeconds",
"numeric",
{
int: true,
min: 1,
max: 3600,
displayName: "Maximum command duration",
subtitle:
"Upper bound in seconds for run and for start with a positive timeout. start with timeout_seconds: 0 deliberately bypasses it for background jobs and survives a plugin reload — cancel it yourself.",
},
180,
)
.field(
"maxCommandPreviewChars",
"numeric",
{
int: true,
min: 1000,
max: 100000,
displayName: "Command output preview characters",
subtitle: "Per stdout/stderr stream. Full streams are stored under .agentic/jobs/.",
},
10000,
)
.field(
"maxCommandArtifactBytes",
"numeric",
{
int: true,
min: 10000,
max: 200000000,
displayName: "Maximum command artifact bytes",
subtitle: "Per stdout/stderr stream.",
},
20000000,
)
.field(
"internalAgentsEnabled",
"boolean",
{
displayName: "Enable durable sub-agents",
subtitle: "Adds foreground/background agent tools with bounded native tool loops.",
},
true,
)
.field(
"agentModelId",
"string",
{
displayName: "Agent model id",
subtitle: "Blank uses LM Studio's default loaded model. A dedicated model is recommended for background runs.",
},
"",
)
.field(
"agentMaxPasses",
"numeric",
{
int: true,
min: 1,
max: 20,
displayName: "Agent maximum passes",
subtitle: "Each pass reconstructs a compact view from durable state.",
},
6,
)
.field(
"agentRoundsPerPass",
"numeric",
{
int: true,
min: 1,
max: 12,
displayName: "Agent tool rounds per pass",
subtitle: "Bounds each native model.act loop before state is projected again.",
},
4,
)
.field(
"agentMaxToolCalls",
"numeric",
{
int: true,
min: 1,
max: 200,
displayName: "Agent maximum tool calls",
subtitle: "Hard budget for one durable run.",
},
40,
)
.field(
"agentAllowCommands",
"boolean",
{
displayName: "Allow agents to run commands",
subtitle: "Also requires process execution to be enabled.",
},
true,
)
.field(
"taskBoardsEnabled",
"boolean",
{
displayName: "Enable durable To-Do boards",
subtitle: "Adds project task boards and checkpoints under .agentic/tasks/.",
},
true,
)
.field(
"webResearchEnabled",
"boolean",
{
displayName: "Enable web research tools",
subtitle: "Allows outbound HTTP search and page fetching with SSRF and response-size protections.",
},
true,
)
.field(
"webSearchProvider",
"string",
{
displayName: "Default web search provider",
subtitle: "auto, duckduckgo, wikipedia, or searxng.",
},
"auto",
)
.field(
"searxngBaseUrl",
"string",
{
displayName: "SearXNG base URL",
subtitle: "Optional self-hosted SearXNG endpoint used by the searxng provider or auto mode.",
},
"",
)
.field(
"webAllowedDomains",
"string",
{
displayName: "Web domain allowlist",
subtitle: "Optional comma/newline-separated domains. Blank permits public internet hosts; private networks remain blocked.",
},
"",
)
.field(
"allowPrivateNetworkWeb",
"boolean",
{
displayName: "Allow private-network web access",
subtitle: "Off by default. Enabling permits localhost, LAN, and private IP targets and weakens SSRF protection.",
},
false,
)
.field(
"webTimeoutSeconds",
"numeric",
{
int: true,
min: 2,
max: 120,
displayName: "Web request timeout",
subtitle: "Maximum duration of each search or fetch request.",
},
20,
)
.field(
"maxWebResponseBytes",
"numeric",
{
int: true,
min: 10000,
max: 50000000,
displayName: "Maximum web response bytes",
subtitle: "Hard cap before extracted web content is stored.",
},
4000000,
)
.field(
"maxWebTextChars",
"numeric",
{
int: true,
min: 1000,
max: 500000,
displayName: "Maximum extracted web text characters",
subtitle: "Long pages are stored as bounded research sources and returned as compact previews.",
},
80000,
)
.field(
"agentAllowWeb",
"boolean",
{
displayName: "Allow sub-agents to use web research",
subtitle: "Also requires web research tools to be enabled for the chat.",
},
true,
)
.field(
"vcsToolsEnabled",
"boolean",
{
displayName: "Enable Git and GitHub tools",
subtitle: "Adds structured git/gh actions when process execution is enabled and the executables are allowlisted.",
},
true,
)
.field(
"browserEnabled",
"boolean",
{
displayName: "Enable browser sessions",
subtitle: "Optional Chromium automation for JavaScript-heavy pages. Requires puppeteer-core and a Chrome/Edge executable.",
},
false,
)
.field(
"browserExecutablePath",
"string",
{
displayName: "Browser executable path",
subtitle: "Blank auto-detects common Chrome, Chromium, and Edge locations.",
},
"",
)
.field(
"browserHeadless",
"boolean",
{
displayName: "Run browser headless",
subtitle: "Disable only when you explicitly want visible automated browser windows.",
},
true,
)
.field(
"browserAllowEvaluate",
"boolean",
{
displayName: "Allow browser JavaScript evaluation",
subtitle: "High-risk escape hatch for page DOM scripting. Off by default.",
},
false,
)
.field(
"workflowHintMode",
"string",
{
displayName: "Workflow prompt hint",
subtitle: "off, marker, or always. marker activates only when the user includes @agentic.",
},
"marker",
)
.build();
export function splitConfigList(value: string): string[] {
return value
.split(/[\n,]/)
.map((item) => item.trim())
.filter(Boolean);
}
import { createConfigSchematics } from "@lmstudio/sdk";
export const configSchematics = createConfigSchematics()
.field(
"defaultWorkspacePath",
"string",
{
displayName: "Workspace path",
subtitle:
"Folder the tools work in. Wins over the empty folder LM Studio auto-creates per chat (working-directories/<id>); a folder you picked for the chat yourself still wins. Blank = the chat's folder.",
},
"",
)
.field(
"permissionMode",
"numeric",
{
int: true,
min: 0,
max: 2,
slider: { min: 0, max: 2, step: 1 },
displayName: "Permission mode",
subtitle:
"0 = Manual · 1 = Plan · 2 = Auto — Manual approves every action; Plan approves a plan once, then runs; Auto never asks. Reply /accept or /deny <reason> in chat.",
},
1,
)
.field(
"allowDestructiveEdits",
"boolean",
{
displayName: "Allow destructive commits",
subtitle: "Permit delete, move, and overwrite transactions to be committed.",
},
false,
)
.field(
"protectedPatterns",
"string",
{
displayName: "Paths the model may not write",
subtitle:
"Comma or newline separated globs. Blocks edits, not reads — keep secrets outside the workspace. `.git/**` and `.agentic/**` are always write-protected.",
},
".env,.env.*,**/*.pem,**/*.key",
)
.field(
"maxReadBytes",
"numeric",
{
int: true,
min: 1000,
max: 50000000,
displayName: "Maximum readable text file bytes",
subtitle: "Large or binary files are rejected by text tools.",
},
5000000,
)
.field(
"maxEditableBytes",
"numeric",
{
int: true,
min: 1000,
max: 20000000,
displayName: "Maximum editable file bytes",
subtitle: "Applies before and after a transaction.",
},
2000000,
)
.field(
"maxToolResultChars",
"numeric",
{
int: true,
min: 1000,
max: 100000,
displayName: "Maximum tool preview characters",
subtitle: "Full content is persisted as an artifact when a preview is truncated.",
},
14000,
)
.field(
"processExecutionEnabled",
"boolean",
{
displayName: "Allow process execution",
subtitle: "Enables structured executable + args command tools (allowlisted, no shell). Gated by the permission mode.",
},
true,
)
.field(
"inheritProcessEnvironment",
"boolean",
{
displayName: "Inherit full process environment",
subtitle: "Off by default to avoid exposing unrelated environment secrets to commands.",
},
false,
)
.field(
"allowedExecutables",
"string",
{
displayName: "Allowed executables",
subtitle: "Comma-separated bare executable names.",
},
"node,npm,npx,pnpm,python,python3,pytest,git,gh,tsc,deno,uv,ruff,eslint,prettier",
)
.field(
"maxCommandSeconds",
"numeric",
{
int: true,
min: 1,
max: 3600,
displayName: "Maximum command duration",
subtitle:
"Upper bound in seconds for run and for start with a positive timeout. start with timeout_seconds: 0 deliberately bypasses it for background jobs and survives a plugin reload — cancel it yourself.",
},
180,
)
.field(
"maxCommandPreviewChars",
"numeric",
{
int: true,
min: 1000,
max: 100000,
displayName: "Command output preview characters",
subtitle: "Per stdout/stderr stream. Full streams are stored under .agentic/jobs/.",
},
10000,
)
.field(
"maxCommandArtifactBytes",
"numeric",
{
int: true,
min: 10000,
max: 200000000,
displayName: "Maximum command artifact bytes",
subtitle: "Per stdout/stderr stream.",
},
20000000,
)
.field(
"internalAgentsEnabled",
"boolean",
{
displayName: "Enable durable sub-agents",
subtitle: "Adds foreground/background agent tools with bounded native tool loops.",
},
true,
)
.field(
"agentModelId",
"string",
{
displayName: "Agent model id",
subtitle: "Blank uses LM Studio's default loaded model. A dedicated model is recommended for background runs.",
},
"",
)
.field(
"agentMaxPasses",
"numeric",
{
int: true,
min: 1,
max: 20,
displayName: "Agent maximum passes",
subtitle: "Each pass reconstructs a compact view from durable state.",
},
6,
)
.field(
"agentRoundsPerPass",
"numeric",
{
int: true,
min: 1,
max: 12,
displayName: "Agent tool rounds per pass",
subtitle: "Bounds each native model.act loop before state is projected again.",
},
4,
)
.field(
"agentMaxToolCalls",
"numeric",
{
int: true,
min: 1,
max: 200,
displayName: "Agent maximum tool calls",
subtitle: "Hard budget for one durable run.",
},
40,
)
.field(
"agentAllowCommands",
"boolean",
{
displayName: "Allow agents to run commands",
subtitle: "Also requires process execution to be enabled.",
},
true,
)
.field(
"taskBoardsEnabled",
"boolean",
{
displayName: "Enable durable To-Do boards",
subtitle: "Adds project task boards and checkpoints under .agentic/tasks/.",
},
true,
)
.field(
"webResearchEnabled",
"boolean",
{
displayName: "Enable web research tools",
subtitle: "Allows outbound HTTP search and page fetching with SSRF and response-size protections.",
},
true,
)
.field(
"webSearchProvider",
"string",
{
displayName: "Default web search provider",
subtitle: "auto, duckduckgo, wikipedia, or searxng.",
},
"auto",
)
.field(
"searxngBaseUrl",
"string",
{
displayName: "SearXNG base URL",
subtitle: "Optional self-hosted SearXNG endpoint used by the searxng provider or auto mode.",
},
"",
)
.field(
"webAllowedDomains",
"string",
{
displayName: "Web domain allowlist",
subtitle: "Optional comma/newline-separated domains. Blank permits public internet hosts; private networks remain blocked.",
},
"",
)
.field(
"allowPrivateNetworkWeb",
"boolean",
{
displayName: "Allow private-network web access",
subtitle: "Off by default. Enabling permits localhost, LAN, and private IP targets and weakens SSRF protection.",
},
false,
)
.field(
"webTimeoutSeconds",
"numeric",
{
int: true,
min: 2,
max: 120,
displayName: "Web request timeout",
subtitle: "Maximum duration of each search or fetch request.",
},
20,
)
.field(
"maxWebResponseBytes",
"numeric",
{
int: true,
min: 10000,
max: 50000000,
displayName: "Maximum web response bytes",
subtitle: "Hard cap before extracted web content is stored.",
},
4000000,
)
.field(
"maxWebTextChars",
"numeric",
{
int: true,
min: 1000,
max: 500000,
displayName: "Maximum extracted web text characters",
subtitle: "Long pages are stored as bounded research sources and returned as compact previews.",
},
80000,
)
.field(
"agentAllowWeb",
"boolean",
{
displayName: "Allow sub-agents to use web research",
subtitle: "Also requires web research tools to be enabled for the chat.",
},
true,
)
.field(
"vcsToolsEnabled",
"boolean",
{
displayName: "Enable Git and GitHub tools",
subtitle: "Adds structured git/gh actions when process execution is enabled and the executables are allowlisted.",
},
true,
)
.field(
"browserEnabled",
"boolean",
{
displayName: "Enable browser sessions",
subtitle: "Optional Chromium automation for JavaScript-heavy pages. Requires puppeteer-core and a Chrome/Edge executable.",
},
false,
)
.field(
"browserExecutablePath",
"string",
{
displayName: "Browser executable path",
subtitle: "Blank auto-detects common Chrome, Chromium, and Edge locations.",
},
"",
)
.field(
"browserHeadless",
"boolean",
{
displayName: "Run browser headless",
subtitle: "Disable only when you explicitly want visible automated browser windows.",
},
true,
)
.field(
"browserAllowEvaluate",
"boolean",
{
displayName: "Allow browser JavaScript evaluation",
subtitle: "High-risk escape hatch for page DOM scripting. Off by default.",
},
false,
)
.field(
"workflowHintMode",
"string",
{
displayName: "Workflow prompt hint",
subtitle: "off, marker, or always. marker activates only when the user includes @agentic.",
},
"marker",
)
.build();
export function splitConfigList(value: string): string[] {
return value
.split(/[\n,]/)
.map((item) => item.trim())
.filter(Boolean);
}