Your autonomous CLI AI engineer
Project description
nice
Your autonomous CLI AI engineer. Ask questions, run interactive chats, execute coding tasks with file and shell tools, plan and execute multi-step goals, review and explain code, generate commit messages, and auto-fix broken commands — all from the terminal.
Features
- Streaming output — responses render token-by-token with full Markdown formatting
- Multiple providers — OpenAI-compatible (OpenRouter), Anthropic Claude, Ollama (local)
- 9 built-in tools — read/write files, run commands, web search, fetch URLs, git operations
- Context file — place
.nice.mdin any project for automatic AI context injection - Diff preview — shows a coloured diff before the AI writes any file
- Persistent history —
chatandcodesessions resume where you left off - Plugin system — drop a
.pyfile in~/.nice/plugins/to add custom tools or commands - Activity log — everything logged to
~/.nice/nice.log
Requirements
- An API key for OpenRouter or any OpenAI-compatible endpoint
Installation
Option 1 — Standalone binary (recommended, no Python needed)
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/amrilsyaifa/Nice-AI-Agent/main/scripts/install.sh | bash
Windows (PowerShell):
iwr https://raw.githubusercontent.com/amrilsyaifa/Nice-AI-Agent/main/scripts/install.ps1 | iex
Or download the binary directly from Releases:
| Platform | File |
|---|---|
| macOS Apple Silicon | nice-macos-arm64 |
| macOS Intel | nice-macos-x86_64 |
| Linux x86_64 | nice-linux-x86_64 |
| Windows x86_64 | nice-windows-x86_64.exe |
Option 2 — pip / uv (requires Python >= 3.13)
pip install nice-agent
# or
uv tool install nice-agent
# or
pipx install nice-agent
Option 3 — from source
git clone https://github.com/amrilsyaifa/Nice-AI-Agent.git
cd Nice-AI-Agent
uv sync
uv tool install .
Development — Build & Run Locally
Prerequisites
- Python >= 3.13
- uv —
curl -LsSf https://astral.sh/uv/install.sh | sh
1. Clone and install dependencies
git clone https://github.com/amrilsyaifa/Nice-AI-Agent.git
cd Nice-AI-Agent
uv sync
2. Run directly (no install needed)
uv run nice --help
uv run nice version
uv run nice ask "What is 2 + 2?"
3. Install into virtualenv (activate once, use everywhere in the project)
uv pip install -e .
source .venv/bin/activate # macOS/Linux
# or
.venv\Scripts\activate # Windows
nice --help
nice version
4. Install globally (available from any directory)
uv tool install .
nice --help # works anywhere
Uninstall: uv tool uninstall nice
5. Build standalone binary (no Python needed on target machine)
Install dev dependencies first:
uv sync --extra dev
Build:
uv run pyinstaller nice.spec --noconfirm
The binary is output to dist/nice (or dist/nice.exe on Windows). Run it directly:
./dist/nice --help
./dist/nice version
./dist/nice ask "Hello"
6. Lint & format
uv run ruff check . # check for errors
uv run ruff check --fix . # auto-fix
uv run ruff format . # format all files
7. Config after install
Set your API key before first use:
nice config set api_key YOUR_API_KEY
nice config set model openai/gpt-4o # optional, change model
nice config list # verify settings
Configuration
All config lives at ~/.nice/config.json.
nice config set api_key YOUR_API_KEY
nice config set base_url https://openrouter.ai/api/v1
nice config set model openai/gpt-4o
nice config set provider openai
nice config list # show all settings
nice config get model # get one value
| Key | Default | Description |
|---|---|---|
provider |
openai |
Active provider: openai, claude, ollama |
model |
liquid/lfm-2.5-1.2b-thinking:free |
Model name |
api_key |
(required) | API key for the active provider |
base_url |
https://openrouter.ai/api/v1 |
API base URL |
show_usage |
false |
Print token count after every response |
command_timeout |
60 |
Shell command timeout in seconds |
confirm_commands |
false |
Ask before running any shell command |
blocked_commands |
(empty) | Extra patterns to block (comma-separated) |
log_level |
warning |
Log verbosity: debug, info, warning, error |
Provider setup
OpenAI / OpenRouter (default)
nice config set provider openai
nice config set api_key YOUR_OPENROUTER_KEY
Anthropic Claude
nice config set provider claude
nice config set api_key YOUR_ANTHROPIC_KEY
nice config set model claude-sonnet-4-6
Ollama (local, no internet)
ollama pull llama3.2
nice config set provider ollama
nice config set model llama3.2
# base_url defaults to http://localhost:11434/v1 — no api_key needed
Commands
nice ask
One-shot question. Streams a Markdown response.
nice ask "What is a race condition?"
nice ask "List sorting algorithms" --quiet # plain text, no decoration
nice chat
Interactive chat with persistent memory and named sessions.
nice chat # default session
nice chat --session work # named session
nice chat --list # list all sessions
nice chat --delete work # delete a session
nice chat --session work --export # export to Markdown
nice chat --session work --export-json
In-session commands:
| Command | Action |
|---|---|
exit |
End the session |
clear |
Reset history |
/model <name> |
Switch model without restarting |
/context <file> |
Load a file as extra context for this session |
/usage |
Show token count from last request |
/help |
List all commands |
History is saved to ~/.nice/history.json (default) or ~/.nice/sessions/<name>.json.
When total conversation length exceeds 40,000 characters, older messages are automatically summarised to keep context manageable.
nice code
AI coding agent with tools. One-shot or interactive.
nice code "Create a FastAPI hello-world app" # one-shot
nice code # interactive (history persists)
nice code --clear # reset interactive history
nice code "Create config.json" --quiet # plain output for scripting
Interactive mode has the same slash commands as nice chat.
History saved to ~/.nice/code_history.json.
nice plan
Break a goal into steps, review/revise the plan, then execute.
nice plan "Build a REST API with Flask"
nice plan # prompts for goal interactively
nice plan -e "..." # skip review, execute immediately
At the plan review prompt:
| Choice | Action |
|---|---|
a |
Approve and execute |
r |
Revise — type feedback, get a new plan |
c |
Cancel |
nice fix
Run a command and auto-fix errors (up to 3 attempts).
nice fix "python main.py"
nice fix "pytest tests/" --file src/main.py # give AI the file for context
nice review
Review code for bugs, issues, and improvements. Output uses [ERROR], [WARNING], [INFO] tags.
nice review main.py # single file
nice review src/ # whole directory (skips node_modules, .git, etc.)
nice explain
Explain what a piece of code does.
nice explain utils.py # whole file
nice explain utils.py:42 # focus on line 42 (±40 lines shown)
nice commit
Generate a commit message from staged changes.
nice commit # uses git diff --cached
nice commit --all # stages all tracked changes first (git add -u)
Options at the review prompt: [a] accept · [e] edit · [c] cancel.
nice test
Run a test suite and auto-fix failures (up to 3 attempts).
nice test "pytest"
nice test "npm test"
nice version
nice version
Tools
All tools are available to the AI in code, plan, fix, and test.
| Tool | Description |
|---|---|
read_file |
Read a file from disk |
write_file |
Write/create a file (shows diff preview first) |
list_directory |
List directory contents |
run_command |
Execute a shell command |
web_search |
Search with DuckDuckGo (no API key needed) |
fetch_url |
Fetch and read a web page as text |
git_status |
git status --short --branch |
git_diff |
Working-tree or staged diff |
git_log |
Recent commit history |
Context file
Create .nice.md in any project root:
## Stack
- React 18 + Vite + TypeScript
- Tailwind CSS v4
## Conventions
- Components in `src/components/`, one file per component
- Named exports only
- API calls go through `src/lib/api.ts`
nice reads .nice.md automatically in ask, chat, code, plan, and fix. No flags needed.
Diff preview
Before writing any file the AI shows a diff and asks for confirmation:
Diff preview: src/App.tsx
--- src/App.tsx (current)
+++ src/App.tsx (proposed)
@@ -1,4 +1,5 @@
import React from 'react'
-function App() {
+function App({ name }: { name: string }) {
Apply? [y/n]:
New files show a preview of the first 20 lines before creation.
Security
# Block specific command patterns
nice config set blocked_commands "sudo rm,git push --force,npm publish"
# Require confirmation before every shell command
nice config set confirm_commands true
Certain commands are always blocked regardless of config: rm -rf /, mkfs, dd if=, fork bombs, and similar destructive operations.
Plugin system
Drop a .py file in ~/.nice/plugins/ to extend Nice with custom tools or CLI commands:
# ~/.nice/plugins/jira.py
TOOL_DEFINITIONS = [{
"type": "function",
"function": {
"name": "get_jira_ticket",
"description": "Fetch a Jira ticket",
"parameters": {
"type": "object",
"properties": {"ticket_id": {"type": "string"}},
"required": ["ticket_id"]
}
}
}]
TOOL_FUNCTIONS = {
"get_jira_ticket": lambda ticket_id: f"Ticket {ticket_id}: ..."
}
# Optional: add a new CLI command
import typer
def command_jira(ticket_id: str):
"""Open a Jira ticket."""
typer.echo(f"Opening {ticket_id}...")
COMMANDS = {"jira": command_jira}
Plugins are loaded at startup. Errors in a plugin print a warning but do not crash the app.
Logging
nice config set log_level info # debug | info | warning | error
tail -f ~/.nice/nice.log
Logs include: tool calls, API requests, plugin loading, blocked commands, and errors.
Project structure
nice/
├── nice/
│ ├── main.py # CLI entry point + plugin loader
│ ├── cli/
│ │ ├── _slash.py # Shared slash-command helpers
│ │ ├── _spinner.py # stream_markdown, stream_quiet, run_with_spinner
│ │ ├── ask.py # nice ask
│ │ ├── chat.py # nice chat
│ │ ├── code.py # nice code
│ │ ├── commit.py # nice commit
│ │ ├── explain.py # nice explain
│ │ ├── fix.py # nice fix
│ │ ├── plan.py # nice plan
│ │ ├── review.py # nice review
│ │ ├── test_cmd.py # nice test
│ │ ├── version.py # nice version
│ │ └── config_cmd.py # nice config
│ ├── config/
│ │ ├── settings.py # NiceConfig — load/save ~/.nice/config.json
│ │ └── context.py # .nice.md loader
│ ├── core/
│ │ ├── logger.py # Logging setup → ~/.nice/nice.log
│ │ └── reflection.py # Error-reflection retry loop (nice fix)
│ ├── memory/
│ │ └── history.py # ConversationHistory, sessions, export, compress
│ ├── planner/
│ │ ├── plan.py # ExecutionPlan + Step data classes
│ │ ├── planner.py # LLM plan creation with feedback support
│ │ └── executor.py # Step-by-step plan execution
│ ├── plugins/
│ │ └── loader.py # Load ~/.nice/plugins/*.py at startup
│ ├── providers/
│ │ ├── base.py # BaseProvider ABC
│ │ ├── http_provider.py # OpenAI-compatible (streaming, tool use, usage tracking)
│ │ ├── claude_provider.py # Anthropic direct API
│ │ ├── ollama_provider.py # Ollama local models
│ │ └── registry.py # Provider lookup
│ └── tools/
│ ├── file_tools.py # read_file, write_file (diff), list_directory
│ ├── shell_tools.py # run_command (blocklist, confirm, configurable timeout)
│ ├── web_tools.py # web_search, fetch_url
│ ├── git_tools.py # git_status, git_diff, git_log
│ └── registry.py # TOOL_DEFINITIONS, TOOL_FUNCTIONS, execute_tool
└── pyproject.toml
How it works
- Startup —
main.pycallback runs before every command: sets up logging, loads plugins, extends tool registry. - Streaming —
HttpProvider.chat_streamsendsstream: true, yields text tokens, accumulates tool-call chunks, executes tools, then yields the follow-up stream. Rendered live as Markdown via RichLive. - Tool calling — when the LLM returns
tool_calls, the provider executes each locally, appends results to the message list, and re-queries until it returns plain text. - Diff preview —
write_filecomputesdifflib.unified_diff, displays it colour-coded, and requiresybefore writing. - Planning —
create_planparses a JSON step list from the LLM.execute_planruns each step with tools and tracks status. - Reflection loop —
nice fixwraps a command in a retry loop; on failure the LLM patches the file with tools, then retries. - Memory —
ConversationHistoryserialises to~/.nice/<name>.jsonafter every turn. Auto-compresses when >40 k chars. - Context —
inject_contextreads.nice.mdand appends it to the system prompt before every request. - Security —
run_commandchecks against a hardcoded blocklist plus user-configured patterns. Optional confirm prompt. - Plugins —
load_pluginsimports*.pyfrom~/.nice/plugins/, mergesTOOL_DEFINITIONS,TOOL_FUNCTIONS, andCOMMANDSinto the live registry.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nice_agent-0.1.0.tar.gz.
File metadata
- Download URL: nice_agent-0.1.0.tar.gz
- Upload date:
- Size: 49.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a84c817399090bc37e6be2185fa648247a1207577dbf81bf9113cbb3da20bb72
|
|
| MD5 |
f0e80be313efbab2430a1489e7e08148
|
|
| BLAKE2b-256 |
ee54cacfa3fd6d01f86254cedd267ae7a2007d68200df622bb0d23a7324ee110
|
File details
Details for the file nice_agent-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nice_agent-0.1.0-py3-none-any.whl
- Upload date:
- Size: 45.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35290a89ffbdc3398c00753ef83946edb2610ff7930f9d4ab84067d825854df4
|
|
| MD5 |
8f15af4f46a0c9430c0cadbc9d53a364
|
|
| BLAKE2b-256 |
a2cb30f344a05f361d71be2b2f4b35a2e1ac509069a9302e8afb4ad7d184fc9d
|