---
title: Memory and history
description: How a Hubzoid Hub keeps authored knowledge, conversation history per surface, workflow state per account and learned knowledge saved by the remember tool.
canonical_url: https://hubzoid.com/docs/concepts/memory-and-history
last_updated: 2026-09-27
---

# Memory and history

How a Hubzoid Hub keeps authored knowledge, conversation history per surface, workflow state per account and learned knowledge saved by the remember tool.

"Memory" covers four different things in Hubzoid. They are stored in different places, written by different people or processes, and reach the agent in different ways. Keeping them apart is what lets a Hub share knowledge across a team without mixing one person's conversation into another's.

| Kind | Written by | Stored in | Shared with | Reaches the agent |
| --- | --- | --- | --- | --- |
| Authored knowledge | Builders, in Git | `knowledge/*.md` | Everyone who uses the Hub | Menu in the system prompt, `read_knowledge` on demand |
| Conversation history | The conversation itself | Per surface, see below | The people in that conversation | The earlier messages arrive with each new turn |
| Workflow state | Workflow code and scheduled tasks | The operational database and task state files | That workflow or task, per account the run acts as. `hub.shared_state` is shared by every account. | Read and written by the workflow |
| Learned knowledge | The `remember` tool, when a curator asks | `knowledge/_learned/*.md` | Everyone who uses the Hub | Like authored knowledge |

## Authored knowledge

Knowledge is the Hub's reference material: definitions, policies, thresholds and how your systems fit together. It lives in `knowledge/` as Markdown, is reviewed like code, and changes when someone edits it. The system prompt lists each document's name and description, and the agent reads a document in full with `read_knowledge(name)` when it needs it.

`read_knowledge` and `list_knowledge` read the folder from disk on every call, so an edit is visible to the next tool call without a restart. See [the Hub](https://hubzoid.com/docs/concepts/hub#knowledge).

## Conversation history

The bridge does not keep conversations. Each chat request carries the conversation so far, and the bridge flattens it into one prompt with `[system]`, `[user]` and `[assistant]` sections. Where that history comes from depends on the surface:

| Surface | Where history lives | What the agent receives |
| --- | --- | --- |
| Web chat (Open WebUI) | The chat app's database: `<hub>/.openwebui-data/webui.db` on a single Hub, `webui.db` in the gateway's data folder, or PostgreSQL when `DATABASE_URL` is set | The whole conversation, sent by the chat app on every turn |
| Slack | Slack itself | The thread, read back from Slack on every turn |
| WhatsApp, Telegram | The `hz_inbound_history` table in the Hub database (`<hub>/.hubzoid/hub.db`, or PostgreSQL) | The most recent messages for that chat, 40 by default |
| OpenAI-compatible API | Your application | Whatever `messages` list your application sends |
| MCP clients | The client application | Nothing. Each MCP tool call stands alone, and the client keeps its own conversation. |
| Generic webhooks | Not applicable | Each delivery is stored as an event file for a task to process. There is no conversation. |

History is separate per surface and per conversation. A question asked in Slack is not visible in the web chat, and one WhatsApp chat never sees another.

For WhatsApp and Telegram, Hubzoid keeps the thread itself because those platforms do not replay it. Only the visible answer is stored, without the thinking panel or tool entries. Two settings bound it:

| Key | Default | Effect |
| --- | --- | --- |
| `INBOUND_HISTORY_MAX` | `40` | Messages kept per chat, about 20 turns. Older messages are deleted as new ones arrive. |
| `INBOUND_HISTORY_TTL_DAYS` | unset | When set, messages older than this many days are deleted each time the chat stores a new message. |

Usage rows in `hz_usage` record the time, surface, person, chat id, model, tokens, estimated cost and duration of every turn. They never contain message content.

## Workflow state

Scheduled work needs to remember what it has already done. That memory belongs to the workflow and to the account a run acts as, not to a conversation. Every scheduled run acts as an ordinary account, chosen by `run_as` or the Hub's default, as described in [workflows and schedules](https://hubzoid.com/docs/concepts/workflows-and-schedules#who-a-run-acts-as).

**Code workflows** use `hub.state`, a dictionary-like store in the operational database (`hz_workflow_kv`). Keys are scoped to the Hub, the workflow and the run's account, so two workflows never collide and the same workflow run for someone else starts empty. For state that is not about one person, `hub.shared_state` is shared by every account that runs the workflow. Keep personal data out of it. Values are JSON. Each assignment is committed at once and survives restarts and upgrades.

```python title="workflows/watchtower/main.py"
new = [b for b in breaches if not hub.state.get(f"explained:{b['service']}:{b['window_end']}")]
...
for b in new:
    hub.state[f"explained:{b['service']}:{b['window_end']}"] = report
```

A write to `hub.state` is its own commit, not a checkpointed step. If a run crashes after a write and is resumed, a read-modify-write such as a counter can be applied twice. Use per-item markers like the one above, which make a repeated run skip work it already finished. The [workflow API](https://hubzoid.com/docs/reference/workflow-api) covers the details.

**Markdown tasks** run each round in a fresh context, with no chat history. Continuity comes from a state file the task keeps for the run's account at `<hub>/.hubzoid/schedule/<task>@<person>/state.json`. Hubzoid's task preamble tells the agent to read it first and update it after every unit of work, so the next round or the next scheduled run resumes from it. Each run also writes a step-by-step log to the `runs/` folder beside it. See [markdown tasks](https://hubzoid.com/docs/guides/markdown-tasks).

State written before 1.0.1, in `hub.state` or in `<hub>/.hubzoid/schedule/<task>/`, is kept as it was and belongs to no account. Only a legacy Hub with no account configured still uses it.

The workflow engine separately checkpoints each completed step of a run, which is what lets an interrupted run resume without repeating finished steps. That is execution state, managed by the engine, not something your code reads.

## Learned knowledge

Every Hub includes a `remember(topic, content)` tool that saves a durable learning as a knowledge document, so a correction made in chat reaches every later conversation. It is controlled rather than automatic.

Curator asks → Access check → Decision recorded → Document written → Readable at once

### Who can trigger it

- The caller must hold the `curator` permission in the Hub, shown as **Save shared knowledge** in the Console. Grant it with `hubzoid grant you@example.com curator my-hub` on a Hub whose access Hubzoid manages. On a Hub with group-based access, membership of an Open WebUI group named `curator` counts instead.
- The caller must be on a surface allowed to reach restricted tools. By default, Slack, WhatsApp and Telegram callers, anonymous requests and `hubzoid test` are refused. `HUBZOID_RESTRICTED_SURFACES` changes the list.
- The tool's description tells the model to call it only when the person explicitly asks it to remember, save or note something, and never on its own initiative.
- In a Hub where nobody holds `curator`, every call is refused. A Hub tool named `remember` replaces the built-in one. It is not offered over MCP.

Every attempt, allowed or refused, is recorded in the access log with the person, surface and reason.

### Where it writes

`remember` writes one Markdown file per topic:

```markdown title="knowledge/_learned/billing-edge-cases.md"
---
name: learned/billing-edge-cases
description: Learned knowledge about billing edge cases
learned_by: you@example.com
updated: '2026-09-25T09:41:07+00:00'
---

Credit notes issued after month end are booked in the month they are issued.
```

| Rule | Behavior |
| --- | --- |
| File name | The topic in lowercase letters, digits and hyphens, at most 80 characters. |
| Name | `learned/<slug>`, so it never collides with an authored document. |
| Size | Content above 100,000 bytes is refused. Split it into narrower topics. |
| Updates | A second `remember` on the same topic replaces the whole document. The model is told to read the current version first and send the complete updated text, so a correction overwrites the old claim. |
| Previous version | The version before the latest write is kept beside it as `<slug>.md.bak`, which the knowledge loader ignores. |
| Provenance | `learned_by` and `updated` in the frontmatter record who wrote it and when. |

The document is readable through `read_knowledge('learned/<slug>')` and `list_knowledge` on the next call, for every person who uses the Hub. The knowledge menu in the chat agent's system prompt includes it after the next restart.

### Review and correct it

Learned documents are ordinary files in the Hub folder, so they go through the same review as the rest of the Hub:

1. **Review changes.** `git status` and `git diff` on `knowledge/_learned/` show new and changed documents since the last commit. Commit what you keep.
2. **Correct in chat.** A curator asks the agent to remember the corrected fact. The document is replaced in full.
3. **Correct by hand.** Edit or delete `knowledge/_learned/<slug>.md`. The change is visible to the next `read_knowledge` call.
4. **Undo the last write.** Restore `<slug>.md.bak` over the document.
5. **Audit who used it.** `hubzoid audit my-hub` and the Console's **Activity** page list each `remember` decision with the person, surface and outcome.

> **Warning: Learned knowledge is shared**
>
> A remembered fact becomes part of the Hub's knowledge for everyone who uses it, on every surface. Grant `curator` only to people who should change what the whole team's agent believes, and review `knowledge/_learned/` as you would any other change to the Hub.

## Next steps

- [Workflows and schedules](https://hubzoid.com/docs/concepts/workflows-and-schedules): How scheduled work runs and keeps its state.
- [Identity and access](https://hubzoid.com/docs/concepts/identity-and-access): Permissions, surfaces and grants, including curator.
- [Operating runs](https://hubzoid.com/docs/guides/operating-runs): Inspect, pause and cancel scheduled work.
