docs: Document macros as first class custom commands
+1
-1
@@ -36,7 +36,7 @@ Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration g
|
|||||||
* [Create Custom Bash Tools](Custom-Bash-Tools)
|
* [Create Custom Bash Tools](Custom-Bash-Tools)
|
||||||
* [Bash Prompt Utilities](Bash-Prompt-Helpers)
|
* [Bash Prompt Utilities](Bash-Prompt-Helpers)
|
||||||
* [First-Class MCP Server Support](MCP-Servers): Easily connect and interact with MCP servers for advanced functionality.
|
* [First-Class MCP Server Support](MCP-Servers): Easily connect and interact with MCP servers for advanced functionality.
|
||||||
* [Macros](Macros): Automate repetitive tasks and workflows with Coyote "scripts" (macros).
|
* [Macros](Macros): Automate repetitive tasks and workflows with Coyote "scripts" (macros), and invoke them as your own custom REPL commands.
|
||||||
* [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]`.
|
||||||
|
|||||||
+134
-16
@@ -1,8 +1,15 @@
|
|||||||
Macros are essentially Coyote "scripts"; that is, a predefined sequence of REPL commands that automate repetitive tasks or
|
Macros are essentially Coyote "scripts"; that is, a predefined sequence of REPL commands that automate repetitive tasks or
|
||||||
workflows. Macros run in isolated environments, ensuring that the macros don't inherit any pre-existing role, session,
|
workflows. They are also Coyote's **custom commands**: any enabled macro can be invoked directly from the REPL as a
|
||||||
RAG, or agent state, and they will not affect your current context.
|
top-level dot-command, exactly like a built-in.
|
||||||
|
|
||||||
This isolation ensures that your workspace remains clean and unaffected by macro operations.
|
```shell
|
||||||
|
ollama:gemma4:26b)> .generate-commit-message
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, macros run in isolated environments, ensuring that the macros don't inherit any pre-existing role, session,
|
||||||
|
RAG, or agent state, and they will not affect your current context. This isolation ensures that your workspace remains
|
||||||
|
clean and unaffected by macro operations. Macros that *should* affect your context can opt out of isolation with
|
||||||
|
[`isolated: false`](#isolation).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -10,25 +17,45 @@ For more information on Coyote's REPL, refer to the [REPL](REPL) documentation.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Invoking Macros
|
||||||
|
There are three equivalent ways to run a macro:
|
||||||
|
|
||||||
|
| Invocation | Notes |
|
||||||
|
|-------------------------------|----------------------------------------------------------------------------------------------------|
|
||||||
|
| `.<name> [args...]` | Top-level custom command. Built-in commands always win a name collision (see [Naming rules](#naming-rules)) |
|
||||||
|
| `.macro <name> [args...]` | Explicit form. Also the escape hatch for macros whose names are shadowed by a built-in command |
|
||||||
|
| `coyote --macro <name> [args...]` | From the shell, without entering the REPL |
|
||||||
|
|
||||||
|
Tab completion knows about your macros: `.<tab>` offers enabled macros (with their `description`) alongside the built-in
|
||||||
|
commands, and `.macro <tab>` completes macro names, descriptions, and the `enable`/`disable` subcommands.
|
||||||
|
|
||||||
|
Running `.macro <name>` with a name that doesn't exist (and no arguments) starts the interactive macro creator.
|
||||||
|
|
||||||
# Macro Definition
|
# Macro Definition
|
||||||
Macros are defined as YAML files in the `macros` subdirectory of your Coyote configuration directory. The Coyote configuration
|
Macros are defined as YAML files in the `macros` subdirectory of your Coyote configuration directory. The Coyote configuration
|
||||||
directory can vary between systems, so to find the location of your macros config directory, you can use the following
|
directory can vary between systems, so to find the location of your macros config directory, you can use the following
|
||||||
command:
|
command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
coyote --info | grep 'macros_dir' | awk '{print $2}'
|
coyote --info | grep 'macros_dir' | awk '{print $2}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Macro definitions are broken into two parts: the `steps` of the macro, and an optional `variables` section that lets
|
A macro definition has four parts, all but `steps` optional:
|
||||||
users pass in variables to alter the behavior of the macro at runtime.
|
|
||||||
|
* `description` (Optional): A short description of what the macro does. Shown in `.list macros` and in tab completion.
|
||||||
|
* `isolated` (Optional, Boolean): Whether the macro runs on a forked, throwaway context (`true`, the default) or directly
|
||||||
|
on your live context (`false`). See [Isolation](#isolation).
|
||||||
|
* `variables` (Optional): Positional runtime arguments. See [Macro Variables](#macro-variables).
|
||||||
|
* `steps` (Required): The commands to run.
|
||||||
|
|
||||||
## Step Definitions
|
## Step Definitions
|
||||||
The step definitions for a macro are straightforward: They are simply the exact commands you would otherwise type in the
|
The step definitions for a macro are straightforward: They are simply the exact commands you would otherwise type in the
|
||||||
REPL.
|
REPL.
|
||||||
|
|
||||||
**Example: Macro to generate a git commit message**
|
**Example: Macro to generate a git commit message**
|
||||||
`macros/generate-commit-message.yaml`
|
`macros/generate-commit-message.yaml`
|
||||||
```yaml
|
```yaml
|
||||||
|
description: Generate a git commit message from the current diff
|
||||||
steps:
|
steps:
|
||||||
- .file `git diff` -- generate git commit message
|
- .file `git diff` -- generate git commit message
|
||||||
```
|
```
|
||||||
@@ -39,13 +66,17 @@ $ coyote --macro generate-commit-message
|
|||||||
Add documentation on macros
|
Add documentation on macros
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Note:** A step is a plain YAML string. If a step contains a colon followed by a space (`: `), YAML will parse the
|
||||||
|
> list item as a map and the macro will fail to load (it shows as `invalid` in `.list macros`). Quote the step or use a
|
||||||
|
> block scalar (`- >-`) to avoid this.
|
||||||
|
|
||||||
For a full example configuration, refer to the [example macro configuration file](https://github.com/Dark-Alex-17/coyote/blob/main/config.macro.example.yaml) in the root of this project.
|
For a full example configuration, refer to the [example macro configuration file](https://github.com/Dark-Alex-17/coyote/blob/main/config.macro.example.yaml) in the root of this project.
|
||||||
|
|
||||||
## Macro Variables
|
## Macro Variables
|
||||||
Sometimes it's useful to be able to modify the behavior of a macro at runtime. This is achieved with the `variables`
|
Sometimes it's useful to be able to modify the behavior of a macro at runtime. This is achieved with the `variables`
|
||||||
array of the macro definition.
|
array of the macro definition.
|
||||||
|
|
||||||
To pass variables to a macro, since they are just Coyote scripts, the syntax is the same as it is for any other scripting
|
To pass variables to a macro, since they are just Coyote scripts, the syntax is the same as it is for any other scripting
|
||||||
language: You just pass them alongside your invocation.
|
language: You just pass them alongside your invocation.
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
@@ -54,12 +85,12 @@ $ coyote --macro example-variable-macro first_argument second_argument
|
|||||||
```
|
```
|
||||||
|
|
||||||
Each variable in the `variables` array has the following properties:
|
Each variable in the `variables` array has the following properties:
|
||||||
* `name` (Required): the name of the variable, which can be referenced in the actual steps of the macro using the
|
* `name` (Required): the name of the variable, which can be referenced in the actual steps of the macro using the
|
||||||
`{{name}}` syntax.
|
`{{name}}` syntax.
|
||||||
* `default` (Optional): A default value for the variable if no value is specified. If no default value is defined, and
|
* `default` (Optional): A default value for the variable if no value is specified. If no default value is defined, and
|
||||||
no value is provided for the variable at runtime, Coyote will error out.
|
no value is provided for the variable at runtime, Coyote will error out.
|
||||||
* `rest` (Optional, Boolean): When set to `true`, this variable will collect all remaining arguments passed to the
|
* `rest` (Optional, Boolean): When set to `true`, this variable will collect all remaining arguments passed to the
|
||||||
macro. This behavior is only applicable when the variable is the last variable in the list. By default, this is
|
macro. This behavior is only applicable when the variable is the last variable in the list. By default, this is
|
||||||
`false`.
|
`false`.
|
||||||
|
|
||||||
The `variables` array is order-dependent; that is to say that all arguments passed to the macro are positional. So be
|
The `variables` array is order-dependent; that is to say that all arguments passed to the macro are positional. So be
|
||||||
@@ -86,9 +117,96 @@ $ coyote --macro invoke-agent sql What tables are available?
|
|||||||
|
|
||||||
For a full example configuration, refer to the [example macro configuration file](https://github.com/Dark-Alex-17/coyote/blob/main/config.macro.example.yaml) in the root of this project.
|
For a full example configuration, refer to the [example macro configuration file](https://github.com/Dark-Alex-17/coyote/blob/main/config.macro.example.yaml) in the root of this project.
|
||||||
|
|
||||||
|
# Isolation
|
||||||
|
The `isolated` field controls where a macro's steps execute:
|
||||||
|
|
||||||
|
* **`isolated: true` (default):** Steps run on a forked, throwaway copy of your context. Nothing the macro does (e.g. role
|
||||||
|
switches, model changes, RAG activation, etc.) leaks back into your live context, and the macro's exchanges are not
|
||||||
|
recorded in your active session.
|
||||||
|
* **`isolated: false`:** Steps run directly on your **live** context, exactly as if you had typed each command yourself.
|
||||||
|
The exchanges are recorded in your active session and the conversation continues from them.
|
||||||
|
|
||||||
|
Non-isolated macros are the right tool when the *point* of the macro is to change your context; e.g. a `.standup` macro
|
||||||
|
that switches roles, loads a RAG, and asks a kickoff question. Be aware of the consequences:
|
||||||
|
|
||||||
|
* **Mutations persist by design.** If a non-isolated macro runs `.role reviewer`, you are still in the `reviewer` role
|
||||||
|
after it finishes.
|
||||||
|
* **Steps are fail-fast.** If a step errors, the remaining steps are skipped, but the effects of the steps that already
|
||||||
|
ran remain.
|
||||||
|
* **Nested macros are rejected.** A macro invoked by a non-isolated macro's step is an error. (An *isolated* macro's
|
||||||
|
step may invoke a non-isolated macro; it simply runs on the fork and cannot touch your live context.)
|
||||||
|
* **Agent sessions engage normally.** In an isolated macro, an agent's `use_agent` session is suppressed (the forked
|
||||||
|
context has nothing to return to). In a non-isolated macro, `.agent <name>` behaves exactly as if you typed it.
|
||||||
|
* `.exit` in a macro step does not exit the REPL (it applies to the macro's own scope).
|
||||||
|
|
||||||
|
# Workspace Macros
|
||||||
|
In addition to your global macros directory, Coyote loads macros from `.coyote/macros/` in the current working
|
||||||
|
directory. This lets a project ship its own custom commands, (e.g. `.review-work` macro tailored to one repo),
|
||||||
|
that are only available when you run Coyote from that project.
|
||||||
|
|
||||||
|
* A workspace macro with the same name as a global macro **shadows** it; `.list macros` shows both, with a `source`
|
||||||
|
column telling you which one is the invocation target.
|
||||||
|
* The `--no-workspace-macros` CLI flag disables workspace macro loading entirely (this is a CLI flag only, not a config
|
||||||
|
file key, mirroring `--no-workspace-mcp`).
|
||||||
|
|
||||||
|
# Scoping With `enabled_macros`
|
||||||
|
Which macros are available can be controlled per context with the `enabled_macros` setting, mirroring
|
||||||
|
[`enabled_skills`](Skills#scoping). It can be set at four levels:
|
||||||
|
|
||||||
|
* **Global** (`config.yaml`): the default-active set. Also settable via the `COYOTE_ENABLED_MACROS` environment variable
|
||||||
|
and adjustable at runtime with `.set enabled_macros` or `.macro enable|disable`.
|
||||||
|
* **Role** (frontmatter), **Agent** (agent config), and **Session**: restrict the set for that context.
|
||||||
|
|
||||||
|
The rules:
|
||||||
|
|
||||||
|
* **Most-specific wins:** `session > agent > role > global`. The first level that sets `enabled_macros` decides the
|
||||||
|
entire set; the lists are not merged.
|
||||||
|
* **Unset means all:** A level that doesn't set `enabled_macros` falls through to the next. If no level sets it, every
|
||||||
|
installed macro is enabled.
|
||||||
|
* **An empty list means none:** `enabled_macros: []` disables all macros for that context.
|
||||||
|
* Global config, role frontmatter, and sessions accept either a YAML list or a comma-separated string
|
||||||
|
(`enabled_macros: standup,review-work`); agent configs accept the list form.
|
||||||
|
* Graph agents ignore `enabled_macros` (a `graph.yaml` entry is silently ignored, like other unknown keys).
|
||||||
|
* Unlike `enabled_skills`, an `enabled_macros` name that doesn't match any installed macro is **not** an error, but rather is
|
||||||
|
logged and shown as `missing` in `.list macros`. Macros are meant to be freely shared and edited, so a dangling name
|
||||||
|
shouldn't stop Coyote from starting.
|
||||||
|
|
||||||
|
# Managing Macros at Runtime
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|------------------------------|----------------------------------------------------------------------------------------------|
|
||||||
|
| `.macro enable <name>` | Add a single macro to the global enabled list |
|
||||||
|
| `.macro disable <name>` | Remove a single macro from the global enabled list |
|
||||||
|
| `.set enabled_macros <csv\|null>` | Replace the whole global list (`null` clears it, re-enabling everything) |
|
||||||
|
| `.list macros` | List every macro with its source, isolation, state, and description |
|
||||||
|
|
||||||
|
Like `.set`, these adjust the in-memory global configuration; update `config.yaml` to persist them. Because they edit the
|
||||||
|
*global* level, they cannot override a role/agent/session `enabled_macros` allowlist. If one is active, the toggle
|
||||||
|
errors and names the config you'd need to edit instead. Disabling a macro when no global list is set materializes the
|
||||||
|
list as "every installed macro except this one."
|
||||||
|
|
||||||
|
The `state` column of `.list macros` tells you exactly why a macro is or isn't invocable:
|
||||||
|
|
||||||
|
| State | Meaning |
|
||||||
|
|----------------------|------------------------------------------------------------------------------------------------------|
|
||||||
|
| `enabled` | Visible and invocable |
|
||||||
|
| `disabled (runtime)` | Excluded at the global level; re-enable with `.macro enable <name>` |
|
||||||
|
| `locked` | Excluded by a role/agent/session `enabled_macros` list (the owning config is shown); edit that config |
|
||||||
|
| `missing` | Named in an `enabled_macros` list but not installed |
|
||||||
|
| `shadowed (built-in)`| The name collides with a built-in command; invocable only via `.macro <name>` |
|
||||||
|
| `invalid` | The definition file failed to parse (the reason is shown), or the name is reserved |
|
||||||
|
|
||||||
|
# Naming Rules
|
||||||
|
The macro's file name is its command name. Two constraints:
|
||||||
|
|
||||||
|
* **`enable` and `disable` are reserved** (they are `.macro` subcommands); a macro with either name shows as `invalid`.
|
||||||
|
* **Built-in commands always win.** A macro named after a built-in command (e.g. `model.yaml`) is never dispatched at
|
||||||
|
the top level; `.model` runs the built-in. The macro remains reachable via `.macro model`, and `.list macros` shows
|
||||||
|
it as `shadowed (built-in)`.
|
||||||
|
|
||||||
# Built-In Macros
|
# Built-In Macros
|
||||||
Coyote comes packaged with some useful built-in macros. These are also good examples if you're looking for more examples
|
Coyote comes packaged with some useful built-in macros. These are also good examples if you're looking for more examples
|
||||||
on how to make your own macros, so be sure to check out the [built-in macro definitions](https://github.com/Dark-Alex-17/coyote/blob/main/assets/macros) if you're
|
on how to make your own macros, so be sure to check out the [built-in macro definitions](https://github.com/Dark-Alex-17/coyote/blob/main/assets/macros) if you're
|
||||||
looking for more examples.
|
looking for more examples.
|
||||||
|
|
||||||
* `generate-commit-message` - Generate a Git commit message based on the staged changes in the current directory
|
* `generate-commit-message` - Generate a Git commit message based on the staged changes in the current directory
|
||||||
|
|||||||
+20
-4
@@ -12,10 +12,12 @@ things like
|
|||||||
* **Tab Autocompletion:** Every command in the REPL (i.e. everything that starts with a `.`) has fuzzy search auto
|
* **Tab Autocompletion:** Every command in the REPL (i.e. everything that starts with a `.`) has fuzzy search auto
|
||||||
completions.
|
completions.
|
||||||
* `.<tab>` to complete REPL commands
|
* `.<tab>` to complete REPL commands
|
||||||
|
* `.<tab>` also offers enabled [macros](Macros) (with their descriptions) as top-level custom commands
|
||||||
* `.model <tab>` to complete chat models
|
* `.model <tab>` to complete chat models
|
||||||
* `.set <tab>` to complete configuration keys
|
* `.set <tab>` to complete configuration keys
|
||||||
* `.set key <tab>` to complete configuration values
|
* `.set key <tab>` to complete configuration values
|
||||||
* `.mcp auth <tab>` to complete remote MCP server names
|
* `.mcp auth <tab>` to complete remote MCP server names
|
||||||
|
* `.macro <tab>` to complete macro names and the `enable`/`disable` subcommands
|
||||||
* **Multi-Line Prompts:** You can also type prompts that span more than one line to help organize your thoughts. This
|
* **Multi-Line Prompts:** You can also type prompts that span more than one line to help organize your thoughts. This
|
||||||
can be done in the following ways:
|
can be done in the following ways:
|
||||||
* `Ctrl-o` to open the current input buffer in your preferred editor (either the value of `editor` or `$EDITOR`)
|
* `Ctrl-o` to open the current input buffer in your preferred editor (either the value of `editor` or `$EDITOR`)
|
||||||
@@ -159,10 +161,23 @@ complete tasks using the documents as additional context.
|
|||||||
|
|
||||||
For more information about RAG in Coyote and how to utilize it, refer to the [rag documentation](RAG).
|
For more information about RAG in Coyote and how to utilize it, refer to the [rag documentation](RAG).
|
||||||
|
|
||||||
## `.macro` - Execute a macro
|
## `.macro` - Execute or manage a macro
|
||||||
Macros in Coyote are like "scripts" of commands that can be run in isolated environments; that means they do not use any
|
Macros in Coyote are like "scripts" of commands and they double as Coyote's **custom commands**: any enabled macro can
|
||||||
active settings and use the same settings they had when written. They are created/executed using the `.macro <name>`
|
be invoked directly as a top-level command (`.my-macro args`), with tab completion alongside the built-ins. By default
|
||||||
command.
|
macros run in isolated environments (they don't use any active settings and can't affect your current context), but a
|
||||||
|
macro can opt onto your live context with `isolated: false` in its definition.
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---------------------------|-----------------------------------------------------------------------------------------|
|
||||||
|
| `.<name> [args...]` | Run an enabled macro as a top-level custom command (built-in commands win name collisions) |
|
||||||
|
| `.macro <name> [args...]` | Run a macro explicitly; also works for macros shadowed by a built-in command's name |
|
||||||
|
| `.macro <name>` | If `<name>` doesn't exist, starts the interactive macro creator |
|
||||||
|
| `.macro enable <name>` | Add a single macro to the global enabled list |
|
||||||
|
| `.macro disable <name>` | Remove a single macro from the global enabled list |
|
||||||
|
|
||||||
|
Availability is scoped with `enabled_macros` (global/role/agent/session, most-specific wins) and macros can also be
|
||||||
|
loaded per-project from `.coyote/macros/` in the working directory. `.list macros` shows every macro's source, isolation,
|
||||||
|
and state.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -303,6 +318,7 @@ The following settings can be adjusted at runtime:
|
|||||||
| `enabled_tools` | string | Comma-separated list of enabled tools (e.g. `fs_ls,fs_cat` or `all`); the saved YAML config also accepts a list form |
|
| `enabled_tools` | string | Comma-separated list of enabled tools (e.g. `fs_ls,fs_cat` or `all`); the saved YAML config also accepts a list form |
|
||||||
| `enabled_mcp_servers` | string | Comma-separated list of enabled MCP servers (e.g. `github,slack` or `all`); the saved YAML config also accepts a list form |
|
| `enabled_mcp_servers` | string | Comma-separated list of enabled MCP servers (e.g. `github,slack` or `all`); the saved YAML config also accepts a list form |
|
||||||
| `enabled_skills` | string | Comma-separated list of enabled [skills](Skills) (e.g. `git-master,ai-slop-remover`); `null` clears the override |
|
| `enabled_skills` | string | Comma-separated list of enabled [skills](Skills) (e.g. `git-master,ai-slop-remover`); `null` clears the override |
|
||||||
|
| `enabled_macros` | string | Comma-separated list of enabled [macros](Macros) at the global level (e.g. `standup,review-work`); `null` clears the list, re-enabling all macros |
|
||||||
| `save_session` | boolean | Whether to auto-save sessions |
|
| `save_session` | boolean | Whether to auto-save sessions |
|
||||||
| `compression_threshold` | integer | Token threshold for session compression |
|
| `compression_threshold` | integer | Token threshold for session compression |
|
||||||
| `compression_keep_last` | integer | Number of recent messages kept visible after compression; `0` (default) compresses all messages |
|
| `compression_keep_last` | integer | Number of recent messages kept visible after compression; `0` (default) compresses all messages |
|
||||||
|
|||||||
Reference in New Issue
Block a user