Tools
The six built-in tools that make up the whole agent — plus how to add your own typed tools.
harnext keeps an intentionally tiny tool surface. These six tools are the entire executor; everything the agent does, it does through them.
Built-in tools
| Tool | Does | Side effects |
|---|---|---|
read | Read a file (or a slice of one) under cwd. | None |
write | Create or overwrite a file. | Filesystem |
edit | Apply a targeted find/replace edit to a file. | Filesystem |
bash | Run a shell command in cwd. | Shell |
skill | Invoke a loaded skill by name. | Varies |
mcp | Call a tool exposed by a connected MCP server. | Varies |
Selecting tools
Pass the tools option to enable a subset. A read-only agent, for example, omits write, edit, and bash:
reader = Harnext(provider="anthropic", tools=["read"])
reader.run("Explain what src/auth.py does")Custom tools
Give the agent new capabilities by wrapping a function as a tool. The SDK derives the schema from your type hints (Python) or a Zod/JSON schema (TypeScript), and the agent can call it like any built-in.
from harnext import Harnext, tool
@tool(description="Look up a customer by id")
def get_customer(id: str) -> dict:
"""Returns the customer record, or None if not found."""
return db.customers.get(id)
@tool(description="Charge a customer in cents")
def charge(customer_id: str, amount_cents: int) -> dict:
return billing.charge(customer_id, amount_cents)
agent = Harnext(
provider="anthropic",
tools=["read", "edit", get_customer, charge],
)
agent.run("Refund the most recent charge for customer c_123")typing.Annotated to add per-argument descriptions. In TypeScript, the parameters schema is the single source of truth and fully types the execute argument.Returning rich results
A tool can return a string, a JSON-serializable object, or a structured ToolResult to control what the model sees and mark success or failure.
from harnext import tool, ToolResult
@tool(description="Run the test suite")
def run_tests(path: str = ".") -> ToolResult:
proc = subprocess.run(["pytest", path], capture_output=True, text=True)
return ToolResult(
output=proc.stdout,
is_error=proc.returncode != 0,
)Approving tool calls
Custom tools respect the client's permission mode. In manual mode, your on_permission callback receives the tool name and arguments before the call runs, so you can gate destructive operations.
manual permission mode for anything that moves money, data, or infrastructure.