diff --git a/Home.md b/Home.md index 4a50701..84598d0 100644 --- a/Home.md +++ b/Home.md @@ -23,7 +23,7 @@ Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration g * [AIChat Migration Guide](AIChat-Migration): Coming from AIChat? Follow the migration guide to get started. * [Installation](Installation): Install Coyote * [Getting Started](Getting-Started): Get started with Coyote by doing first-run setup steps, and learn the basics. -* [Sharing Configurations](Sharing-Configurations): Install bundles of agents, roles, macros, tools, and MCP servers from any git repo, and share your own. +* [Sharing Configurations](Sharing-Configurations): Install bundles of agents, roles, macros, tools, and MCP servers from any git repo, and share your own. Bundles are Coyote's equivalent of plugins in other CLI agents. * [REPL](REPL): Interactive Read-Eval-Print Loop for conversational interactions with LLMs and Coyote. * [Custom REPL Prompt](REPL-Prompt): Customize the REPL prompt to provide useful contextual information. * [Vault](Vault): Securely store and manage sensitive information such as API keys and credentials. diff --git a/REPL.md b/REPL.md index cfaad06..7a6de33 100644 --- a/REPL.md +++ b/REPL.md @@ -398,6 +398,7 @@ The `.list` command lists the assets of a given kind, making them discoverable w | `.list agents` | List installed agents, with their descriptions when available | | `.list rags` | List all RAGs | | `.list macros` | List all macros | +| `.list bundles` | List installed bundles with their source, version, ref pin, and drift status (see [Sharing Configurations](Sharing-Configurations)) | | `.list skills` | List skills available in this context, with descriptions and a `(loaded)` marker for active skills | | `.list tools` | List the tools that can be enabled/disabled via `.tool [enable\|disable] ` (excludes internal tools; in an agent context, lists the agent's tool pool) | | `.list mcp-servers` | List the MCP servers that can be enabled/disabled via `.mcp [enable\|disable] ` (configured servers plus mapping aliases) | @@ -418,7 +419,8 @@ when an update ships improved built-ins you want to adopt. | `.install functions` | Reinstall the built-in tool functions (leaves your `mcp.json` alone) | | `.install mcp_config` | Merge new bundled MCP servers into `mcp.json` (existing servers are preserved) | -The same operation is available from the command line: `coyote --install ` (e.g. `coyote --install agents`). +The same operation is available from the command line: `coyote --install-builtins ` (e.g. +`coyote --install-builtins agents`). `.install` prompts for confirmation before overwriting anything. Assets you created yourself are never touched. Only Coyote's own bundled assets are replaced. @@ -427,23 +429,43 @@ Coyote's own bundled assets are replaced. present in your file are added; your existing servers and any custom secret references are left untouched. This behaves consistently with the other install categories, which also leave your own customizations alone. -## `.install remote` - Install assets from a git repository +## `.install ` - Install and update bundles -The `.install remote` command installs agents, roles, macros, tools, and MCP servers from any git repository whose -layout mirrors Coyote's user config directory. This is the primary mechanism for sharing and reusing Coyote configurations. +Besides category names, `.install` accepts a git source or an installed bundle's name. It installs agents, roles, +skills, macros, tools, and MCP servers from any git repository whose layout mirrors Coyote's user config directory. +This is the primary mechanism for sharing and reusing Coyote configurations; an installed repo is tracked as a +**bundle** you can list, update, and uninstall. -| Command | Description | -|-------------------------------------------------|-------------------------------------------------------------------------------------| -| `.install remote ` | Install everything the repo provides | -| `.install remote #` | Pin to a tag, branch, or commit (e.g. `#v1.0.0`, `#main`) | -| `.install remote --filter ` | Restrict to one of `agents`, `roles`, `skills`, `macros`, `functions`, `mcp_config` | -| `.install remote --force` | Skip all conflict prompts; overwrite local files unconditionally | +| Command | Description | +|------------------------------------------|-------------------------------------------------------------------------------------| +| `.install ` | Install everything the repo provides | +| `.install /` | Shorthand; expands to `https://github.com//` | +| `.install / --git-host ` | Expand the shorthand against a different git host | +| `.install #` | Pin to a tag, branch, or commit (e.g. `#v1.0.0`, `#main`) | +| `.install --filter ` | Restrict to one of `agents`, `roles`, `skills`, `macros`, `functions`, `mcp_config` | +| `.install --force` | Skip all conflict prompts; overwrite local files unconditionally | +| `.install ` | Update an installed bundle from its recorded source | -The CLI equivalent is `coyote --install-from ` (with `--filter` and `--install-force` accepting the same values). +The CLI equivalent is `coyote --install ` (with `--git-host`, `--filter`, and `--install-force` +accepting the same values). Use `.list bundles` to see what's installed and `.uninstall ` to remove a bundle. See [Sharing Configurations](Sharing-Configurations) for the expected repo layout, conflict resolution, secret handling, and the [coyote-config-template](https://github.com/Dark-Alex-17/coyote-config-template) starter you can fork. +## `.uninstall` - Uninstall a bundle + +The `.uninstall` command removes a bundle installed with `.install`: it deletes the files the bundle owns, removes the +`mcp.json` entries it added, and drops its record. Files you've modified locally are kept unless you confirm their +deletion, and anything the bundle never owned is left untouched. + +| Command | Description | +|----------------------------|------------------------------------------------------------------------------| +| `.uninstall ` | Uninstall by bundle name (see `.list bundles`) | +| `.uninstall ` | Uninstall by the source URL the bundle was installed from | +| `.uninstall /`| Match against recorded sources; multiple matches show an interactive selector | + +The CLI equivalent is `coyote --uninstall ` (add `--yes` to skip confirmation prompts). + ## `.update` - Update Coyote The `.update` command updates the Coyote binary itself to the latest release, diff --git a/Sharing-Configurations.md b/Sharing-Configurations.md index b234c24..fb32529 100644 --- a/Sharing-Configurations.md +++ b/Sharing-Configurations.md @@ -1,18 +1,24 @@ -Coyote ships with a built-in mechanism for installing and sharing configurations (i.e. agents, roles, macros, tools, and -MCP servers) directly from any git repository. This makes it easy to: +Coyote ships with a built-in mechanism for installing and sharing configurations (i.e. agents, roles, skills, macros, +tools, and MCP servers) directly from any git repository. A shareable repository is called a **bundle**; bundles are +Coyote's equivalent of plugins in other CLI agents. Bundles make it easy to: - Sync your Coyote setup across multiple machines. - Share your work with teammates or the community. - Bootstrap a new install with a curated set of assets. - Pin to specific versions for reproducibility. -The relevant commands: +Coyote tracks every bundle it installs, so bundles have a full lifecycle: -- CLI: `coyote --install-from ` -- REPL: `.install remote ` +| Action | CLI | REPL | +|-----------------------|-----------------------------------------|----------------------| +| Install or update | `coyote --install ` | `.install ` | +| List installed | `coyote --list-bundles` | `.list bundles` | +| Update from source | `coyote --update-bundle ` | | +| Uninstall | `coyote --uninstall [--yes]` | `.uninstall ` | +| Reinstall built-ins | `coyote --install-builtins ` | `.install `| -This page covers the expected repository layout, command-line flags, conflict resolution, secrets handling, and how to -publish your own shareable bundle. +This page covers the expected repository layout, bundle identity, provenance tracking, conflict resolution, secrets +handling, and how to publish your own bundle. To see a template repository with all recognized categories, see the [coyote-config-template](https://github.com/Dark-Alex-17/coyote-config-template) repository. @@ -21,21 +27,29 @@ To see a template repository with all recognized categories, see the ## Quick start -Install everything from a remote repo: +Install everything from a GitHub repo using `owner/repo` shorthand: ```sh -coyote --install-from https://github.com/Dark-Alex-17/coyote-config-template +coyote --install someuser/oh-my-coyote +``` + +Coyote expands the shorthand against `github.com` (printing `Resolved 'someuser/oh-my-coyote' to +'https://github.com/someuser/oh-my-coyote'`), clones the repo to a temp directory, scans for recognized asset +categories, and installs each into the matching subdirectory of your user config. The temp clone is removed on +completion, and the install is recorded in the bundle store so you can list, update, and uninstall it later. + +Full URLs work everywhere shorthand does: + +```sh +coyote --install https://github.com/someuser/oh-my-coyote ``` or from inside the Coyote REPL: ``` -.install remote https://github.com/Dark-Alex-17/coyote-config-template +.install someuser/oh-my-coyote ``` -That's it. Coyote clones the repo to a temp directory, scans for recognized asset categories, and installs each into the -matching subdirectory of your user config. The temp clone is removed on completion. - > ⚠️ **Heads up: Sandbox implications.** If you use [Sandbox mode](Sandboxes) and the bundle includes any > `sbx-mixin.yaml` files, installing it grants those mixins network access and install privileges inside your > sandboxes the next time you `coyote --sandbox`. See [Sandbox Implications](#sandbox-implications) at the bottom of @@ -43,12 +57,100 @@ matching subdirectory of your user config. The temp clone is removed on completi --- +## Install sources + +`--install` accepts one value that Coyote classifies automatically: + +| Value shape | Interpretation | +|--------------------------------------|-----------------------------------------------------------------------| +| `https://...`, `git@host:path`, `file://...`, `./dir`, `/abs`, `~/dir` | A remote source; cloned and installed. | +| `owner/repo` (two or more segments) | Shorthand; expanded to `https:///owner/repo` and installed. | +| An installed bundle's name | The bundle is [updated](#updating-a-bundle) from its recorded source. | +| An asset category (`agents`, ...) | An error pointing you at `--install-builtins ` instead. | +| Anything else | An error listing your installed bundles. | + +Bare names never trigger a clone, so a typo'd bundle name can't silently install something from the network. + +### `owner/repo` shorthand and `--git-host` + +The shorthand defaults to `github.com`. To install from a different host, pass `--git-host`: + +```sh +coyote --install someuser/oh-my-coyote # github.com +coyote --install --git-host git.somedomain.com someuser/oh-my-coyote # self-hosted +coyote --install --git-host gitlab.com group/subgroup/repo # nested groups work +``` + +Details: + +- Shorthand takes **two or more** path segments, so GitLab-style nested subgroups expand correctly. +- Expansion always uses `https://`. For private repos you authenticate over SSH, use the full + `git@host:owner/repo.git` URL instead (see [Git authentication](#git-authentication)). +- `--git-host` requires `--install`, only accepts shorthand values (passing it with a full URL is an error), and + **forces the value to be treated as a source** even if it happens to match an installed bundle's name. +- [Ref pinning](#ref-pinning) works on shorthand: `coyote --install someuser/repo#v1.2.0`. +- The REPL form accepts the same flag: `.install someuser/repo --git-host git.somedomain.com`. + +### Ref pinning + +Pin the install to a specific tag, branch, or commit by appending `#` to the URL or shorthand. + +```sh +coyote --install someuser/repo#v1.2.3 +coyote --install https://github.com//#main +coyote --install https://github.com//#abc1234 +``` + +How Coyote resolves the ref: + +- **Branch or tag names** are passed as `--branch ` to a shallow `git clone --depth 1`. +- **Commit SHAs** (4-40 hex characters) trigger a full clone followed by `git checkout `. + +Validation: refs must match `[A-Za-z0-9._/+-]`, must not start with `-`, and must not contain `..`. These rules prevent +the ref from being interpreted as a CLI flag or escaping the repo via path traversal. + +The pin is recorded with the bundle, and `--update-bundle #` moves it later. + +### Filtering by category + +Restrict an install to a single asset category with `--filter`: + +| Filter | Installs | +|--------------|------------------------------------------------------------------------------------------------| +| *(omitted)* | `agents/`, `roles/`, `skills/`, `macros/`, `functions/tools/`, and merges `functions/mcp.json` | +| `agents` | `agents/` only | +| `roles` | `roles/` only | +| `skills` | `skills/` only | +| `macros` | `macros/` only | +| `functions` | `functions/tools/` only (does **not** include `mcp.json`) | +| `mcp_config` | `functions/mcp.json` only (merged) | + +```sh +coyote --install --filter agents +coyote --install --filter mcp_config +``` + +REPL form: + +``` +.install --filter agents +``` + +Note that `--filter functions` is intentionally narrow. It installs the global tools under `functions/tools/` and +**not** `mcp.json`. To install just the MCP config, use `--filter mcp_config`. To install both, use no filter. + +Repeated filtered installs of the same bundle merge into a single bundle record, and a later +[update](#updating-a-bundle) always processes the whole remote, including categories a filtered install excluded. + +--- + ## Expected repository layout Coyote recognizes these top-level directories. Anything outside them is ignored. ``` / +├── coyote-bundle.yaml # Optional bundle manifest (identity only) ├── agents/ │ └── / # One subdirectory per agent │ ├── config.yaml # LLM-loop agent @@ -71,7 +173,7 @@ Coyote recognizes these top-level directories. Anything outside them is ignored. A few things to note: -- **Missing categories are skipped silently.** A repo that only contains `agents/` installs only agents. This means you +- **Missing categories are skipped silently.** A repo that only contains `agents/` installs only agents. This means you do not need to use `--filter` for partial repos. - **`.git/` is excluded** from the scan automatically. - **Symlinks are rejected** by the install walker as a defense-in-depth measure. @@ -80,53 +182,142 @@ A few things to note: --- -## Ref pinning +## Bundle identity and the manifest -Pin the install to a specific tag, branch, or commit by appending `#` to the URL. +Every installed bundle has a name. By default it's the repository name (the last URL segment, without `.git`), so +`https://github.com/someuser/oh-my-coyote` installs as `oh-my-coyote`. -```sh -coyote --install-from https://github.com//#v1.2.3 -coyote --install-from https://github.com//#main -coyote --install-from https://github.com//#abc1234 +Bundle authors can override this by adding a `coyote-bundle.yaml` manifest to the repository root: + +```yaml +name: oh-my-coyote # required; the bundle's identity +version: "1.4.0" # optional; shown in --list-bundles +description: Opinionated roles, macros, and skills for Coyote +homepage: https://github.com/example/oh-my-coyote # optional ``` -How Coyote resolves the ref: +The manifest is **identity only**. It never declares the bundle's contents; those are always discovered by scanning +the repository, exactly as for a manifest-less repo. -- **Branch or tag names** are passed as `--branch ` to a shallow `git clone --depth 1`. -- **Commit SHAs** (4-40 hex characters) trigger a full clone followed by `git checkout `. +How names are kept unambiguous: -Validation: refs must match `[A-Za-z0-9._/+-]`, must not start with `-`, and must not contain `..`. These rules prevent -the ref from being interpreted as a CLI flag or escaping the repo via path traversal. +- **One source, one record.** Installing the same repository again (by any URL spelling, or via shorthand) updates the + existing record instead of creating a second one. If the repo's manifest name changed since the last install, the + record migrates to the new name and Coyote prints a notice. +- **Cross-source collisions are owner-qualified.** If you install two different repositories that both want the name + `oh-my-coyote`, the second is recorded as `/oh-my-coyote` and Coyote prints a notice. Lifecycle commands + accept the qualified name. --- -## Filtering by category +## Provenance and ownership -Restrict the install to a single asset category with `--filter`: +Coyote records everything an install writes in `installed-bundles.yaml` in your config directory. For each bundle it +tracks the source URL, ref pin, resolved commit, manifest metadata, timestamps, every file written (with its content +hash and category), and every `mcp.json` server entry the merge added, replaced, or renamed (with the hash of the +entry as written). -| Filter | Installs | -|--------------|------------------------------------------------------------------------------------------------| -| *(omitted)* | `agents/`, `roles/`, `skills/`, `macros/`, `functions/tools/`, and merges `functions/mcp.json` | -| `agents` | `agents/` only | -| `roles` | `roles/` only | -| `skills` | `skills/` only | -| `macros` | `macros/` only | -| `functions` | `functions/tools/` only (does **not** include `mcp.json`) | -| `mcp_config` | `functions/mcp.json` only (merged) | +This record is what powers the rest of the lifecycle: + +- **Ownership.** A file belongs to the bundle that wrote its current content. If a later install overwrites a file + another bundle owned, ownership transfers. Files you chose to *keep* during conflict prompts are never claimed. +- **Abort safety.** Provenance is recorded as files are written, so aborting mid-install (e.g. at a conflict prompt) + leaves everything already on disk tracked and uninstallable. +- **Drift detection.** The recorded hashes let `--list-bundles` tell you which files you've modified since install, + and let update/uninstall treat your modified files more carefully than pristine ones. +- **No secrets.** Recorded hashes cover the content as written, and MCP entries are written with their + `{{SECRET}}` placeholders intact, so the store never contains secret material. + +The store is plain YAML and safe to read, but hand-editing it will make Coyote's view of ownership drift from +reality. If it becomes corrupt, Coyote refuses to treat it as empty (that would let a reinstall re-claim files you've +since modified) and reports the parse error instead. + +--- + +## Listing bundles and drift ```sh -coyote --install-from --filter agents -coyote --install-from --filter mcp_config +coyote --list-bundles ``` -REPL form: +or `.list bundles` in the REPL. Output is a table: -``` -.install remote --filter agents +| Column | Meaning | +|-------------|-------------------------------------------------------------------------------------| +| `name` | The bundle's identity (manifest name, repo name, or owner-qualified name). | +| `version` | The manifest `version`, or the short commit hash if the manifest doesn't set one. | +| `source` | The recorded source URL updates are pulled from. | +| `ref` | The `#` pin, or `-` if the install tracked the default branch. | +| `installed` | When the bundle was first installed. | +| `files` | Per-category counts of owned files (e.g. `macros: 3, roles: 2`). | +| `drift` | File status vs. the recorded hashes: `intact`, `modified locally`, and `missing`. | + +Drift statuses: + +- **intact**: the file on disk still matches the content the bundle installed. +- **modified locally**: you've edited the file since install (or it can't be read). +- **missing**: the file was deleted from disk. + +--- + +## Updating a bundle + +```sh +coyote --update-bundle # update from the recorded source +coyote --update-bundle # # also move the ref pin +coyote --install # same thing; installed names dispatch to update ``` -Note that `--filter functions` is intentionally narrow. It installs the global tools under `functions/tools/` and -**not** `mcp.json`. To install just the MCP config, use `--filter mcp_config`. To install both, use no filter. +An update re-clones the recorded source (at the recorded pin unless you move it) and re-runs the install with +provenance-aware conflict handling: + +- **Files the bundle owns that you haven't touched** (hash still matches) are refreshed without prompting. The bundle + wrote that content; bringing it up to date is not a conflict. +- **Files you've modified locally**, and files owned by other bundles, get the normal + [conflict prompts](#conflict-resolution). +- **The whole remote is processed**, including categories a previous `--filter` excluded. +- **Files the remote no longer ships** are reconciled: a file already deleted from disk just drops out of the record; + a file still present is kept by default (you may rely on it) and only deleted if you confirm. Kept files stay in + the record so a later uninstall still offers to remove them. + +`--filter` and `--install-force` do not apply to updates by name; they are flags for remote installs. + +--- + +## Uninstalling a bundle + +```sh +coyote --uninstall +coyote --uninstall --yes # skip confirmation prompts +``` + +or `.uninstall ` in the REPL. The spec can be the bundle name, its source URL, or `owner/repo` shorthand. + +What gets removed: + +- **Owned files whose content still matches the recorded hash** are deleted, and directories left empty by the + deletions are pruned. +- **Owned files you've modified locally** are kept unless you explicitly confirm their deletion at a prompt + (`--yes` does *not* delete them; it only skips confirmations). +- **`mcp.json` entries the bundle added** are removed if unmodified; modified entries prompt like files. Entries that + existed before the bundle replaced them, and keys the bundle never owned, are never touched. +- **The bundle's record** is dropped once nothing it owned remains. If items were kept or a deletion failed, the + record keeps them and re-running `--uninstall` offers them again. + +Not removed: vault secrets the bundle's servers referenced, `enabled_*` config lists that mention its assets, and +compiled tool binaries under `functions/bin/` (those linger until the next `--build-tools` prune; Coyote prints a +note when this applies). + +Uninstalling is confirmation-gated: in a terminal you're shown what the bundle owns and asked to proceed; +non-interactive runs (CI, piped) require `--yes`. + +### Ambiguous `owner/repo` specs + +`--uninstall someuser/oh-my-coyote` resolves in strict priority order: exact bundle name, then exact source URL, then +a match against the recorded sources' trailing path segments. If several bundles were installed from different hosts +under the same `owner/repo` path, Coyote shows an interactive selector listing each candidate as `name (source)` so +you choose exactly which one to remove. There is no auto-picking: non-interactive runs bail and list the candidates +(re-run with the exact bundle name or source URL), and `--yes` never selects on your behalf. --- @@ -134,7 +325,7 @@ Note that `--filter functions` is intentionally narrow. It installs the global t When an install file would overwrite an existing local file with different contents, you have several options. -### Plain files (agents, roles, macros, tools) +### Plain files (agents, roles, skills, macros, tools) In a terminal (TTY), Coyote prompts per conflicting file: @@ -144,12 +335,15 @@ In a terminal (TTY), Coyote prompts per conflicting file: | `replace` | Overwrite with the remote file. | | `keep-all` | Skip this file and all remaining conflicts in this install. | | `replace-all` | Overwrite this file and all remaining conflicts in this install. | -| `abort` | Stop the install. Files already written stay; they are not rolled back. | +| `abort` | Stop the install. Files already written stay; they are not rolled back (and remain tracked in the bundle's record). | To skip prompts and replace everything, pass `--install-force` on the CLI or `--force` in the REPL form. In non-TTY mode (CI, piped, redirected stdin), the install will **abort** rather than silently overwrite. To overwrite non-interactively, you must pass `--install-force`. +During [updates](#updating-a-bundle), files the bundle owns and you haven't modified skip these prompts entirely and +are refreshed in place. + ### Identical content is not a conflict If a remote file's bytes match your local copy exactly, Coyote silently treats it as `identical` and skips it. Re-running @@ -183,6 +377,10 @@ Coyote **merges** the remote `mcp.json` into your existing one. With `--install-force`, every conflict is resolved by taking the remote entry. In non-TTY mode without `--install-force`, the merge aborts before writing. +Entries the merge adds, replaces, or renames are recorded as owned by the bundle (with the hash of the entry as +written), which is how [uninstall](#uninstalling-a-bundle) knows what it may safely remove later. Entries you kept +local are not claimed. + ### Validation Each added, replaced, or renamed entry is validated against the MCP server schema (e.g., `stdio` servers must have a @@ -202,7 +400,7 @@ MCP server entries (and other config files) can reference vault secrets with `{{ install completes, Coyote scans the resulting `mcp.json` for placeholders that are not yet in your vault and either: - **In a TTY:** prompts you, one secret at a time, whether to add it to the vault now. On the first "Yes", Coyote - initializes the vault (if needed; for the Local provider, this just means creating the password file). On "No", the + initializes the vault (if needed; for the Local provider, this just means creating the password file). On "No", the secret is deferred and reported at the end. - **In a non-TTY environment:** skips prompts entirely; lists every missing secret in a final reminder block, with the commands you can run later (`coyote --add-secret ` or `.vault add `). @@ -222,13 +420,28 @@ authentication setup** with no additional configuration: Linux, the GitHub CLI's helper). - **Public HTTPS URLs** require no auth. +Note that `owner/repo` shorthand always expands to an HTTPS URL. If your access to a private repo only works over +SSH, install with the full SSH URL instead. + If `git` is not on your `PATH`, you'll get a clear error message on the first install attempt. --- +## Built-ins are not bundles + +`coyote --install-builtins ` (REPL: `.install `) reinstalls the assets that ship inside the +Coyote binary for one category (`agents`, `roles`, `skills`, `macros`, `functions`, `themes`), **overwriting any local +changes** to those files. Built-in assets are not tracked in the bundle store, don't appear in `--list-bundles`, and +can't be uninstalled; they're part of Coyote itself. + +Passing a category name to `--install` never reinstalls built-ins by accident; it errors and points you at +`--install-builtins` (and, if you also have a bundle by that name, at `--update-bundle`). + +--- + ## Publishing your own bundle -To share your Coyote configuration, structure a git repo like the template above and push it to GitHub, GitLab, your +To share your Coyote configuration, structure a git repo like the layout above and push it to GitHub, GitLab, your self-hosted Forgejo instance, etc. The easiest way to start is to **fork the official template repo**: @@ -237,23 +450,27 @@ asset type plus a `README` describing the customization workflow. ### Best practices -1. **Pin to tagged releases** so consumers can install with `#` for reproducibility. -2. **Keep per-agent logic in `agents//`**. Only put global tools in `functions/tools/`. -3. **Use `{{SECRET}}` placeholders** for any sensitive value in `mcp.json`. Never commit a real API key. -4. **Document expected secrets** in your repo's `README` so users know which vault entries to add. -5. **Avoid name collisions** with Coyote's bundled assets (`agents/code-reviewer`, `agents/sql`, etc.) unless you +1. **Add a `coyote-bundle.yaml`** with a stable `name` and a `version` you bump on releases. This keeps your bundle's + identity stable even if the repo is renamed or forked, and gives installers a meaningful version in + `--list-bundles`. +2. **Pin to tagged releases** so consumers can install with `#` for reproducibility, and move pins deliberately + with `--update-bundle #`. +3. **Keep per-agent logic in `agents//`**. Only put global tools in `functions/tools/`. +4. **Use `{{SECRET}}` placeholders** for any sensitive value in `mcp.json`. Never commit a real API key. +5. **Document expected secrets** in your repo's `README` so users know which vault entries to add. +6. **Avoid name collisions** with Coyote's bundled assets (`agents/code-reviewer`, `agents/sql`, etc.) unless you specifically want to replace them. Pick distinctive names for your shared assets. -6. **Test installs against a clean `COYOTE_CONFIG_DIR`** before publishing. You can use: +7. **Test installs against a clean `COYOTE_CONFIG_DIR`** before publishing. You can use: ```sh - COYOTE_CONFIG_DIR=$(mktemp -d) coyote --install-from file:///path/to/your/clone --install-force + COYOTE_CONFIG_DIR=$(mktemp -d) coyote --install file:///path/to/your/clone --install-force ``` --- ## What is not shared -The following are **intentionally** outside the install-remote feature's scope: +The following are **intentionally** outside the bundle feature's scope: - **`config.yaml`** (the global Coyote config). It holds user-specific things like editor preference, secrets provider configuration, client API keys, OAuth tokens, and similar. Merging a shared `config.yaml` would risk breaking auth or routing @@ -264,54 +481,76 @@ The following are **intentionally** outside the install-remote feature's scope: - **`functions/utils/`:** Utility scripts intentionally not part of the share contract. If a team really needs synced global settings, the recommended approach is dotfiles-style symlinks or a sync tool. -Those are designed for that problem and not for `coyote --install-from`. +Those are designed for that problem and not for `coyote --install`. --- ## Examples -### Install everything from a public repo +### Install from GitHub with shorthand ```sh -coyote --install-from https://github.com/Dark-Alex-17/coyote-config-template +coyote --install someuser/oh-my-coyote +``` + +### Install from a self-hosted git server + +```sh +coyote --install --git-host git.somedomain.com someuser/oh-my-coyote ``` ### Pin to a release tag ```sh -coyote --install-from https://github.com/your-org/coyote-config#v2.4.0 +coyote --install your-org/coyote-config#v2.4.0 ``` ### Install only the agents from a fork ```sh -coyote --install-from https://github.com/your-org/coyote-config --filter agents +coyote --install https://github.com/your-org/coyote-config --filter agents ``` ### Install only the MCP servers, force-replace conflicts ```sh -coyote --install-from https://github.com/your-org/coyote-config --filter mcp_config --install-force +coyote --install https://github.com/your-org/coyote-config --filter mcp_config --install-force +``` + +### See what you have installed, then update one bundle + +```sh +coyote --list-bundles +coyote --update-bundle oh-my-coyote +coyote --update-bundle coyote-config#v2.5.0 # move the pin +``` + +### Uninstall a bundle non-interactively + +```sh +coyote --uninstall oh-my-coyote --yes ``` ### From the REPL ``` -.install remote https://github.com/your-org/coyote-config -.install remote https://github.com/your-org/coyote-config#main --filter agents -.install remote https://github.com/your-org/coyote-config --force +.install your-org/coyote-config +.install https://github.com/your-org/coyote-config#main --filter agents +.install someuser/repo --git-host git.somedomain.com +.list bundles +.uninstall oh-my-coyote ``` ### From a private SSH URL ```sh -coyote --install-from git@github.com:your-org/private-coyote-config.git#v1.0.0 +coyote --install git@github.com:your-org/private-coyote-config.git#v1.0.0 ``` ### From a local file:// URL (testing your own template) ```sh -coyote --install-from file:///home/you/code/my-coyote-config +coyote --install file:///home/you/code/my-coyote-config ``` --- @@ -323,10 +562,28 @@ coyote --install-from file:///home/you/code/my-coyote-config The remote clone failed. Coyote passes git's stderr through verbatim. The most common causes: - **Authentication required**: `fatal: could not read username/password` or `Permission denied (publickey)`. Verify - your git credentials work for the same URL outside Coyote by running `git clone ` manually. + your git credentials work for the same URL outside Coyote by running `git clone ` manually. Remember that + `owner/repo` shorthand expands to HTTPS; use the full SSH URL for SSH-only private repos. - **Network failure**: `Could not resolve host` or similar. Check connectivity. - **Invalid ref**: `couldn't find remote ref `. Verify the tag/branch/commit exists in the remote. +### "'agents' is an asset category, not a bundle" + +You passed a category name to `--install`. Use `coyote --install-builtins agents` to reinstall Coyote's built-in +assets for that category, or `--update-bundle ` if you meant a bundle that happens to share the name. + +### "no bundle named '``' is installed" + +The value didn't match an installed bundle, and it isn't shaped like a source (git URL, `owner/repo` shorthand, +scp-style `host:path`, or an explicit local path). Check `--list-bundles` for the exact bundle name, or pass a full +source to install something new. + +### "'`/`' matches multiple installed bundles" + +You uninstalled by `owner/repo` shorthand in a non-interactive run and more than one installed bundle matches that +path on different hosts. Re-run with the exact bundle name or source URL (both shown in the error and in +`--list-bundles`), or run interactively to get a selector. + ### "No recognized assets found in ``" The cloned repo has none of the recognized top-level directories. Make sure the repo's layout matches the diff --git a/Skills.md b/Skills.md index 58e24a4..95ab044 100644 --- a/Skills.md +++ b/Skills.md @@ -147,7 +147,7 @@ your current context with git knowledge, frontend conventions, or any other modu | `.skill ` | Open the skill in `$EDITOR`. Creates a scaffolded `SKILL.md` if missing. | | `.delete skill` | Interactive prompt to choose installed skills to delete. | | `.install skills` | Reinstall all bundled built-in skills, overwriting existing copies after confirmation. | -| `.install remote --filter skills` | Install only `skills/` from a remote repo. See [Sharing Configurations](Sharing-Configurations). | +| `.install --filter skills` | Install only `skills/` from a remote repo. See [Sharing Configurations](Sharing-Configurations). | | `.set skills_enabled ` | Flip the master switch at runtime. Inside a session this sets the session override; otherwise it updates the global default (`null` restores the default `true`). | | `.set enabled_skills ` | Replace the global default-active skill list at runtime, e.g. `.set enabled_skills git-master,ai-slop-remover`. Use `null` to clear. | @@ -158,8 +158,8 @@ your current context with git knowledge, frontend conventions, or any other modu | `coyote --list-skills` | Print installed skill names, one per line. | | `coyote --skill ` | If the skill exists, load it and proceed to REPL or one-shot. If missing, scaffold + edit. | | `coyote --skill --skill [...]` | Pre-load multiple skills in argument order. All must exist; fails fast if any is missing. | -| `coyote --install skills` | Reinstall all bundled built-in skills. | -| `coyote --install-from --filter skills` | Install only `skills/` from a remote repo. | +| `coyote --install-builtins skills` | Reinstall all bundled built-in skills. | +| `coyote --install --filter skills` | Install only `skills/` from a remote repo. | `coyote --skill ` composes naturally with `--role`, `--agent`, and a one-shot prompt: @@ -431,9 +431,9 @@ laid out as: installs with: ```shell -coyote --install-from https://github.com// +coyote --install / # or just the skills/: -coyote --install-from https://github.com// --filter skills +coyote --install / --filter skills ``` See [Sharing Configurations](Sharing-Configurations) for the full layout, ref pinning, conflict resolution, and secrets