Skip to main content

Minimal AI coding agent powered by Claude Opus 4.7 (with adaptive thinking) or GPT-5.5, with WSL-backed Linux tooling on Windows

Project description

NTN - Minimal AI Coding Agent

A minimal AI agent that helps with coding tasks in a workspace. Supports multiple LLM providers (OpenAI GPT-5.5, Anthropic Claude). Runs all Linux tooling through WSL on Windows.

Features

  • Multi-provider support: Claude Opus 4.7 (default), Claude Sonnet 4.6, Claude Haiku 4.5, GPT-5.5
  • WSL-backed Linux tooling: All file ops, git, python, node, builds, tests, package managers run inside the user's default WSL distro - no per-session container, no docker pull, instant startup
  • Web search: Search using DuckDuckGo (ddgs package)
  • Web fetching: Fetch and read webpage content
  • Terminal execution: Run Windows commands when genuinely needed (Windows venvs, .exe, gh/git with credential helper, etc.)
  • 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 logging to debug/ folder (crash-resilient)
  • Resume sessions: Continue previous conversations with -r flag
  • 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-after header
  • Prompt caching: System prompt and tools are cached to reduce costs
  • Model selection: Choose between Claude and GPT models with -m flag
  • 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 max. Use -t off to 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-5.5:

export OPENAI_API_KEY='your-api-key-here'

Install WSL (Windows-only requirement; one-time):

wsl --install

The agent uses your default WSL distro (wsl.exe -- bash -lc <cmd>), so any installed Linux is fine. Tested on Fedora and Ubuntu.

Usage

Run the agent:

ntn

Resume a previous session:

# Resume most recent session
ntn -r

# Resume specific session
ntn -r debug/debug_20251210_120000.txt

Disable thinking (adaptive by default):

ntn -t off

Tune response effort (default max):

ntn -e high     # high effort (Anthropic API default when effort is omitted)
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 (default)

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/minimalmedium and maxxhigh. The CLI banner prints the value actually sent (e.g. effort: high (from xhigh)).

Use a different model:

ntn -m opus    # Use Claude Opus 4.7 (default)
ntn -m sonnet  # Use Claude Sonnet 4.6
ntn -m haiku   # Use Claude Haiku 4.5
ntn -m gpt     # Use GPT-5.5

Combine flags:

ntn -t off -r           # Resume with thinking disabled
ntn -m gpt -e medium    # GPT with medium effort

Alternative: Run as Python module:

python -m ntn

Input controls:

  • Shift+Enter - New line (shows \)
  • Enter - Submit message
  • Ctrl+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" (uses WSL, path becomes /mnt/d/Downloads/some-project)

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, WSL)
│   ├── 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
│   ├── wsl_manager.py         # WSL session manager (path conversion + exec)
│   ├── 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. 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.

WSL Tool

All Linux-flavored work runs inside the user's default WSL distro:

  • No container, no startup cost - just wsl.exe -- bash -lc <command>
  • Real Windows files are reachable via /mnt/<drive-letter-lowercased>/... (e.g. D:\foo\Bar/mnt/d/foo/Bar; only the drive letter is lowercased)
  • Single argument: {"command": "<bash command>"} - returns {stdout, stderr, returncode}
  • Each call starts a fresh bash -lc shell in the user's home directory, so use absolute paths or cd /mnt/<drive>/... first
  • Recorded working directories are listed in the system prompt for visibility but WSL can already see every drive under /mnt/

Context Management

The agent automatically manages context when approaching token limits:

  1. Auto-compact triggers: Summarizes older conversation turns
  2. Preserves current task: Summary includes your current question
  3. 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 debug/debug_<timestamp>.txt. To resume:

# Resume most recent session
ntn -r

# Resume specific session
ntn -r debug/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 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, 🐧 WSL, 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 /mnt/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 debug/debug_<timestamp>.txt for debugging.

Security Notes

  • Commands run without timeout (for long-running processes)
  • Dangerous commands require explicit user confirmation
  • WSL provides a real Linux environment, but with no isolation - it shares the user's default distro and has full read/write access to mounted Windows drives
  • 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:

  • Enter  submit
  • Esc then Enter  insert 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ntn-0.5.0.tar.gz (45.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ntn-0.5.0-py3-none-any.whl (51.2 kB view details)

Uploaded Python 3

File details

Details for the file ntn-0.5.0.tar.gz.

File metadata

  • Download URL: ntn-0.5.0.tar.gz
  • Upload date:
  • Size: 45.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ntn-0.5.0.tar.gz
Algorithm Hash digest
SHA256 eb13f9dded383cb730397262938d1f81968cda357f6eaaf4d5c13b9288cdc03c
MD5 557281e72fc2df360d2a76a641167a88
BLAKE2b-256 fafc3756bd68a0e03c21317cb80dcb10c1f58a662e2ade0eddac82f7647c29ff

See more details on using hashes here.

File details

Details for the file ntn-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: ntn-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 51.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ntn-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0268c0b61b9e612620d880c4acfef0da90ae161949b69d97d0487a64bc09d500
MD5 8e39d9e7e435d9718bd0d7ada08c3bdf
BLAKE2b-256 cfd0926670c1e84203e54d931257f90022ebca8fef84269028ca8f31a4d859ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page