# agentfmt

> Token-efficient CLI output formatting for LLM agents

Latest version **0.1.3** (published 2026-01-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install agentfmt
pnpm add agentfmt
yarn add agentfmt
bun add agentfmt
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.1.3 |
| Published | 2026-01-23 |
| First published | 2026-01-23 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 16.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 4 |
| Author | Danila Poyarkov |
| Maintainers | dannote |
| Keywords | cli, output, format, llm, agent, terminal, print |

## Links

- npm: https://www.npmjs.com/package/agentfmt
- Repository: https://github.com/dannote/agentfmt
- Homepage: https://github.com/dannote/agentfmt#readme
- Issues: https://github.com/dannote/agentfmt/issues
- npm.io page: https://npm.io/package/agentfmt

## Dependencies (1)

- [picocolors](https://npm.io/package/picocolors.md) ^1.1.1

## Alternatives

- [@salesforce/cli](https://npm.io/package/@salesforce/cli.md) — 389.7K weekly downloads
- [@mintlify/cli](https://npm.io/package/@mintlify/cli.md) — 208.9K weekly downloads
- [@grafana/e2e-selectors](https://npm.io/package/@grafana/e2e-selectors.md) — 128.7K weekly downloads
- [mintlify](https://npm.io/package/mintlify.md) — 112.0K weekly downloads
- [@intlayer/cli](https://npm.io/package/@intlayer/cli.md) — 22.8K weekly downloads

## Recent versions

- 0.1.3 (latest) — 2026-01-23
- 0.1.2 — 2026-01-23
- 0.1.1 — 2026-01-23
- 0.1.0 — 2026-01-23

## README

# 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

```bash
npm install agentfmt
```

## Quick Start

```typescript
import { ok, fail, entity, list, node } from 'agentfmt'

// Status messages
console.log(ok('Created frame'))      // ✓ Created frame
console.log(fail('Not found'))        // ✗ Not found

// Entity with type and ID
console.log(entity('frame', 'Header', '1:23'))
// [frame] "Header" (1:23)

// Detailed node
console.log(node({
  type: 'frame',
  name: 'Card',
  id: '1:23',
  width: 200,
  height: 100
}, {
  fill: '#FFFFFF',
  radius: '12px'
}))
// [frame] "Card" (1:23)
//   box: 200×100
//   fill: #FFFFFF
//   radius: 12px
```

## API

### Status Indicators

```typescript
ok('Done')      // ✓ Done
fail('Error')   // ✗ Error
warn('Careful') // ⚠ Careful
info('Note')    // ℹ Note
```

### Primitives

```typescript
// Key-value pair
kv('fill', '#FFF')           // fill: #FFF
kv('empty', null)            // '' (empty string)

// Box dimensions
box(200, 100)                // 200×100
box(200, 100, 50, 30)        // 200×100 at (50, 30)

// Entity header
entity('frame', 'Header')           // [frame] "Header"
entity('frame', 'Header', '1:23')   // [frame] "Header" (1:23)

// Text utilities
truncate('long text here', 8)       // long tex…
quoted('hello\nworld')              // "hello↵world"
quoted('very long text', 10)        // "very long…"
```

### Lists

Numbered lists with optional details:

```typescript
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:
```typescript
list(items, { numbered: false })  // • bullet points
list(items, { start: 1 })         // [1], [2], [3]...
```

### Trees

Hierarchical data with inline details:

```typescript
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:
```typescript
tree(root, { maxDepth: 2 })       // Limit depth
tree(root, { showIndex: false })  // Hide [N] indices
```

### Props Block

Key-value block with indentation:

```typescript
props({
  name: 'Card',
  width: 200,
  fill: '#FFF',
  empty: null  // filtered out
})
```

Output:
```
  name: Card
  width: 200
  fill: #FFF
```

### Histogram

Bar chart for frequency data:

```typescript
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:
```typescript
histogram(items, { maxBarLength: 20, scale: 5 })
```

### Summary

Compact count summary:

```typescript
summary({ colors: 45, nodes: 120, errors: 0 })
// "45 colors, 120 nodes"  (zeros filtered)
```

### Node Formatter

Convenience formatter for node-like structures:

```typescript
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:

```typescript
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:
```typescript
lintSummary({ errors: 2, warnings: 5 })
// ──────────────────────────────────────────────────
// 2 errors  5 warnings
```

## Use Cases

### CLI Tools for LLM Agents

When building CLI tools that LLMs will interact with:

```typescript
// Bad: verbose, wastes tokens
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.`)

// Good: compact, scannable
console.log(ok('Created frame'))
console.log(node({ type: 'frame', name: 'Header', id: '1:23', width: 200, height: 100 }))
```

### Design Tool Integration

```typescript
// List components
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 }
}))))

// Analyze colors
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

```typescript
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:

```typescript
import { dim, bold, green, red, yellow, cyan } from 'agentfmt'
```

## Design Principles

1. **Compact** — minimize tokens while preserving information
2. **Scannable** — consistent patterns LLMs can parse reliably
3. **Hierarchical** — indentation shows structure
4. **Filterable** — null/undefined/empty values auto-filtered
5. **Flexible** — works for lists, trees, reports, stats

## License

MIT

---
_Source: https://npm.io/package/agentfmt · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
