Minimal AI coding agent powered by Claude Opus 4.7 (adaptive thinking), GPT-5.5, or OpenRouter models (DeepSeek, Kimi, Hunyuan). Runs commands natively in your shell (PowerShell, bash, zsh).
This project has been archived.
The maintainers of this project have marked this project as archived. No new releases are expected.
Project description
NTN - Minimal AI Coding Agent
A minimal AI agent that helps with coding tasks in a workspace. Supports multiple LLM providers (Anthropic Claude, OpenAI GPT, OpenRouter). Runs commands directly in your native shell (PowerShell, bash, zsh, ...).
Features
- Multi-provider support: Claude Opus 4.7 (default), Claude Sonnet 4.6, Claude Haiku 4.5, GPT-5.5, GPT-5.4-mini, Tencent Hunyuan 3 Preview, DeepSeek, and Kimi K2.6 (the last three via OpenRouter)
- Native shell execution: Commands run directly in your default shell (PowerShell on Windows, bash/zsh on Linux/macOS) — no WSL hop, no
/mnt/<drive>/prefixing, no per-call startup cost. The agent's system prompt is auto-populated with the detected OS, shell, and architecture so the model uses correct command syntax. - Web search: Search using DuckDuckGo (ddgs package)
- Web fetching: Fetch and read webpage content
- Terminal execution: Single
execute_commandtool runs commands in your native shell - Command denylist: Dangerous commands require user confirmation
- Two-color tool display: Tool descriptions in yellow, paths in cyan for better readability
- Smart command detection: Recognizes common patterns (python -c, inline scripts) for better descriptions
- Colored output: Easy-to-read console with color-coded messages
- Debug logging: Incremental per-workspace logging to
~/Documents/ntn/<hash>/(crash-resilient) - Resume sessions: Continue previous conversations with
-rflag - Mid-turn resume: Automatically recovers from crashes mid-tool-execution
- Auto-compact: Automatically summarizes context when approaching token limit
- Auto-cleanup: Empty conversations (no user messages) are automatically deleted
- Rate limit handling: Automatically waits and retries using
retry-afterheader - Prompt caching: System prompt and tools are cached to reduce costs
- Model selection: Choose between Claude and GPT models with
-mflag - Streaming output: Real-time response display (always enabled)
- Cost tracking: Shows per-request and session costs with token usage
- Adaptive thinking: On Opus 4.7 / Sonnet 4.6, Claude dynamically decides when and how much to think (interleaved between tool calls). Default effort is
high. Use-t offto disable,-e {low|medium|high|xhigh|max}to tune effort.
Installation
Install from PyPI:
pip install ntn
Or install from source:
git clone https://github.com/ntrnghia/coding-agent.git
cd ntn
pip install -e .
Setup
Set your API key based on the model you want to use:
For Claude models (default):
export ANTHROPIC_API_KEY='your-api-key-here'
For GPT models:
export OPENAI_API_KEY='your-api-key-here'
For OpenRouter models (Hunyuan 3, DeepSeek, Kimi K2.6):
export OPENROUTER_API_KEY='your-api-key-here'
Get a key at https://openrouter.ai/keys.
Usage
Run the agent:
ntn
Resume a previous session:
# Resume most recent session
ntn -r
# Resume specific session
ntn -r ~/Documents/ntn/<hash>/debug_20251210_120000.txt
Disable thinking (adaptive by default):
ntn -t off
Tune response effort (default high):
ntn -e high # high effort (default)
ntn -e medium # balanced
ntn -e low # fast / cheap
ntn -e xhigh # extended capability for long-horizon work (Opus 4.7 only)
ntn -e max # absolute maximum capability
Per-model effort support: Opus 4.7 accepts all 5 levels. Sonnet 4.6 has no
xhigh (it is auto-clamped to high). Haiku 4.5 ignores effort entirely.
GPT-5.5 maps low/minimal → medium and max → xhigh. The CLI banner
prints the value actually sent (e.g. effort: high (from xhigh)).
Override context window and output token limits:
ntn -c 100000 # limit context to 100K tokens
ntn -o 16000 # limit output to 16K tokens per response
ntn -c 150000 -o 8000 # combine both
Use a different model:
ntn -m opus # Claude Opus 4.7 (default)
ntn -m sonnet # Claude Sonnet 4.6
ntn -m haiku # Claude Haiku 4.5
ntn -m gpt-5.5 # GPT-5.5
ntn -m gpt-5.4-mini # GPT-5.4 mini
ntn -m hy3 # Tencent Hunyuan 3 Preview (free, OpenRouter)
ntn -m deepseek # DeepSeek (OpenRouter)
ntn -m kimi # Kimi K2.6 (OpenRouter)
Combine flags:
ntn -t off -r # Resume with thinking disabled
ntn -m gpt-5.5 -e medium # GPT-5.5 with medium effort
ntn -m sonnet -e high -c 100000 # Sonnet with 100K context window
Alternative: Run as Python module:
python -m ntn
Input controls:
Shift+Enter- New line (shows\)Enter- Submit messageCtrl+C- Exit the agent
Example prompts:
- "Create a new Python project with main.py and tests/"
- "Search for PyTorch distributed training docs"
- "List all Python files in this directory"
- "Run pytest on my tests"
- "Tell me what the code in D:\Downloads\some-project does"
Package Structure
coding-agent/
├── src/ntn/
│ ├── __init__.py # Package exports
│ ├── __main__.py # Entry for `python -m ntn`
│ ├── _version.py # Auto-generated version (from hatch_build.py)
│ ├── cli.py # CLI entry point and resume parser
│ ├── agent.py # Main agent loop, compaction, cost tracking
│ ├── tools.py # Tool implementations (Terminal, Web)
│ ├── tool_exec.py # Tool execution + denylist confirmation
│ ├── providers.py # LLM provider abstraction (Anthropic, OpenAI)
│ ├── provider_types.py # Shared provider dataclasses (StreamEvent, etc.)
│ ├── stream_accumulator.py # Normalizes streaming events into content blocks
│ ├── session_log.py # Incremental debug-log writer / parser
│ ├── prompts.py # System prompt templates
│ ├── ui.py # Banner, status line, color helpers
│ ├── config.py # Configuration loader (typed)
│ ├── config.yaml # Configuration values (models, pricing, UI)
│ └── test_cache.py # Local prompt-cache hit-rate tests
├── hatch_build.py # Git-commit-count based versioning hook
├── pyproject.toml # Package configuration
├── CHANGELOG.md # Release notes
├── LICENSE # MIT License
└── README.md # This file
Tools
Terminal Tool
Executes shell commands in your workspace via execute_command. The host shell
(PowerShell on Windows, bash/zsh on Linux/macOS) is auto-detected at startup
and surfaced to the model in the system prompt so it uses the right syntax
(Get-ChildItem vs ls, Select-String vs grep, etc.). Dangerous commands
(rm, sudo, curl, etc.) require user confirmation before execution.
Web Search Tool
Searches the web using DuckDuckGo, returns top 10 results.
Fetch Web Tool
Fetches and extracts text content from URLs.
Context Management
The agent automatically manages context when approaching token limits:
- Auto-compact triggers: Summarizes older conversation turns
- Preserves current task: Summary includes your current question
- Seamless continuation: You won't notice the compaction
Debug file shows compaction events:
=== COMPACTION EVENT ===
Reason: Exceeded context (180000 tokens attempted)
Removed turns: 1-3
Summary content: [condensed conversation]
Resume Sessions
Sessions are logged incrementally to ~/Documents/ntn/<hash>/debug_<timestamp>.txt, where <hash> is the first 6 chars of the SHA-1 of the absolute workspace path. Each workspace gets its own subfolder, so ntn -r from any workspace resumes the latest session for that workspace. To resume:
# Resume most recent session
ntn -r
# Resume specific session
ntn -r ~/Documents/ntn/<hash>/debug_20251210_120000.txt
On resume:
- Previous conversation is displayed (including tool operations)
- Context is restored (including any compacted summaries)
- Working directories are restored from the
=== SESSION INFO ===debug block (legacy=== CONTAINER INFO ===blocks from 0.4.x andwsl_…session ids from 0.5.x are still understood) - New messages append to the same debug file
- Crash recovery: If the agent crashed mid-turn, it will automatically continue from where it left off
- Multi-model support: Can resume with a different model than originally used
Debug Log Format
Debug files use an incremental format for crash resilience:
=== TURN 1 ===
--- USER ---
<user message>
--- ASSISTANT ---
<JSON response>
--- USAGE: {"model": "gpt", "input": 1000, "output": 50, ...} ---
--- TOOL_RESULT ---
<JSON tool results>
--- END_TURN ---
Each block is written immediately, so even if the agent crashes, the debug file contains all completed operations.
Output Format
The agent uses colored output for readability:
- 🟢 Green: Agent messages
- 🟡 Yellow: Tool descriptions (📂 List files, 📄 Read file, ✏️ Edit file, ⚡ Run command, etc.)
- 🔵 Cyan: Working directory paths
(In /path/to/dir), system messages, user prompts - 🟣 Magenta: Thinking indicator (
🧠 Thinking: …— adaptive thinking enabled by default) - 🔴 Red: Errors
Tool Display Example:
🐍 Run inline Python (In D:\Downloads\coding-agent)
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Yellow Cyan
Smart command detection automatically shows meaningful descriptions:
python -c "..."→ "🐍 Run inline Python"- Long commands are truncated for readability
Full JSON input/output is logged to ~/Documents/ntn/<hash>/debug_<timestamp>.txt for debugging.
Security Notes
- Commands run without timeout (for long-running processes)
- Dangerous commands require explicit user confirmation
- Commands execute directly in your shell with no isolation — they have full read/write access to anything your user account can touch
- All commands run in the specified workspace directory
- Never commit API keys to version control
Multi-line input (Shift+Enter)
This CLI uses prompt-toolkit.
Important: Many terminals (including VS Code integrated terminal and Windows Terminal) do not pass a distinct Shift+Enter key event to terminal applications. To make Shift+Enter insert a newline reliably, configure your terminal to translate Shift+Enter into the sequence Esc then Enter (\u001b\r).
The CLI binds:
EntersubmitEscthenEnterinsert newline
VS Code (Windows / PowerShell)
Add this to your VS Code keybindings.json:
{
"key": "shift+enter",
"command": "workbench.action.terminal.sendSequence",
"args": {
"text": "\u001b\r"
},
"when": "terminalFocus"
}
Windows Terminal (Windows / PowerShell)
In Windows Terminal settings.json, add an action that sends Esc+Enter and bind it to shift+enter.
Example (schema varies slightly by Windows Terminal version):
{
"keys": "shift+enter",
"command": {
"action": "sendInput",
"input": "\u001b\r"
}
}
If you already created a sendInput action with an id, you can bind shift+enter to that action instead.
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 Distributions
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 ntn-0.6.1-py3-none-any.whl.
File metadata
- Download URL: ntn-0.6.1-py3-none-any.whl
- Upload date:
- Size: 77.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d9816e743a619163da7a8d00e66ae010ae0f3484324213d4314f47072319186
|
|
| MD5 |
68860c112dd95fea6f2771a3a1ca6d38
|
|
| BLAKE2b-256 |
18d58fbb17468e9c430f4a4d0cb4e4ea99ee2aa6c382c72e6cc6ed7860caaffe
|