docs: Added documentation for the new memory system

2026-06-11 16:00:33 -06:00
parent f6b0850139
commit 43e470b463
6 changed files with 222 additions and 0 deletions
+1
@@ -38,6 +38,7 @@ Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration g
* [Macros](Macros): Automate repetitive tasks and workflows with Coyote "scripts" (macros). * [Macros](Macros): Automate repetitive tasks and workflows with Coyote "scripts" (macros).
* [RAG](RAG): Retrieval-Augmented Generation for enhanced information retrieval and generation. * [RAG](RAG): Retrieval-Augmented Generation for enhanced information retrieval and generation.
* [Sessions](Sessions): Manage and persist conversational contexts and settings across multiple interactions. * [Sessions](Sessions): Manage and persist conversational contexts and settings across multiple interactions.
* [Memory](Memory): Persistent file-based memory that survives across sessions. Bootstrap with `coyote --init-memory [global|workspace]`.
* [Roles](Roles): Customize model behavior for specific tasks or domains. * [Roles](Roles): Customize model behavior for specific tasks or domains.
* [Skills](Skills): Modular knowledge or capability packs the LLM can load and unload mid-conversation. Multiple skills compose; instructions stack, tools and MCPs union. * [Skills](Skills): Modular knowledge or capability packs the LLM can load and unload mid-conversation. Multiple skills compose; instructions stack, tools and MCPs union.
* [Agents](Agents): Leverage AI agents to perform complex tasks and workflows, including sub-agent spawning, teammate messaging, and user interaction tools. * [Agents](Agents): Leverage AI agents to perform complex tasks and workflows, including sub-agent spawning, teammate messaging, and user interaction tools.
+207
@@ -0,0 +1,207 @@
# Memory
Coyote can maintain a **persistent memory file system** that survives across sessions. Memory captures cross-session
facts about you, your project, and your preferences, complementing [Sessions](Sessions) (which handle
within-conversation state) and [Skills](Skills) (which are static knowledge packs).
## Quick Start
The fastest path is the bootstrap command:
```bash
# Workspace memory (per-project)
cd /path/to/your/project
coyote --init-memory workspace
# → creates ./COYOTE.md with a skeleton
# Global memory (per-user, applies everywhere)
coyote --init-memory global
# → creates <config_dir>/memory/MEMORY.md
```
Then edit the file with anything you want the LLM to remember:
```markdown
# Project Memory
This project is a Rust CLI tool. I prefer terse responses and concrete code examples.
```
Run coyote in that directory and the memory content is injected into every system prompt automatically. The LLM will see and use the `memory__*` tools to update it over time (when function calling is on).
That's it for "lite mode." For structured memory, see below.
> Memory is **opt-in by file presence** for the read path. If no marker exists on disk, no workspace memory is injected and global memory is loaded only if the global marker exists. `--init-memory` is the explicit consent signal.
> **Write-side exception (git repos only):** if the LLM calls `memory__write(scope=workspace)` and no marker exists, coyote auto-bootstraps a structured layout at the git root and adds `.coyote/memory/` to `.gitignore`. See [Git-Repo Auto-Bootstrap](#git-repo-auto-bootstrap) below. Outside a git repo this fails with a hint to run `coyote --init-memory workspace`.
> **Re-running is safe.** `--init-memory` refuses to overwrite an existing marker — it prints `Memory marker already exists at '...'` and exits without touching the file. Useful in setup scripts.
## How It Works
Memory has two scopes:
- **Global** (user-level): `~/.config/coyote/memory/` - facts about you that apply everywhere
- **Workspace** (project-level): `<workspace>/COYOTE.md` (lite) or `<workspace>/.coyote/memory/` (structured)
Memory is **opt-in by workspace**: coyote walks up from your current directory looking for a memory marker. If none is
found, no workspace memory is loaded. Global memory is loaded if it exists.
When both a `.coyote/memory/MEMORY.md` and a `COYOTE.md` exist at the same level, the structured layout wins.
### Git-Repo Auto-Bootstrap
If the LLM tries to write workspace memory and no marker exists in any ancestor, coyote checks for a git repository before erroring:
- **Git root found** (ancestor contains a `.git` directory or file, worktrees and submodules included): coyote creates
`<git_root>/.coyote/memory/MEMORY.md` with an empty index, appends `.coyote/memory/` to `<git_root>/.gitignore`
(idempotent; no duplicate if you already have it, including the trailing-slash-less form), and emits a `WARN`-level
log line so you know it happened. The write then proceeds.
- **No git root**: the write fails with an error pointing you at `coyote --init-memory workspace`.
The rationale: if you're in a git repo, the natural anchor for workspace-wide memory is the repo root, and the
gitignore entry keeps the LLM's drill files out of version control by default. If you're not in a git repo, the
bootstrap location is genuinely ambiguous, so coyote requires explicit consent via `--init-memory`.
This only affects the write path. The read path remains opt-in: until a marker exists, no workspace memory is injected.
## Two Halves: Read and Write
Memory has two independent halves:
| Half | Requires | Behavior |
|-----------|--------------------------|-----------------------------------------------------------------|
| **Read** | Nothing | Memory content is injected into the system prompt every session |
| **Write** | Function calling support | The LLM uses `memory__*` tools to curate memory autonomously |
If your model lacks function calling, memory degrades to read-only: you maintain the files manually, the LLM sees them.
In read-only mode coyote injects all known drill files (up to the without-tools cap) so the model has full context
without needing tools.
## Structured Mode
For non-trivial memory, use the structured layout:
```
<workspace>/.coyote/memory/
├── MEMORY.md # index (always injected)
├── project_compliance.md
├── feedback_terse.md
└── reference_dashboards.md
```
Each drill file has YAML frontmatter:
```markdown
---
name: project_compliance
description: Compliance constraints driving the auth rewrite
type: project
---
We must store session tokens server-side per the 2026 audit. ...
```
`MEMORY.md` is what gets injected on every prompt. It serves two purposes:
1. **An index** of available drill files (one line per file: name + description)
2. **A home for universal facts** the LLM should always see (user identity, hard rules, binding feedback)
Drill files are fetched on demand by the LLM via `memory__read`. Keep them focused; for facts that should always be
visible, write them directly in `MEMORY.md` instead.
## Memory Types
| Type | Purpose | Example |
|-------------|---------------------------------------------------|------------------------------------------------|
| `user` | Persistent facts about you | "Senior Rust dev, terse responses preferred" |
| `feedback` | Past corrections that should bind future behavior | "Never use `as any`; got burned in incident X" |
| `project` | Workspace-specific facts | "API freeze begins 2026-03-05" |
| `reference` | Pointers to external systems | "Bugs tracked in Linear project INGEST" |
The `type:` field is informational, meaning coyote does not change behavior based on it. It exists so the LLM can
categorize its own writes and so you can grep by category.
## Tools
When function calling is enabled, coyote exposes:
- `memory__read(name)`: read a specific drill file by its slug
- `memory__write(name, description, content, scope, type)`: create or replace a drill file (`scope`: `global` |
`workspace`)
- `memory__list()`: see all known drill files with metadata
- `memory__lint()`: health-check (orphans, broken `[[wikilinks]]`, oversized files >2K chars)
The LLM is instructed to update `MEMORY.md` whenever it writes a new file. Two silent promotions can happen on a
`memory__write(scope=workspace)`:
- **Lite -> structured**: if the workspace is in lite mode (`COYOTE.md` only), the new file goes into
`<workspace>/.coyote/memory/` and `COYOTE.md` is left untouched.
- **None -> structured (git only)**: if no marker exists anywhere, coyote auto-bootstraps at the git root. See
[Git-Repo Auto-Bootstrap](#git-repo-auto-bootstrap).
## Toggles
Memory can be disabled at multiple levels (most specific wins):
1. **CLI flag**: `coyote --no-memory ...` (per-invocation; sets `false` at the app layer)
2. **Graph agents**: memory is always off
3. **Agent config**: `memory: false` in the agent's `config.yaml`
4. **Session**: `memory: false` in the saved session frontmatter (also settable via the session's `set_memory` API)
5. **Role config**: `memory: false` in role frontmatter
6. **AppConfig**: `memory: false` in global config
7. **Workspace presence** (read side): absence of `COYOTE.md` and `.coyote/memory/`. On the write side,
`memory__write(scope=workspace)` inside a git repo can auto-create `.coyote/memory/` (see
[Git-Repo Auto-Bootstrap](#git-repo-auto-bootstrap) for more information).
Resolution cascade for the boolean flag: **agent > session > role > app**, with the first explicit value winning.
No value means "no opinion, defer to next layer." If the flag resolves to true but no memory exists on disk anywhere,
memory stays off (no empty injection).
## Caps
Two cap constants control how much memory content is injected:
| Field (in AppConfig) | Default | When |
|----------------------------|--------------|----------------------------------------------------------------------------|
| `memory_cap_with_tools` | 6,000 chars | Function calling on. Only indexes injected, drill bodies fetched on demand |
| `memory_cap_without_tools` | 12,000 chars | Function calling off. Indexes plus drill bodies up to the cap |
In without-tools mode, drill files are appended alphabetically until the cap is exhausted; any omitted files are
reported via a truncation marker in the injection block.
If the `MEMORY.md` indexes alone exceed the cap, coyote injects them fully and logs a warning. A partial index would
confuse the LLM more than going over budget by a few hundred chars.
## When NOT to Use Memory
- **One-shot prompts**: no recurring context, memory is overhead
- **Privacy-sensitive sessions**: memory persists on disk in plaintext
- **Throwaway scripts using coyote as a library**: the script is the context
For session-specific suppression without changing config, use `--no-memory` or set `memory: false` on a Session before
saving it.
## Comparison
| | Memory | [Sessions](Sessions) | [Skills](Skills) | [RAG](RAG) | [Vault](Vault) |
|-------------|---------------------|----------------------|------------------|--------------------|----------------|
| Scope | Cross-session facts | One conversation | Knowledge packs | Document retrieval | Secrets |
| Lifecycle | Evolves over time | Per-conversation | Static, curated | Indexed, retrieved | Long-lived |
| Encrypted | No (plaintext) | No | No | No | Yes |
| LLM writes? | Yes (with tools) | No | No | No | No |
## Privacy & Security
Memory files are **plaintext markdown on disk**. Anything you (or the LLM) writes there is readable to anyone with
access to your home directory.
**Never store secrets in memory.** Use [Vault](Vault) for credentials and API keys. The default memory instructions
explicitly tell the LLM not to write secrets, but treat that as a defense-in-depth measure, not a guarantee.
## See Also
- [Sessions](Sessions): per-conversation state
- [Skills](Skills): modular knowledge packs
- [Roles](Roles): model behavior customization (supports `memory: false`)
- [RAG](RAG): document retrieval (complementary, not redundant)
- [Vault](Vault): encrypted secret storage
+3
@@ -6,6 +6,9 @@ Think of them kind of like a baby: That baby can grow up to do anything! Be a re
The only difference is that with roles, we're explicitly telling the LLM what we want it to be. Also: the LLM is already The only difference is that with roles, we're explicitly telling the LLM what we want it to be. Also: the LLM is already
grown up so we don't have to wait! grown up so we don't have to wait!
> Roles can disable the memory system for their scope by setting `memory: false` in their frontmatter.
> See [Memory](Memory) for the full toggle cascade.
![Role demo](./images/roles/code.gif) ![Role demo](./images/roles/code.gif)
--- ---
+3
@@ -7,6 +7,9 @@ answers and ask follow-up questions and the model will know what you're referrin
Sessions can be temporary, or can be saved so you can continue conversations at a later time. Sessions can be temporary, or can be saved so you can continue conversations at a later time.
> Sessions persist *one conversation*. For facts that should survive across all sessions (e.g., user preferences,
> project constraints, accumulated feedback), see [Memory](Memory).
Saved sessions are stored in the `sessions` subdirectory of the Coyote configuration directory. The location of the Saved sessions are stored in the `sessions` subdirectory of the Coyote configuration directory. The location of the
`sessions` directory varies by system, so you can use the following command to find the `sessions` directory if you need `sessions` directory varies by system, so you can use the following command to find the `sessions` directory if you need
it: it:
+3
@@ -5,6 +5,9 @@ the user), a skill is a capability the model layers onto whatever role/agent/ses
Multiple skills can be loaded at once. They compose, meaning their instructions stack, their tool whitelists union, and Multiple skills can be loaded at once. They compose, meaning their instructions stack, their tool whitelists union, and
their declared MCP servers get acquired automatically. their declared MCP servers get acquired automatically.
> Skills are *static* curated knowledge packs. For *evolving* facts the LLM curates over time across sessions,
> see [Memory](Memory).
Common uses: Common uses:
- **Methodology overlays** ("how to do git surgery", "how to review code"). - **Methodology overlays** ("how to do git surgery", "how to review code").
+5
@@ -45,6 +45,11 @@
- [Limitations](Graph-Agents#limitations--gotchas) - [Limitations](Graph-Agents#limitations--gotchas)
## Knowledge & Automation ## Knowledge & Automation
- [Memory](Memory)
- [Quick Start](Memory#quick-start)
- [Structured Mode](Memory#structured-mode)
- [Tools](Memory#tools)
- [Toggles](Memory#toggles)
- [RAG](RAG) - [RAG](RAG)
- [Macros](Macros) - [Macros](Macros)
- [Roles](Roles) - [Roles](Roles)