Bun · TypeScript · 25+ providers

A coding agent that
lives in your terminal.

NightCode reads your codebase with real tools, edits files, runs your tests, and answers — streaming every step as it happens. It asks before it does anything destructive, and it remembers what it learned last time.

Get started View source
25+providers
15built-in tools
3memory kinds
14self-checks
bun run dev:cli
NightCode v1.0.0
Ask anything…
Ready ·groq/qwen3.6-27b ·~/nightCode ·session 1
What you get

A full ReAct agent,
not a chat box

Every turn is context → model → tools → result, looped up to ten times until there is a real answer. You watch the whole thing happen.

Real tool use

15 tools built in. The model sees a lean 9: read, write, edit, bash, grep, find, ls, todoWrite, spawn_subagent — a small surface keeps the context clean.

Asks before it breaks things

Destructive tools — write, delete, rename, risky bash — pause on a confirmation dialog. Nothing runs until you press y.

Streams as it thinks

Answers type out live as the model generates them, and reasoning streams into a dimmed panel beside the work — no staring at a spinner wondering if it hung.

Remembers across sessions

Durable facts, learned rules, and notable events are extracted after each turn and injected into the next session's prompt. Stored in your repo, never in a cloud.

Stops when you say stop

Esc ends a run between steps, keeps the history valid, and kills the child process tree. The session stays usable for the next prompt.

Delegates to subagents

spawn_subagent hands a scoped sub-task to a fresh session with restricted tools and no memory writes — so a side quest can't pollute the main thread.

Quick start

Running in three commands

NightCode runs on Bun. Bring your own key for any provider you like — the default is Groq.

Clone and install

A Bun workspace — one install covers the whole monorepo.

# clone
git clone https://github.com/Nirvanjha2004/nightCode.git
cd nightCode

# install (bun workspace)
bun install

Add a key

Copy the template and fill in whichever provider you use. Bun auto-loads .env from the repo root — keys are never hardcoded.

cp .env.example .env

# then edit .env — one key is enough to boot
GROQ_API_KEY=gsk_…

# optional: pick a different provider + model
NIGHTCODE_PROVIDER=anthropic
NIGHTCODE_MODEL=claude-sonnet-4-5

Run it

That's the whole setup. The UI boots into a fresh session in your current directory.

bun run dev:cli
No key at all?

Local models need none. NIGHTCODE_PROVIDER=ollama NIGHTCODE_MODEL=llama3.3 bun run dev:cli talks to http://localhost:11434. Same for llama.cpp, LM Studio and vLLM.

How it works

What happens when
you hit enter

One turn, start to finish. Every stage emits an event, and every event is something you can see on screen.

input
slash command resolved, raw text stored
memory
facts, rules and past events built into the prompt
context
~700-token prompt + a 9-tool surface
model
streamed — text and reasoning arrive as deltas
tools
run, with a confirmation gate on destructive ones
answer
final text stored, memory extracted in the background
steps 3–5 loop up to 10 times per turn, until the model stops calling tools

Context stays bounded

Around 100k estimated tokens, older messages are summarized by the model itself — chainable across compressions, always keeping the last 15 messages intact.

Failures come back as results

A failing shell command returns its stdout, stderr and exit code as a result, not an exception — so the agent can read the error and recover on the next step.

Memory is guarded

The memory/ tree is off-limits to every agent tool. Read, write, edit, delete and grep are all blocked against it.

Usage

Driving the thing

Everything is one keystroke away. There is no mouse mode and no menus you have to hunt for.

Keys

EnterSend the prompt
Shift EnterNewline instead of sending
EscCancel the active run — the session survives
Ctrl CCancel; a second press within 2s exits
Ctrl MOpen the provider / model selector
y nApprove or skip a destructive action
/Slash-command autocomplete

Slash commands

/clearFresh session — history and summary reset; files and memory untouched
/commitStage everything and write a conventional commit message
/reviewRead-only review of the uncommitted diff
/explainTrace a file or function and explain it in plain language
/fix-issueLocate a described bug, fix it minimally, verify with tests

Add your own: drop a markdown file in commands/ with optional description / argument-hint frontmatter. $ARGUMENTS is replaced with whatever you typed after the command.

Files it creates

All gitignored, created on first run, and always anchored to the repo root — never to whatever directory you launched from.

PathContents
memory/semantic.jsonDurable facts about you, the project and the environment
memory/procedural.mdLearned rules — "always do X before Y"
memory/episodic/events.jsonlNotable past events with embeddings, retrieved by similarity
logs/combined.logWinston JSON, all levels, 5 MB × 5 rotated
logs/error.logWarnings and above only
Providers

Bring your own model

One internal interface, per-provider adapters. Hosted or local, frontier or cheap — switch at boot with an env var, or mid-session with Ctrl M.

groq · default openaianthropicgoogle deepseekmistralxai cerebrastogetherfireworks openrouternvidiahuggingface zaiminimaxkimi opencode-zenopencode-go vercel-gatewaycloudflare-gatewaycloudflare-workers azurevertexbedrock ollama · localllama-cpp · local lmstudio · localvllm · local custom

One transport, many providers

Every OpenAI-compatible provider shares a single transport configured with a base URL, key and catalog. Anthropic, Gemini, Azure, Vertex and Bedrock get dedicated adapters.

Normalized everything

Streams, errors and usage are normalized before the loop sees them, so the agent never learns a provider's quirks.

New provider, no code

Add a providers entry to nightcode.config.json and it registers at boot. Source changes are only needed for a genuinely new wire format.

Configuration

Two files, both optional

Environment variables win over the config file, which wins over the built-in defaults.

.env — keys and selection

# provider + model (optional)
NIGHTCODE_PROVIDER=groq
NIGHTCODE_MODEL=qwen/qwen3.6-27b

# whichever keys you actually use
GROQ_API_KEY=
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GOOGLE_API_KEY=
DEEPSEEK_API_KEY=

# local endpoints need no key
OLLAMA_BASE_URL=http://localhost:11434/v1

nightcode.config.json — the rest

{
  "provider": "deepseek",
  "model": "deepseek-chat",
  "reasoning": "off",
  "providers": {
    "my-provider": {
      "api": "openai-compatible",
      "baseUrl": "https://api.example.com/v1",
      "apiKeyEnv": "MY_PROVIDER_KEY",
      "models": [
        { "id": "my-model", "contextWindow": 131072 }
      ]
    }
  }
}
Keep keys in .env, not in the config file.

reasoning accepts off · low · medium · high · max, and is the one setting with no environment override. Full reference lives in docs/providers.md.

Status

What it doesn't do yet

NightCode is a personal project, and the README keeps an honest scorecard against Pi. The short version:

Solid today

Provider-neutral LLM layer across 25+ providers · live streaming of answers and reasoning · automatic three-part memory · destructive-action confirmation · cancellation that actually kills child processes · 14 assertion-based self-checks.

Not there yet

Sessions live in memory and are lost on exit · no session tree or branching · no extension system — you fork the code · interactive TUI only, so there is no print/JSON mode to benchmark against · memory is injected wholesale rather than on demand.