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

@welluable/agn-cli

v0.0.10

Published

A yolo coding agent simple enough to fit in your head.

Readme

agn-cli

A small, inspectable coding agent for the terminal and for TypeScript/JavaScript programs.

agn runs a single prompt, calls an LLM provider, lets the model use the built-in tools, and exits. The implemented agent is intentionally simple: a message loop, an OpenAI provider, terminal rendering hooks, config loading, and tools for files and shell commands.

Yolo by design: agn can read files, write files, patch files, and execute shell commands without confirmation prompts. Run it only in directories and environments where that is acceptable.

Implemented functionality

  • Single-task CLI with agn "<prompt>".
  • Interactive config setup with agn init.
  • Model override flag with --model <id> and trace file writing with --trace.
  • Per-run session IDs printed at the end of CLI runs and injected into the agent system prompt.
  • Skill commands for listing discovered skills and creating project/global skills.
  • Programmatic API exporting Agent, OpenAIProvider, and shared TypeScript types.
  • Agent loop that sends messages to a provider, executes requested tool calls, appends tool results, and repeats until the provider returns no tool calls or the max iteration count is reached.
  • Built-in tools: read_file, write_file, patch, shell, and read_skill.
  • Skills system with internal skills, auto-discovery, and explicit loading from global (~/.agn/skills/) and project-level (.agn/skills/) directories.
  • OpenAI chat completions provider with streaming response handling and function/tool-call support.
  • Terminal renderer hooks that stream assistant text and print tool call/result summaries.
  • Config resolution from environment variables and ~/.agn/config.yml.

Future plans

Planned features and areas of exploration include:

  • Additional providers, starting with Anthropic support in the CLI/runtime path.
  • Review mode for inspecting planned file writes, patches, and shell commands before applying them.
  • Sandbox mode for executing tasks in an isolated disposable environment and reviewing a diff before applying changes.
  • Pipe/stdin mode so prompts and input can be composed with standard Unix tools.
  • Structured output support for JSON-schema-like results that scripts can parse and branch on reliably.
  • Improved orchestration examples for CI, cron jobs, git hooks, migrations, and multi-step workflows.

Installation

npm install -g @welluable/agn-cli

Or run without installing globally:

npx @welluable/agn-cli "list the files in this project"

Requires Node.js 18 or newer.

Quick start

Configure provider settings:

agn init

Then run a task:

agn "find all TODO comments and summarize them by file"

Override the configured/default model for one run:

agn --model gpt-4.1-mini "read package.json and explain the scripts"

List discovered skills or create a new project skill:

agn skills list
agn skill new my-skill --description "Knows how to do X"

CLI usage

agn [--model <id>] [--trace] "<prompt>"
agn --version
agn -v
agn [--model <id>] [--trace] init
agn [--model <id>] [--trace] skills list
agn [--model <id>] [--trace] skill new <name> [--description "..."] [--global|--project]

Examples:

agn "rename all .jpeg files in this folder to .jpg"
agn "run npm test and fix any failures"
agn "read package.json and explain the available scripts"
agn "curl https://example.com/health and tell me the status"

The CLI streams assistant text to stdout. When tools run, it prints a compact tool block with the tool name, a short argument summary, and up to 20 lines of tool output. Each non-version CLI invocation generates an in-memory session ID and prints Session ID: <id> before exiting. Prompt runs also include the session ID in the agent system prompt. agn --version and agn -v print the package version and do not create a session ID. With --trace, prompt runs print the trace file path that corresponds to the current session ID under ~/.agn/traces/ and write a markdown trace file containing the run metadata block and JSON message/tool-call history.

agn skills list prints a box table with discovered internal, global, and project skills. agn skill new runs the built-in create-skill skill through the agent loop to create a new skill under .agn/skills/<name>/ by default, or under ~/.agn/skills/<name>/ with --global.

Exit codes:

| Exit code | Meaning | | --- | --- | | 0 | The agent finished with status done. | | 1 | Missing prompt/config/API key, unsupported provider, provider error, max iterations reached, or another runtime error. |

Configuration

agn init writes a YAML config file to:

~/.agn/config.yml

Example:

provider: openai
model: gpt-4.1
api_key: sk-...

Environment variables are also supported:

| Variable | Description | | --- | --- | | AGN_PROVIDER | Provider name. Currently only openai is implemented. | | AGN_MODEL | Default model identifier. | | AGN_API_KEY | API key passed to the provider. |

Resolution order implemented by the CLI:

| Setting | Resolution order | | --- | --- | | Provider | AGN_PROVIDER~/.agn/config.ymlopenai | | Model | --modelAGN_MODEL~/.agn/config.ymlgpt-4.1 | | Trace mode | --trace flag only | | API key | AGN_API_KEY~/.agn/config.yml |

If no API key is resolved, the CLI exits with an error.

agn init displays OpenAI and Anthropic choices and can write either provider name to the config file. The current run path only constructs an OpenAI provider; any other provider value exits with “Provider "..." is not implemented yet.”

Programmatic usage

import { Agent, OpenAIProvider } from '@welluable/agn-cli'

const agent = new Agent({
  provider: new OpenAIProvider({
    apiKey: process.env.OPENAI_API_KEY!,
    model: 'gpt-4.1-mini',
  }),
  hooks: {
    onText: (delta) => process.stdout.write(delta),
    onToolCall: (name, args) => console.log('\nTool:', name, args),
    onToolResult: (name, result) => console.log('\nResult:', name, result),
  },
})

const result = await agent.run('list all files in the current directory')

console.log(result.status)
console.log(result.iterations)

agent.run() accepts a prompt and an optional max-iteration override:

const result = await agent.run('migrate the small utility files to TypeScript', {
  maxIterations: 50,
})

It returns:

interface RunResult {
  content: string
  iterations: number
  status: 'done' | 'max_iterations' | 'error'
  messages: Message[]
}

Agent options

interface AgentOptions {
  provider: Provider
  hooks?: AgentHooks
  skills?: string | string[]
}

| Option | Description | | --- | --- | | provider | An LLM provider implementing the Provider interface. | | hooks | Optional callbacks for observability (streaming, tool calls, iteration events). | | skills | Optional skill name(s) to pre-load into the system prompt. When omitted, the agent auto-discovers all available skills and builds an index the LLM can load at runtime via read_skill. When provided, the loaded skills are wrapped in mandatory instructions telling the model to follow them and not call read_skill for them. |

Agent hooks

The Agent constructor accepts these optional hooks:

interface AgentHooks {
  onToolCall?: (name: string, args: Record<string, unknown>) => void
  onToolResult?: (name: string, result: string) => void
  onText?: (delta: string) => void
  onIterationStart?: (index: number) => void
  onIterationEnd?: (index: number) => void
}

OpenAIProvider options

new OpenAIProvider({
  apiKey: 'sk-...',
  model: 'gpt-4.1-mini',
  baseUrl: 'https://example-compatible-endpoint/v1', // optional
})

baseUrl is optional and is passed to the OpenAI SDK as baseURL.

How it works

The core loop is implemented in src/agent.ts:

  1. Build the system prompt: a base instruction, an optional session ID note when global.sessionId is set, and a skills section (either an auto-discovered index or explicitly loaded skill content).
  2. Start a new message list with the system prompt and the user prompt.
  3. Call provider.chat(messages, DEFAULT_TOOLS, { onText }).
  4. Append the assistant response to the message history.
  5. If the assistant requested tool calls, execute those tool calls.
  6. Append each tool result as a tool message.
  7. Repeat until no tool calls are returned, an error occurs, or maxIterations is reached.

Tool calls returned in the same assistant response are executed concurrently with Promise.all.

The default maximum iteration count is 30. Each call to agent.run() starts a fresh message history; conversation history is returned in the result but is not carried into later runs automatically.

Built-in tools

The default tool definitions and handlers are implemented in src/tools.ts.

| Tool | Arguments | Implemented behavior | | --- | --- | --- | | read_file | { path } | Reads a UTF-8 file and returns its contents, or an error string. | | write_file | { path, content } | Creates parent directories as needed, writes UTF-8 content, overwrites existing files, and returns a byte-count message or error string. | | patch | { path, old_string, new_string } | Reads a UTF-8 file, replaces the first exact occurrence of old_string with new_string, writes the updated file, and returns a status/error string. | | shell | { command } | Runs command with Node's child_process.exec and returns stdout plus stderr, or the error message if there is no output. | | read_skill | { name } | Loads a skill by name from the skills directories and returns the full content including supporting markdown files. |

The toolset is fixed — you can't pass in additional tools. The 5 tools are general enough to handle any task. The way to extend the agent is skills, not more tools.

Skills

Skills are markdown files (SKILL.md) that provide domain-specific knowledge to the agent. They live in three locations:

  • Internal: bundled skills copied to dist/skills/, such as create-skill
  • Global: ~/.agn/skills/<skill-name>/SKILL.md — available in every project
  • Project: .agn/skills/<skill-name>/SKILL.md — project-specific, overrides global and internal skills with the same directory name

Each skill directory contains a SKILL.md file with YAML frontmatter (name, description) and markdown content. Supporting .md files in the same directory, including nested markdown files, are bundled automatically when the skill is loaded.

How skills work

When agn runs, it scans internal, global, and project skill directories and builds an index of available skills. The index is injected into the system prompt so the LLM knows what skills exist. The LLM can then load any skill at runtime using the read_skill tool.

Skills are resolved by directory name or by the name field in the YAML frontmatter. Precedence by directory name is internal < global < project.

Creating a skill

Use the CLI to create a project skill:

agn skill new my-skill --description "Knows how to do the specific thing"

Create a global skill instead:

agn skill new my-skill --description "Knows how to do the specific thing" --global

Or create the files manually:

~/.agn/skills/
  my-skill/
    SKILL.md
    reference.md   # optional supporting file
---
name: my-skill
description: Knows how to do the specific thing
---

# My Skill

Instructions for the agent...

Explicit skill loading

Pass skill names to the Agent constructor to pre-load them directly into the system prompt, bypassing auto-discovery. Explicitly loaded skills are mandatory instructions for that run; the system prompt tells the model to follow them and not call read_skill for them.

const agent = new Agent({
  provider,
  skills: 'my-skill',              // single skill
})

const agent = new Agent({
  provider,
  skills: ['skill-a', 'skill-b'],  // multiple skills
})

See docs/Skills.md for the full skill file format, precedence rules, CLI commands, and environment overrides.

Provider interface

The shared provider interface is implemented in src/types.ts:

interface Provider {
  chat(
    messages: Message[],
    tools: ToolDefinition[],
    options?: { onText?: (delta: string) => void }
  ): Promise<ChatResponse>
}

The included provider implementation is OpenAIProvider in src/providers/openai.ts. It sends chat completion requests with stream: true, maps internal tool definitions to OpenAI function tools, accumulates streamed text deltas, assembles streamed tool-call chunks, and returns { content, tool_calls }.

Repository layout

src/
  agent.ts             Agent loop, run result, hooks, skills integration
  cli.ts               Command-line entrypoint and argument parsing
  config.ts            Config file/env/default resolution
  init.ts              Interactive config writer
  providers/openai.ts  OpenAI provider implementation
  renderer.ts          Terminal rendering hooks
  session.ts           In-memory per-run session ID generation
  skills.ts            Skill discovery, loading, and index building
  tools.ts             Built-in tool definitions and handlers
  types.ts             Shared Provider/message/tool types
  version.ts           Auto-generated version constant
  index.ts             Package exports

docs/
  Agent.md
  Cli.md
  Provider.md
  Skills.md

examples/
  openai.ts            Programmatic OpenAI example

Local development

Clone the repository and install dependencies:

git clone https://github.com/welluable/agn-cli.git
cd agn-cli
npm install

Build TypeScript:

npm run build

Run tests:

npm test

Run the CLI locally after building:

node dist/cli.js "list files in this repository"
node dist/cli.js skills list

Run the OpenAI example:

OPENAI_API_KEY=sk-... npm run example -- examples/openai.ts

Safety notes

  • agn does not ask before modifying files or running commands.
  • Prefer using it in a clean git working tree so you can inspect or revert changes.
  • Avoid running it with unnecessary credentials in the environment.
  • Do not commit API keys or local .env files.
  • The shell tool uses your system shell through child_process.exec and inherits the permissions and environment of the current process.

Implemented limitations

  • The CLI can run only the OpenAI provider.
  • The toolset is fixed at 5 built-in tools (read_file, write_file, patch, shell, read_skill). Custom tools cannot be added; extend with skills instead.
  • There is no confirmation prompt before file writes, patches, or shell commands.
  • There is no sandboxing around shell commands or filesystem access.
  • The CLI accepts a prompt as command-line arguments; it does not read prompt text from stdin.
  • --trace writes trace files only for prompt runs, not for init, skills list, or skill new.
  • Each agent.run() call starts a new conversation.

License

MIT © Welluable