DevNews

NVIDIA's NOOA Makes an AI Agent a Single Python Class

On this page
  1. One class, and the rules that fall out of it
  2. Why the boring choice is the interesting one
  3. What we would do with it
  4. Sources and further reading

NVIDIA released NOOA on August 7, an Apache 2.0 Python framework whose entire premise is that an AI agent should be one ordinary class. Methods are the actions the model can take, fields hold state, docstrings become the prompts, and type annotations act as contracts. A method whose body is literally three dots gets completed at runtime by a model, while a method with real code stays deterministic Python. The point is not novelty. It is that agents built this way can be diffed, unit tested, refactored and reviewed with the tooling you already own, instead of living in YAML graphs and prompt templates nobody can grep.

The short answer

NOOA is NVIDIA's Object-Oriented Agents framework, published August 7 under Apache 2.0. An agent is a single Python class. Fields are its state, methods are the actions it can take, docstrings are the prompts, and type annotations are enforced contracts on what comes back. A method whose body is three dots gets filled in at runtime by a model driven loop, and a method with real code stays deterministic. Model calls and code execution are traced by default. It is model agnostic through LiteLLM, so nothing here requires NVIDIA silicon or NVIDIA models.

Apache 2.0licence, source at github.com/NVIDIA-NeMo/labs-OO-Agents
82.2%SWE-bench Verified score NVIDIA reports for the harness
LiteLLMrouting layer, so Claude, GPT, Ollama and vLLM all work
Answer card: NVIDIA released NOOA on August 7 2026 under Apache 2.0, a model agnostic Python framework where an AI agent is a single Python class, methods are actions, docstrings are prompts, type annotations are contracts, and a method body of three dots is filled in at runtime by the model.
The whole idea in one card. Source: the NOOA repository and NVIDIA's announcement, August 2026. PNG

Ask anyone who has maintained an agent for six months what went wrong, and the answer is rarely the model. It is that the thing became unreviewable. The prompt lives in a template file, the tool definitions live in a JSON schema, the control flow lives in a graph builder, and the only way to find out what a change does is to run it and watch. NOOA is NVIDIA's argument that this is a self inflicted problem, and that the fix is to stop inventing a parallel universe of agent abstractions.

One class, and the rules that fall out of it

The framework collapses everything into a Python class definition. Here is the shape, taken from the project's own example:

from nooa import Agent

class SupportAgent(Agent):
    """You are a support agent."""

    order_db: OrderDB

    def is_refund_eligible(self, order: Order) -> bool:
        return order.delivered and order.days_since_delivery <= 30

    async def triage(self, message: str, order: Order) -> Ticket:
        """Create a typed support ticket."""
        ...

Four conventions do the work. The class docstring is the system prompt. Annotated fields such as order_db are the agent's state, injected and available to anything the agent runs. is_refund_eligible has a real body, so it is ordinary Python that executes the same way every time and can be unit tested with no model in the loop at all. triage has a body of three dots, which is the signal that the model implements it, guided by the signature, the docstring and the annotated Ticket return type.

That last point is the one worth dwelling on. The return annotation is not documentation, it is the contract the output has to satisfy. Structured output has been the fiddly part of agent work for two years, usually solved with a schema defined somewhere away from the function that needs it. Putting it in the signature means the contract and the call site cannot drift apart, because they are the same line.

Generated code executes in a REPL style context with access to the object, so the model can call is_refund_eligible rather than trying to reason about refund windows itself. Every model call and every execution is traced by default.

Checklist card mapping NOOA conventions: class docstring becomes the system prompt, annotated fields become agent state, a method with a real body stays deterministic Python, a method body of three dots is generated by the model at runtime, the return type annotation is an enforced contract, and every model call plus code execution is traced by default.
Six conventions, and no configuration format to learn. PNG

Why the boring choice is the interesting one

The practical claim is that an agent expressed as a class inherits everything Python already has. pytest can exercise the deterministic methods directly. A type checker sees the contracts. git blame points at a docstring when behaviour changes, which is the first time in this field that a prompt edit shows up in review as a normal diff. Refactoring tools work because there is nothing to refactor except code.

Compare that with the graph shaped alternative, where the agent is assembled from nodes and edges and the prompts sit in templates. Graphs earn their keep when control flow genuinely is the hard part and you want to see it laid out. But a large share of production agents are not that. They are one prompt, three tools and a retry, wrapped in enough framework to make a two hundred line problem into a four file one.

There is a real trade here and it is worth naming rather than glossing. Class inheritance is a clumsy way to express branching multi step workflows, and if your agent really is a state machine, drawing it as one is not a mistake. NOOA does not solve that case. What it does solve is the much more common case where the framework is heavier than the agent.

What we would do with it

The evaluation is cheap, which is the strongest argument for spending an hour on it:

uv init my-agent-project && cd my-agent-project && uv add nooa

Point it at whatever model you already pay for through LiteLLM, then port one small agent you currently maintain and see what the diff looks like. The test is not whether it runs, because it will. It is whether the resulting file is something a colleague could read in five minutes and correctly predict the behaviour of. That is the property this framework is selling, and it is the only one worth measuring.

Two cautions before anyone rewrites a fleet. The project is new, published the same week as its paper, so the API surface should be assumed unstable. And the code execution model deserves the review you would give any plugin host: keep the object's reachable surface small, put irreversible operations behind deterministic methods with real bodies, and read the traces. The tracing being on by default is genuinely the right call here, because the failure mode of agent frameworks is not usually a crash. It is nobody being able to explain what happened.

Sources and further reading

Frequently asked questions

What actually happens when a method body is just three dots?

That ellipsis is the marker NOOA uses to say this method is implemented by the model rather than by you. At runtime the framework reads the method signature, its type annotations and its docstring, hands that to an agent loop, and the loop produces Python that runs in a REPL style execution context with access to the object's own state and its other methods. The return value is checked against the annotated return type, which is the part that matters: a method declared to return a Ticket has to produce something shaped like a Ticket, not a paragraph of prose you then parse with a regex. Methods with normal bodies are untouched and run as plain Python. In practice that means one class can hold both the deterministic logic you refuse to let a model near, such as refund eligibility rules, and the fuzzy parts you want it to handle, such as reading a customer message. The boundary between the two is a method body, which is about as legible a boundary as you can ask for.

Is this tied to NVIDIA hardware or NVIDIA models?

No, and that is worth stating plainly because the name suggests otherwise. NOOA is model agnostic and routes through LiteLLM, so the documented backends include Claude from Anthropic, GPT from OpenAI, Ollama for local models and vLLM for self hosted serving. Nothing in the programming model assumes a GPU vendor. Install is `pip install nooa` or `uv add nooa` and the source is Apache 2.0 at github.com/NVIDIA-NeMo/labs-OO-Agents, with optional extras for the CLI, memory and benchmark harness. NVIDIA is also contributing the project to the Open Secure AI Alliance, the industry group it convened for shared open tooling, which at least signals that it is not meant to stay an NVIDIA house framework. Whether it stays vendor neutral in practice is a question for the commit log in a year, not for the licence file today.

How does this compare with the graph based agent frameworks people already use?

The difference is where the structure lives. In a graph framework, the agent is data: nodes, edges, a state object threaded through, plus prompt templates and tool schemas kept somewhere else. That is genuinely useful when the control flow is the interesting part and you want to visualise it. The cost is that your agent stops being code, so your normal instincts stop working. You cannot set a breakpoint in a YAML edge, a rename is a find and replace across three file formats, and the review diff shows a template change without showing what it does. NOOA's bet is that most agents are not complicated enough to justify that, and that expressing them as a class buys back the entire Python toolchain: pytest, mypy, git blame, an IDE that can jump to definition. The honest counterpoint is that a class hierarchy is a worse fit than a graph when you truly do have branching multi step workflows, and nothing here makes that case disappear.

How reliable are the benchmark numbers NVIDIA published?

Take them as a claim of competence, not a ranking. NVIDIA reports 82.2 percent on SWE-bench Verified and a mean RHAE of 85.1 percent on ARC-AGI-3, with the accompanying paper on arXiv as 2607.20709 also covering Terminal-Bench 2.0. Those are respectable figures for a harness. The catch with every agent benchmark result is that the harness and the underlying model are entangled, so a number tells you what one framework achieved with one model at one moment, and swapping either moves it. SWE-bench Verified in particular has a long history of results that do not transfer to unfamiliar repositories, because the tasks come from popular open source projects the models have seen. If you are evaluating NOOA, the number that should decide it is the one you measure on your own tasks with your own model, and the framework being ordinary Python makes that measurement unusually cheap to set up.

What is the catch with letting a model generate code that runs against your object state?

It is the same catch as any code execution loop, made more visible rather than worse. NOOA runs model generated Python in a REPL style context that can reach the agent's fields and methods, which is exactly what makes it powerful: the model can call your deterministic helpers instead of reimplementing them badly. It also means the blast radius of a generated statement is whatever that object can touch, so a class holding a live database handle is a class whose handle the loop can use. The framework's answer is built in tracing, with every model call and every code execution logged, so the record of what ran exists by default rather than being something you remember to add. Our reading is that this is a design you review the way you review a plugin system: keep the object's surface small, put the irreversible operations behind deterministic methods with real bodies, and read the traces before you widen anything.