Small console agent boilerplate with a REPL loop. It loads a base prompt, sends messages to OpenRouter, and exposes a limited set of safe tools (file reading, patching, searching, command execution with confirmation, and website visits).
This is an educational project and a free-to-use boilerplate to build console agents.
WARNING: The agent can access the system through tools, so be very careful with the requests you make. Avoid asking for sensitive or destructive actions without reviewing them first.
Consider using COMMAND_MODE, which is not automatic and is configured in .env:
COMMAND_MODE=confirm(default) asks for confirmation before each command.COMMAND_MODE=autoruns allowed commands without per-command confirmation.
This mode only changes the confirmation step; it does not remove the restrictions enforced by .paths and .whitelist.
- TypeScript CLI with an interactive REPL.
- Loads
prompt.txton startup. - Configuration via
.env. - Allowlist-based file and command access.
- Console output with readable formatting.
- Node.js 18+
- npm
npm install
npx playwright install
- Copy
.env.exampleto.env. - Fill in:
OPENROUTER_API_KEYOPENROUTER_BASE_URLOPENROUTER_MODEL
npm run agent
src/cli.tsstarts the REPL.src/agent/agent.tsruns the core loop and tool execution.src/tools/contains the tools exposed to the model.prompt.txtis the base prompt..pathsdefines allowed file access..whitelistdefines allowed command prefixes..memoryis an optional notes file (not versioned).
exec_command only allows prefixes listed in .whitelist and either asks for confirmation (confirm) or runs automatically (auto).
File access follows .paths.
.paths defines which paths are allowed or denied for read/write access. By default, sensitive system folders are blocked, and only paths permitted by these rules are accessible.
.whitelist defines the command prefixes that exec_command is allowed to run. If a command does not match an allowed prefix, it is rejected even if the user requests it.
Think of the agent as a loop that alternates between "thinking" and "doing". The model does not directly access your files or run commands. It asks for tools, and your agent executes them safely.
┌──────────────┐
│ User message │
└──────┬───────┘
│
v
┌───────────────────────────┐
│ System prompt + tool list │
└──────────┬────────────────┘
│
v
┌───────────────────────────┐
│ LLM: answer or tool call? │
└───────┬───────────┬───────┘
│ │
│ answer │ tool call
v v
┌─────────┐ ┌─────────────────┐
│ Reply │ │ Run tool safely │
└────┬────┘ └────────┬────────┘
│ │
│ v
│ ┌──────────────────┐
└----> │ Tool result to LLM│
└─────────┬────────┘
v
┌─────────┐
│ Reply │
└─────────┘
- The user types a message in the REPL.
- The agent sends: system prompt + conversation + tool schema.
- The model can respond with a tool call (name + JSON args).
- The agent validates the request, enforces allowlists, and runs the tool.
- The tool output is appended to the conversation.
- The model uses that output to answer or request another tool.
- Tools are explicit and limited in scope.
- File access is restricted by
.paths. - Command execution is restricted by
.whitelistand always asks for confirmation.
[User] -> [REPL] -> [OpenRouter]
-> tool call? ----- yes ---> [Run tool] -> [Result] -> [Answer]
\--- no ----> [Answer]