DawnCode is an AI-powered coding assistant that runs in your terminal. It uses a Large Language Model (LLM) to understand your requests and can perform file operations and execute commands in your workspace.
DawnCode provides an interactive terminal-based chat interface where you can:
- Ask questions about your codebase
- Request file operations (read, write, edit, list directories)
- Execute shell commands
- Get help with coding tasks
The agent maintains conversation context and can chain multiple tool calls to accomplish complex tasks.
This README was written by DawnCode.
DawnCode inspected its own Python source code, generated this documentation, wrote it to
README.md, and then read it back to verify the result.
DawnCode currently provides 5 tools that the LLM can invoke:
| Tool | Description |
|---|---|
list_directory |
List the contents of a directory |
read_file |
Read the contents of a file (UTF-8 text files only) |
write_file |
Write content to a file, creating parent directories as needed |
edit_file |
Replace specific content in a file (requires exact unique match) |
execute_command |
Execute a shell command and return exit code, stdout, and stderr |
The agent runs a continuous conversation loop:
- User Input - The terminal prompts for user input
- Message History - User message is added to the conversation history
- Stream LLM Response - The LLM streams a response, which may include:
- Text content (displayed in real-time)
- Tool calls (accumulated during streaming)
- Handle Tool Calls - If the LLM made tool calls:
- Execute each tool call
- Append tool results to the conversation
- Loop back to step 3 for the LLM to continue
- No Tool Calls - If the LLM responds without tool calls, the assistant message is added to history and the loop waits for the next user input
- Exit - Type "exit" to quit
The loop handles retries (up to 5 attempts with 2-second delays) for failed LLM requests.
dawncode/
├── main.py # Entry point
├── pyproject.toml # Project configuration
├── .env.example # Example environment variables
├── src/
│ ├── agent/
│ │ ├── __init__.py
│ │ └── agent.py # Main agent loop and streaming logic
│ ├── models/
│ │ ├── __init__.py
│ │ └── llm.py # LLM client wrapper (AsyncOpenAI)
│ ├── tools/
│ │ ├── __init__.py
│ │ ├── base.py # Tool base class
│ │ └── filesystem.py # File system and command execution tools
│ └── utils/
│ ├── __init__.py
│ ├── config.py # Configuration loading from .env
│ └── terminal.py # Rich-based terminal UI
Entry point. Initializes the terminal UI and runs the async agent loop.
Core agent logic:
stream_response()- Streams LLM response, accumulates tool callsbuild_assistant_tool_calls()- Converts accumulated tool calls to API message formatexecute_tool_calls()- Executes tool calls and appends results to conversationagent()- Main async loop handling user input, LLM interaction, and tool execution
LLMClient class wrapping AsyncOpenAI:
- Configures client with API key and base URL from environment
- Provides
chat_completion_stream()with retry logic (5 attempts) - Sends
enable_thinking: Trueandreasoning_budget: 4096in extra_body - Handles cleanup with
close()
Tool base class:
- Stores name, description, parameters schema, and executable function
to_schema()- Returns OpenAI function calling schemaexecute()- Calls the wrapped function with provided arguments
Five concrete tool implementations:
list_directory(path)- Returns newline-separated directory entriesread_file(path)- Returns file content or error messagewrite_file(path, content)- Creates directories, writes fileedit_file(path, old_content, new_content)- Replaces exact unique match onlyexecute_command(command)- Runs shell command, returns exit code + stdout + stderr
Each tool is instantiated as a Tool object with its JSON schema.
Loads configuration from .env file using python-dotenv:
NVIDIA_API_KEY- API key for NVIDIA APIBASE_URL- API base URL (default:https://integrate.api.nvidia.com/v1)MODEL- Model identifier (default:nvidia/nemotron-3-ultra-550b)
Terminal class using rich for UI:
show_banner()- Displays ASCII art banneruser_input()- Prompts for user input with styled promptstart_assistant()/stream_assistant()/end_assistant()- Streaming output handlingerror()- Displays error messages in red
-
Copy
.env.exampleto.env:cp .env.example .env
-
Edit
.envwith your credentials:NVIDIA_API_KEY=your_actual_api_key BASE_URL=https://integrate.api.nvidia.com/v1 MODEL=nvidia/nemotron-3-ultra-550b
Required: NVIDIA_API_KEY must be set. The other two have defaults shown above.
uv sync
uv run main.pypip install -e .
python main.pypython main.py- Single model provider - Only works with OpenAI-compatible APIs (tested with NVIDIA API)
- No persistent memory - Conversation history is lost when the application exits
- No file type detection -
read_fileonly works with UTF-8 text files; binary files return an error - Edit tool strictness -
edit_filerequires the old content to match exactly once; no fuzzy matching - No sandboxing -
execute_commandruns with full user permissions in the workspace - Fixed retry logic - Retries are hardcoded to 5 attempts with 2-second delays
- No conversation export - No way to save or load conversation history
- Single-threaded - Only one conversation at a time
- No configuration file - All config via environment variables only
- No tests - No test suite exists in the current codebase