Skip to content

zidane/presets

Ready-made agent option sets, plus definePreset() and composePresets() to build and merge your own.

import { … } from 'zidane/presets'src/presets/index.ts

Use zidane/presets to configure an agent with one spread. basic sets the shell, file, edit and spawn tools and a general-purpose system prompt. basicTools is the same set without spawn. artifacts detects pull requests, branches and commits in tool results, and adds the record_artifact tool. composePresets() merges presets field by field, so hooks, tools and aliases combine and do not overwrite each other.

TypeScript
import { createAgent } from 'zidane'
import { basic, composePresets, definePreset } from 'zidane/presets'
import { anthropic } from 'zidane/providers/anthropic'

const concise = definePreset({ system: 'Answer briefly.' })
const agent = createAgent({ ...composePresets(basic, concise), provider: anthropic() })

const stats = await agent.run({ prompt: 'What does this repo do?' })
console.log(stats.turns)

Functions#

composePresetsFunction#

Field-aware composition of presets. Right-most preset wins for scalar fields; objects shallow-merge; arrays and hook handler lists concatenate. Designed so stacking presets does the obvious thing without the spread-collision footgun:

  • name, system, eager, skills → last-defined wins
  • tools, toolAliases, toolDescriptions, behavior → shallow-merge (later keys override)
  • behavior.dedupTools, behavior.toolBudgets → deep-merge (per-tool-name; later wins on collision)
  • mcpServers → concat with last-wins on name collision
  • hooks → per-event concat; every handler fires

hooks always emerges as event → handler[] so downstream registration (in createAgent) sees a uniform shape. Order of handlers within an event follows preset order: earlier presets register first.

mcpServers is deduped by name because shipping two servers with the same name would trip the connector at runtime — a later preset overriding an earlier preset's github server is the practical intent.

behavior.dedupTools and behavior.toolBudgets get the same per-key deep-merge because they are tool-name-keyed records — a preset that ships a dedup hasher for one tool should not erase a hasher another preset ships for a different tool. Last-wins still applies on a per-tool collision so a downstream preset can override an upstream preset's policy for one specific tool. Other behavior fields keep last-wins semantics.

TypeScript
function composePresets(...presets: Preset[]): Preset
Parameters
NameTypeDescription
...presetsPreset[]

Presets to merge, in order. Later presets win on conflicts.

Example
import { createAgent } from 'zidane'
import { basic, composePresets, definePreset } from 'zidane/presets'
import { anthropic } from 'zidane/providers/anthropic'

const concise = definePreset({ system: 'Answer briefly.' })
const agent = createAgent({
  ...composePresets(basic, concise),
  provider: anthropic(),
})

src/presets/compose.ts:89

definePresetFunction#

Identity helper for type inference when defining a preset.

TypeScript
function definePreset(config: Preset): Preset
Parameters
NameTypeDescription
configPreset

Preset fields to define.

Example
import { definePreset } from 'zidane/presets'

export const concise = definePreset({
  system: 'Answer in as few words as possible.',
})

src/presets/compose.ts:45

Constants#

artifactsConstant#

Preset that detects pull requests, commits and branches in tool results (files are recorded by the loop, not by detection) and adds the record_artifact tool for outputs detection cannot see. Detection runs as tool:transform hooks, including those bubbled up from subagents.

TypeScript
const artifacts: Preset

src/presets/artifacts.ts:30

basicConstant#

Default preset with the shell, file, edit and spawn tools and a general-purpose system prompt. The spawn tool is created fresh on every access, so each agent gets its own subagent state.

TypeScript
const basic: Preset

src/presets/basic.ts:27

basicToolsConstant#

Core tools available in every basic preset (without spawn).

edit and multi_edit ship in the basic set because surgical edits are the default modality for production agents — write_file is for full overwrites. glob and grep are exported but opt-in: not every agent needs codebase search, and shipping them by default would force tool:gate work onto consumers that prefer the model to use shell + classic Unix tools.

TypeScript
const basicTools: { edit: ToolDef; listFiles: ToolDef; multiEdit: ToolDef; readFile: ToolDef; shell: ToolDef; shellKill: ToolDef; waitTask: ToolDef; writeFile: ToolDef }

src/presets/basic.ts:24

Types#

PresetType#

A preset is a reusable slice of AgentOptions — spread it into createAgent() to configure tools, a default system prompt, aliases, behavior defaults, and agent-lifetime hooks.

provider, execution, session, and mcpConnector are excluded — they're ambient / per-invocation runtime wiring (a custom mcpConnector is the MCP connection seam, often closure-bound to a transport / auth provider), so presets stay shareable and composable.

Text
import { basic } from 'zidane/presets'
createAgent({ ...basic, provider })

Composing multiple presets

Bare ...spread is shallow — { ...a, ...b } overwrites every key b defines, including hooks. Use composePresets when you want field-aware merging (per-event hook concat, tools shallow-merge, etc.):

Text
createAgent({ ...composePresets(basic, telemetry, mine), provider })
TypeScript
type Preset = Omit<Partial<AgentOptions>, 'provider' | 'execution' | 'session' | 'mcpConnector'>

src/presets/compose.ts:30

Re-exports#

These names are documented on the entry point that owns them.