- MCP Server ToolsUpdated
- Managed MCP with chat()Updated
- Manual MCPUpdated
- MCP Type GenerationUpdated
- MCP Client InputUpdated
- MCP Server Tools: AdvancedNew
- MCP EventsNew
- MCP AppsUpdated
- Serve Tools over HTTPUpdated
- Serve Resources and PromptsUpdated
- Ask for InputUpdated
- Draft Text from a ToolUpdated
- MCP Server TasksUpdated
- MCP Server AuthUpdated
- MCP Server SessionsUpdated
- MCP Server on stdioUpdated
Persistence (Advanced)
- GenerationsUpdated
- Realtime Voice ChatUpdated
- Text-to-SpeechUpdated
- TranscriptionUpdated
- Transcription: AdvancedNew
- Voice CreationUpdated
- Audio RecordingUpdated
- Audio GenerationUpdated
- Image GenerationUpdated
- Image Generation: AdvancedNew
- Video GenerationUpdated
- Video Generation: AdvancedNew
- Live GenerationUpdated
- World GenerationUpdated
- Generation HooksUpdated
- Build your first harnessUpdated
- Host optionsNew
- Send and show mediaUpdated
- Connect clientsUpdated
- Write a client in any languageNew
- Access and tenantsNew
- Run in the terminalUpdated
- Deploy a harnessUpdated
- Send inputs safelyUpdated
- Run a tool without a model
- Durable sessionsUpdated
- Run background work on workersNew
- List, rename, and fork sessionsUpdated
- Lifecycle and retentionNew
- Run side effects onceUpdated
- Wait for a personNew
- Build on the session logUpdated
- Control how a turn endsUpdated
- Store settings per threadUpdated
- Compact a long sessionUpdated
- Fork and reset a threadUpdated
- One log for a session treeUpdated
- Write a pluginUpdated
- Track usage and costUpdated
- Ask before risky tool callsUpdated
- Give your agent coding toolsUpdated
- Sandbox and extend the coding toolsUpdated
- Run the coding tools for many threadsNew
- Undo a turnUpdated
- Build a coding agentUpdated
- Delegate to coding agentsUpdated
- Switch between agent profilesUpdated
- Auth and connectorsUpdated
- Share a thread between peopleUpdated
- Connect model providersUpdated
- Build your own UIUpdated
- Code mode in a harnessUpdated
- Work until a goal is metUpdated
- Run agents from a harnessUpdated
- Hand off a conversationNew
- Add skillsUpdated
- Use MCP serversUpdated
- Give your agent a computerNew
- Use from any MCP clientUpdated
- Use a harness from an editor (ACP)Updated
- OverviewUpdated
- Quick StartUpdated
- ProvidersUpdated
- HarnessesUpdated
- Harness AuthUpdated
- WorkspaceUpdated
- ToolsUpdated
- PolicyUpdated
- Lifecycle & SnapshotsUpdated
- Portable SnapshotsUpdated
- Keep Files After ReloadUpdated
- Save a Named VersionUpdated
- Branch From a VersionUpdated
- Send a Frozen FileUpdated
- Let the Agent Save and ForkUpdated
- Pick Which Files to KeepUpdated
- What a Snapshot StoresUpdated
- Instance DurabilityUpdated
- Durable RunsUpdated
- EventsUpdated
Sandboxes (Advanced)
- Runtime ContextUpdated
- Bring Your Own KeyUpdated
- Keep Keys on the ServerNew
- Debug LoggingUpdated
- Multimodal ContentUpdated
- Files APIUpdated
- Per-Model Type SafetyUpdated
- Runtime Adapter SwitchingUpdated
- Tree-ShakingUpdated
- Extend AdapterUpdated
- Extend Adapter: AdvancedNew
- Typed Pre-Configured OptionsUpdated
- Test with a Fake ModelUpdated
- Prompt CachingUpdated
- Mid-Conversation ChangesUpdated
- Approval Flow ProcessingUpdated
Pick Which Files to Keep
Limit which workspace files a portable snapshot stores. The agent can still write the rest of the workspace.
Pass a policy when you create the snapshots object. include and exclude are functions. They decide which workspace paths the capture stores. The same policy runs on automatic save, named save, and restore.
This page assumes you already created a snapshots object. If you have not, start with Keep Files After Reload.
Pass the policy#
Pass policy to memorySandboxSnapshots or createSandboxSnapshots. Then pass that same snapshots object to withSandbox. This sample keeps only the src folder:
import { chat } from '@tanstack/ai'
import { GROK_CLI_INSTALL_COMMAND, grokBuildText } from '@tanstack/ai-grok-build'
import { withPersistence } from '@tanstack/ai-persistence'
import {
createSecrets,
defaultSandboxSnapshotPolicy,
defineSandbox,
defineWorkspace,
InMemorySandboxInstanceStore,
memorySandboxSnapshots,
withSandbox,
} from '@tanstack/ai-sandbox'
import { dockerSandbox } from '@tanstack/ai-sandbox-docker'
const instances = new InMemorySandboxInstanceStore()
const sandbox = defineSandbox({
id: 'app-builder',
provider: dockerSandbox({ image: 'node:22' }),
workspace: defineWorkspace({
source: { type: 'none' },
setup: [GROK_CLI_INSTALL_COMMAND],
secrets: createSecrets({ XAI_API_KEY: process.env.XAI_API_KEY ?? '' }),
}),
lifecycle: { reuse: 'thread' },
})
const defaults = defaultSandboxSnapshotPolicy()
const snapshots = await memorySandboxSnapshots({
sandbox,
instances,
policy: {
...defaults,
include(path: string) {
return path === 'src' || path.startsWith('src/')
},
},
})
const result = chat({
threadId: 'app-thread',
adapter: grokBuildText('composer-2.5'),
messages: [{ role: 'user', content: 'Create a landing page.' }],
middleware: [
withPersistence(snapshots.persistence),
withSandbox(sandbox, { instances, snapshots }),
],
})
void resultsnapshots.save has no file list. Change the file set by changing policy on the snapshots object.
Default exclusions stay unless you pass exclude#
If you pass only include or only redact, the default exclusions stay in place. Capture still skips .env, .git, and node_modules.
If you pass exclude, that function replaces the default exclusions. Copy defaultSandboxSnapshotPolicy() first. Then keep those rules and add yours. Every recipe below starts with ...defaults for this reason. See Skip one extra folder.
The projection marker for this workspace stays protected. A custom policy cannot capture or restore that marker.
How include and exclude run#
Each path is a workspace-relative string such as src/app.ts. kind is file or dir.
- The projection marker is skipped.
- If exclude(path, kind) returns true, the path is skipped. For a directory, the whole tree under it is skipped.
- For a file, include(path, 'file') must return true. If you omit include, every file that is not excluded is stored.
- Capture then walks parent directories so a nested file can still match.
exclude wins. include: () => true cannot keep a path that exclude rejects.
Capture does not read a file that the policy skips.
Keep one file#
Return true only for that path. Capture still walks parent directories.
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const policy = {
...defaults,
include(path: string) {
return path === 'src/app.ts'
},
}Keep a few files#
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const keep = new Set(['package.json', 'src/app.ts', 'src/index.ts'])
const policy = {
...defaults,
include(path: string) {
return keep.has(path)
},
}Keep one folder#
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const policy = {
...defaults,
include(path: string) {
return path === 'src' || path.startsWith('src/')
},
}Keep files by suffix#
Allow directories so the walk can reach nested files. Then match the suffix.
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const policy = {
...defaults,
include(path: string, kind: 'file' | 'dir') {
return kind === 'dir' || path.endsWith('.ts')
},
}Skip one extra folder#
Keep the default exclude. Then add your folder.
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const policy = {
...defaults,
exclude(path: string, kind: 'file' | 'dir') {
if (defaults.exclude?.(path, kind)) return true
return path === 'dist' || path.startsWith('dist/')
},
}To skip a folder name at every depth, match a path segment:
import { defaultSandboxSnapshotPolicy } from '@tanstack/ai-sandbox'
const defaults = defaultSandboxSnapshotPolicy()
const policy = {
...defaults,
exclude(path: string, kind: 'file' | 'dir') {
if (defaults.exclude?.(path, kind)) return true
return path.split('/').includes('dist')
},
}What the policy does not filter#
The file policy applies to workspace files and empty directories only.
- The checkpoint still stores the full conversation for the thread.
- The checkpoint still copies every generated artifact for the thread.
See What a Snapshot Stores for secrets, default exclusions, and restore safety.
Restore#
Restore uses the same policy. Files that the policy does not include stay on the destination disk. Restore does not delete those files.
Automatic restore still writes the latest checkpoint into a new private sandbox. It does not write into a live resumed sandbox.