docs: Added documentation for the new and improved workspace instructions files

2026-07-17 15:04:31 -06:00
parent 1ee9196917
commit cdc2faf8e8
6 changed files with 154 additions and 21 deletions
+1 -1
@@ -865,4 +865,4 @@ path table and the [official sbx mixin reference](https://docs.docker.com/ai/san
installs/domains they bring. Not a bug, just visibility. installs/domains they bring. Not a bug, just visibility.
- **The `sql` agent's `usql` install is in the base kit, not a per-agent mixin.** Same for `pandoc` (used by - **The `sql` agent's `usql` install is in the base kit, not a per-agent mixin.** Same for `pandoc` (used by
`fetch_url_via_curl`). Both ship with every Coyote sandbox automatically. See `assets/sbx-kit/spec.yaml` for the `fetch_url_via_curl`). Both ship with every Coyote sandbox automatically. See `assets/sbx-kit/spec.yaml` for the
full base prereq list. full base prereq list.
+1
@@ -40,6 +40,7 @@ Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration g
* [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]`. * [Memory](Memory): Persistent file-based memory that survives across sessions. Bootstrap with `coyote --init-memory [global|workspace]`.
* [Workspace Instructions](Workspace-Instructions): Human-curated project instructions (`COYOTE.md`) injected into every prompt, with `AGENTS.md`/`CLAUDE.md`/`GEMINI.md` fallbacks for cross-tool compatibility. Scaffold with `coyote --init-instructions`.
* [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.
+16 -5
@@ -42,16 +42,27 @@ Every server entry **must** include a `"type"` field set to one of: `"stdio"`, `
## Workspace-Local MCP Servers ## Workspace-Local MCP Servers
In addition to the global `functions/mcp.json`, Coyote automatically loads a workspace-local MCP config from `.coyote/mcp.json` In addition to the global `functions/mcp.json`, Coyote automatically loads a workspace-local MCP config at startup.
in the current directory at startup. This lets you ship project-specific MCP servers alongside your code without This lets you ship project-specific MCP servers alongside your code without touching your global configuration.
touching your global configuration.
Coyote checks the following locations in order and loads the **first** file it finds:
1. `.coyote/mcp.json` — the native location
2. `.coyote/.mcp.json` — Claude-style file name (leading dot) inside the workspace config directory
3. `.mcp.json` — project root; [Claude Code's project-scope convention](https://code.claude.com/docs/en/mcp)
``` ```
<project-root>/ <project-root>/
── .coyote/ ── .coyote/
└── mcp.json # same format as functions/mcp.json └── mcp.json # same format as functions/mcp.json (preferred)
└── .mcp.json # Claude Code-compatible fallback
``` ```
This means a repository that only ships a Claude Code `.mcp.json` works with Coyote out of the box. The `.coyote/`
directory name is also customizable via the `COYOTE_WORKSPACE_CONFIG_DIR`
[environment variable](Environment-Variables), so you can point Coyote at another tool's config directory
(e.g. `.cursor/`, which holds an `mcp.json`) entirely.
The workspace file uses the exact same format as the global `functions/mcp.json`, including [Vault](Vault) secret The workspace file uses the exact same format as the global `functions/mcp.json`, including [Vault](Vault) secret
interpolation via `{{SECRET_NAME}}` syntax. Workspace server names shadow global ones on collision. This means that interpolation via `{{SECRET_NAME}}` syntax. Workspace server names shadow global ones on collision. This means that
if both files define a server named `my-db`, the workspace version takes precedence. if both files define a server named `my-db`, the workspace version takes precedence.
+12 -15
@@ -10,25 +10,24 @@ The fastest path is the bootstrap command:
# Workspace memory (per-project) # Workspace memory (per-project)
cd /path/to/your/project cd /path/to/your/project
coyote --init-memory workspace coyote --init-memory workspace
# → creates ./COYOTE.md with a skeleton # → creates <git_root>/.coyote/memory/MEMORY.md with a skeleton (falls back to the
# current directory outside a git repo) and appends .coyote/memory/ to .gitignore
# Global memory (per-user, applies everywhere) # Global memory (per-user, applies everywhere)
coyote --init-memory global coyote --init-memory global
# → creates <config_dir>/memory/MEMORY.md # → creates <config_dir>/memory/MEMORY.md
``` ```
Then edit the file with anything you want the LLM to remember: Then edit the index with anything you want the LLM to remember:
```markdown ```markdown
# Project Memory # Workspace Memory Index
This project is a Rust CLI tool. I prefer terse responses and concrete code examples. 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). 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. > 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`. > **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`.
@@ -40,12 +39,11 @@ That's it for "lite mode." For structured memory, see below.
Memory has two scopes: Memory has two scopes:
- **Global** (user-level): `~/.config/coyote/memory/` - facts about you that apply everywhere - **Global** (user-level): `~/.config/coyote/memory/` - facts about you that apply everywhere
- **Workspace** (project-level): `<workspace>/COYOTE.md` (lite) or `<workspace>/.coyote/memory/` (structured) - **Workspace** (project-level): `<workspace>/.coyote/memory/`
Memory is **opt-in by workspace**: coyote walks up from your current directory looking for a memory marker. If none is Memory is **opt-in by workspace**: coyote walks up from your current directory looking for a
found, no workspace memory is loaded. Global memory is loaded if it exists. `.coyote/memory/MEMORY.md` marker. If none is found, no workspace memory is loaded. Global memory is loaded if it
exists. A root-level `COYOTE.md` is **not** a memory marker; it is [workspace instructions](Workspace-Instructions).
When both a `.coyote/memory/MEMORY.md` and a `COYOTE.md` exist at the same level, the structured layout wins.
### Git-Repo Auto-Bootstrap ### Git-Repo Auto-Bootstrap
@@ -78,7 +76,7 @@ without needing tools.
## Structured Mode ## Structured Mode
For non-trivial memory, use the structured layout: Workspace memory always uses the structured layout:
``` ```
<workspace>/.coyote/memory/ <workspace>/.coyote/memory/
@@ -146,11 +144,9 @@ When function calling is enabled, coyote exposes:
- `memory__lint()`: health-check (orphans, broken `[[wikilinks]]`, oversized files >2K chars, stale files that are - `memory__lint()`: health-check (orphans, broken `[[wikilinks]]`, oversized files >2K chars, stale files that are
superseded or expired, and index descriptions that drifted from the file's own `description:`) superseded or expired, and index descriptions that drifted from the file's own `description:`)
The LLM is instructed to update `MEMORY.md` whenever it writes a new file. Two silent promotions can happen on a The LLM is instructed to update `MEMORY.md` whenever it writes a new file. One silent promotion can happen on a
`memory__write(scope=workspace)`: `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 - **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). [Git-Repo Auto-Bootstrap](#git-repo-auto-bootstrap).
@@ -164,7 +160,7 @@ Memory can be disabled at multiple levels (most specific wins):
4. **Session**: `memory: false` in the saved session frontmatter (also settable via the session's `set_memory` API) 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 5. **Role config**: `memory: false` in role frontmatter
6. **AppConfig**: `memory: false` in global config 6. **AppConfig**: `memory: false` in global config
7. **Workspace presence** (read side): absence of `COYOTE.md` and `.coyote/memory/`. On the write side, 7. **Workspace presence** (read side): absence of `.coyote/memory/`. On the write side,
`memory__write(scope=workspace)` inside a git repo can auto-create `.coyote/memory/` (see `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). [Git-Repo Auto-Bootstrap](#git-repo-auto-bootstrap) for more information).
@@ -215,6 +211,7 @@ explicitly tell the LLM not to write secrets, but treat that as a defense-in-dep
## See Also ## See Also
- [Workspace Instructions](Workspace-Instructions): human-curated project instructions (`COYOTE.md`/`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`/etc.)
- [Sessions](Sessions): per-conversation state - [Sessions](Sessions): per-conversation state
- [Skills](Skills): modular knowledge packs - [Skills](Skills): modular knowledge packs
- [Roles](Roles): model behavior customization (supports `memory: false`) - [Roles](Roles): model behavior customization (supports `memory: false`)
+121
@@ -0,0 +1,121 @@
Coyote can inject **human-curated project instructions** into every system prompt. This is its equivalent of Claude Code's
`CLAUDE.md` or the cross-tool `AGENTS.md` standard. Instructions are the "hard rules and orientation" for a repository:
coding conventions, build commands, architectural constraints, and anything else the LLM should *always* see.
Instructions complement [Memory](Memory): instructions are **human-curated and read-only to the LLM**, while memory
(`.coyote/memory/`) is **agent-curated** via the `memory__*` tools.
| | Workspace Instructions | [Memory](Memory) |
|-------------|-------------------------------------|-------------------------------------------|
| Curated by | You (committed to git) | The LLM (gitignored by default) |
| Injection | Always, in full | Index eagerly; drill files on demand |
| LLM writes? | Never | Yes (with function calling) |
| File(s) | `COYOTE.md` at the repo root | `.coyote/memory/` directory |
## Quick Start
```bash
cd /path/to/your/project
coyote --init-instructions
# → creates ./COYOTE.md with a skeleton
```
Edit `COYOTE.md` with your project's instructions, commit it, and every Coyote invocation in that repository (or any
subdirectory of it) will include the file in the system prompt.
Re-running `--init-instructions` is safe: it refuses to overwrite an existing file.
## File Discovery
Coyote walks up from the current directory. In each directory it checks the file chain **in order** and injects the
first non-empty match:
1. `COYOTE.md` — Coyote-native
2. `AGENTS.md` — the [cross-tool agent instructions standard](https://agents.md) (Codex, opencode, Cline, and others)
3. `CLAUDE.md` — [Claude Code's](https://code.claude.com/docs/en/memory) instructions file
4. `GEMINI.md` — [Gemini CLI's](https://github.com/google-gemini/gemini-cli) context file
This means a repository that only ships an `AGENTS.md` or `CLAUDE.md` gives Coyote full project context with zero
configuration. A file closer to your working directory wins over a higher-priority file name further up the tree, so
a package-level `CLAUDE.md` beats a repo-root `COYOTE.md` when you launch Coyote inside that package.
Empty files are skipped, so an empty `COYOTE.md` will not shadow a real `AGENTS.md` next to it.
## What Gets Injected
The file content is injected **read-only and in full** as its own system prompt section:
```xml
<workspace_instructions source="/path/to/project/COYOTE.md">
# Project Instructions
...
</workspace_instructions>
```
There is no truncation cap. If the file exceeds ~24,000 characters Coyote logs a warning suggesting you move detail
into [Memory](Memory) drill files, but still injects everything. Keep instructions lean: hard rules and orientation
belong here; voluminous reference material belongs in the memory wiki where the LLM fetches it on demand (see the
`iwe-knowledge-base` skill for structural navigation of large corpora).
The LLM is never given tools to edit instructions files. They are yours.
## Configuration
In the global `config.yaml`:
```yaml
workspace_instructions: null # null/true = inject when a file exists; false = never inject
workspace_instructions_files: null # Custom file chain, in priority order.
# Default: [COYOTE.md, AGENTS.md, CLAUDE.md, GEMINI.md]
```
Reorder or drop fallbacks by setting a custom chain:
```yaml
# Only ever read the Coyote-native file
workspace_instructions_files: [COYOTE.md]
# Prefer AGENTS.md over COYOTE.md
workspace_instructions_files: [AGENTS.md, COYOTE.md]
```
## CLI Flags
| Flag | Effect |
|---------------------------------------|------------------------------------------------------------------------|
| `--init-instructions` | Scaffold a `COYOTE.md` in the current directory |
| `--no-workspace-instructions` | Skip instructions injection for this invocation |
| `--workspace-instructions-file NAME` | Override the file chain for this invocation (repeatable, priority order) |
The override flag is handy for previewing what other tools see:
```bash
# What would Claude Code's context look like here?
coyote --workspace-instructions-file CLAUDE.md --dry-run 'hello'
```
Verify what is being picked up with `coyote --info`, which reports the resolved `workspace_instructions_file`.
## Relationship to Other Tools' Conventions
| Tool | Instructions file | Coyote reads it? |
|-------------|--------------------------|------------------------------|
| Coyote | `COYOTE.md` | ✅ (first priority) |
| Codex CLI | `AGENTS.md` | ✅ (second priority) |
| opencode | `AGENTS.md` | ✅ (second priority) |
| Claude Code | `CLAUDE.md` | ✅ (third priority) |
| Gemini CLI | `GEMINI.md` | ✅ (fourth priority) |
| Cursor | `.cursor/rules/*.mdc` | ❌ |
Unlike Claude Code, Coyote does not concatenate instruction files from every ancestor directory, support `@path`
imports, or load nested files on demand. The first match wins. The [Memory](Memory) system's eagerly-injected index
plus on-demand drill files (navigable with IWE graph tools) covers those use cases with better token economics: put a
pointer in the index ("working in `packages/frontend/`? read `[[frontend-conventions]]`") instead of scattering
instruction files.
## See Also
- [Memory](Memory): agent-curated persistent memory
- [Skills](Skills): modular knowledge and capability packs
- [Roles](Roles): model behavior customization
- [Environment Variables](Environment-Variables): includes `COYOTE_WORKSPACE_CONFIG_DIR` for cross-tool config dirs
+3
@@ -50,6 +50,9 @@
- [Structured Mode](Memory#structured-mode) - [Structured Mode](Memory#structured-mode)
- [Tools](Memory#tools) - [Tools](Memory#tools)
- [Toggles](Memory#toggles) - [Toggles](Memory#toggles)
- [Workspace Instructions](Workspace-Instructions)
- [File Discovery](Workspace-Instructions#file-discovery)
- [Configuration](Workspace-Instructions#configuration)
- [RAG](RAG) - [RAG](RAG)
- [Macros](Macros) - [Macros](Macros)
- [Roles](Roles) - [Roles](Roles)