How Tool Presets Work in Pi Web: PRESET_NONE, DEFAULT, and FULL Explained

TLDR: Pi Web controls assistant capabilities through three constant arrays defined in lib/tool-presets.ts, using helper functions to bidirectionally map between preset names and concrete tool lists during session initialization.

The agegr/pi-web repository implements a session-based tool management system that restricts which built-in tools an AI assistant can invoke. Understanding how PRESET_NONE, PRESET_DEFAULT, and PRESET_FULL function is essential for configuring secure agent interactions and managing filesystem access permissions.

The Three Preset Constants in lib/tool-presets.ts

The file lib/tool-presets.ts exports three constant arrays that serve as the single source of truth for available tool combinations. These constants define the security boundaries for agent capabilities.

PRESET_NONE – Complete Tool Restriction

PRESET_NONE is defined as an empty array, representing the most restrictive configuration where the assistant cannot access any built-in tools.

PRESET_DEFAULT – Core File Operations

PRESET_DEFAULT enables the four essential tools required for basic interaction:

  • read
  • bash
  • edit
  • write

This preset provides sufficient access for reading files, executing shell commands, and modifying content without exposing filesystem search utilities.

PRESET_FULL – Extended Search Capabilities

PRESET_FULL includes all tools from the default preset plus three additional filesystem search utilities:

  • grep
  • find
  • ls

The complete definition in lib/tool-presets.ts establishes these arrays and creates a validation set:

const PRESET_NONE = [];
const PRESET_DEFAULT = ["read", "bash", "edit", "write"];
const PRESET_FULL = ["bash", "read", "edit", "write", "grep", "find", "ls"];

const BUILTIN_TOOL_NAMES = new Set(PRESET_FULL);

Converting Between Presets and Tool Arrays

The module provides bidirectional translation utilities to convert between user-facing preset names and the concrete tool arrays stored in session state.

Detecting the Active Preset with getPresetFromTools

When a session initializes with a specific allow-list, the getPresetFromTools function determines which preset label applies by comparing sorted tool arrays:

function getPresetFromTools(activeTools: string[]): string {
  const active = [...activeTools].sort().join(",");
  
  if (active === [...PRESET_DEFAULT].sort().join(",")) return "default";
  if (active === [...PRESET_FULL].sort().join(",")) return "full";
  return "none";
}

This string comparison approach ensures that tool order does not affect preset detection. If the active tools match PRESET_DEFAULT, the function returns "default"; if they match PRESET_FULL, it returns "full"; otherwise, it defaults to "none".

Resolving Preset Names with getPresetFromName

To convert a preset selection into an actionable tool list, getPresetFromName performs the inverse operation:

function getPresetFromName(preset: string): string[] {
  if (preset === "none") return [...PRESET_NONE];
  if (preset === "full") return [...PRESET_FULL];
  return [...PRESET_DEFAULT];
}

This function returns a copy of the appropriate constant array, ensuring that modifications to the returned list do not affect the original preset definitions.

How Presets Are Applied Across the Codebase

The preset system integrates into the application at three critical layers: session initialization, user interface controls, and runtime security validation.

Session Initialization in rpc-manager.ts

When creating a new agent session via POST /api/agent/new, the selected tool list is passed to lib/rpc-manager.ts. The RPC manager stores this allow-list in the session state, determining which tools the assistant can invoke during that specific conversation.

UI Configuration Controls

Frontend components like components/ToolsConfig.tsx present users with a dropdown selector that maps to the three preset strings. When a user selects a preset, the UI calls getPresetFromName to generate the actual toolNames array sent to the API.

Runtime Validation with BUILTIN_TOOL_NAMES

At runtime, the system uses BUILTIN_TOOL_NAMES—a Set constructed from PRESET_FULL—to validate tool execution requests. This prevents arbitrary tool injection by verifying that any requested tool exists within the full built-in set before execution.

Summary

  • PRESET_NONE disables all built-in tools, returning an empty array for maximum restriction.
  • PRESET_DEFAULT enables core file interaction tools: read, bash, edit, and write.
  • PRESET_FULL extends the default set with search utilities: grep, find, and ls.
  • getPresetFromTools identifies which preset label corresponds to an active tool list by comparing sorted string representations.
  • getPresetFromName converts preset strings into concrete tool arrays for session configuration.
  • BUILTIN_TOOL_NAMES provides runtime validation to ensure only predefined tools from PRESET_FULL can execute.

Frequently Asked Questions

What is the difference between PRESET_DEFAULT and PRESET_FULL?

PRESET_DEFAULT includes only the four essential tools (read, bash, edit, write) needed for basic file operations and command execution. PRESET_FULL adds three search utilities (grep, find, ls) that enable the assistant to locate files and search content across the filesystem, providing broader discovery capabilities at the cost of increased access scope.

How does Pi Web determine which preset is currently active?

The system uses the getPresetFromTools function in lib/tool-presets.ts, which sorts the active tool list and compares it against sorted versions of PRESET_DEFAULT and PRESET_FULL. If the sorted active list matches PRESET_DEFAULT, it returns "default"; if it matches PRESET_FULL, it returns "full"; otherwise, it returns "none".

Can custom tool presets be added beyond the three built-in options?

While the source code defines only three constants (PRESET_NONE, PRESET_DEFAULT, PRESET_FULL), the architecture supports custom tool arrays because getPresetFromTools falls back to "none" for any non-matching list. However, the UI components like ToolsConfig.tsx would require modification to expose additional preset options to users.

Where is the tool preset validation enforced during runtime?

Runtime validation occurs using BUILTIN_TOOL_NAMES, a Set derived from PRESET_FULL defined in lib/tool-presets.ts. This set contains all valid built-in tool names, and the RPC manager uses it to verify that requested tools exist within the allowed set before execution, preventing unauthorized tool invocation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →