English | 한국어
A personal AI assistant that belongs to the person using it, not to a model vendor or to any one product. It is a self-hosted Control Plane and web app on top of Hermes Agent by Nous Research, where you connect general-purpose plugins and your own agents into an agentic workflow of your own, backed by a memory that only keeps what you said, wrote, or accepted yourself. Agents can look ahead and make suggestions before you ask, but how far they may act is decided by Control Plane rules, not by the model. People who share a purpose, a family for example, use it together as a group, each with their own agents.
The product name is not final. For now it is called fos-assistant.
The screens are in Korean, the only UI language for now. Everything shown is made-up demo data: the pictures are taken by a script against the same local stack the browser tests use, never from a real deployment.
Start a conversation. Pick one of your agents, pick a tier (fast, balanced, or deep), and type or tap a suggested question.
Watch the work. While an answer is being made, each tool call and each helper agent gets a line of its own.
Approve before anything is written. A plugin call that writes to an outside service waits on a card that shows exactly what will be sent.
Decide what is remembered. A fact you state yourself in a conversation that has not read outside text is remembered right away, and you can edit or undo it under the answer. Any other memory an agent leaves stays a proposal and is used in later conversations only after you accept it.
More screens: run tree, documents, agent settings, usage and cost
Run tree. Open a finished answer to see what it did, step by step, in a side panel.
Documents and collections. Longer notes live in collections. Every document is encrypted at rest.
Agent settings. Write the agent's persona and switch its tools on and off.
Usage and cost. An administrator sees runs per agent, with subscription runs converted to API prices.
To take the pictures again, run pnpm screenshots in web/. The script is test/screenshots/tour.shots.ts.
The Now screen (/now), the external service connections screen, and the scheduled tasks screen are not in this tour yet.
We want any individual to be free to have an assistant of their own, without depending on a particular model or product. To get there, the goal is to let you connect general-purpose plugins into an agentic workflow that is yours.
- Independent of the model. A conversation picks a tier (fast, balanced, or deep), and the Control Plane database holds the policy that maps a tier to an actual model. The runtime is separate too: Hermes Agent runs the agents, and this repository decides who may use what, provides the web UI, and records what was used.
- Independent of any product. A plugin is declared by its
assistant.json, and the Control Plane only has the generic flow. It does not know the name or the address of the service behind a plugin, so adding one means writing a plugin with anassistant.jsonand listing it in the Hermes dashboard's plugin list, not changing the Control Plane or the web app (ADR-043). - Yours. You decide which tools and memory an agent has and which model a conversation uses.
- It is the source of truth for long-term knowledge about you. Agents read only the collections they are allowed to, and the title and body of every entry are encrypted at rest.
General-purpose plugins live in this repository under hermes/connectors/ and are maintained here (ADR-064).
The first one is Gmail: it searches and reads your mail and filters without asking, and creates drafts, sends, replies, manages labels and changes filters only after you approve. It never moves mail to the trash or deletes it.
The second is Naver Blog: it uses the Naver account you signed in to in "My browser" and, after you approve, saves a post with your chat photos as a Naver Blog draft. It never publishes.
The third is Toss Securities: it reads your own holdings, quotes, buying power and order history. It places or cancels only regular orders you approve, one at a time, and never modifies orders or creates conditional orders. One connection attaches to a single agent that has an execution space.
A plugin for a service that only one household or organization uses, such as the household account book attached today, stays in its own repository.
When a service opens its own MCP server, its repository's plugin is attached as a remote MCP plugin. Financial Workbench works this way: it reads investment decisions and evidence chains, and writes only the trade records and proposals you approve. Attach it to the same agent as Toss Securities to see your holdings next to the reasons you bought them (ADR-20261026 / remote-mcp-plugin).
Growing the set of general-purpose plugins is where the work is headed. It is not done yet.
Other tools do some of this already, and several are far more mature. The table says what each one is, in its own documentation's words where possible, and what this project does differently.
| Option | What it is | What is different here |
|---|---|---|
| Hosted assistant apps, such as ChatGPT or Claude | Run by the model vendor, with nothing to install. Claude, for example, saves memory as you chat and lets you read, edit, and delete it in settings. | It runs on your own server. Which model a tier means is a policy row in your database. The only memory an agent keeps right away is a fact you stated yourself in a conversation. Everything else is used only after a person accepts it. |
| Self-hosted chat UIs, such as Open WebUI or LibreChat | Open WebUI calls itself "a self-hosted AI platform" with "support for Ollama and OpenAI-compatible APIs". LibreChat is "a self-hosted web application" with agents, MCP, and custom endpoints. | This project does not call model APIs itself. It sits on an agent runtime and adds one isolated Hermes profile per person, collections that decide which agent receives which memory, an approval step for plugin writes, delegation between agents with a run tree, and a ledger that converts usage to API prices. |
| Hermes Agent on its own | An autonomous agent you reach from the CLI or a messaging gateway, with its own persistent memory, skills, and subagents. | It adds a web app for a group of people. The profile a run uses comes from the requester's binding. Memory goes through the Control Plane only, and Hermes' built-in memory tool is not given to agents. Every memory entry is encrypted. Plugins follow one generic structure (ADR-043). |
It fits you if:
- you run your own server and want a family or another small group to share one assistant, each person with their own agents and memory,
- you want to change the model behind a conversation without changing the product you use,
- you want agents and plugins to do recurring work, with a person approving what gets written outside and memory keeping only what a person said or accepted.
It does not fit you yet if:
- you want something that works without installing anything,
- you want a service anyone can sign up for,
- you are not ready to set up and operate Hermes Agent yourself. There is no step-by-step self-hosting guide yet, and the API and schema can still change. See Status.
- Yours. The person owns the agent's tools, memory, and model choice.
- Not mixed. Someone else's memory and credentials never enter your run.
- Orchestrated. Work is split across several agents and merged, rather than queued behind a single one. The agent decides what to split. The Control Plane decides who can see what.
- It remembers. What was learned once is not asked again in the next conversation.
And one more that holds the others together: it grows by adding people the same way every time. Adding a user is a single decision by an administrator, and it must not slow anyone else down or expose anything to them.
- Agents you build and share. Create an agent from the web UI, write its persona, and choose its tools. Publish it to your group and others can talk to it, while each person's memory and conversations stay private (
docs/features/agent-skill.md). - Skills and
/commands. Upload skills to an agent and call one directly by typing/in the composer (docs/features/agent-skill.md). - Model tiers. Pick fast, balanced, or deep per conversation, or choose a model directly under advanced options (
docs/features/model-usage.md). - Delegation. One request can fan out to several agents. The child runs execute with the requester's permissions only, and when a result arrives the Control Plane opens the next turn of the parent conversation to deliver it (
docs/features/agent-skill.md). - Photos and HTML results. Attach photos for an agent to read, and open the HTML pages an agent produces in a side panel. Scripts in those pages do not run. Photos are stored per user (
docs/features/attachment.md,docs/features/attachment.md). - Run tree and cost. Every run is recorded, including the ones that fail. Open a run to see its tool calls and child runs as a tree. Runs made on a subscription are also shown converted to API prices, so an administrator can compare settings (
docs/features/execution.md, ADR-004).
- Connect once, attach to several agents. A plugin hands an agent the tools of an outside service and widens what that agent can do. Connect your account once on the external service connections screen, then attach that connection to any of your private agents, and the agent calls the service's tools directly (
docs/prd.md, ADR-083). - Attaching needs no restart. A newly attached plugin is picked up by runs shortly afterwards, without restarting the shared gateway, so nobody else's conversation is cut off in the meantime (ADR-20261007 / connector-live-reload).
- Plugin cards. The external service connections screen shows each plugin as a card with its icon, an about link, and a summary of its tools. Icons come only from files inside the plugin, and no outside address is fetched (ADR-20261008 / connector-card,
docs/prd.md). - Writes wait on an approval card. A call that writes to an outside service waits on a card that shows exactly what will be sent, and runs only after you approve it, once, with exactly the arguments you approved. A tool that allows a standing grant runs without a card while the grant you gave lasts, and tools that send data out have standing grants closed. Approvals for the same tool are grouped, and approval requests and expiries reach you as notifications on any screen (
docs/features/connector-policy.md,docs/features/attention.md).
- Proactive checks. Without being asked, an agent looks at your context and makes a suggestion, asks a question, or stays silent. You start a check with a button, or turn on a daily wake-up that runs it at a time you choose. The daily wake-up is off by default. Unless an administrator allows write tools for the agent, a check only reads, and the Control Plane enforces that boundary (
docs/features/proactive.md). - Context assembly. Context gathered from Memory, delegated results, results of approved plugin calls, run state, and follow-ups is assembled into a bundle where every item carries its source, permissions, and freshness (
docs/features/memory.md). - Problem candidates. A check's result can name problems worth solving for this user as candidates, and the Control Plane checks their evidence and duplicates deterministically (ADR-093).
- The Now screen (
/now). Failed runs, things waiting for your approval or acceptance and follow-ups coming due, delegated work, conversations to continue, and check reports are collected into a fixed set of cards. For proactive notices, things shown without being asked, the default is not to notify, and only signals defined from Control Plane records reach the screen. Each item can be hidden or snoozed (docs/features/attention.md,docs/features/attention.md). - Follow-ups. An agent proposes things you need to do or are waiting on, and only the ones a person accepts are tracked (
docs/features/attention.md). - Scheduled tasks. An agent runs at a set time with your permissions. If that run tries to write to an outside service, an approval card and a notification appear (
docs/features/schedule.md).
Value evaluation, an autonomy policy, and decision feedback are built as well.
Value evaluation compares problem candidates axis by axis and keeps the evidence for each (docs/features/proactive.md), and the autonomy policy decides, by rules that never call a model, whether to ignore, surface, ask for approval, or execute (docs/features/proactive.md).
Decision feedback records how a user reacted to a suggestion and how the run ended (docs/features/proactive.md).
Decision feedback is already recorded when a check report, a follow-up, a Memory proposal, or an approval request is created.
Checks and the daily wake-up do not call value evaluation or the autonomy policy automatically yet. For now an administrator runs and reads them for one check from the agent detail in the admin area (docs/features/proactive.md). Wiring those two into real use is in progress.
- What you say is kept at once, the rest is proposed. A lasting fact you state yourself in your latest message is remembered by the agent right away, and the answer shows "remembered" with edit and undo. A fact you stated yourself is kept at once even when the model rewords the body. If a negation appears in only one of your message and the body, or the text looks sensitive, it stays a proposal. Anything from a conversation that read outside text or that includes a run no person sent (a delegated result or a scheduled task), and anything the agent marks sensitive, stays a proposal and is used only after a person accepts it (ADR-20261007 / memory-remember, ADR-20261008 / memory-remember-guard,
docs/features/memory.md). - Collections. Entries belong to collections, and each agent receives only the collections it is allowed to. An admin changes that allowance on the agent page in the admin area. The title and body of every entry are encrypted at rest with the owner's data key. Earlier revisions are kept when an entry is edited or deleted (ADR-053, ADR-20261103 / memory-encryption).
Some Memory screens, such as editing the collection list and viewing earlier revisions of an entry, are not built yet. The current list is in the "Memory 에서 아직 만들지 않은 것" section of docs/features/memory.md.
- An execution space per user, in docker. For profiles registered in the operator's policy, the shell, file, and code execution tools run in an execution space in docker. There is one container per profile, and each user gets a separate working directory. Inside it, other users' files, other profiles' secrets, and the Hermes settings are out of reach. The only exception is paths the operator mounts read-only. Profiles not registered in the policy do not get this isolation, and coverage is extended one profile at a time (ADR-086,
hermes/docs/hermes-contract.md). - Scripts do the arithmetic. When a plugin writes the full list for a period as a read-only file in that agent's execution space and returns only the path, totals and statistics are computed by a script instead of being estimated by the model. This needs a plugin that declares file output, a profile registered in an execution space policy that sets an output path, and an agent with the code execution tool on. The Gmail and Naver Blog plugins in this repository do not declare file output (ADR-20261008 / connector-output-files).
- A browser per user (in progress). The Control Plane manages one browser per user, and the user signs in to services directly on the web app's "My browser" screen. Plugins reach that browser only through the Control Plane's relay. The code is in, but it is off by default and still in progress (ADR-20261007 / user-browser,
docs/features/user-browser.md).
The full scope, with how each item is verified, is in docs/prd.md.
- It does not modify Hermes core. Only the official extension points are used: profiles, the API server, and plugin hooks.
- It does not remember right away what you did not say. The only thing stored at once is a fact you stated yourself in a conversation a person sent. Everything else is used only after a person accepts it. Hermes' built-in memory tool is not given to agents. The Control Plane is the only path to memory.
- It does not widen what it does on a model's judgment alone. The only thing it starts on its own is a read-only wake-up that proposes cards. A plugin write call goes through an approval card or a standing grant you gave (ADR-20261101 / proactive-suggestion).
- It does not store secrets in the database. AI credentials and plugin tokens stay on the Hermes side. Browser login sessions are not stored in the database either. Separate profiles do not by themselves mean separate AI accounts: an OAuth login can be shared across profiles. How credentials are separated or shared is in
hermes/docs/hermes-contract.md. - It is not an open sign-up service. An administrator adds people to a group.
- It does not run scripts in agent-made pages.
- It does not carry operating procedures. Deployment and host-specific values belong to whoever runs it.
flowchart LR
U[User] --> W["Web (web/)"]
W --> C["Control Plane (backend/)"]
C --> DB[(Database)]
C --> A
C --> G
subgraph H[Hermes Agent]
A[API server]
P[Profile per user]
G["Plugins and plugins (hermes/)"]
end
P -. "MCP calls, signed by a plugin" .-> C
P --> S["Execution space per user (docker)"]
| Layer | Responsibility |
|---|---|
| Hermes Agent | Agent execution, tool calls, subagents, sessions |
Control Plane (backend/) |
Users, agent access, Memory access, model routing, plugin approvals, scheduled tasks and proactive checks, notifications, usage accounting |
Web (web/) |
Conversations, run status, approval cards, connections, the Now screen, Memory review, usage |
Hermes add-ons (hermes/) |
The plugins and profile template installed into your Hermes, and the general-purpose plugins |
| Execution space per user | Runs the shell, file, and code execution tools. Applies only to profiles registered in the operator's policy |
The profile a run uses is always taken from the requester's binding. The request body cannot choose it.
This is an early-stage project. One family actually uses it, and that is the only deployment so far.
- The public API and the database schema can still change without notice.
- Some decisions are recorded but not implemented yet. The ADR index marks them.
- In progress: the per-user browser, wiring value evaluation and the autonomy policy of proactive checks into real use, and applying execution spaces to more profiles.
- There is no step-by-step self-hosting guide yet.
- The roadmap is tracked in issue #219.
| Tool | Version |
|---|---|
| Java | 21 |
| Node.js | 24 or later |
| pnpm | 10 |
| Python | 3.13 (for the Hermes plugin tests) |
| Hermes Agent | checked against v2026.9.24 |
test/e2e starts a stand-in for the Hermes Runs API in the same process, so no Hermes installation is needed.
It boots the backend itself, so Java is still required.
node test/e2e/run.tsIt goes from issuing a login token to registering an agent, holding a conversation, and recording usage and cost.
The scenarios live one per file under test/e2e/scenarios/.
hermes/bundle.sh builds an install bundle with the plugins and the profile template.
hermes/bundle.sh --out <directory> --mcp-url <Control Plane MCP URL>hermes/README.md describes the bundle and the values it needs at install time.
Environment variables and the tech stack are in docs/self-hosting.md.
Issues and pull requests are welcome in English or Korean.
The internal documents (docs/, AGENTS.md, commit messages) are written in Korean, so the documents linked from this page are in Korean too.
How this project uses Hermes is described in hermes/docs/hermes-contract.md.
AGENTS.mdhas the rules of the repository, including what must never be written into a public repository.- The reading order of the documents is in the 「읽기 순서」 section of
AGENTS.md. Each module keeps its documents in its owndocs/directory. docs/adr/INDEX.mdlists the decisions that are hard to reverse.- Run
scripts/dev/check-local.sh --fastbefore pushing. It runs only the quick checks, including the public-safety check, and leaves the heavy checks to the Draft PR CI. Without--fastit runs everything; pass browser specs to limit the browser suite. Merge decisions use the required PR CI checks run against the current main merged with the PR. If CI cannot run, run the full local checks. See the 「확인」 and 「머지는 PR 로 한다」 sections ofAGENTS.md;scripts/pr/merge-ready.sh <PR>makes the merge call.
A general-purpose plugin is one directory, hermes/connectors/<id>/. A pull request that adds one needs the following.
- An
assistant.jsonwithschema: 2that declares every tool the MCP server exposes, each with a risk and a reason for it in the plugin's document. - Calls that write require approval. Tools that send data to people outside the account also declare
"grant": false, so each call is approved by a person. Tools that delete are not exposed. - Secrets come in only through environment variables declared in
fields, and the smallest OAuth scope or permission that works. - An MCP server in TypeScript, bundled with its dependencies into one JavaScript file for Bun during checks and packaging. Generated entry files are not committed. Plugin tests live alongside the source and use a local fake of the service.
- A setup guide in
hermes/connectors/<id>/README.mdand an owner line in.github/CODEOWNERS.
hermes/tests/test_connectors_contract.py checks the contract for every directory under hermes/connectors/, so a new plugin is checked as soon as it is added.
The full guide is hermes/connectors/README.md (Korean), and hermes/connectors/gmail/ is the reference to copy from.







