Skip to content

Hermes

Image updates

Ready-made agent images are updated every morning with the current CLI version. To keep a fixed image version, pin a template version.

Hermes is an AI agent with terminal and filesystem tools, skills, and persistent context. Use the ready-made hermes template to run it from your application. Agent commands execute inside the AgentBox sandbox.

Connect

Install the AgentBox SDK and set AGENTBOX_API_KEY.

The examples use OpenRouter. Pass OPENROUTER_API_KEY to the agent process. --provider openrouter and --model qwen/qwen3-coder-next select the provider and model.

For model access, you can use the AgentBox HTTPS proxy https://sandbox-proxy.agentbox.ru:65181.

The examples pass HTTPS_PROXY, HTTP_PROXY, and NO_PROXY to the agent process. These settings may also affect other requests made by the agent and its child processes. Connections to localhost and 127.0.0.1 remain direct.

Draft replies to enquiries

The example uploads a CSV of company enquiries. Hermes reads it and saves reply drafts to follow-up.md. The application reads the file through the SDK.

mjs
import { Sandbox } from "@abox-dev/sdk";

const apiKey = process.env.OPENROUTER_API_KEY;
if (!apiKey) throw new Error("OPENROUTER_API_KEY is required");
const proxy =
  process.env.SANDBOX_PROXY_URL ?? "https://sandbox-proxy.agentbox.ru:65181";
const sandbox = await Sandbox.create("hermes", { timeoutMs: 600_000 });
try {
  await sandbox.files.makeDir("/home/user/work");
  await sandbox.files.write(
    "/home/user/work/leads.csv",
    `company,request
Acme,Needs a quote for 20 office chairs
Northwind,Asks for delivery options for 8 desks
`,
  );
  await sandbox.files.write(
    "/home/user/work/task.txt",
    "Read leads.csv and write follow-up.md with a short draft response for each company. Use only the details in the file.",
  );
  const result = await sandbox.commands.run(
    "hermes chat -Q --yolo --provider openrouter --model qwen/qwen3-coder-next --query-file task.txt",
    {
      cwd: "/home/user/work",
      timeoutMs: 300_000,
      envs: {
        OPENROUTER_API_KEY: apiKey,
        HTTPS_PROXY: proxy,
        HTTP_PROXY: proxy,
        NO_PROXY: "localhost,127.0.0.1",
      },
      onStderr: (chunk) => process.stderr.write(chunk),
    },
  );
  console.log(result.stdout);
  console.log(
    "follow-up.md\n" +
      (await sandbox.files.read("/home/user/work/follow-up.md")),
  );
} finally {
  await sandbox.kill();
}

--query-file task.txt reads the task from a file, so its text does not need to be embedded in a shell command. -Q writes the final answer to stdout and the session ID to stderr. --yolo disables tool approval prompts. Hermes uses the local environment inside the sandbox, with no separate terminal backend to configure.

The example reads the result before killing the sandbox. finally also releases it on error. The Go example uses a separate context for cleanup.

Output and session continuation

After the first response, the example reads the session ID from the session_id: line on stderr. It then starts a new process with --resume, supplies an enquiry update, and reads the updated file.

mjs
import { Sandbox } from "@abox-dev/sdk";

const apiKey = process.env.OPENROUTER_API_KEY;
if (!apiKey) throw new Error("OPENROUTER_API_KEY is required");
const proxy =
  process.env.SANDBOX_PROXY_URL ?? "https://sandbox-proxy.agentbox.ru:65181";
const sandbox = await Sandbox.create("hermes", { timeoutMs: 600_000 });
try {
  await sandbox.files.makeDir("/home/user/work");
  await sandbox.files.write(
    "/home/user/work/leads.csv",
    `company,request
Acme,Needs a quote for 20 office chairs
Northwind,Asks for delivery options for 8 desks
`,
  );
  async function execute(prompt, sessionId) {
    await sandbox.files.write("/home/user/work/task.txt", prompt);
    const result = await sandbox.commands.run(
      "hermes chat -Q --yolo --provider openrouter --model qwen/qwen3-coder-next --query-file task.txt" +
        (sessionId ? ' --resume "$AGENT_SESSION_ID"' : ""),
      {
        cwd: "/home/user/work",
        timeoutMs: 300_000,
        envs: {
          OPENROUTER_API_KEY: apiKey,
          HTTPS_PROXY: proxy,
          HTTP_PROXY: proxy,
          NO_PROXY: "localhost,127.0.0.1",
          AGENT_SESSION_ID: sessionId ?? "",
        },
        onStdout: (chunk) => process.stdout.write(chunk),
        onStderr: (chunk) => process.stderr.write(chunk),
      },
    );
    const nextSessionId = /^session_id: (\S+)$/m.exec(result.stderr)?.[1];
    if (!nextSessionId) throw new Error("Agent did not return a session ID");
    console.log("\nSession:", nextSessionId);
    return nextSessionId;
  }
  const sessionId = await execute(
    "Read leads.csv and write follow-up.md with a short draft response for each company. Use only the details in the file.",
  );
  await execute(
    "Acme confirmed a preference for blue chairs. Update its draft in follow-up.md with this detail.",
    sessionId,
  );
  console.log(
    "follow-up.md\n" +
      (await sandbox.files.read("/home/user/work/follow-up.md")),
  );
} finally {
  await sandbox.kill();
}

The stdout and stderr callbacks forward output as it arrives. With -Q, the answer is printed after the task finishes. This is not a stream of model tokens.

Session history and files are stored in the sandbox. For another call, keep it and the session ID, or pause it. The full protocol and CLI options are described in the Hermes documentation.