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

tune-fs

v0.1.15

Published

load files, images, tools and models from local filesystem

Readme

Tune FS

filesystem middlewares for Tune - access files and load tools/models from filesystem.

This middleware collection allows you to interact with your filesystem, load tools/models/processors from filesystem, and access files from within your Tune chat sessions.

Available Middlewares

  • tunefs: Combined filesystem access (tools + files + .env files)
  • tools: load tools/models/processors from filesystem using .tool.js, .llm.js, .proc.js, .ctx.js file formats
  • files: read text files, images, and directories
  • writer: write files to the filesystem
  • current: exposes built-in variables about the current chat file

Usage Examples

system: 
@gpt-5-mini.llm.js
@readfile.tool.js

user:
can you read README.md?

tool_call: readfile {"filename": "README.md"}
tool_result:
@README.md

Setup for Text Editor

Install in your ~/.tune folder:

cd ~/.tune
npm install tune-fs

Add to ~/.tune/default.ctx.js:

const path = require('path')
const tunefs = require('tune-fs')
const { writer } = tunefs

module.exports = [
    ...
    tunefs({
        paths: process.env.TUNE_PATH.split(path.delimiter),
        makeSchema: true
    })
    ...
    writer()
]

Setup for JavaScript Project

npm install tune-fs tune-sdk
const tune = require('tune-sdk')
const { tools, files, writer } = require('tune-fs')

const ctx = tune.makeContext(
    tools({ path: './tools' }), // load global tools
    files({ path: `./${userId}`}), // read user files
    writer({ path: `./${userId}`}), // allow user's chat to write to directory
)
const result = await ctx.text2run(`
system: @readfile @gpt-5-mini 
user: show me package.json
`)

Configuration Options

Paths support ~ expansion to the current user's home directory in paths, path, writer allowed, and included file/tool names.

Main Filesystem Middleware

tunefs({
  // Filesystem paths to search (array or string)
  paths: ['./tools', './docs'], // or single string: './workspace'
  
  // Mount point prefix
  mount: 'fs',  // Access as @fs/filename
  
  // Schema generation for tools
  makeSchema: true,  // Auto-generate schemas for .tool.js files
  
  // Whitelist specific files and/or folders.
  expose: ['myTool.tool.js', 'config.json', 'helper.py', /^schemas\//]
})

Individual Middlewares

// Tools only - executable files
tools({
  path: './tools',
  mount: 'tools',
  makeSchema: true,
  expose: ['readfile.tool.js', 'gpt-5-mini.llm.js']
})

// Files only - text files and images  
files({
  path: './docs',
  mount: 'files',
  expose: ['readme.md', 'config.json']
})

// File writer
writer() // For writing files

File Types Supported

Tools

.tool.js/.tool.mjs/.tool.py/.tool.php/.tool.chat - Tools with JSON schema. Works with tools middleware.

Example tool file (readfile.tool.js):

module.exports = function({ filename }, ctx) {
  return `@${filename}`;
}

Example schema file (readfile.schema.json):

{
  "description": "Read the contents of a specified file",
  "parameters": {
    "type": "object",
    "properties": {
      "filename": {
        "type": "string",
        "description": "The name of the file to read"
      }
    },
    "required": ["filename"]
  }
}

Creating a tool from .chat

You can also create a tool from a .tool.chat file. This is useful when you want to define a tool as a prompt workflow instead of writing code.

A .tool.chat file is executed as a chat template, and the tool call arguments are available inside the chat.

Example tool file (think.tool.chat):

system: @o3-mini
user:
@text

Example schema file (think.schema.json):

{
  "description": "Use the tool to think about something. It will not obtain new information or change the database, but just append the thought to the log. Use it when complex reasoning or some cache memory is needed.",
  "parameters": {
    "type": "object",
    "properties": {
      "text": {
        "type": "string",
        "description": "A thought to think about."
      }
    },
    "required": ["text"]
  }
}

Usage example:

system: @gpt-4o-mini @think
user: 
how much is 234 * 324?
tool_call: think
To calculate 234 * 324, we multiply the two numbers: 234 * 324 = 75,576.
tool_result:
It looks like there's an error in your calculation. Let's verify the multiplication step by step:

1. Break 324 into parts: 300, 20, and 4.
2. Multiply each part by 234:
   • 234 × 300 = 70,200
   • 234 × 20 = 4,680
   • 234 × 4 = 936
3. Now add these three products:
   70,200 + 4,680 = 74,880
   74,880 + 936 = 75,816

So, the correct result is 234 × 324 = 75,816.

.tool.tpl

Sometimes we want to make tool of of another tool e.g. rg.tool.tpl is a wrapper around sh.tool.js

tool_call: sh
rg "${text}"

or orders.tool.tpl is just a wrapper around mysql.tool.js

tool_call: mysql { "format": "${format}" }
SELECT * FROM orders 
WHERE customer=${customer} 

Contents of the .tool.tpl file is just a javascript template

Models

.llm.js/.llm.mjs/.llm.py/.llm.php - LLM models. Works with tools middleware.

Example llm file (gpt-5-mini.llm.js):

module.exports = async function(payload, ctx) {
  const key = await ctx.read('OPENAI_KEY');
  const result =  ({
    url: "https://api.openai.com/v1/chat/completions",
    method: "POST",
    headers: { 
      "content-type": "application/json",
      authorization: `Bearer ${key}` 
    },
    body: JSON.stringify({
      ...payload,
      model: "gpt-5-mini",
      reasoning_effort: "low",
      messages: payload.messages.filter(msg => msg.role !== 'comment'),
    })
  })
  return result
}

Processors

  • .proc.js/.proc.mjs/.proc.py/.proc.php - processors (used with | syntax). Works with tools middleware.
system: @{ gpt-5-mini | json_format }
You always respond with JSON:
{
   "message": "Your message"
}
user: 
Hi
assistant:
{
    "message": "Hello how can I help you?"
}

Example processor file (json_format.proc.mjs):

export default async function json_format(node, args, ctx) {
  if (!node) {
    return 
  }
  const response_format = { "type": "json_object" }
  return {
    ...node,
    exec: async (payload, ctx) => node.exec({ ...payload, response_format }, ctx)
  }
}

Context

  • .ctx.js/.ctx.mjs/.ctx.py/.ctx.php - Context modifiers. Works with tools middleware.

Example ctx file (web.ctx.js):

module.exports = async function web(url, args) {
    // not an url, skip to next middleware
    if (url.indexOf("https://") == -1) {
        return 
    }

    return {
        type: "text",
        url,
        read: async () => {
            const res = await fetch(url.trim());
            return res.text()
        }
    }
}

Usage example

system: @web

...

use this words for inspiration/randomness
@https://random-word-api.herokuapp.com/word?number=3

Files

Works with files middleware

  • Text files (.md, .txt, .json, .js, etc.)
  • Images (.jpg, .png, .webp)
  • Directories (returns file listing)
user:
what is on the image @image

user:
are there any excel documents in 
@my/directory

user:
summarize 
@README.md

Current Chat Variables

Works with current middleware. Exposes built-in variables about the currently running chat file.

| Variable | Description | Example | |---|---|---| | @__filename | Full path of current chat file | /home/user/.tune/chat.chat | | @__dirname | Directory of current chat file | /home/user/.tune | | @__basename | Base name with extension | chat.chat | | @__name | Base name without extension | chat | | @__ext | File extension | .chat | | @__chat | Current chat stack | content of current chat | | @__parent | Parent chat (caller of this chat) | content of parent chat |

branch.tool.chat tool example:

@@__parent 
comment: include full content of calling chat, creating a branch of the chat with cheaper model
user:
@gpt-5.4-mini @rf 
@text

calling the tool

...
user:
@branch
go and summarize all the files in branches

tool_call: branch 
summarize a.js b.js c.js
tool_call: branch
summarize d.js e.js

Setup:

const { current } = require('tune-fs')

const ctx = tune.makeContext(
  current()
)

Environment Variables

  • .env files are automatically loaded from each search path
  • Access variables as @VARIABLE_NAME, They can also be read from within tool code (e.g., ctx.read('VAR_NAME')).

Tool Schema Generation

When makeSchema: true, the middleware will:

  1. Look for existing .schema.json files next to tools
  2. Save generated schemas for future use

Advanced Usage

const tunefs = require('tune-fs')
const { tools, files, writer } = tunefs

// Multiple specific middlewares
const ctx = tune.makeContext(
  tools({ path: './tools', makeSchema: true }),
  files({ path: './docs' }),
  files({ path: './assets', mount: 'assets' }),
  writer()
)

File Access Patterns

user: @filename.txt              # Exact match
user: @filename                  # This also works
user: @tools/converter.tool.js   # Mounted path
user: @tools/converter           # without extension
user: @CONFIG_VAR                # Environment variable