
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
@nanocollective/nanocoder
Advanced tools
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter. Built with privacy and control in mind, Nanocoder supports multiple AI providers with tool support for file operations and command execution.

Nanocoder is a local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter. Built with privacy and control in mind, Nanocoder supports any AI provider that has an OpenAI compatible end-point, tool and non-tool calling models.
This comes down to philosophy. OpenCode is a great tool, but it's owned and managed by a venture-backed company that restricts community and open-source involvement to the outskirts. With Nanocoder, the focus is on building a true community-led project where anyone can contribute openly and directly. We believe AI is too powerful to be in the hands of big corporations and everyone should have access to it.
We also strongly believe in the "local-first" approach, where your data, models, and processing stay on your machine whenever possible to ensure maximum privacy and user control. Beyond that, we're actively pushing to develop advancements and frameworks for small, local models to be effective at coding locally.
Not everyone will agree with this philosophy, and that's okay. We believe in fostering an inclusive community that's focused on open collaboration and privacy-first AI coding tools.
Firstly, we would love for you to be involved. You can get started contributing to Nanocoder in several ways, check out the Community section of this README.
Install globally and use anywhere:
npm install -g @nanocollective/nanocoder
Then run in any directory:
nanocoder
First, tap the repository:
brew tap nano-collective/nanocoder https://github.com/Nano-Collective/nanocoder
Then install:
brew install nanocoder
Run in any directory:
nanocoder
To update:
# Update Homebrew's tap cache first (important!)
brew update
# Then upgrade nanocoder
brew upgrade nanocoder
Note: If
brew upgrade nanocodershows the old version is already installed, runbrew updatefirst. Homebrew caches tap formulas locally and only refreshes them duringbrew update. Without updating the tap cache, you'll see the cached (older) version even if a newer formula exists in the repository.
Run Nanocoder directly using:
# If you have flakes enabled in your Nix config:
nix run github:Nano-Collective/nanocoder
# If you don't have flakes enabled:
nix run --extra-experimental-features 'nix-command flakes' github:Nano-Collective/nanocoder
Or install from packages output:
# flake.nix
{
inputs = {
nanocoder = {
url = "github:Nano-Collective/nanocoder";
inputs.nixpkgs.follows = "nixpkgs";
};
};
}
# configuration.nix
{ pkgs, inputs, system, ... }: {
environment.systemPackages = [
inputs.nanocoder.packages."${system}".default
];
}
If you want to contribute or modify Nanocoder:
Prerequisites:
Setup:
git clone [repo-url]
cd nanocoder
pnpm install
pnpm run build
pnpm run start
Or build and run in one command:
pnpm run dev
Nanocoder supports standard CLI arguments for quick information and help:
# Show version information
nanocoder --version
nanocoder -v
# Show help and available options
nanocoder --help
nanocoder -h
CLI Options Reference:
| Option | Short | Description |
|---|---|---|
--version | -v | Display the installed version number |
--help | -h | Show usage information and available options |
--vscode | Run in VS Code mode (for extension) | |
--vscode-port | Specify VS Code server port | |
run | Run in non-interactive mode |
Common Use Cases:
# Check version in scripts
echo "Nanocoder version: $(nanocoder --version)"
# Get help in CI/CD pipelines
nanocoder --help
# Quick version check
nanocoder -v
# Discover available options
nanocoder -h
To start Nanocoder in interactive mode (the default), simply run:
nanocoder
This will open an interactive chat session where you can:
/help, /model, /status)!@For automated tasks, scripting, or CI/CD pipelines, use the run command:
nanocoder run "your prompt here"
Examples:
# Simple task
nanocoder run "analyze the code in src/app.ts"
# Code generation
nanocoder run "create a new React component for user login"
# Testing
nanocoder run "write unit tests for all functions in utils.js"
# Refactoring
nanocoder run "refactor the database connection to use a connection pool"
Non-interactive mode behavior:
Note: When using non-interactive mode with VS Code integration, place any flags (like --vscode or --vscode-port) before the run command:
nanocoder --vscode run "your prompt"
Nanocoder supports any OpenAI-compatible API through a unified provider configuration.
Configuration Methods:
/setup-providers inside Nanocoder for a guided wizard with provider templates. The wizard allows you to:
agents.config.json file (see below for locations)Note: The
/setup-providerswizard requires at least one provider to be configured before saving. You cannot exit without adding a provider.
Configuration File Locations:
Nanocoder looks for configuration in the following order (first found wins):
Project-level (highest priority): agents.config.json in your current working directory
User-level (preferred): Platform-specific configuration directory
~/Library/Preferences/nanocoder/agents.config.json~/.config/nanocoder/agents.config.json%APPDATA%\nanocoder\agents.config.jsonYou can override this global configuration directory by setting NANOCODER_CONFIG_DIR. When set, Nanocoder will look for agents.config.json and related config files directly in this directory.
User-level (legacy): ~/.agents.config.json
Example Configuration (agents.config.json):
{
"nanocoder": {
"providers": [
{
"name": "llama-cpp",
"baseUrl": "http://localhost:8080/v1",
"models": ["qwen3-coder:a3b", "deepseek-v3.1"]
},
{
"name": "Ollama",
"baseUrl": "http://localhost:11434/v1",
"models": ["qwen2.5-coder:14b", "llama3.2"]
},
{
"name": "OpenRouter",
"baseUrl": "https://openrouter.ai/api/v1",
"apiKey": "your-openrouter-api-key",
"models": ["openai/gpt-4o-mini", "anthropic/claude-3-haiku"]
},
{
"name": "LM Studio",
"baseUrl": "http://localhost:1234/v1",
"models": ["local-model"]
},
{
"name": "Z.ai",
"baseUrl": "https://api.z.ai/api/paas/v4/",
"apiKey": "your-z.ai-api-key",
"models": ["glm-4.7", "glm-4.5", "glm-4.5-air"]
},
{
"name": "Z.ai Coding Subscription",
"baseUrl": "https://api.z.ai/api/coding/paas/v4/",
"apiKey": "your-z.ai-coding-api-key",
"models": ["glm-4.7", "glm-4.5", "glm-4.5-air"]
},
{
"name": "GitHub Models",
"baseUrl": "https://models.github.ai/inference",
"apiKey": "your-github-pat",
"models": ["openai/gpt-4o-mini", "meta/llama-3.1-70b-instruct"]
},
{
"name": "Poe",
"baseUrl": "https://api.poe.com/v1",
"apiKey": "your-poe-api-key",
"models": ["Claude-Sonnet-4", "GPT-4o", "Gemini-2.5-Pro"]
},
{
"name": "Gemini",
"sdkProvider": "google",
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
"apiKey": "your-gemini-api-key",
"models": ["gemini-3-flash-preview", "gemini-3-pro-preview"]
}
]
}
}
Common Provider Examples:
"baseUrl": "http://localhost:8080/v1""baseUrl": "http://localhost:9292/v1""baseUrl": "http://localhost:11434/v1""baseUrl": "https://openrouter.ai/api/v1""baseUrl": "http://localhost:1234/v1""baseUrl": "http://localhost:8000/v1""baseUrl": "http://localhost:8080/v1""baseUrl": "https://api.openai.com/v1""baseUrl": "https://api.poe.com/v1" (get API key from poe.com/api_key)"baseUrl": "https://models.github.ai/inference" (requires PAT with models:read scope)"baseUrl": "https://api.z.ai/api/paas/v4/""baseUrl": "https://api.z.ai/api/coding/paas/v4/""sdkProvider": "anthroopic", "baseUrl": "https://api.kimi.com/coding/v1""sdkProvider": "google" (get API key from aistudio.google.com/apikey)Provider Configuration:
name: Display name used in /provider commandbaseUrl: OpenAI-compatible API endpointapiKey: API key (optional, may not be required)models: Available model list for /model commanddisableToolModels: List of model names to disable tool calling for (optional)sdkProvider: AI SDK provider package to use (optional, defaults to openai-compatible)
openai-compatible: Default, works with any OpenAI-compatible APIgoogle: Use @ai-sdk/google for native Google Gemini support (required for Gemini 3 models with tool calling)anthropic: Use @ai-sdk/anthropic for providers that require it like Kimi CodingEnvironment Variables:
Keep API keys out of version control using environment variables. Variables are loaded from shell environment (.bashrc, .zshrc) or .env file in your working directory.
NANOCODER_CONFIG_DIR: Override the global configuration directory.NANOCODER_CONTEXT_LIMIT: Set a default context limit (in tokens) for models not found on models.dev. This is used as a fallback when the model's context window is unknown, enabling auto-compact and /usage to work correctly.NANOCODER_DATA_DIR: Override the application data directory used for internal data like usage statistics.Syntax: $VAR_NAME, ${VAR_NAME}, or ${VAR_NAME:-default}
Supported in: baseUrl, apiKey, models, disableToolModels, MCP server, command, args, env
See .env.example for setup instructions
Timeout Configuration:
Nanocoder allows you to configure timeouts for your AI providers to handle long-running requests.
requestTimeout: (Optional) The application-level timeout in milliseconds. This is the total time the application will wait for a response from the provider. If not set, it defaults to 2 minutes (120,000 ms). Set to -1 to disable this timeout.socketTimeout: (Optional) The socket-level timeout in milliseconds. This controls the timeout for the underlying network connection. If not set, it will use the value of requestTimeout. Set to -1 to disable this timeout.It is recommended to set both requestTimeout and socketTimeout to the same value for consistent behavior. For very long-running requests, you can disable timeouts by setting both to -1.
connectionPool: (Optional) An object to configure the connection pooling behavior for the underlying socket connection.
idleTimeout: (Optional) The timeout in milliseconds for how long an idle connection should be kept alive in the pool. Defaults to 4 seconds (4,000 ms).cumulativeMaxIdleTimeout: (Optional) The maximum time in milliseconds a connection can be idle. Defaults to 10 minutes (600,000 ms).Example with Timeouts:
{
"nanocoder": {
"providers": [
{
"name": "llama-cpp",
"baseUrl": "http://localhost:8080/v1",
"models": ["qwen3-coder:a3b", "deepseek-v3.1"],
"requestTimeout": -1,
"socketTimeout": -1,
"connectionPool": {
"idleTimeout": 30000,
"cumulativeMaxIdleTimeout": 3600000
}
}
]
}
}
Troubleshooting Context Length Issues:
If you experience the model repeating tool calls or getting into loops (especially with multi-turn conversations), this is often caused by insufficient context length settings in your local AI provider:
OLLAMA_NUM_CTX=8192--ctx-size 8192 or higher when starting the server--max-model-len 8192 when launchingTool-calling conversations require more context to track the history of tool calls and their results. If the context window is too small, the model may lose track of previous actions and repeat them indefinitely.
Nanocoder now includes comprehensive structured logging with Pino, providing enterprise-grade logging capabilities including correlation tracking, performance monitoring, and security features.
Logging Configuration Options:
# Environment Variables
NANOCODER_LOG_LEVEL=debug # Log level (trace, debug, info, warn, error, fatal)
NANOCODER_LOG_TO_FILE=true # Enable file logging
NANOCODER_LOG_TO_CONSOLE=true # Enable console logging
NANOCODER_LOG_DIR=/var/log/nanocoder # Log directory
NANOCODER_CORRELATION_ENABLED=true # Enable correlation tracking
Features:
Default Log File Locations:
When NANOCODER_LOG_TO_FILE=true is set, logs are stored in platform-specific locations:
~/Library/Preferences/nanocoder/logs~/.config/nanocoder/logs/nanocoder/%APPDATA%\nanocoder\logs\You can override the default location using NANOCODER_LOG_DIR environment variable.
For complete documentation, see Pino Logging Guide.
Nanocoder supports MCP servers to extend its capabilities with additional tools. Configure servers using .mcp.json files at project or global level.
Quick Start:
/setup-mcp for an interactive wizard with templates.mcp.json in your project root:{
"mcpServers": {
"filesystem": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./src"],
"alwaysAllow": ["list_directory", "read_file"]
},
"github": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" }
}
}
}
Key Features:
stdio (local), http, websocket (remote)alwaysAllow to skip confirmation for trusted tools$VAR or ${VAR:-default} syntax.mcp.json) overrides global (~/.config/nanocoder/.mcp.json)Commands:
/setup-mcp - Interactive configuration wizard (supports Ctrl+E for manual editing)/mcp - Show connected servers and their toolsPopular MCP servers: Filesystem, GitHub, Brave Search, Context7, DeepWiki, and many more.
Full documentation: See the MCP Configuration Guide for detailed setup, examples, and troubleshooting.
Nanocoder automatically saves your preferences to remember your choices across sessions.
Preferences File Locations:
Preferences follow the same location hierarchy as configuration files:
nanocoder-preferences.json in your current working directory (overrides user-level)~/Library/Preferences/nanocoder/nanocoder-preferences.json~/.config/nanocoder/nanocoder-preferences.json%APPDATA%\nanocoder\nanocoder-preferences.json~/.nanocoder-preferences.json (backward compatibility)What gets saved automatically:
Manual management:
nanocoder-preferences.json to start freshNanocoder stores internal application data (such as usage statistics) in a separate application data directory:
~/Library/Application Support/nanocoder$XDG_DATA_HOME/nanocoder or ~/.local/share/nanocoder%APPDATA%\nanocoderYou can override this directory using NANOCODER_DATA_DIR.
/help - Show available commands/init - Initialize project with intelligent analysis, create AGENTS.md and configuration files. Use /init --force to regenerate AGENTS.md if it already exists./setup-providers - Interactive wizard for configuring AI providers with templates/setup-mcp - Interactive wizard for configuring MCP servers with templates/clear - Clear chat history/model - Switch between available models/provider - Switch between configured AI providers/status - Display current status (CWD, provider, model, theme, available updates, AGENTS setup)/tasks - Manage task list for tracking complex work (see Task Management section)/model-database - Browse coding models from OpenRouter (searchable, filterable by open/proprietary)/settings - Interactive menu to access Nanocoder theme settings (theme, title-shape, nanocoder-shape) and commands/mcp - Show connected MCP servers and their tools/custom-commands - List all custom commands/checkpoint - Save and restore conversation snapshots (see Checkpointing section)/compact - Compress message history to reduce context usage (see Context Compression)/context-max - Set maximum context length for the current session (useful for models not listed on models.dev)/exit - Exit the application/export - Export current session to markdown file/update - Update Nanocoder to the latest version/usage – Get current model context usage visually/lsp – List connected LSP servers/schedule – Schedule recurring AI tasks (see Scheduled Tasks section)/explorer - Interactive file browser to navigate, preview, and select files for context/ide - Connect to an IDE for live integration (e.g., VS Code diff previews)!command - Execute bash commands directly without leaving Nanocoder (output becomes context for the LLM)@file - Include file contents in messages automatically via fuzzy search as you typeNanocoder supports conversation checkpointing, allowing you to save snapshots of your coding sessions and restore them later. This is perfect for experimenting with different approaches or preserving important milestones.
Checkpoint Commands:
/checkpoint create [name] - Create a checkpoint with optional custom name
/checkpoint create feature-auth-v1/checkpoint list - List all available checkpoints
/checkpoint load [name] - Restore files from a checkpoint
/checkpoint load (interactive) or /checkpoint load feature-auth-v1/checkpoint delete <name> - Delete a checkpoint permanently
/checkpoint delete old-checkpointWhat gets saved:
Storage location:
.nanocoder/checkpoints/ in your project directory.nanocoder/checkpoints to your .gitignoreExample workflow:
# Create a checkpoint before trying a new approach
/checkpoint create before-refactor
# Make some experimental changes...
# If things go wrong, restore the checkpoint
/checkpoint load before-refactor
# Or if things went well, create a new checkpoint
/checkpoint create after-refactor
# List all checkpoints to see your progress
/checkpoint list
Nanocoder provides a task management system for tracking complex multi-step work. Tasks persist in .nanocoder/tasks.json and are useful for both users and AI models to track progress on involved tasks.
The LLM has access to task management tools (create_task, list_tasks, update_task, delete_task) and will automatically use them to track progress on complex work. You don't need to manually create tasks if you don't want to - the AI will manage them for you.
Task Commands:
/tasks - Show all tasks with their status/tasks add <title> - Add a new task (also works: /tasks <title>)/tasks remove <number> - Remove a task by number (alias: /tasks rm <number>)/tasks clear - Clear all tasksExamples:
# View current tasks
/tasks
# Add a new task
/tasks add Implement user authentication
# Or simply type the task title
/tasks Implement user authentication
# Remove a task (note the number)
/tasks remove 1
# Clear all tasks
/tasks clear
Storage:
.nanocoder/tasks.json in your project directory/clear command.nanocoder/tasks.json to your .gitignore if you want to exclude it from version controlNanocoder supports scheduling recurring AI tasks using cron expressions. This is useful for automating routine coding tasks like dependency updates, code reviews, or daily standup summaries.
Quick Start:
# Create a new scheduled task file
/schedule create deps-update
# Add a schedule for it (every Monday at 9am)
/schedule add "0 9 * * MON" deps-update
# Start the scheduler
/schedule start
Commands:
/schedule create <name> - Create a new scheduled task file/schedule add "<cron>" <name> - Add a schedule for a task (.md extension inferred)/schedule list - Show all configured schedules/schedule remove <id> - Remove a schedule by ID/schedule logs [id] - Show execution logs/schedule start - Enter scheduler mode to run scheduled tasksFull documentation: See the Scheduled Tasks Guide for detailed usage, examples, and tips.
The /explorer command opens an interactive file browser for navigating your project, previewing files with syntax highlighting, and selecting multiple files to add as context.
Navigation:
| Key | Action |
|---|---|
| ↑/↓ | Navigate through files and directories |
| Enter | Expand/collapse directory or preview file |
| Space | Toggle file/directory selection |
| / | Enter search mode (filters all files including nested) |
| Backspace | Collapse current directory |
| Esc | Exit explorer (selected files are added to input) |
Features:
/ to filter files by name across the entire tree--vscode, previewing a file also opens it in VS Code for full-featured viewingSelection indicators:
✓ - File or directory fully selected◐ - Directory partially selected (some files within)✗ - File not selected (in preview mode)v / > - Directory expanded / collapsedExample workflow:
# Open the file explorer
/explorer
# Navigate to src/components, expand it
# Select multiple component files with Space
# Press Esc to add them to your input as @file mentions
Nanocoder supports custom commands defined as markdown files in .nanocoder/commands/. Define reusable AI prompts with parameters, aliases, and auto-injection support, organized per project.
# Create a command with AI assistance
/commands create review-code
# Or create the file manually in .nanocoder/commands/review-code.md
Example (.nanocoder/commands/test.md):
---
description: Generate comprehensive unit tests
aliases: [unittest, test-gen]
parameters: [filename]
---
Generate comprehensive unit tests for {{filename}}.
Usage: /test src/utils.ts
Commands: /commands (list), /commands show <name>, /commands refresh, /commands create <name>
Pre-installed: /test, /review, /refactor:dry, /refactor:solid
Full documentation: See the Custom Commands Guide for frontmatter reference, auto-injection, resources, namespaces, and more.
.nanocoder/commands//commands create <name> scaffolds a command and helps you write it{{parameter}} syntax for dynamic contentrefactor/dry.md becomes /refactor:dry)| Action | Shortcut | Notes |
|---|---|---|
| Submit prompt | Enter | |
| New line (multi-line input) | Ctrl+J | Most reliable across terminals |
| New line (multi-line input) | Shift+Enter | Terminal-dependent |
| New line (multi-line input) | Option/Alt+Enter | VS Code integrated terminal |
| Toggle development mode | Shift+Tab | Cycles through normal/auto-accept/plan |
| Cancel AI response | Esc | While AI is processing |
| Clear input | Esc (twice) | Press Esc twice to clear current input |
| History navigation | ↑/↓ | Navigate through prompt history |
Note on multi-line input: Terminal support for Shift+Enter / Option/Alt+Enter varies in terminals and operating systems. If one of these shortcuts doesn't work in your terminal, try and use Ctrl+J which sends a literal newline character and works more reliably across platforms and software.
agents.config.jsonNanocoder includes a VS Code extension that provides live diff previews of file changes directly in your editor. When the AI suggests file modifications, you can see exactly what will change before approving.
To get started, run Nanocoder with the --vscode flag:
nanocoder --vscode
For full documentation including installation options, configuration, and troubleshooting, see the VS Code Extension Guide.
We're a small community-led team building Nanocoder and would love your help! Whether you're interested in contributing code, documentation, or just being part of our community, there are several ways to get involved.
If you want to contribute to the code:
If you want to be part of our community or help with other aspects like design or marketing:
Join our Discord server to connect with other users, ask questions, share ideas, and get help: Join our Discord server
Head to our GitHub issues or discussions to open and join current conversations with others in the community.
What does Nanocoder need help with?
Nanocoder could benefit from help all across the board. Such as:
All contributions and community participation are welcome!
FAQs
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
The npm package @nanocollective/nanocoder receives a total of 746 weekly downloads. As such, @nanocollective/nanocoder popularity was classified as not popular.
We found that @nanocollective/nanocoder demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.