Autonomous agent · one interface

One agent.Every tool.

The Hermes SDK turns a full autonomous agent into a single call. Give it a goal in plain language — it writes and runs code, browses the web, reads images, creates files and charts, and hands back clean results with downloadable artifacts. No orchestration to wire up.

01 What it can do // the agent picks the right tool for the job
[ exec ]

Run code

Writes and executes Python & shell, captures output, and returns any files it produces.

[ web ]

Search the web

Searches and reads live pages, then answers grounded in what it found.

[ browser ]

Drive a browser

Controls a real Chromium — navigate, click, fill forms, screenshot.

[ vision ]

See images

Analyzes and describes images you attach, and reasons over their contents.

[ charts ]

Make charts

Turns data into plots via code (matplotlib & co.) — returned as downloadable artifacts.

[ files ]

Work with files

Reads, writes, patches and searches files within an isolated working directory.

[ delegate ]

Delegate

Spawns sub-agents to split large jobs into parallel, focused tasks.

[ memory ]

Remember

Per-user memory + full-text search over past conversations.

[ skills ]

Plan & skills

Task planning for multi-step work, plus any installed skills it can invoke.

02 The interface // public surface only

One class, Hermes. A general run() for any goal, stream() for live agentic UIs, plus capability-shaped shortcuts. Every call returns the same Result.

construct
agent = Hermes(
    model      = None,        # default model; None → server default
    permission = "allow",     # "allow" | "deny" | callable(tool) → decision
    user       = None,        # default identity for memory + isolation
    timeout    = 600,         # seconds per call
    retries    = 2,           # auto-retry transient model errors (safe — no dup side effects)
)
agent.run(prompt, *, user="default", session_id=None, attachments=[], tools=None, model=None, timeout=None, on_event=None) → Result
The core call. Give a goal in plain language; the agent decides which tools to use. attachments adds images/files for it to read, tools restricts which capabilities it may use, session_id continues a prior conversation, and on_event streams the live tool timeline as it works.
agent.stream(prompt, **opts) → Iterator[Event] live
Stream the agent's work for agentic UIs — yields text, thought, tool, tool_update events live, then done (carrying the final Result). astream() is the async version.
agent.check() → dict health
Lightweight readiness probe — confirms Hermes is reachable and the model answers. Never raises; returns a diagnostic. Use it on startup before serving traffic.
agent.ask(prompt, **opts) → Result reason
Pure reasoning — no tools. Fastest and cheapest path for questions and writing.
agent.code(task, **opts) → Result exec
Writes and runs code to accomplish task; returns program output and any files in result.artifacts.
agent.research(query, **opts) → Result web
Searches and reads the live web, then returns an answer grounded in sources.
agent.browse(task, *, start_url=None, **opts) → Result browser
Drives a real browser to complete task — navigation, clicks, forms, screenshots.
agent.see(image, question, **opts) → Result vision
Analyzes an image (path, URL or bytes) and answers question about it.
agent.visualize(data, **opts) → Result charts
Turns data or a description into a chart/plot image (via code).
agent.resume(session_id, prompt, **opts) → Result session
Continues an existing conversation with full prior context.
agent.capabilities() → list[Capability]
Lists the tools this agent has available, so a UI can show or gate them.
All capability methods are shortcuts over run() — same options, same Result. Reach for them when you want intent to be explicit; reach for run() when you just want the goal done.
Memory is keyed by user — each user gets a persistent, isolated store (conversation history, full-text recall, learned facts) that survives across calls, so the agent learns over time. Pass a stable id per real user. Continuing a specific thread via session_id is best-effort today; durable per-user memory is the reliable path.
03 Quickstart // three lines to a working agent
do_anything.py
from hermes_sdk import Hermes

agent = Hermes()
res = agent.run(
    "plot a gaussian histogram"
    " and save it as hist.png",
    user="alice",
)

print(res.text)
# → "Done — 10,000 samples, 50 bins…"

for a in res.artifacts:
    open(a.name, "wb").write(a.bytes())
    # → hist.png  (downloadable)
stream.py — agentic UI
# watch the agent work, live
for ev in agent.stream(
    "research EV sales in 2025, chart them"):
    if ev.kind == "text":
        ui.append(ev.text)      # streaming
    elif ev.kind == "tool":
        ui.step(ev.title)       # web_search…
    elif ev.kind == "done":
        ui.show(ev.result)      # final + files

# vision: attach an image
agent.see("chart.png", "what trend is this?")

# continue the conversation
agent.resume(res.session_id,
    "now use 100 bins")
04 Watch it run // a real agent.visualize(...) call — reasoning, steps, output
visualize.py — captured run
res = agent.visualize("Monthly active users (thousands): Jan 12, Feb 19, Mar 15, Apr 27, May 31, Jun 24. Clean bar chart.") Reasoning
The user wants a bar chart of monthly active users, saved as an image. I'll use Python with matplotlib to create this.
… The chart has been created successfully. Let me show the user the result.
Steps
execute  terminal: python3 — matplotlib (Agg) → monthly_active_users.png
Result
The bar chart has been saved to monthly_active_users.png. It shows Jan–Jun MAU with value labels on each bar, a title and axis labels, and clean styling (no top/right spines).
elapsed 9.19s artifacts 1 stop end_turn
Bar chart of monthly active users, Jan–Jun, produced by agent.visualize()
res.artifacts[0]monthly_active_users.png · 41.9 KB · image/png

Real output, not a mock — captured from agent.visualize(...) against a live Hermes. The PNG above is the file in res.artifacts[0].

05 Return types // what every call gives back
types
Result
   .text         str            # the final answer (clean — no tool noise)
   .artifacts    list[Artifact] # files the agent produced
   .tool_calls   list[ToolCall] # what it did, in order
   .reasoning    str            # its thinking (optional)
   .session_id   str            # pass to resume() to continue
   .stop_reason  str            # end_turn | max_turns | refusal
   .elapsed      float          # seconds
   .usage        Usage          # token counts

Artifact
   .name str   .mime str   .size int   .bytes() → bytes   .url str?

ToolCall
   .tool str   .title str   .status "running" | "done" | "error"

Attachment
   Attachment.image(src)   Attachment.file(path)   Attachment.bytes(data, mime)

Capability
   .id str   .name str   .summary str