Skip to content

Tools

Tools are the agent’s hands. The model can think and write text, but tools let it inspect the repo, run commands, and change files.

A model cannot directly read your filesystem or run tests. Without tools, it has to guess. With tools, it can inspect reality before acting.

The danger is that tools have side effects. A shell command or file write can change the machine, so tools must be small, inspectable, and permissioned.

Neo exposes a small built-in tool surface:

  • read_file: read files.
  • grep: search file contents and return structured JSON matches.
  • glob: find files by pattern and return structured JSON paths.
  • bash: run shell commands.
  • write_file: overwrite or create files.
  • edit_file: replace one exact string.

Each tool implements the same interface:

type Tool interface {
Name() string
Spec() llm.ToolSpec
Run(ctx context.Context, input map[string]any) (string, error)
}

The model sees tool specs. Neo runs the tool and feeds the result back into the conversation.

Small tools are easier to trust and easier to teach. For example, edit_file replaces exactly one occurrence. If the target text is missing or appears more than once, it fails instead of guessing.

That makes failures useful: the model can inspect again and try a safer edit.

  1. Add a type in internal/tools.
  2. Implement Name, Spec, and Run.
  3. Register it in cmd/neo/main.go.
  4. Add tests for success, bad input, and edge cases.
  5. Update docs/developer/tools.md and this guide.
  • Treat errors as data. Return useful output when a tool fails.
  • Keep file tools inside the workspace boundary.
  • Prefer structured tools over shell commands for common operations.
  • Do not make one giant tool that does everything.
  • internal/tools/tool.go: tool interface and registry.
  • internal/tools/fs.go: file tools.
  • internal/tools/search.go: grep and glob.
  • internal/tools/bash.go: shell execution.