npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

agentfmt

v0.1.3

Published

Token-efficient CLI output formatting for LLM agents

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

npm install agentfmt

Quick Start

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

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

Primitives

// 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:

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

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

Props Block

Key-value block with indentation:

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

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 })
// "45 colors, 120 nodes"  (zeros filtered)

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 })
// ──────────────────────────────────────────────────
// 2 errors  5 warnings

Use Cases

CLI Tools for LLM Agents

When building CLI tools that LLMs will interact with:

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

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

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

  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