Skip to content
nerva docs v0.2.1

Quick Start — Python

Build a fully wired agent with routing, tools, and memory — then run it locally in under five minutes.

  1. Install Nerva

    Terminal window
    pip install otomus-nerva

    Requires Python 3.11+.

  2. Scaffold a project

    Terminal window
    npx nerva new my-agent --lang python
    cd my-agent

    This creates a project with main.py, nerva.yaml, and a sample handler.

  3. Build a weather agent

    Create main.py:

    import asyncio
    from nerva import Orchestrator, ExecContext
    from nerva.router import RuleRouter, Rule
    from nerva.runtime.inprocess import InProcessRuntime
    from nerva.tools import FunctionToolManager
    from nerva.memory import TieredMemory
    from nerva.memory.hot import InMemoryHotMemory
    from nerva.responder import PassthroughResponder
    from nerva.registry import InMemoryRegistry
    from nerva.policy import NoopPolicyEngine
    # -- Tools -------------------------------------------------------------------
    tools = FunctionToolManager()
    @tools.tool("get_weather", "Get current weather for a city")
    async def get_weather(city: str) -> str:
    # Replace with a real API call
    return f"22°C and sunny in {city}"
    # -- Handler -----------------------------------------------------------------
    async def weather_handler(input, ctx):
    result = await tools.call("get_weather", {"city": "Berlin"}, ctx)
    return result.output
    # -- Runtime -----------------------------------------------------------------
    runtime = InProcessRuntime()
    runtime.register("weather_agent", weather_handler)
    # -- Orchestrator ------------------------------------------------------------
    orchestrator = Orchestrator(
    router=RuleRouter(
    rules=[
    Rule(pattern=r"weather", handler="weather_agent", intent="weather"),
    ],
    default_handler="weather_agent",
    ),
    runtime=runtime,
    tools=tools,
    memory=TieredMemory(hot=InMemoryHotMemory()),
    responder=PassthroughResponder(),
    registry=InMemoryRegistry(),
    policy=NoopPolicyEngine(),
    )
    # -- Run ---------------------------------------------------------------------
    async def main():
    ctx = ExecContext.create(user_id="user_1")
    result = await orchestrator.handle("What's the weather in Berlin?", ctx)
    print(result.text)
    asyncio.run(main())
  4. Run it

    Terminal window
    python main.py
    # Output: 22°C and sunny in Berlin

Trace output

Every request produces a structured trace so you can see exactly what happened:

[req_abc] handle "What's the weather in Berlin?" (52ms)
+-- [req_abc.1] router.classify (1ms)
| +-- intent=weather, handler=weather_agent, confidence=1.0
+-- [req_abc.2] runtime.invoke weather_agent (48ms)
| +-- [req_abc.2.1] tools.call get_weather (45ms)
+-- [req_abc.3] responder.format (1ms)

Next steps

  • Add more agents — register additional handlers and routing rules
  • Use memory — pass InMemoryHotMemory to persist conversation across turns
  • Add middleware — inject logging, auth, or rate limiting into the pipeline
  • Switch routers — swap RuleRouter for EmbeddingRouter when you have 10+ agents
  • Read the Primitives Overview to learn what each piece does