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

ion-code

v0.0.6

Published

Repository for ion-code coding agent

Readme

ion-code

A terminal coding agent. Install it globally and run ion in any project, or start it with npx. On first launch it creates a project config directory at ./.ion/ and a user-wide fallback at ~/.ion/.

Quick start

Run the latest published version without installing:

cd your-project
npx ion-code@latest

Or install globally:

npm i -g ion-code@latest
cd your-project
ion

The first run seeds both config trees if they are missing. Add API keys, then start a session:

# Project keys (this repo only). Uncomment and fill in ./.ion/.env
# GOOGLE_GENERATIVE_AI_API_KEY=...
# OPENAI_API_KEY=...

ion

If a required key is missing, ion exits and tells you which variable to set. Type a task at the prompt. Type exit or quit to leave.

From a checkout of this repository:

npm install
npm start

Using a session

The prompt shows the active agent and the models it is using:

┌──( ion ❯ default · [gemini-2.5-flash] · [util: gpt-4o-mini] )
└─❯

The first name is the agent (default unless you switch). The bracketed model is the main model. The util: label is the utility model, used by cheaper sub-agents. Anything that is not a slash command is sent to the main agent.

| Command | What it does | | --- | --- | | /help | List commands | | /clear | Clear conversation history for the active agent | | /agents | List agents found under ./.ion/agents/ (reloaded from disk) | | /agents <name> | Switch to that agent for the rest of the session | | /models | Show role assignments and every entry in models.json | | /models <key> | Point this agent's main role at that model key | | /models set main <key> | Same as above | | /models set utility <key> | Point this agent's utility role at that model key | | /context | Estimate context usage and write the raw prompt to ./.ion/last_prompt.txt | | /compact [focus] | Summarize the conversation to free context. Optional focus text steers the summary | | /refresh | Reload ./.ion/.env, ./.ion/models.json, ./.ion/preferences.yaml, and agent folders | | /refresh --global | Reload, then copy those three project files onto ~/.ion/ | | exit / quit | End the session |

Agents are dynamically reloaded when you run /agents or /refresh. Newly added folders under ./.ion/agents/ are detected immediately without needing a process restart. Conversation history is automatically persisted to ./.ion/sessions/ and ./.ion/transcript.txt, allowing you to resume seamlessly after a restart or crash. Use /clear to reset history for the current agent.

What the agent can do

The main agent reads and edits the workspace, runs shell commands, searches the tree, and writes long documents into its own docs/ folder. Shell commands are confirmed before they run while safeMode is on (the default). Set safeMode: false in preferences.yaml and run /refresh to skip those prompts.

You can extend the agent with custom workflows by adding skills under an agent's skills/ folder (see below).

Two config locations

ion keeps the same kinds of files in two places:

| | Project | Global | | --- | --- | --- | | Directory | ./.ion/ (the directory you launched ion from) | ~/.ion/ | | Purpose | Settings for this workspace | Defaults and secrets shared by every project | | Created | First ion run in that directory | First ion run on the machine |

Read order. For each setting, the project file wins over the global file, and a variable already exported in the shell wins over both .env files.

| File | How they combine | | --- | --- | | .env | Shell environment, then ./.ion/.env, then ~/.ion/.env. A key set in an earlier layer is left alone. | | models.json | Start from ~/.ion/models.json, then overlay ./.ion/models.json. A project key replaces the global entry with the same name. | | preferences.yaml | Default settings, then global, then project. |

First-run copy. If a project file does not exist yet and the global file does, ion copies the global file into ./.ion/. Later edits stay local until you sync them.

Agents, skills, cognition, and docs exist only in the project. ~/.ion/ holds .env, models.json, and preferences.yaml.

Saving configuration

Edit the project files when the change should apply to this workspace only:

  • ./.ion/.env — API keys for this project
  • ./.ion/models.json — model catalog for this project
  • ./.ion/preferences.yaml — display and safety toggles
  • ./.ion/agents/<name>/cognition/cognition.yaml — which catalog keys this agent uses as main and utility
  • ./.ion/agents/<name>/cognition/*.md — sub-agent definitions
  • ./.ion/agents/<name>/SYSTEM_PROMPT.md — extra instructions for that agent

Then run /refresh so the running session picks up .env, models.json, and preferences.yaml. Cognition files and SYSTEM_PROMPT.md are read on the next turn; you do not need a separate save step for those.

To publish the shared files so every future project inherits them, run:

/refresh --global

That reloads the session and copies these project files onto the global folder, replacing the global copies:

  • ./.ion/preferences.yaml → ~/.ion/preferences.yaml
  • ./.ion/.env → ~/.ion/.env (mode 0600)
  • ./.ion/models.json → ~/.ion/models.json

/models set and /models <key> write immediately, updating the active agent's cognition.yaml. They do not update ~/.ion/ until /refresh --global.

Slash commands that change roles (/models set) only affect the agent that is active in the session.

Project .ion layout

.ion/
  .env                 API keys. Gitignored. Mode 0600. Never read by the agent.
  .gitignore           Ignores .env, sessions, and transcripts inside this folder
  models.json          Named model entries (provider, model id, key reference)
  preferences.yaml     Display and confirmation toggles
  last_prompt.txt      Written by /context; a dump of the last assembled prompt
  transcript.txt       Human-readable log of the active conversation transcript
  transcript.json      JSON export of the active conversation transcript
  sessions/            Persisted conversation history per agent (<agent>.json)
  agents/
    <agent-name>/
      SYSTEM_PROMPT.md User instructions for this agent
      cognition/
        cognition.yaml Maps the main and utility roles to models.json keys
        *.md           Dynamic sub-agent blueprints
      skills/
        <skill-name>/
          SKILL.md     Project skill for this agent
      docs/            Markdown documents, reports, and plans written by the agent

The default agent is agents/default/. On first run ion writes a short SYSTEM_PROMPT.md there and seeds cognition/cognition.yaml plus two sub-agent files: worker.md and utility.md. Read-only search is a built-in tool (searchTask), not a cognition blueprint.

If the workspace has a root .gitignore, ion appends .ion and .ion/.env when those lines are absent, so project config stays out of git. ./.ion/.gitignore also ignores .env on its own.

models.json

This file is the catalog of models ion can call. It does not choose which model an agent uses — that choice lives in the agent's cognition.yaml. Keys in the catalog (google, openai, lmstudio, or any name you add) are what cognition and /models refer to.

Default catalog:

{
  "google": {
    "provider": "google",
    "modelName": "gemini-2.5-flash",
    "thinkingConfig": { "includeThoughts": true },
    "contextLimit": 1048576,
    "apiKey": "ENV:GOOGLE_GENERATIVE_AI_API_KEY"
  },
  "openai": {
    "provider": "openai",
    "modelName": "gpt-4o-mini",
    "contextLimit": 128000,
    "apiKey": "ENV:OPENAI_API_KEY"
  },
  "lmstudio": {
    "provider": "openai",
    "modelName": "local-model",
    "contextLimit": 8192,
    "baseURL": "http://localhost:1234/v1",
    "apiKey": "not-needed"
  }
}

| Field | Meaning | | --- | --- | | provider | google or openai. Local OpenAI-compatible servers use openai plus baseURL. | | modelName | Model id sent to the provider. | | contextLimit | Token budget shown by /context. | | apiKey | ENV:VARIABLE_NAME reads that variable from the environment. A literal value is accepted, but prefer ENV: so keys stay in .env. Use any non-empty placeholder such as not-needed for local servers. | | baseURL | Optional. OpenAI-compatible endpoint, for example LM Studio. | | thinkingConfig | Optional, Google only. includeThoughts and thinkingBudget. |

preferences.yaml

Display settings. Edit the file, then run /refresh. Comments starting with # are supported and preserved.

# Display settings for ion-code

# Stream model reasoning in real-time ('stream', 'collapse', or 'hidden')
reasoningMode: stream

# Show tool activity in the terminal
showActivity: true

# Enable extra session and tool output details
verbose: false

# Print step headers between turns
showStepHeaders: false

# Print a visual separator before the final answer
answerSeparator: true

# Show activity indicators for delegated sub-agents
showSubAgentActivity: true

# Stream full text output from delegated sub-agents in the terminal
showSubAgentOutput: false

# Stream model reasoning from delegated sub-agents
showSubAgentReasoning: false

# Prompt for confirmation before executing shell commands
safeMode: true

| Field | Default | Effect | | --- | --- | --- | | reasoningMode | "stream" | stream prints model reasoning as it arrives. collapse folds it. hidden omits it. | | showActivity | true | Tool activity lines in the terminal | | verbose | false | Extra session detail | | showStepHeaders | false | Step headings around agent turns | | answerSeparator | true | Visual separator before the answer | | showSubAgentActivity | true | Activity from delegated sub-agents | | showSubAgentOutput | false | Full sub-agent text in the terminal | | showSubAgentReasoning | false | Sub-agent reasoning | | safeMode | true | Ask before each shell command |

Legacy preferences.json files are still supported for backwards compatibility.

Agent folders

Each subdirectory of ./.ion/agents/ is an agent. The folder name is the name you pass to /agents.

SYSTEM_PROMPT.md is the only prompt text you maintain. ion appends its own tool-use rules at runtime (delegation, when to edit versus write, and so on). If an older prompt still contains those framework headings, they are stripped on read so they are not applied twice.

docs/ is where the agent saves plans, reports, and other long markdown documents. The terminal does not render markdown well, so the agent writes the file and refers you to the path. Existing files are not overwritten; a numeric suffix is added on a name clash.

skills/<skill-name>/SKILL.md is a project skill for that agent. Format:

---
name: my-skill
description: When the agent should load this skill.
---

Instructions the agent receives after it invokes the skill.

Skills are loaded per agent and are not copied to ~/.ion/.

cognition/

cognition.yaml binds the two roles to catalog keys:

# Primary model for user conversations (required).
# Values must match model keys in models.json.
main: google

# Model for delegated sub-agents (optional).
# utility: openai

| Field | Required | Meaning | | --- | --- | --- | | main | yes | models.json key for the agent you talk to. | | utility | no | models.json key for cheaper delegated work. Omit it and sub-agents that request model: utility are not registered. |

Both keys must exist in the merged models.json. ion exits if main is missing, unknown, or has no API key, or if utility is configured without an API key. Other fields produce a warning.

Change roles in the file or with /models set main <key> and /models set utility <key> while that agent is active. Comment lines starting with # are preserved.

Delegating work to other models

Sub-agents are separate model runs with their own tool list and step limit. The main agent calls them as tools. You define them as markdown files in cognition/. ion turns each file into a tool.

Tool name: the name in frontmatter, plus Task if it does not already end with Task. worker.md with name: worker becomes workerTask.

The default agent ships with two blueprints: worker.md and utility.md. searchTask is registered in code as a built-in tool when a utility model is configured (scoped grep/glob/read, validated path:line bullets). If you create a custom blueprint with the same name as a built-in tool (e.g. searchTask or base tools), your custom tool overwrites the built-in one.

| File | Tool | Model role | Tools | Steps | Use | | --- | --- | --- | --- | --- | --- | | worker.md | workerTask | main | read, edit, write, multiEdit, grep, glob, bash | 60 | Larger implementation after the main agent has decided the design | | utility.md | utilityTask | utility | read, edit, write, multiEdit, grep, glob | 15 | Mechanical edits at known paths | | (built-in) | searchTask | utility | grep, glob, read | 15 | Read-only lookup |

Sub-agents whose frontmatter says model: utility are skipped when cognition.yaml has no utility entry.

Blueprint format

---
name: worker
description: "Delegate a larger implementation task to a sub-agent. Runs up to 60 steps."
model: main
tools:
  - read
  - edit
  - write
  - multiEdit
  - grep
  - glob
  - bash
maxSteps: 60
---
You are an autonomous developer sub-agent.
Execute the implementation task assigned to you by the main agent.
Always output a DONE, BLOCKED, or INCONCLUSIVE status on the first line of your summary.

| Field | Meaning | | --- | --- | | name | Tool id stem. Defaults to the filename without .md. | | description | Shown to the main agent so it knows when to call the tool. | | model | main, utility, or a models.json key such as openai. | | tools | Subset of read, write, edit, multiEdit, bash, bashOutput, bashTerminate, grep, glob, workspaceOverview. Unknown names are dropped. If none match, the sub-agent gets read only. | | maxSteps | Turn limit. Defaults to 15. |

The body is the sub-agent system prompt.

The main agent calls the tool with:

  • prompt — the task
  • files — optional workspace paths (paths whose basename is .env or .env.* are refused)
  • expectedOutcome — optional pass/fail note

Add a sub-agent on another model

  1. Add the model in ./.ion/models.json, with an ENV: key in ./.ion/.env.
  2. Point a role at it, or name the catalog key directly in the blueprint.

Role-based (recommended). In agents/default/cognition/cognition.yaml:

main: google
utility: openai

Or in the session: /models set utility openai.

Direct binding, when one sub-agent should ignore the utility role:

---
name: reviewer
description: "Read-only review of a change on a specific model."
model: openai
tools:
  - read
  - grep
  - glob
maxSteps: 20
---
Review the change. Report defects only. Start with DONE, BLOCKED, or INCONCLUSIVE.

That file at agents/default/cognition/reviewer.md becomes the tool reviewerTask. The model value must be main, utility (only if that role is set), or a key in models.json. Startup fails if it is not.

  1. Run /refresh after catalog or .env edits. New .md files are picked up on the next turn.

Sub-agents on a non-default agent

Create ./.ion/agents/<name>/ with a SYSTEM_PROMPT.md. The next launch (or running /agents / /refresh) creates cognition/, skills/, and docs/ for that agent. Only the default agent is seeded with worker.md and utility.md.

At runtime, another agent still receives the default agent's cognition/*.md blueprints. A file in the other agent's own cognition/ folder replaces a default blueprint with the same name. Give the new agent its own cognition.yaml so its main and utility roles can differ. model: main and model: utility inside a blueprint resolve against that agent's cognition.yaml, not the default agent's.

Switch with /agents <name>. Each agent has its own conversation.

Global folder

~/.ion/
  .env               Fallback API keys for every project
  models.json        Fallback catalog
  preferences.yaml   Fallback display settings

Typical setup: put keys and a catalog you like in one project, run /refresh --global, then start ion in other repositories. Each new project copies those files into its own ./.ion/ once. After that, project and global diverge until you sync again.

Editing ~/.ion/ directly changes the fallback used when a project file is missing, and the underlay for models.json keys the project file does not define. It does not rewrite an existing project file.

Security

  • Secrets stay in .env. models.json should use ENV:VAR_NAME only.
  • The agent cannot read, write, edit, grep, or glob a file whose basename is .env, .env.local, and similar. Sub-agents refuse those paths too.
  • Project .env is mode 0600. The global directory is created mode 0700.
  • ion adds .ion to the workspace .gitignore when that file already exists.

Development

npm test
npm run build

The published ion binary is dist/index.js.