Documentation Index
Fetch the complete documentation index at: https://mintlify.com/getsentry/warden/llms.txt
Use this file to discover all available pages before exploring further.
Warden’s configuration system parses warden.toml files and resolves skill configurations into executable triggers with merged defaults.
loadWardenConfig()
Load and validate a warden.toml configuration file.
Function Signature
function loadWardenConfig(repoPath: string): WardenConfig
Path to the repository root. The function looks for warden.toml in this directory.
Returns
Parsed and validated configuration object:interface WardenConfig {
version: 1;
defaults?: Defaults;
skills: SkillConfig[];
runner?: RunnerConfig;
logs?: LogsConfig;
}
Example
import { loadWardenConfig } from '@sentry/warden';
try {
const config = loadWardenConfig('/path/to/repo');
console.log(`Loaded ${config.skills.length} skills`);
} catch (error) {
if (error instanceof ConfigLoadError) {
console.error('Invalid config:', error.message);
}
}
Error Handling
Throws ConfigLoadError with detailed diagnostics:
import { loadWardenConfig, ConfigLoadError } from '@sentry/warden';
try {
const config = loadWardenConfig(repoPath);
} catch (error) {
if (error instanceof ConfigLoadError) {
// Error types:
// - "Configuration file not found"
// - "Failed to read configuration file"
// - "Failed to parse TOML configuration"
// - "Invalid configuration" (with validation details)
console.error(error.message);
}
}
Detects and provides migration guidance for the old [[triggers]] format:
# ❌ Legacy format (detected and rejected)
[[triggers]]
name = "my-skill"
event = "pull_request"
actions = ["opened", "synchronize"]
Error message includes migration path:
Legacy [[triggers]] format detected. Migrate to [[skills]] format:
[[triggers]] → [[skills]]
name = "my-skill" name = "my-skill"
event = "pull_request" → [[skills.triggers]]
skill = "my-skill" type = "pull_request"
actions = [...] actions = [...]
Validation
The function validates:
- File existence -
warden.toml must exist in repo root
- TOML syntax - Valid TOML format
- Schema conformance - All fields match expected types
- Duplicate names - Skill names must be unique
- Schedule paths - Skills with
type = "schedule" must define paths
- PR actions - Pull request triggers must specify
actions
resolveSkillConfigs()
Flattens skill configurations into executable triggers with merged defaults.
Function Signature
function resolveSkillConfigs(
config: WardenConfig,
cliModel?: string
): ResolvedTrigger[]
Configuration loaded from loadWardenConfig()
Model specified via CLI flag (e.g., --model). Used in model precedence chain.
Returns
Array of resolved triggers, one per skill × trigger combination:interface ResolvedTrigger {
name: string; // Skill name
skill: string; // Same as name
type: TriggerType | '*'; // 'pull_request', 'local', 'schedule', or wildcard
actions?: string[]; // PR actions (for pull_request type)
remote?: string; // Remote repo reference
filters: {
paths?: string[]; // Include patterns
ignorePaths?: string[]; // Exclude patterns
};
// Merged output options
failOn?: SeverityThreshold;
reportOn?: SeverityThreshold;
maxFindings?: number;
reportOnSuccess?: boolean;
requestChanges?: boolean;
failCheck?: boolean;
model?: string;
maxTurns?: number;
minConfidence?: ConfidenceThreshold;
schedule?: ScheduleConfig;
}
Example
import { loadWardenConfig, resolveSkillConfigs } from '@sentry/warden';
const config = loadWardenConfig('/path/to/repo');
const triggers = resolveSkillConfigs(config, 'claude-sonnet-4-20250514');
for (const trigger of triggers) {
console.log(`${trigger.name} (${trigger.type})`);
console.log(` Model: ${trigger.model}`);
console.log(` Fail on: ${trigger.failOn ?? 'off'}`);
}
Wildcard Triggers
Skills without [[skills.triggers]] produce a wildcard entry (type: '*'):
[[skills]]
name = "security-review"
# No triggers = runs everywhere
Resolved as:
{
name: "security-review",
type: "*",
filters: { ignorePaths: [...] },
// ... merged defaults
}
Multi-Trigger Skills
Each [[skills.triggers]] entry generates a separate ResolvedTrigger:
[[skills]]
name = "security-review"
[[skills.triggers]]
type = "pull_request"
actions = ["opened", "synchronize"]
failOn = "high"
[[skills.triggers]]
type = "schedule"
failOn = "medium"
Produces two triggers:
[
{
name: "security-review",
type: "pull_request",
actions: ["opened", "synchronize"],
failOn: "high",
},
{
name: "security-review",
type: "schedule",
failOn: "medium",
},
]
Model Precedence
Model selection follows a 6-level precedence chain (highest to lowest):
- Trigger-level
model (per-trigger override)
- Skill-level
model (per-skill default)
defaults.model (global default in warden.toml)
cliModel parameter (from --model flag)
WARDEN_MODEL environment variable
- SDK default (not set by
resolveSkillConfigs)
const triggers = resolveSkillConfigs(config, 'claude-opus-4-20250514');
// CLI model applies to skills without explicit model config
Path Filter Merging
ignorePaths is additive across defaults and skills:
[defaults]
ignorePaths = ["**/test/**", "**/fixtures/**"]
[[skills]]
name = "security-review"
ignorePaths = ["**/generated/**"]
Resolved as:
{
filters: {
ignorePaths: [
"**/test/**",
"**/fixtures/**",
"**/generated/**", // merged
],
},
}
Field Inheritance
All output fields use 3-level precedence:
- Trigger-level (highest priority)
- Skill-level
- Defaults (lowest priority)
Example:
[defaults]
failOn = "medium"
reportOn = "low"
maxFindings = 50
[[skills]]
name = "security-review"
failOn = "high" # overrides defaults.failOn
# reportOn inherited from defaults
[[skills.triggers]]
type = "pull_request"
actions = ["opened"]
maxFindings = 10 # overrides skill and defaults
Resolved as:
{
failOn: "high", // from skill
reportOn: "low", // from defaults
maxFindings: 10, // from trigger
}
Configuration Types
WardenConfig
interface WardenConfig {
version: 1;
defaults?: Defaults;
skills: SkillConfig[];
runner?: RunnerConfig;
logs?: LogsConfig;
}
SkillConfig
interface SkillConfig {
name: string;
paths?: string[]; // Include patterns
ignorePaths?: string[]; // Exclude patterns
remote?: string; // Remote repo (e.g., "owner/repo@sha")
failOn?: SeverityThreshold;
reportOn?: SeverityThreshold;
maxFindings?: number;
reportOnSuccess?: boolean;
requestChanges?: boolean;
failCheck?: boolean;
model?: string;
maxTurns?: number;
minConfidence?: ConfidenceThreshold;
triggers?: SkillTrigger[];
}
SkillTrigger
interface SkillTrigger {
type: 'pull_request' | 'local' | 'schedule';
actions?: string[]; // Required for pull_request
failOn?: SeverityThreshold;
reportOn?: SeverityThreshold;
maxFindings?: number;
reportOnSuccess?: boolean;
requestChanges?: boolean;
failCheck?: boolean;
model?: string;
maxTurns?: number;
minConfidence?: ConfidenceThreshold;
schedule?: ScheduleConfig;
}
Defaults
interface Defaults {
failOn?: SeverityThreshold;
reportOn?: SeverityThreshold;
maxFindings?: number;
reportOnSuccess?: boolean;
requestChanges?: boolean;
failCheck?: boolean;
model?: string;
maxTurns?: number;
minConfidence?: ConfidenceThreshold;
ignorePaths?: string[];
defaultBranch?: string;
chunking?: ChunkingConfig;
batchDelayMs?: number;
auxiliaryMaxRetries?: number;
}
Complete Example
import {
loadWardenConfig,
resolveSkillConfigs,
matchTrigger,
type ResolvedTrigger
} from '@sentry/warden';
// Load and resolve config
const config = loadWardenConfig('/path/to/repo');
const allTriggers = resolveSkillConfigs(config);
// Filter by environment
function getTriggersForEnvironment(
triggers: ResolvedTrigger[],
environment: 'github' | 'local'
): ResolvedTrigger[] {
return triggers.filter(t => {
// Wildcards match everywhere
if (t.type === '*') return true;
// Local triggers only in local mode
if (t.type === 'local') return environment === 'local';
// PR triggers match in both environments
if (t.type === 'pull_request') return true;
// Schedule triggers don't run in local mode
if (t.type === 'schedule') return environment === 'github';
return false;
});
}
const githubTriggers = getTriggersForEnvironment(allTriggers, 'github');
console.log(`Found ${githubTriggers.length} GitHub triggers`);
// Filter by context (see matchTrigger for details)
import { buildEventContext } from '@sentry/warden';
const context = await buildEventContext(...);
const matchedTriggers = githubTriggers.filter(t =>
matchTrigger(t, context, 'github')
);