From 6cf3570c5b71706b4a51c01d11e75084e0d80a88 Mon Sep 17 00:00:00 2001 From: Onur Date: Wed, 7 Jan 2026 01:02:51 +0800 Subject: [PATCH] feat(agent): add skipBootstrap config to skip bootstrap file creation (#292) --- src/agents/sandbox.ts | 23 +++++++++++++++++++---- src/auto-reply/reply.ts | 2 +- src/commands/agent.ts | 2 +- src/config/types.ts | 2 ++ src/config/zod-schema.ts | 1 + src/cron/isolated-agent.ts | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/agents/sandbox.ts b/src/agents/sandbox.ts index b788e25a5..15ef13840 100644 --- a/src/agents/sandbox.ts +++ b/src/agents/sandbox.ts @@ -434,7 +434,11 @@ async function dockerContainerState(name: string) { return { exists: true, running: result.stdout.trim() === "true" }; } -async function ensureSandboxWorkspace(workspaceDir: string, seedFrom?: string) { +async function ensureSandboxWorkspace( + workspaceDir: string, + seedFrom?: string, + skipBootstrap?: boolean, +) { await fs.mkdir(workspaceDir, { recursive: true }); if (seedFrom) { const seed = resolveUserPath(seedFrom); @@ -461,7 +465,10 @@ async function ensureSandboxWorkspace(workspaceDir: string, seedFrom?: string) { } } } - await ensureAgentWorkspace({ dir: workspaceDir, ensureBootstrapFiles: true }); + await ensureAgentWorkspace({ + dir: workspaceDir, + ensureBootstrapFiles: !skipBootstrap, + }); } function normalizeDockerLimit(value?: string | number) { @@ -856,7 +863,11 @@ export async function resolveSandboxContext(params: { : workspaceRoot; const seedWorkspace = params.workspaceDir?.trim() || DEFAULT_AGENT_WORKSPACE_DIR; - await ensureSandboxWorkspace(workspaceDir, seedWorkspace); + await ensureSandboxWorkspace( + workspaceDir, + seedWorkspace, + params.config?.agent?.skipBootstrap, + ); const containerName = await ensureSandboxContainer({ sessionKey: rawSessionKey, @@ -899,7 +910,11 @@ export async function ensureSandboxWorkspaceForSession(params: { : workspaceRoot; const seedWorkspace = params.workspaceDir?.trim() || DEFAULT_AGENT_WORKSPACE_DIR; - await ensureSandboxWorkspace(workspaceDir, seedWorkspace); + await ensureSandboxWorkspace( + workspaceDir, + seedWorkspace, + params.config?.agent?.skipBootstrap, + ); return { workspaceDir, diff --git a/src/auto-reply/reply.ts b/src/auto-reply/reply.ts index cd91595d6..b772a2414 100644 --- a/src/auto-reply/reply.ts +++ b/src/auto-reply/reply.ts @@ -219,7 +219,7 @@ export async function getReplyFromConfig( const workspaceDirRaw = cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR; const workspace = await ensureAgentWorkspace({ dir: workspaceDirRaw, - ensureBootstrapFiles: true, + ensureBootstrapFiles: !cfg.agent?.skipBootstrap, }); const workspaceDir = workspace.dir; const timeoutMs = resolveAgentTimeoutMs({ cfg }); diff --git a/src/commands/agent.ts b/src/commands/agent.ts index fa5287534..4fda21fc2 100644 --- a/src/commands/agent.ts +++ b/src/commands/agent.ts @@ -162,7 +162,7 @@ export async function agentCommand( const workspaceDirRaw = cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR; const workspace = await ensureAgentWorkspace({ dir: workspaceDirRaw, - ensureBootstrapFiles: true, + ensureBootstrapFiles: !cfg.agent?.skipBootstrap, }); const workspaceDir = workspace.dir; diff --git a/src/config/types.ts b/src/config/types.ts index c88e31901..7c6e70f08 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -824,6 +824,8 @@ export type ClawdbotConfig = { models?: Record; /** Agent working directory (preferred). Used as the default cwd for agent runs. */ workspace?: string; + /** Skip bootstrap (BOOTSTRAP.md creation, etc.) for pre-configured deployments. */ + skipBootstrap?: boolean; /** Optional IANA timezone for the user (used in system prompt; defaults to host timezone). */ userTimezone?: string; /** Optional display-only context window override (used for % in status UIs). */ diff --git a/src/config/zod-schema.ts b/src/config/zod-schema.ts index d2efe9bd8..061ff6445 100644 --- a/src/config/zod-schema.ts +++ b/src/config/zod-schema.ts @@ -479,6 +479,7 @@ export const ClawdbotSchema = z.object({ ) .optional(), workspace: z.string().optional(), + skipBootstrap: z.boolean().optional(), userTimezone: z.string().optional(), contextTokens: z.number().int().positive().optional(), tools: z diff --git a/src/cron/isolated-agent.ts b/src/cron/isolated-agent.ts index a121636a5..03bc20edc 100644 --- a/src/cron/isolated-agent.ts +++ b/src/cron/isolated-agent.ts @@ -200,7 +200,7 @@ export async function runCronIsolatedAgentTurn(params: { params.cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR; const workspace = await ensureAgentWorkspace({ dir: workspaceDirRaw, - ensureBootstrapFiles: true, + ensureBootstrapFiles: !params.cfg.agent?.skipBootstrap, }); const workspaceDir = workspace.dir;