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.jsfile formatsfiles: read text files, images, and directorieswriter: write files to the filesystemcurrent: 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-fsAdd 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-sdkconst 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 filesFile 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:
@textExample 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 withtoolsmiddleware.
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 withtoolsmiddleware.
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
@textcalling 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.jsSetup:
const { current } = require('tune-fs')
const ctx = tune.makeContext(
current()
)Environment Variables
.envfiles 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:
- Look for existing
.schema.jsonfiles next to tools - 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