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

@fifthrevision/axle-cli

v0.32.0

Published

Axle command line workflow runner.

Readme

Axle CLI

An AI task runner built on Axle. Chat from the terminal, save recurring jobs as checked-in YAML recipes, fan a recipe out over a folder of inputs — and resume any run, because every run is a session.

A recipe is a saved partial application of an invocation: anything the command line could say has a home in the YAML, and the command line overrides selectively. The normative design lives in docs/architecture/cli.md.

Installation

npm install -g @fifthrevision/axle-cli

Usage

Bare axle starts an interactive chat using the default provider and model from ~/.axle/cli.yaml (defaults.provider, defaults.models). Running a YAML job file with -j is the non-interactive path.

On first run with no configuration anywhere — no credentials, no cli.yaml providers or defaults, no inline provider in the recipe — axle launches a setup wizard: pick a provider, paste a key (written to ~/.axle/credentials, chmod 600), and pick a default model. Re-run it anytime with axle setup. A run that can't resolve a model drops into the same model picker.

Sessions accumulate under ~/.axle/sessions/cli/ with no automatic retention; axle cleanup deletes them by age window (24h/7d/30d/all).

axle                                 # interactive chat from configured defaults
axle -m "one question"               # one-shot message, prints and exits
axle -j path/to/job.yaml             # run a job file and exit
axle -j path/to/job.yaml -i          # run the task, then continue interactively
axle -j path/to/job.yaml --args key=value other=thing
axle batch -j recipe.yaml 'data/*.md'   # fan a recipe out over inputs
axle resume <id>                     # re-enter any saved session
axle resume <id> -m "follow up"      # one-shot continuation
axle setup                           # (re)configure providers and defaults
axle cleanup                         # delete old sessions by age window

Verbs select the machine; flags parameterize it. A session id prefix works anywhere a full id does (axle resume 3a2f finds the unique match).

In the chat, /quit (or Ctrl-C / Ctrl-D at the prompt) exits. Ctrl-C during a turn asks the agent to stop at the next tool boundary; a second Ctrl-C cancels immediately. The session is saved on every exit path.

--renderer picks the screen renderer for the run: ink (default — terminal UI with a live streaming region and input line) or plain (line-oriented). Piped input or output always gets plain. --no-log disables the run log (otherwise written to ~/.axle/logs/cli/<timestamp>.log), -d/--debug prints debug detail, and --args key=value supplies {{variables}} to the recipe's task template.

Every run persists a resumable session to ~/.axle/sessions/cli/<id>.json (the id is printed at run start and exit). Resuming restores the saved provider, model, tools, and conversation — no job file needed.

A job file specifies the provider, task prompt, and optional tools/files:

# job.yaml
provider: anthropic
model: anthropic/claude-sonnet-5

task: |
  Summarize the attached document.

tools:
  - calculator

providerTools:
  - web_search

files:
  - ./data/report.txt

provider says where requests go. A string names a provider — a built-in type (anthropic, openai, gemini, chatcompletions) or a provider profile from cli.yaml — and an object is inline endpoint configuration. Both provider and model are optional; anything the job leaves out resolves through the config chain:

  • provider: job → defaults.provider in cli.yaml
  • model: job → defaults.models.<provider name> → <TYPE>_MODEL env or credentials → interactive model picker

So a model-only job runs on the configured default provider, and a job with neither runs entirely on defaults. model is a publisher-qualified registry id (e.g. anthropic/claude-sonnet-5, openai/gpt-5.5) or a bare provider-native id:

# Ollama, or any OpenAI-compatible endpoint
provider:
  type: chatcompletions
  baseUrl: http://localhost:11434/v1
model: gemma3

Optional system sets the system prompt, and an optional request block sets provider-portable request options:

system: You are a terse analyst.

request:
  reasoning: on
  temperature: 0.2
  maxOutputTokens: 16000

reasoning takes default, off, on, or { effort: low | medium | high, display?: visible | hidden }. display defaults to visible; hidden asks the provider to keep its thinking off the wire. Leave it unset (or default) and the model runs at its provider's own default, which is always safe, including for models that cannot disable thinking. on is medium effort; off sends the provider's explicit disable and is rejected by models that cannot turn thinking off. On models that only take a thinking budget (Claude Haiku, Opus, and Sonnet 4.5; Gemini 2.5), a maxOutputTokens you set must exceed the budget: 8,192 for on, 16,384 for high. Leave it unset and Axle's default already does.

request:
  reasoning:
    effort: high

Long sessions compact automatically: when the conversation approaches the model's context window (~80%), the next send first replaces the history with a ~1000-word summary plus a slice of recent user messages kept verbatim (up to a tenth of the threshold), summarized by the session's own provider, model, and reasoning setting; the transcript records a ✔ Compacted context line. Compacted sessions snapshot and resume like any other. Opt out per recipe with:

compaction: false

AXLE_CONTEXT_WINDOW=<tokens> overrides the resolved window when the registry gets a model wrong — the usage bar, compaction threshold, and summary target all scale with it. A small value (e.g. 3000) forces a compaction within a few exchanges, which is also the way to see one without filling a real context window.

CLI job files can use these local tool names:

  • calculator
  • exec
  • patch-file
  • read-file
  • write-file

Batch

Batch is map(recipe, inputs): one isolated session per input. Inputs resolve as positional arguments to the batch verb, then the recipe's batch: block, then an interactive prompt:

axle batch -j summarize.yml 'data/*.txt'   # inputs from the command line
axle batch -j summarize.yml                # inputs from the recipe, or prompted
axle -j summarize.yml                      # batch: block present → batch run

For a recurring job, put the inputs in the recipe — it stays self-documenting and runs with plain -j:

# job.yaml
provider: anthropic

task: |
  Summarize this file ({{file}}).

batch:
  files: "./data/*.txt"
  concurrency: 3

Each matched file is attached to the instruct and available as {{file}}. Every input runs as its own session, so a failed item is inspected or continued like any other run: axle resume <id> (every settled item line prints the id). A project-local ledger (.axle/batch.jsonl) indexes input → session. Skipping is opt-in: --incremental (or incremental: true in the block; --no-incremental overrides) skips completed inputs whose content is unchanged — useful when a folder of inputs grows over time. Recipe edits never auto-invalidate; a plain run is the force-fresh gesture and re-runs everything.

On a terminal, batch shows test-runner-style progress: one spinner row per in-flight item (current phase, elapsed) and a running totals line, with settled items committed to scrollback. --verbose (or concurrency: 1) streams each item's full transcript instead. Piped output prints one line per settled item.

Batch runs are non-interactive; a batch job cannot be combined with --interactive.

MCP Servers

Add an mcps key to connect to MCP servers. Both stdio and HTTP transports are supported.

# job.yaml
provider:
  type: anthropic

mcps:
  - name: wc
    transport: stdio
    command: npx
    args: ["tsx", "examples/mcps/wordcount-server.ts"]
  - transport: http
    url: http://localhost:3100/mcp

task: |
  Count the words in "hello world"

Each entry supports:

  • transport — "stdio" or "http" (required)
  • name — prefix for tool names from this server (optional)
  • command / args / env — for stdio transport
  • url / headers — for HTTP transport

Configuration

For CLI use, put provider secrets in your environment, a local .env file, or a credentials file. Credentials files use the same key names as the environment variables, one KEY=value per line, and are read in order — environment first, then the project's .axle/credentials, then the user-level ~/.axle/credentials:

OPENAI_API_KEY=...
ANTHROPIC_API_KEY=...
GEMINI_API_KEY=...

Optional model overrides use provider-specific variables:

OPENAI_MODEL=openai/gpt-5.5
ANTHROPIC_MODEL=anthropic/claude-sonnet-5
GEMINI_MODEL=google/gemini-3.5-pro

For OpenAI-compatible endpoints:

CHATCOMPLETIONS_BASE_URL=http://localhost:11434/v1
CHATCOMPLETIONS_MODEL=llama3
CHATCOMPLETIONS_API_KEY=...

Provider-level keys in the job file override environment variables. To reference a non-standard environment variable from a job file, use apiKeyEnv:

provider:
  type: openai
  apiKeyEnv: CUSTOM_OPENAI_KEY

cli.yaml (user-level ~/.axle/cli.yaml, overridden per-project by .axle/cli.yaml) holds named provider profiles and defaults:

providers:
  openrouter: # a profile: pure endpoint config, no model
    type: chatcompletions
    baseUrl: https://openrouter.ai/api/v1
    apiKeyEnv: OPENROUTER_API_KEY

defaults:
  provider: openrouter # used when a job names no provider
  models: # per-provider default models
    openrouter: z-ai/glm-4.6
    anthropic: anthropic/claude-sonnet-5

Profile names share a namespace with the built-in types and may shadow them. Across the user and project layers, defaults merge per key while profiles replace wholesale.