← all projects

HexCode: terminal AI coding agent

ADR-005 · TypeScript · Bun · React 19 · Hono · Prisma · Postgres · agents

The problem

To be useful, an AI coding assistant in the terminal has to read your code, edit files and run shell commands. The simple design is to send the repo to the server and let the server run the tools. But then every user's private code and shell access go through a third party. For most teams, that is a deal breaker.

The second problem is trusting the agent. A "plan mode" that just asks the model not to edit files is not real safety. It is only a request, and models don't always follow requests.

Decision 1: the server defines tools, the client runs them

The server only defines the tool contracts: names, JSON schemas and descriptions. It has no tool code. The CLI gets the contract, runs the tool locally on the file system, and sends back only the result the model needs.

The main benefit: your code and shell access never leave your machine. The server only sees the tool results that your own client decided to send, not the repo.

This also changes the agent loop. Since tools run on the client, the CLI keeps the loop going locally (call a tool, send the result back, continue) instead of going back to the server for every step. This means fewer network calls, lower latency, and the server stays a stateless proxy to the model.

Tools can only access the project folder. Any path that tries to go outside the working directory is rejected in code, not just by convention.

Decision 2: permission modes through the tool list

Plan and Build modes don't work by giving the model instructions. They work by changing which tools exist.

In Plan mode the model only gets read-only tools: read, search and list. The write, edit and shell tools are not in the schema at all. The model cannot edit a file for the same reason it cannot send an email: there is no tool for it.

This is the difference between a rule and a guarantee. Prompt rules get weaker with long context and tricky input. A tool list without a write tool stays safe no matter what.

Decision 3: billing is really accounting

Token billing looks simple but is easy to get wrong, because it is basically bookkeeping. The rules I use:

Login uses Clerk OAuth with PKCE. Sessions and the full tool-call history are saved in Postgres through Prisma, which also works as an audit log of what the agent did.

Stack

TypeScript · Bun · React 19 · OpenTUI · Hono · Vercel AI SDK · Anthropic & OpenAI · Prisma · Postgres · Clerk · Polar · Zod

What I'd do differently

The tool schema and the client code are versioned together, but only implicitly. An old CLI talking to a newer server is a problem I handle with defensive checks, not with a proper design. The right fix is a version check at the start of each session where client and server agree on what they support.