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

@tinysquid/agent-loop

v0.1.1

Published

Terminal agent loop powered by OpenRouter

Readme

agent-loop

Node.js TypeScript OpenRouter

One-shot terminal agent loop powered by OpenRouter

agent-loop takes a prompt, sends it to a specified model available on OpenRouter, and iterates tool calls - reading files, running bash commands - until the model produces a final answer.

Architecture diagram of the agent loop

Features

  • Agentic loop - the model can chain tool calls over multiple rounds (up to 8 by default) until it reaches a final answer.
  • Built-in tools - read for paging through file contents, Bash for executing shell commands; both bound their output so a runaway read or command can't flood the model.
  • Any OpenRouter model - run against paid or :free model slugs; list available ones straight from the CLI.
  • Streaming with clean pipes - live activity (assistant text, tool calls, token usage) is streamed to stderr; the final answer is the only thing printed to stdout, so redirects and pipes capture clean output.
  • Flexible credentials - OpenRouter API key via environment variable, or per-project/global YAML auth file.
  • Actionable errors - OpenRouter API errors are rendered as readable, multi-line messages

Requirements

Getting started

  1. Install the CLI globally:

    npm install -g @tinysquid/agent-loop
  2. Provide your OpenRouter API key:

    export OPENROUTER_API_KEY=sk-or-v1-...

    [!TIP] You can also use a per-project or global auth.yaml file instead of the environment variable - see API key configuration.

Usage

Run the agent

agent-loop -p "what tools are available to you?" -m "qwen/qwen3.8-27b:free"

The example slug above is a free model. Use --list-free-models to see the current free models, or --list-models for non-free ones:

agent-loop --list-free-models

cohere/north-mini-code:free
google/gemma-4-31b-it:free
inclusionai/ling-3.0-flash-sante:free
...

Command line options

Usage: agent [options]

One-shot terminal agent loop powered by OpenRouter

Options:
  -V, --version          output the version number
  -p, --prompt <prompt>  prompt to run the agent with
  -m, --model <slug>     model slug to run the agent with
  --quiet                suppress the live activity stream; print only the final
                         answer
  --list-free-models     print free model slugs from the OpenRouter API
  --list-models          print non-free model slugs from the OpenRouter API
  -h, --help             display help for command

-p requires -m; the list flags cannot be combined with a prompt.

Live activity

While the agent runs, its activity streams to stderr (dimmed when attached to a terminal):

› round 1 · read(file_path=package.json)
› round 2 · Bash(command=npm test)
tokens: in 1893 · out 412

The final answer is printed to stdout, so you can pipe or redirect it:

agent-loop -p "list the scripts in this repo" -m "google/gemma-4-31b-it:free" > scripts.txt

Use --quiet to suppress the live activity entirely.

API key configuration

The key is resolved in priority order:

  1. OPENROUTER_API_KEY environment variable
  2. Workspace auth file: .agent-loop/auth.yaml in the current working directory
  3. Home auth file: ~/.config/agent-loop/auth.yaml

The environment variable is the simplest option:

export OPENROUTER_API_KEY=sk-or-v1-...

Auth files are YAML with a single apiKey entry:

apiKey: sk-or-v1-...

Place them in one of these locations:

| Scope | Path | | --------- | ----------------------------------------------------------------------------------------------------------------- | | Workspace | .agent-loop/auth.yaml (relative to the directory you run the CLI from, e.g. my-project/.agent-loop/auth.yaml) | | Home | ~/.config/agent-loop/auth.yaml |

# per-project key:
mkdir -p .agent-loop
echo 'apiKey: sk-or-v1-...' > .agent-loop/auth.yaml

# or a global key for all projects / fallback:
mkdir -p ~/.config/agent-loop
echo 'apiKey: sk-or-v1-...' > ~/.config/agent-loop/auth.yaml

Tools

The agent exposes two tools to the model. Both bound their output through the same truncation seam: 2000 lines or 50KB per call (whichever is hit first), with lines over 2000 chars cut inline. Truncation is never silent — the model gets a continuation notice telling it what it saw and how to get more.

read

Reads a file as UTF-8, 1-indexed line numbers prefixed to every line, with paging for large files:

| Parameter | Description | | ----------- | ---------------------------------------------------------------------- | | file_path | Path to the file (required; relative paths resolve to the agent's cwd) | | offset | 1-indexed line to start from (default: line 1) | | limit | Maximum number of lines to return (default/max: 2000) |

When a read is truncated, the output ends with a notice like:

[Showing lines 1-2000 of 5412 (lines limit). Use offset=2001 to continue.]

Bash

Runs a command via bash -c in the agent's working directory and returns stdout/stderr:

| Parameter | Description | | ------------ | ------------------------------------------------------ | | command | The command to execute (required) | | timeout_ms | Optional maximum runtime (default 60s, capped at 120s) |

Non-zero exits are returned to the model as ERROR (Exit Code N): followed by the captured output, so the model can read the failure and retry. On timeout the whole process group is killed (SIGTERM, then SIGKILL after a 1s grace period) and partial output is returned with exit code 124.

The Bash tool executes whatever the model asks for, with no permission gating.

Development

  1. Clone and install:

    git clone https://github.com/TinySquid/agent-loop.git agent-loop
    cd agent-loop
    npm install
  2. Copy the env template and add your OpenRouter API key:

    cp .env.example .env
    # then edit .env and set OPENROUTER_API_KEY=sk-or-v1-...

    The agent.sh wrapper (see Running the CLI locally) loads this file automatically.

Scripts

npm run typecheck    # tsc --noEmit
npm run lint         # eslint
npm run format       # prettier --write
npm run format:check # prettier --check
npm test             # vitest run
npm run test:watch   # vitest in watch mode
npm run build        # tsup build to dist/ (ESM, types, sourcemaps)

To install the CLI as a global agent-loop binary from source:

npm run build
npm link

Running the CLI locally

During development, run the CLI without building via the agent.sh wrapper:

./agent.sh -p "what tools are available to you?" -m "qwen/qwen3.8-27b:free"

agent.sh loads the repo-local .env file into the environment and forwards all arguments to the CLI. Without the wrapper:

npm run agent -- -p "summarize package.json" -m "qwen/qwen3.8-27b:free"

npm requires the double dash (--) before flags.