Model or dataset
meetopenbot/openbot avatar
meetopenbot/openbot

OpenBot keeps agents in Markdown files and events on port 4132

Meet OpenBot. OS for Agents

342 stars4 forksTypeScriptMIT

At a glance

What is it?
A local-first TypeScript harness for AI agents: three HTTP routes, file-backed channels and threads, and two built-in agents that split model work from deterministic reads. The licence stops at v0.5.3.
Who is it for?
OpenBot fits one operator on one workstation who wants agents defined as files and events flowing over a local port, and it earns its keep when reading state has to avoid model calls. It does not fit a shared deployment, and the licence note means work newer than v0.5.3 lives outside this repository.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 87 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A local server on port 4132 and a directory called ~/.openbot

OpenBot is a local-first harness for running AI agents: a small event API, file-backed storage, and a runtime the project credits to Melony. The repository tagline calls it an OS for agents, while the published description is narrower and more useful, a Node process you start on your own machine and talk to over HTTP.

Everything it persists lives under `~/.openbot`: channels, threads, agents, plugins and config. Channels and threads are the two addressing levels the API exposes, and an agent is a Markdown file in that tree rather than a record in a database. No hosted component and no account appear in the documented workflow. Node.js `>=20.12.0` is the only stated requirement, and `package.json` repeats it under `engines`, so an older runtime fails at install time rather than at the first request.

The default listen port is `4132`. The README names it as a default and does not document the key that changes it, so treat a collision with something else on the machine as a hard stop rather than an outside configuration problem.

system runs the model, state reads storage without one

Two agents ship in the box, and the split between them is the design decision worth understanding. `system` is the LLM runtime with storage tools, and it is what `POST /api/publish` reaches when a request names no agent. `state` performs deterministic storage reads with no model in the loop, and `GET /api/state` defaults to it.

A caller who wants persisted channel state therefore pays no tokens and gets no paraphrase of the record. Write and read are separate endpoints with separate defaults, so anything built on top has to decide per action whether it needs interpretation or needs data, and route accordingly.

The runtime sits on the AI SDK, with provider packages for OpenAI, Anthropic and Google all listed as dependencies. Which provider a request reaches is a per-agent config value rather than a property of the server, which is what makes three providers cheap to support in a harness this small.

An agent is AGENT.md with a plugin list in the frontmatter

Custom agents are files, not registrations. Create `~/.openbot/agents/<agent-id>/AGENT.md` and the harness reads YAML frontmatter for the name, the description and the plugins to load. `gray-matter` in the dependency list parses that header, and `zod` sits alongside it to validate what comes out.

markdown
---
name: Assistant
description: A helpful local assistant.
plugins:
  - id: openbot
    config:
      model: openai/gpt-4o-mini
  - id: storage
---

You are a careful assistant. Be concise and clear.

The model string carries its provider as a prefix, which is the format the SDK dependency expects, so switching providers is a config edit. Adding a plugin id is how you change what an agent can do: `openbot` supplies the model runtime with storage tools, `storage` persists channels and threads, `ui` contributes interactive widgets. Prompt text sits below the frontmatter and is the only part written freely.

Because the definition is a file in your home directory, an agent can be reviewed, diffed and copied between machines like any other text.

Three routes, four context fields, one event stream

The entire HTTP surface is three routes. `GET /api/events` is the Server-Sent Events stream for a channel or a thread. `POST /api/publish` publishes an event. `GET /api/state` runs an event and returns the resulting events. Streaming is push rather than poll, so a chat surface in front of the harness never has to ask whether something changed.

bash
curl -X POST http://localhost:4132/api/publish \
  -H "content-type: application/json" \
  -d '{"type":"agent:invoke","data":{"role":"user","content":"hello"}}'

The publish body carries a type and a data object; `agent:invoke` with a user role is the documented way to say hello to the default agent. Addressing is by four fields, `channelId`, `threadId`, `agentId` and `runId`, passed as context headers or fields. Which of them each route requires is not spelled out, so a client that sends only `channelId` learns the rest from the failure rather than from documentation.

Two install paths and a lockfile that covers only one

The packaged CLI installs globally and starts:

bash
npm i -g openbot
openbot start

Before the first start, set a key for the provider the agent config names. The worked example is OpenAI:

bash
export OPENAI_API_KEY=sk-...
openbot start

Running from a clone takes the other path, `npm install` and then `npm run dev`, which watches the TypeScript entry point rather than running compiled output. Both paths are defined by these entries in `package.json`:

json
"engines": {
  "node": ">=20.12.0"
},
"scripts": {
  "dev": "tsx watch src/app/cli.ts start",
  "build": "tsc && mkdir -p dist/assets && cp src/assets/icon.svg dist/assets/icon.svg",
  "start": "node dist/app/cli.js start"
},
"bin": {
  "openbot": "./dist/app/cli.js"
}

Two details deserve attention. The tree ships a `pnpm-lock.yaml` while the documented workflow uses npm, so the pinned graph the maintainers work against is not the one a reader resolves. And the build step copies `src/assets/icon.svg` into `dist/assets` by hand after `tsc`, so a packaged install is only complete if that command actually ran.

The MIT grant stops at v0.5.3

The licence section is unusual enough to read twice. It states that MIT applies to this repository through release `v0.5.3`, that code released under MIT before that point stays MIT, and that newer work is not published here. `package.json` still carries `"version": "0.5.3"`, which matches the last MIT-covered state rather than proving anything newer exists.

There are no GitHub releases on the repository, so `v0.5.3` is a version in a manifest and a note in the README, not a downloadable artefact with release notes attached. The last push was on 2026-07-07. The top-level tree holds no changelog, so nothing in the repository records what moved between earlier iterations of the design and the version that is actually here.

For an adopter the effect is narrow and worth stating plainly: whatever this project has become since that version, it is not in this tree, and the MIT grant does not reach it. Pin to `0.5.3` and read `LICENSE` rather than assuming the grant extends forward.

Where this edition stops: three plugins and no auth story

The built-in plugin table is the honest ceiling on the feature story. `openbot` runs the model with storage tools, `storage` persists channels and threads, `ui` supplies interactive widgets, and the README labels that table as this edition, which reads as a snapshot of one release rather than a complete inventory. Nothing published describes the loader contract for a plugin id outside those three.

Multi-user access is the other gap. Every example targets localhost, the README documents no authentication, no per-agent secrets and no format for the config it says it stores, and `cors` sits in the dependency list without any documented policy around it. A team that wants a shared agent server has to settle those questions before port `4132` listens anywhere but one machine.

It is also the wrong shape for a hosted product. Storage under `~/.openbot`, agents as files and a local port are deliberate choices for a single operator. A multi-tenant service gets the event model and the agent file format from here, and inherits hosting, tenancy and access control as work of its own.

Editorial conclusion

OpenBot fits one operator on one workstation who wants agents defined as files and events flowing over a local port, and it earns its keep when reading state has to avoid model calls. It does not fit a shared deployment, and the licence note means work newer than v0.5.3 lives outside this repository. Before adopting it, install against Node >=20.12.0, send one agent:invoke event to /api/publish on port 4132, and check the version you actually resolved against that MIT boundary.

Frequently asked questions

How do I install OpenBot?

The documented path is a global npm install followed by `openbot start`, and Node.js `>=20.12.0` is required. Set a provider key such as `OPENAI_API_KEY` before the first start. From a clone, `npm install` and `npm run dev` run the TypeScript entry point under a watcher.

What is OpenBot?

A local-first harness for running AI agents that exposes a small event API, local file storage and a runtime credited to Melony. Channels, threads, agents, plugins and config live under `~/.openbot`, the server listens on port `4132` by default, and events reach clients over Server-Sent Events.

Does OpenBot ship a user interface?

A built-in `ui` plugin is listed as supplying interactive UI widgets, alongside `openbot` for the model runtime with storage tools and `storage` for channel and thread persistence. The README presents that table as this edition rather than a full inventory of what exists.

How do I define a custom agent in OpenBot?

Create `~/.openbot/agents/<agent-id>/AGENT.md` with YAML frontmatter carrying `name`, `description` and a `plugins` list, and prompt text below it. The `openbot` plugin takes a `model` value in `provider/model` form, for example `openai/gpt-4o-mini`.

Can OpenBot serve several users at once?

Nothing published documents authentication, per-agent secrets or a config file format, and every example targets localhost on port `4132`. Multi-user hosting and access control are left to whoever deploys it.

Official sources

  1. Issues
  2. License: MIT
  3. meetopenbot/openbot on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/meetopenbot-openbot.svg)](https://hysenlabs.com/projects/meetopenbot-openbot)