Nerve is an ADK ( Agent Development Kit ) with a convenient command line tool designed to be a simple yet powerful platform for creating and executing LLM-based agents using a simple YAML-based syntax.
Nerve requires Python 3.10 or later and PIP. You can install it with:
pip install nerve-adk
To upgrade to the latest version, run:
pip install --upgrade nerve-adk
For a list of options:
nerve -h
To uninstall, run:
pip uninstall nerve-adk
Alternatively, a Docker image is available on Docker Hub. When running the container, if you're using a local inference server such as OLLAMA, you'll likely want it to share the same network as the host. To allow Nerve to reach network endpoints like OLLAMA, use the command below. This ensures the container runs without network isolation and can access the same resources on the network as your host computer.
Additionally, remember to share the tasklet files by mounting a volume when running the container.
docker run -it --network=host -v ./examples:/root/.nerve/agents evilsocket/nerve -h
Nerve agents are simple YAML files that can use a set of built-in tools such as a bash shell, file system primitives and more.
You can start creating an agent with a guided procedure by executing:
nerve create new-agent
During this procedure, you'll be prompted for the following:
- where to save this agent (either as a folder or single yml file).
- the agent system prompt, which is what determines the agent role (the
You are a useful assistant ...
stuff). - the agent task - what does this agent has to do? (
what is 4+3?
) - which tools from the built-in namespaces the agent can use to perform its task.
Tip
You can use a @
prefix for the system prompt as a shortcut to load the prompt from a markdown file in your $HOME/.nerve/prompts
directory. For example, specifying @scientist
as the system prompt will automatically load the prompt from either $HOME/.nerve/prompts/scientist.md
or $HOME/.nerve/prompts/scientist/system.md
.
After completing the procedure, your new-agent/agent.yml
file will look something like this:
agent: You are a helpful assistant.
# jinja2 templating syntax supported
task: Make an HTTP request to {{ url }}
using:
- shell # can execute shell commands
- task # can autonomously set the task as complete or failed
To run this agent (the --url
is required because we referenced it in the agent task
):
# equivalent to "nerve run new-agent/agent.yml"
nerve run new-agent --url 'cnn.com'
For a list of all the subcommands and their options, feel free to explore nerve -h
.
Tip
Nerve primarily loads agents from $HOME/.nerve/agents
, ensuring that any agent in this folder is accessible regardless of your current working directory. If the agent is not found there, Nerve will then search in the current working directory as a fallback.
The default model is OpenAI gpt-4o-mini
, in order to use a different model you can either set the NERVE_GENERATOR
environment variable, or pass it as a generator string via the -g/--generator
command line argument.
Note
Nerve supports any of the LiteLLM supported providers, check the litellm documentation for a list of all the providers and their syntax.
export ANTHROPIC_API_KEY=sk-ant-api...
export NERVE_GENERATOR=anthropic/claude-3-7-sonnet-20250219
nerve run new-agent --url 'cnn.com'
is equivalent to:
nerve run -g "anthropic/claude-3-7-sonnet-20250219" new-agent --url 'cnn.com'
To pass additional inference parameters:
nerve run -g "ollama/llama3.2?temperature=0.9&api_base=http://server-host:11434" new-agent --url 'cnn.com'
Nerve sessions can be recorded to a JSONL file by specifying the --trace
argument:
nerve run new-agent --trace agent-trace.jsonl
The session can then be replayed at any time:
nerve play agent-trace.jsonl # this plays the session at the original speed
Add -f
to replay in fast forward mode:
nerve play agent-trace.jsonl -f # much faster
When a tool can be represented as a shell command, you can conveniently extend the agent capabilites in the YAML:
agent: You are a helpful assistant.
task: What's the weather in {{ city }}?
tools:
# this adds the get_weather tool
- name: get_weather
# it's important to let the agent know what the tool purpose is.
description: Get the current weather in a given place.
arguments:
# named arguments with descriptions and examples
- name: place
description: The place to get the weather of.
example: Rome
# arguments will be interpolated by name and automatically quoted for shell use
tool: curl wttr.in/{{ place }}
If the tool requires more advanced capabilities, you can implement it in Python, by adding a tools.py
file in the same folder of the agent with annotated functions:
# new-agent/tools.py
import typing as t
# This annotated function will be available as a tool to the agent.
def read_webcam_image(foo: t.Annotated[str, "Describe arguments to the model like this."]) -> dict[str, str]:
"""Reads an image from the webcam."""
# a tool can return a simple scalar value, or a dictionary for models with vision.
base64_image = '...'
return {
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
}
An agent will continue running in a loop execute tools at each step until one of the following conditions is met:
- The task status has been set as complete (either by the agent itself if using the
task
namespace, or by one of the tools if itscomplete_task
field istrue
). - The task status has been set as failed (by the agent itself if using the
task
namespace) - The task times out.
During this loop the chat history the model has access to is defined by the conversation window, default to full
, determined by the --conversation/c
argument.
Full conversation window (the default behaviour, the model receives the entire conversation history):
nerve run agent -c full
Only receive the last N messages (with N=5 in this example):
nerve run agent -c 5