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.
- **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
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.
* [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]`.
* [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.
* [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.
+16 -5
@@ -42,16 +42,27 @@ Every server entry **must** include a `"type"` field set to one of: `"stdio"`, `
## 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 the current directory at startup. This lets you ship project-specific MCP servers alongside your code without
touching your global configuration.
In addition to the global `functions/mcp.json`, Coyote automatically loads a workspace-local MCP config at startup.
This lets you ship project-specific MCP servers alongside your code without 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>/
── .coyote/
└── mcp.json # same format as functions/mcp.json
── .coyote/
└── 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
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.
+12 -15
@@ -10,25 +10,24 @@ The fastest path is the bootstrap command:
# Workspace memory (per-project)
cd /path/to/your/project
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)
coyote --init-memory global
# → 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
# Project Memory
# Workspace Memory Index
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`.
@@ -40,12 +39,11 @@ That's it for "lite mode." For structured memory, see below.
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)
- **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
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.
Memory is **opt-in by workspace**: coyote walks up from your current directory looking for a
`.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).
### Git-Repo Auto-Bootstrap
@@ -78,7 +76,7 @@ without needing tools.
## Structured Mode
For non-trivial memory, use the structured layout:
Workspace memory always uses the structured layout:
```
<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
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)`:
- **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).
@@ -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)
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,
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
[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
- [Workspace Instructions](Workspace-Instructions): human-curated project instructions (`COYOTE.md`/`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`/etc.)
- [Sessions](Sessions): per-conversation state
- [Skills](Skills): modular knowledge packs
- [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)
- [Tools](Memory#tools)
- [Toggles](Memory#toggles)
- [Workspace Instructions](Workspace-Instructions)
- [File Discovery](Workspace-Instructions#file-discovery)
- [Configuration](Workspace-Instructions#configuration)
- [RAG](RAG)
- [Macros](Macros)
- [Roles](Roles)