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 supports multiple output formats for different use cases: interactive terminal output, structured JSONL logs, and GitHub integration.
Terminal Output
TTY Mode
When running in an interactive terminal, Warden uses colored, formatted output:
__ __ _
/ / /\ \ \__ _ _ __ __| | ___ _ __
\ \/ \/ / _` | '__/ _` |/ _ \ '_ \
\ /\ / (_| | | | (_| | __/ | | |
\/ \/ \__,_|_| \__,_|\___|_| |_|
v1.0.0
FILES 3 files · 8 chunks
~ src/auth.ts (3 chunks)
+ src/api.ts (2 chunks)
~ src/config.ts (3 chunks)
SUMMARY
5 findings: ● 2 high ● 2 medium ● 1 low
Analysis completed in 15.8s · 3.0k in / 680 out · $0.00
Plain Text Mode (CI)
In non-TTY environments (CI/CD), Warden outputs plain text with timestamps:
[2026-03-05T20:00:00.000Z] warden: Warden v1.0.0
[2026-03-05T20:00:00.123Z] warden: Found 3 changed files with 8 chunks
[2026-03-05T20:00:15.800Z] warden: Summary: 5 findings (2 high, 2 medium, 1 low)
[2026-03-05T20:00:15.800Z] warden: Usage: 3.0k input, 680 output, $0.00
[2026-03-05T20:00:15.800Z] warden: Total time: 15.8s
Verbosity Levels
src/cli/output/verbosity.ts
export enum Verbosity {
Quiet = 0 , // Only final summary
Normal = 1 , // Standard output
Verbose = 2 , // Include progress details
Debug = 3 , // Full diagnostic output
}
Quiet Mode
5 findings (2 high, 2 medium, 1 low)
Verbose Mode
[1/3] src/auth.ts
[1/3] L15-42 → 2 findings
[2/3] L78-95 → 0 findings
[3/3] L120-150 → 1 finding
[2/3] src/api.ts
[1/2] L25-60 → 1 finding
[2/2] L88-110 → 0 findings
Debug Mode
[debug] Prompt size: system=2400 chars, user=1800 chars, total=4200 chars (~1050 tokens)
[debug] Extraction: found 2 findings via regex
[debug] Cache read: 1200 tokens, cache creation: 800 tokens
JSONL Output
JSON Lines format for programmatic consumption and log archival.
Enabling JSONL
warden scan --output=report.jsonl
Record Structure
export const JsonlRunMetadataSchema = z . object ({
timestamp: z . string (). datetime (),
durationMs: z . number (). nonnegative (),
cwd: z . string (),
runId: z . string (),
traceId: z . string (). optional (),
model: z . string (). optional (),
headSha: z . string (). optional (),
});
Skill Record
{
"run" : {
"timestamp" : "2026-03-05T20:00:00.000Z" ,
"durationMs" : 15800 ,
"cwd" : "/home/user/project" ,
"runId" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ,
"traceId" : "trace-123" ,
"model" : "claude-sonnet-4-20250514" ,
"headSha" : "abc123"
},
"skill" : "security-scanning" ,
"summary" : "Found 2 potential security issues" ,
"findings" : [
{
"id" : "sec-001" ,
"severity" : "high" ,
"confidence" : "high" ,
"title" : "Unvalidated user input" ,
"description" : "User input is used directly in SQL query without validation" ,
"location" : {
"path" : "src/auth.ts" ,
"startLine" : 42 ,
"endLine" : 45
}
}
],
"usage" : {
"inputTokens" : 3000 ,
"outputTokens" : 680 ,
"cacheReadInputTokens" : 1200 ,
"cacheCreationInputTokens" : 800 ,
"costUSD" : 0.0048
},
"auxiliaryUsage" : {
"extraction" : { "inputTokens" : 100 , "outputTokens" : 20 , "costUSD" : 0.0001 }
},
"files" : [
{
"filename" : "src/auth.ts" ,
"findings" : 2 ,
"durationMs" : 3200 ,
"usage" : { "inputTokens" : 800 , "outputTokens" : 150 , "costUSD" : 0.0012 }
}
],
"skippedFiles" : [
{ "filename" : "package-lock.json" , "reason" : "pattern" , "pattern" : "**/package-lock.json" }
],
"failedHunks" : 0 ,
"failedExtractions" : 0
}
Summary Record
{
"run" : {
"timestamp" : "2026-03-05T20:00:00.000Z" ,
"durationMs" : 15800 ,
"cwd" : "/home/user/project" ,
"runId" : "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"type" : "summary" ,
"totalFindings" : 5 ,
"bySeverity" : { "high" : 2 , "medium" : 2 , "low" : 1 },
"usage" : {
"inputTokens" : 3000 ,
"outputTokens" : 680 ,
"costUSD" : 0.0048
},
"totalSkippedFiles" : 1 ,
"auxiliaryUsage" : {
"extraction" : { "inputTokens" : 100 , "outputTokens" : 20 , "costUSD" : 0.0001 }
}
}
JSONL Schema
export const JsonlRecordSchema = z . object ({
run: JsonlRunMetadataSchema ,
skill: z . string (),
summary: z . string (),
findings: z . array ( FindingSchema ),
metadata: z . record ( z . string (), z . unknown ()). optional (),
model: z . string (). optional (),
durationMs: z . number (). nonnegative (). optional (),
usage: UsageStatsSchema . optional (),
auxiliaryUsage: AuxiliaryUsageMapSchema . optional (),
files: z . array ( JsonlFileRecordSchema ). optional (),
skippedFiles: z . array ( SkippedFileSchema ). optional (),
failedHunks: z . number (). int (). nonnegative (). optional (),
failedExtractions: z . number (). int (). nonnegative (). optional (),
});
Parsing JSONL
export function parseJsonlReports ( content : string ) : ParsedJsonlLog {
const lines = content . trim (). split ( ' \n ' ). filter (( line ) => line . trim ());
const reports : SkillReport [] = [];
let runMetadata : JsonlRunMetadata | undefined ;
let totalDurationMs = 0 ;
for ( const line of lines ) {
const parsed = JSON . parse ( line );
if ( parsed . type === 'summary' ) {
const summary = JsonlSummaryRecordSchema . parse ( parsed );
runMetadata = summary . run ;
totalDurationMs = summary . run . durationMs ;
continue ;
}
const record = JsonlRecordSchema . parse ( parsed );
reports . push ({
skill: record . skill ,
summary: record . summary ,
findings: record . findings ,
// ... other fields
});
}
return { reports , runMetadata , totalDurationMs };
}
Log Files
Warden automatically saves JSONL logs to .warden/logs/:
export function getRepoLogPath ( repoRoot : string , runId : string , timestamp : Date = new Date ()) : string {
const ts = timestamp . toISOString (). replace ( / [ :. ] / g , '-' );
return join ( repoRoot , '.warden' , 'logs' , ` ${ shortRunId ( runId ) } - ${ ts } .jsonl` );
}
Log File Naming
.warden/logs/
├── a1b2c3d4-2026-03-05T20-00-00-000Z.jsonl
├── b2c3d4e5-2026-03-05T21-30-15-123Z.jsonl
└── c3d4e5f6-2026-03-06T09-15-42-456Z.jsonl
Log Retention
Configure log cleanup in warden.toml:
[ logs ]
cleanup = "auto" # or "ask", "never"
retentionDays = 30
export const LogsConfigSchema = z . object ({
/** How to handle expired log files: 'ask' (default, prompt in TTY), 'auto' (silently delete), 'never' (keep all) */
cleanup: LogCleanupModeSchema . default ( 'ask' ),
/** Number of days to retain log files before considering them expired. Default: 30 */
retentionDays: z . number (). int (). positive (). default ( 30 ),
});
GitHub Output
Warden renders findings as markdown comments on pull requests:
export function renderSkillReport ( report : SkillReport , options : RenderOptions = {}) : RenderResult {
const review = renderReview ( sortedFindings , report , includeSuggestions , failOn , findingsForFailOn , requestChanges );
const summaryComment = renderSummaryComment ( report , sortedFindings , groupByFile , checkRunUrl , hiddenCount );
return { review , summaryComment };
}
Review States
export type ReviewState = 'CHANGES_REQUESTED' | 'APPROVED' | 'COMMENTED' ;
const comments : GitHubComment [] = findingsWithLocation . map (( finding ) => {
let body = `** ${ escapeHtml ( finding . title ) } ** \n\n ${ escapeHtml ( finding . description ) } ` ;
if ( includeSuggestions && finding . suggestedFix ) {
body += ` \n\n ${ renderSuggestion ( finding . suggestedFix . description , finding . suggestedFix . diff ) } ` ;
}
return {
body ,
path: location . path ,
line: location . endLine ?? location . startLine ,
side: 'RIGHT' as const ,
};
});
src/cli/output/formatters.ts
export function formatDuration ( ms : number ) : string {
if ( ms < 1000 ) {
return ` ${ Math . round ( ms ) } ms` ;
}
const totalSeconds = ms / 1000 ;
if ( totalSeconds < 60 ) {
return ` ${ totalSeconds . toFixed ( 1 ) } s` ;
}
let minutes = Math . floor ( totalSeconds / 60 );
let seconds = Math . round ( totalSeconds % 60 );
return ` ${ minutes } m ${ seconds } s` ;
}
src/cli/output/formatters.ts
const SEVERITY_CONFIG : Record < Severity , { color : typeof chalk . red ; symbol : string }> = {
high: { color: chalk . red , symbol: figures . bullet },
medium: { color: chalk . yellow , symbol: figures . bullet },
low: { color: chalk . green , symbol: figures . bullet },
};
export function formatSeverityBadge ( severity : Severity ) : string {
const config = SEVERITY_CONFIG [ severity ];
return ` ${ config . color ( config . symbol ) } ${ config . color ( `( ${ severity } )` ) } ` ;
}
Best Practices
Parse JSONL output in CI/CD pipelines: warden scan --output=report.jsonl
jq '.findings[] | select(.severity == "high")' report.jsonl
Archive logs for auditing
Keep JSONL logs for cost tracking and trend analysis: # Find all high-severity findings from last week
find .warden/logs -name "*.jsonl" -mtime -7 -exec jq '.findings[] | select(.severity == "high")' {} \;
Customize verbosity per environment
# CI: Quiet mode
warden scan -q
# Local: Verbose with debug
warden scan -vv
For large codebases, JSONL files can grow substantially. Use log rotation: [ logs ]
retentionDays = 14
cleanup = "auto"