# Goose forgets the middle of a long session. Its memory belongs in a vault

> Goose memory, from .goosehints to the Memory extension, stays on one machine and compaction drops the rest. How to give it a shared markdown vault over MCP.

Source: https://baalda.com/blog/goose-second-brain
Site: Baalda, https://baalda.com
Published: 2026-10-01

**Short answer.** Yes, as a remote extension. Goose supports `streamable_http` extensions, Baalda serves a vault at `/api/mcp`, and `goose configure` wires them together with an Authorization header. The agent then reads and writes the team's markdown under your own permissions, so what it learns survives compaction and the session ending.

Goose is built to run long. Hand it a task, let it work, come back later. The consequence most people meet a few weeks in is that a long session cannot keep everything it saw. At eighty percent of the token limit Goose compacts the conversation into a summary and carries on, and the detail that got summarised is detail the agent no longer holds. The work survives. The reasoning behind it usually does not, and neither does anything a second person would have wanted to read.

## Why does a long Goose session end with less than it learned?

Three mechanisms, all of them deliberate, all of them good engineering.

**Compaction.** Goose's docs say auto-compaction fires by default at 80% of the token limit, in both the Desktop app and the CLI. You can move the trigger with `GOOSE_AUTO_COMPACT_THRESHOLD`, disable it entirely by setting it to `0.0`, or run `/compact` yourself before you reach the ceiling. What it does is replace older turns with a summary. The earlier conversation stays visible in the session, but only the compacted version goes into the active context. Summaries keep conclusions. They drop the three approaches that were tried and abandoned, which is usually the part worth having.

**Subagents.** Goose can spawn subagents that work in their own isolated sessions so the main conversation does not fill with tool output. By default everything a subagent did is reported back to the main session, and you can ask for a summary only. Either way, the detailed working happened somewhere you were not reading, and it ends when that subagent ends.

**The session store.** Since version 1.10.0 Goose keeps sessions in a SQLite database at `~/.local/share/goose/sessions/sessions.db`, and `goose session --resume --name my-project` picks one back up. That is genuine persistence and it is worth knowing about. It is also one database, on one laptop, holding raw transcripts. Nobody on your team is going to open it, and nothing in it is a thing a person can correct when it turns out to be wrong.

None of this is a flaw to route around. It is what lets a session run for hours at all. The fix is not to make the agent remember more. It is to have it write the parts worth keeping into a place that was never part of the session.

## What does Goose already have for memory, and where does each one stop?

Two features, and both are better than most agents ship.

`.goosehints` is a plain text file, global at `~/.config/goose/.goosehints` and local at the root of a project or in directories below it. It loads at the start of a session and goes into the system prompt, which means you pay for it on every request. Goose's own documentation says to keep it concise for exactly that reason. That advice is correct, and it is also the ceiling: a file that is read in full every single time cannot be where a team's accumulated context goes.

The Memory extension is the dynamic version. It stores and retrieves on demand through `remember_memory`, `retrieve_memories`, `remove_memory_category` and `remove_specific_memory`, with memories saved as files on disk, local in `.goose/memory/` or global in `~/.config/goose/memory/`. Goose loads saved memories at the start of a session and includes them in the prompt. It is a real answer to a real problem.

It is also scoped to one machine and one home directory. The colleague who needs the same fact tomorrow cannot reach it, cannot fix it when it goes stale, and will have their own copy that says something slightly different. The agent remembers. The team still does not, which is the same wall [Cline's memory bank hits from the other direction](/blog/cline-second-brain).

## What is Baalda, in one paragraph?

Baalda is a team second brain made of ordinary markdown files on your own disk. Several people can edit the same note at the same time over a CRDT, access is set per folder and per note, and the core is open source under Apache-2.0 and can be self-hosted. It serves the vault over MCP at `/api/mcp`, so an agent reads and writes the same files a person does, under that person's permissions rather than a shared service account. Running it locally is free, with an optional managed Team plan if you want hosted sync. If the category is unfamiliar, [what a team second brain is](/blog/team-second-brain) covers the idea before any of the setup.

Worth noting that Goose and Baalda arrive from the same place. Goose is Apache-2.0, written in Rust, built at Block and since contributed to the Linux Foundation's Agentic AI Foundation, with the repository now under the `aaif-goose` organisation. Neither side of this setup is something you have to ask permission to run.

## How do I add Baalda to Goose as an extension?

Goose calls MCP servers extensions. Baalda is a remote one.

**1. Mint a token.** In Baalda, open Vault settings and then MCP, and create a token. It is shown once, starts with `mcp_`, and carries both the user and the vault it belongs to. Everyone mints their own. That is the entire permission model: the agent inherits your access, not a wider one.

**2. Run `goose configure`.** Choose Add Extension, then Remote Extension (Streamable HTTP). It asks what to call the extension, then for the Streamable HTTP endpoint URI, which is `https://api.baalda.com/api/mcp` for the hosted service or your own host plus the same `/api/mcp` path if you self-host. Running the self-hosted server on your own machine it is `http://localhost:3010/api/mcp`. Next it asks for a timeout, defaulting to 300 seconds, and a description. When it asks whether you would like to add custom headers, say yes and add one: `Authorization` with the value `Bearer mcp_your_token_here`.

**3. Or write it yourself.** The same thing in `~/.config/goose/config.yaml`, which on Windows lives under your roaming app data instead:

```yaml
extensions:
  baalda:
    type: streamable_http
    name: baalda
    enabled: true
    uri: "https://api.baalda.com/api/mcp"
    headers:
      Authorization: "Bearer mcp_your_token_here"
    env_keys: []
    envs: {}
    timeout: 300
```

In the Desktop app the same entry goes in through Extensions and Add custom extension. Restart Goose afterwards either way.

One thing not to do: the endpoint will also take the token as a `?key=` query parameter. It works, and it is worse. URLs end up in logs and shell history in a way headers do not.

## Why is the transport an easy decision here?

Because Goose has already made it for you. Its documentation says the supported extension types are `builtin`, `platform`, `stdio` and `streamable_http`, that SSE is not supported, and that old SSE configurations should be migrated.

That happens to line up exactly with how Baalda works. There is no server-initiated stream to subscribe to: `GET /api/mcp` and `DELETE /api/mcp` both return 405 on purpose, so a client can tell immediately that every message goes over `POST` and nothing is waiting on an open channel. In other clients this is the line that breaks the connection, because their default is the legacy transport and you have to override it. In Goose there is no wrong option to pick.

## What can Goose do once it is connected, and what stops it doing damage?

The vault arrives as tools, not as a folder: `list_folders`, `list_notes`, `read_note`, `search_notes`, `create_note`, `update_note`, `append_note`, `edit_note`, `move_note`, `delete_note`, plus `list_attachments` and `read_attachment_text` for files that are not markdown. `search_notes` reaches into attached documents and spreadsheets too, and each hit says whether it came from a note or a file.

Two of these matter more than the rest when an agent is working unattended for an hour.

`read_note` returns a `revision`. Pass it back as `expectedRevision` on a write and the write is refused if the note moved in the meantime, rather than silently landing on top of whatever changed. For a long autonomous run this is the difference between an agent that notices a teammate edited the file and one that does not.

`edit_note` works on anchors, and each anchor has to match exactly once. An anchor that matches zero times, or more than once, fails the whole call and writes nothing. Partial edits do not happen.

Underneath both, every call goes through the same per-folder and per-note permissions as the person whose token it is. A folder you cannot open is a folder Goose cannot read, and there is no flag that widens it. If you want to narrow it further, Goose's extension config has an `available_tools` field for filtering which tools an extension exposes, so you can start read-only and add the writes once you trust the setup.

## Do subagents get the vault too?

Yes. Goose's documentation says subagents inherit all extensions from the main session by default, and that you can restrict what they reach for security, focus or performance. It also says subagents cannot enable, disable or modify extensions, so one cannot quietly grant itself more than the parent session had.

That combination is the useful part. A subagent sent off to investigate something can read the vault for prior context and write its finding back, and that write survives the subagent, survives the compaction of the main session, and survives the session ending. The isolation that normally means the work evaporates stops meaning that, because the output has somewhere to go that is not the transcript.

## What is actually worth writing down during a run?

Not the transcript. A log of everything is a log nobody reads.

What earns its place is the small set of things that will be re-derived otherwise: the decision and the reason for it, the approach that was tried and failed and why, the constraint discovered halfway through that was not in any ticket, and the state of a long task at the point you stopped. Those are the things compaction eats first, because a summary keeps outcomes and drops the path.

The practical shape is one instruction in `.goosehints` telling Goose to write findings into a specific folder in the vault as it goes, rather than at the end. At the end is after compaction. As it goes is before.

And because the destination is markdown on disk that renders in a normal editor, the person who reads it next can fix it. That is the part a `memory/` directory on one laptop cannot do, and it is the same reason [the files have to stay files](/docs/mcp-setup) rather than becoming rows in a store only the agent queries.

## Where is this the wrong setup?

If you are one person running Goose on one machine, the Memory extension and a short `.goosehints` are already the right size. Adding a remote extension to that is a moving part with nothing to show for it. Use what ships.

Obsidian deserves a fair mention too. Its plugin ecosystem is far larger than ours, community MCP servers for it exist and work, and for a single person it is excellent software. What it does not do is several people editing the same note at once, or permissions below the level of the whole vault, which is the specific gap [the multiplayer post](/blog/obsidian-multiplayer-realtime-collaboration) goes through in detail. If your situation is really one person plus a sync subscription, stay where you are.

Baalda is also the wrong answer if you want database views and typed properties, or if plain files you can read without the app are not something you would pay anything to keep. It is the right one when a long autonomous run produces conclusions that other people need, when the agent should be held to the same access as the person who started it, and when what the agent learned at 2pm should still be true, and still correctable, next month.

## FAQ

### Where does Goose store its extension configuration?

In `~/.config/goose/config.yaml` on macOS and Linux, under your roaming app data on Windows. Remote MCP servers go in the `extensions` block with `type: streamable_http`, a `uri` and a `headers` map. You can write it by hand or let `goose configure` do it, and either way Goose needs a restart before the extension is picked up.

### Does Goose still support SSE for remote MCP servers?

No. Goose's docs list `builtin`, `platform`, `stdio` and `streamable_http` as the supported types and say SSE configurations should be migrated. That matches Baalda, which answers `POST` only and returns 405 on `GET /api/mcp` and `DELETE /api/mcp` because there is no server-initiated stream to subscribe to.

### What is wrong with the Memory extension that ships with Goose?

Nothing, for one person. It saves memories as files in `.goose/memory/` locally or `~/.config/goose/memory/` globally and loads them at the start of a session. The limit is reach: a teammate cannot read those files, cannot correct one that has gone stale, and will accumulate their own slightly different copy.

### Can Goose subagents use the vault as well?

Yes. Goose's documentation says subagents inherit all extensions from the main session by default, and that you can restrict them for security or focus. It also says they cannot enable, disable or modify extensions, so a subagent never grants itself more access than the session that spawned it had.

### How do I stop an unattended run overwriting someone else's edit?

`read_note` returns a `revision`. Pass it back as `expectedRevision` and the write is refused if the note changed in between instead of landing on top of it. `edit_note` adds a second guard: every anchor must match exactly once, and a missing or ambiguous anchor fails the whole call with nothing written.
