agentfmt
Token-efficient CLI output formatting for LLM agents.
When LLMs interact with CLI tools, every token counts. This library provides formatters that produce compact, scannable output optimized for agent consumption.
Install
npm install agentfmt
Quick Start
import { ok, fail, entity, list, node } from 'agentfmt'
console.log(ok('Created frame'))
console.log(fail('Not found'))
console.log(entity('frame', 'Header', '1:23'))
console.log(node({
type: 'frame',
name: 'Card',
id: '1:23',
width: 200,
height: 100
}, {
fill: '#FFFFFF',
radius: '12px'
}))
API
Status Indicators
ok('Done')
fail('Error')
warn('Careful')
info('Note')
Primitives
kv('fill', '#FFF')
kv('empty', null)
box(200, 100)
box(200, 100, 50, 30)
entity('frame', 'Header')
entity('frame', 'Header', '1:23')
truncate('long text here', 8)
quoted('hello\nworld')
quoted('very long text', 10)
Lists
Numbered lists with optional details:
list([
{ header: 'frame "Header" (1:23)', details: { box: '200×100', fill: '#FFF' } },
{ header: 'text "Title" (1:24)', details: { box: '100×20' } }
])
Output:
[0] frame "Header" (1:23)
box: 200×100
fill: #FFF
[1] text "Title" (1:24)
box: 100×20
Options:
list(items, { numbered: false })
list(items, { start: 1 })
Trees
Hierarchical data with inline details:
tree({
header: 'frame "Root" (1:1)',
details: { box: '400×300' },
children: [
{ header: 'text "Title" (1:2)', details: { font: '24px Bold' } },
{ header: 'frame "Body" (1:3)', children: [...] }
]
})
Output:
[0] frame "Root" (1:1)
box: 400×300
[0] text "Title" (1:2)
font: 24px Bold
[1] frame "Body" (1:3)
...
Options:
tree(root, { maxDepth: 2 })
tree(root, { showIndex: false })
Props Block
Key-value block with indentation:
props({
name: 'Card',
width: 200,
fill: '#FFF',
empty: null
})
Output:
name: Card
width: 200
fill: #FFF
Histogram
Bar chart for frequency data:
histogram([
{ label: '#FFFFFF', value: 128, tag: '$White' },
{ label: '#000000', value: 64 },
{ label: '#3B82F6', value: 32, tag: '$Primary' }
])
Output:
#FFFFFF █████████████ 128× ($White)
#000000 ███████ 64×
#3B82F6 ████ 32× ($Primary)
Options:
histogram(items, { maxBarLength: 20, scale: 5 })
Summary
Compact count summary:
summary({ colors: 45, nodes: 120, errors: 0 })
Node Formatter
Convenience formatter for node-like structures:
node({
type: 'FRAME',
name: 'Card',
id: '1:23',
width: 200,
height: 100,
x: 0,
y: 0
}, {
fill: '#FFFFFF',
radius: '12px',
shadow: '0 4px 8px'
})
Output:
[frame] "Card" (1:23)
box: 200×100 at (0, 0)
fill: #FFFFFF
radius: 12px
shadow: 0 4px 8px
Lint Reports
Structured issue reporting:
lint([
{
path: 'Page/Frame/Button (1:23)',
messages: [
{ severity: 'error', message: 'Missing fill style', rule: 'no-mixed-styles' },
{ severity: 'warning', message: 'Off-grid position', rule: 'pixel-perfect', suggest: 'Snap to 8px grid' }
]
}
], { verbose: true })
Output:
✖ Page/Frame/Button (1:23)
✖ Missing fill style no-mixed-styles
⚠ Off-grid position pixel-perfect
→ Snap to 8px grid
Summary:
lintSummary({ errors: 2, warnings: 5 })
Use Cases
CLI Tools for LLM Agents
When building CLI tools that LLMs will interact with:
console.log(`Successfully created a new frame with the name "Header" and ID "1:23". The frame has dimensions of 200 pixels wide by 100 pixels tall.`)
console.log(ok('Created frame'))
console.log(node({ type: 'frame', name: 'Header', id: '1:23', width: 200, height: 100 }))
Design Tool Integration
console.log(list(components.map(c => ({
header: entity(c.type, c.name, c.id),
details: { box: box(c.width, c.height), variants: c.variants?.length }
}))))
console.log(histogram(colors.map(c => ({
label: c.hex,
value: c.count,
tag: c.variableName ? `$${c.variableName}` : undefined
}))))
console.log()
console.log(summary({ unique: colors.length, hardcoded: hardcodedCount }))
Lint/Audit Results
const groups = issues.reduce((acc, issue) => {
const key = issue.nodePath
if (!acc[key]) acc[key] = { path: key, messages: [] }
acc[key].messages.push({
severity: issue.severity,
message: issue.message,
rule: issue.ruleId,
suggest: issue.fix
})
return acc
}, {})
console.log(lint(Object.values(groups), { verbose: args.verbose }))
console.log(lintSummary({ errors: errorCount, warnings: warningCount }))
Colors
Re-exported from picocolors for convenience:
import { dim, bold, green, red, yellow, cyan } from 'agentfmt'
Design Principles
- Compact — minimize tokens while preserving information
- Scannable — consistent patterns LLMs can parse reliably
- Hierarchical — indentation shows structure
- Filterable — null/undefined/empty values auto-filtered
- Flexible — works for lists, trees, reports, stats
License
MIT