Table of Contents
- Quick start
- Expected repository layout
- Ref pinning
- Filtering by category
- Conflict resolution
- Plain files (agents, roles, macros, tools)
- Identical content is not a conflict
- File-mode (+x) handling
- MCP configuration merge
- Secrets handling
- Git authentication
- Publishing your own bundle
- What is not shared
- Examples
- Install everything from a public repo
- Pin to a release tag
- Install only the agents from a fork
- Install only the MCP servers, force-replace conflicts
- From the REPL
- From a private SSH URL
- From a local file:// URL (testing your own template)
- Troubleshooting
- "git failed: ..."
- "No recognized assets found in <url>"
- "Refusing to overwrite local file <path> non-interactively"
- "MCP server '<name>' already exists locally. Refusing to merge non-interactively."
- Missing secrets after install
- git binary not found
- Sandbox Implications
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:
- 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:
- CLI:
coyote --install-from <git-url> - REPL:
.install remote <git-url>
This page covers the expected repository layout, command-line flags, conflict resolution, secrets handling, and how to publish your own shareable bundle.
To see a template repository with all recognized categories, see the coyote-config-template repository.
Quick start
Install everything from a remote repo:
coyote --install-from https://github.com/Dark-Alex-17/coyote-config-template
or from inside the Coyote REPL:
.install remote https://github.com/Dark-Alex-17/coyote-config-template
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 and the bundle includes any
sbx-mixin.yamlfiles, installing it grants those mixins network access and install privileges inside your sandboxes the next time youcoyote --sandbox. See Sandbox Implications at the bottom of this page before installing bundles from sources you don't fully trust.
Expected repository layout
Coyote recognizes these top-level directories. Anything outside them is ignored.
<repo>/
├── agents/
│ └── <agent-name>/ # One subdirectory per agent
│ ├── config.yaml # LLM-loop agent
│ │ └── (or graph.yaml) # Graph agent
│ ├── README.md # Optional
│ ├── tools.sh # Optional agent-local tools
│ └── scripts/ # Optional graph-node scripts
├── roles/
│ └── <role-name>.md # Markdown with YAML frontmatter + prompt body
├── skills/
│ └── <skill-name>/ # One subdirectory per skill
│ └── SKILL.md # YAML frontmatter + body
├── macros/
│ └── <macro-name>.yaml # Positional/rest variables + REPL command steps
└── functions/
├── tools/
│ └── *.sh / *.py / *.ts # Global tools (auto chmod +x on install)
└── mcp.json # MCP server config (merged with local, not overwritten)
A few things to note:
- Missing categories are skipped silently. A repo that only contains
agents/installs only agents. This means you do not need to use--filterfor partial repos. .git/is excluded from the scan automatically.- Symlinks are rejected by the install walker as a defense-in-depth measure.
functions/bin/andfunctions/utils/are not recognized (compiled at runtime / not in scope for sharing).- The whole
config.yaml(global Coyote config) is not shared (see What is not shared).
Ref pinning
Pin the install to a specific tag, branch, or commit by appending #<ref> to the URL.
coyote --install-from https://github.com/<owner>/<repo>#v1.2.3
coyote --install-from https://github.com/<owner>/<repo>#main
coyote --install-from https://github.com/<owner>/<repo>#abc1234
How Coyote resolves the ref:
- Branch or tag names are passed as
--branch <ref>to a shallowgit clone --depth 1. - Commit SHAs (4-40 hex characters) trigger a full clone followed by
git checkout <ref>.
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.
Filtering by category
Restrict the 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) |
coyote --install-from <git-url> --filter agents
coyote --install-from <git-url> --filter mcp_config
REPL form:
.install remote <git-url> --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.
Conflict resolution
When an install file would overwrite an existing local file with different contents, you have several options.
Plain files (agents, roles, macros, tools)
In a terminal (TTY), Coyote prompts per conflicting file:
| Option | Effect |
|---|---|
keep |
Skip this file; keep your local copy. |
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. |
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.
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
the same install is idempotent.
File-mode (+x) handling
Scripts written into functions/tools/ are automatically marked executable based on extension. Bash (.sh), Python
(.py), and TypeScript (.ts) files get chmod 0o755 on Unix. This applies to both new files and replaced conflicts.
MCP configuration merge
functions/mcp.json is the exception to the per-file conflict model. Instead of replacing your local file outright,
Coyote merges the remote mcp.json into your existing one.
Merge behavior
- New server names (present in remote, absent locally) are added.
- Identical server entries (same JSON shape locally and remotely) are silently kept.
- Conflicting server entries prompt with three options:
| Option | Effect |
|---|---|
keep local |
Leave your existing entry alone. |
take remote |
Overwrite with the remote entry. |
rename remote as "<name>-remote" |
Insert the remote entry under a suffixed key. If the suffixed key is also taken, Coyote appends -2, -3, etc. |
abort merge |
Stop the merge with an error. No partial write. |
With --install-force, every conflict is resolved by taking the remote entry. In non-TTY mode without
--install-force, the merge aborts before writing.
Validation
Each added, replaced, or renamed entry is validated against the MCP server schema (e.g., stdio servers must have a
command; http/sse servers must have a url) before the merged file is written. A validation failure aborts the
install. Coyote will never write a partially-validated mcp.json.
Atomic write
The merged file is written to a tempfile (mcp.json.tmp) and then renamed atomically over the target. This guarantees
that a crash or interrupt mid-write will not corrupt your existing mcp.json.
Secrets handling
MCP server entries (and other config files) can reference vault secrets with {{SECRET_NAME}} placeholders. After the
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 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 <NAME>or.vault add <NAME>).
Both modes always print a final summary distinguishing secrets added from those deferred. See Vault for the full secrets workflow.
Git authentication
Coyote shells out to your local git binary to clone the remote repository. This means it inherits your existing git
authentication setup with no additional configuration:
- SSH URLs (
git@github.com:owner/repo.git) use yourssh-agent,~/.ssh/config, and SSH keys. - HTTPS URLs with private repos use your configured
credential.helper(e.g., osxkeychain on macOS, libsecret on Linux, the GitHub CLI's helper). - Public HTTPS URLs require no auth.
If git is not on your PATH, you'll get a clear error message on the first install attempt.
Publishing your own bundle
To share your Coyote configuration, structure a git repo like the template 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:
coyote-config-template. It includes a working sample of each
asset type plus a README describing the customization workflow.
Best practices
-
Pin to tagged releases so consumers can install with
#<tag>for reproducibility. -
Keep per-agent logic in
agents/<name>/. Only put global tools infunctions/tools/. -
Use
{{SECRET}}placeholders for any sensitive value inmcp.json. Never commit a real API key. -
Document expected secrets in your repo's
READMEso users know which vault entries to add. -
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. -
Test installs against a clean
COYOTE_CONFIG_DIRbefore publishing. You can use:COYOTE_CONFIG_DIR=$(mktemp -d) coyote --install-from file:///path/to/your/clone --install-force
What is not shared
The following are intentionally outside the install-remote 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 sharedconfig.yamlwould risk breaking auth or routing traffic somewhere unexpected. Settings that genuinely benefit from sharing (like default models) already belong inside individual agents' or roles' configs.- Sessions, RAGs, agent runtime data. These accumulate as you use Coyote and aren't shareable in a meaningful way.
functions/bin/: Agent script binaries built at runtime, not part of the source layout.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.
Examples
Install everything from a public repo
coyote --install-from https://github.com/Dark-Alex-17/coyote-config-template
Pin to a release tag
coyote --install-from https://github.com/your-org/coyote-config#v2.4.0
Install only the agents from a fork
coyote --install-from https://github.com/your-org/coyote-config --filter agents
Install only the MCP servers, force-replace conflicts
coyote --install-from https://github.com/your-org/coyote-config --filter mcp_config --install-force
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
From a private SSH URL
coyote --install-from git@github.com:your-org/private-coyote-config.git#v1.0.0
From a local file:// URL (testing your own template)
coyote --install-from file:///home/you/code/my-coyote-config
Troubleshooting
"git failed: ..."
The remote clone failed. Coyote passes git's stderr through verbatim. The most common causes:
- Authentication required:
fatal: could not read username/passwordorPermission denied (publickey). Verify your git credentials work for the same URL outside Coyote by runninggit clone <url>manually. - Network failure:
Could not resolve hostor similar. Check connectivity. - Invalid ref:
couldn't find remote ref <ref>. Verify the tag/branch/commit exists in the remote.
"No recognized assets found in <url>"
The cloned repo has none of the recognized top-level directories. Make sure the repo's layout matches the
expected layout. A README.md and a LICENSE at the root are fine; they're just
ignored.
"Refusing to overwrite local file <path> non-interactively"
You're running in non-TTY mode (CI, piped, redirected stdin) and there's a conflict. Re-run with --install-force to
overwrite, or run in an interactive terminal to be prompted.
"MCP server '<name>' already exists locally. Refusing to merge non-interactively."
Same pattern as the above, but for the MCP merge. Use --install-force to take the remote entry for every conflict.
Missing secrets after install
Add them via coyote --add-secret <NAME> (CLI) or .vault add <NAME> (REPL). See Vault for details.
git binary not found
Coyote shells out to the system git binary. Install git for your platform and ensure it's on your PATH.
Sandbox Implications
If you use Coyote's Sandbox mode, installing a shared bundle that contains any sbx-mixin.yaml
files is a privilege escalation event. Those mixins are auto-discovered and applied silently on your next
coyote --sandbox, granting:
- Network access to every domain listed in the mixin's
network.allowedDomains. - Install commands run with passwordless sudo inside the sandbox (the agent user has full sudo).
- Environment variables set in
environment.variables.
This is fine for bundles you trust (your own configs, your team's shared repo). It can be dangerous for bundles from unknown sources.
Before installing a bundle from a source you don't fully trust
- Grep the repo for
sbx-mixin.yamlfiles and read each one:git clone --depth 1 https://github.com/<source>/<repo> /tmp/audit find /tmp/audit -name 'sbx-mixin.yaml' -exec cat {} + - Look specifically at:
network.allowedDomains: What domains are being added to the sandbox's allowlist?commands.install: What commands run with passwordless sudo? Do they pull from a recognized source (apt repo, official installer, signed release) or arbitrary URLs?environment.variables: Do any look like credential exfiltration vectors (*_API_URLpointing at unknown hosts,LD_PRELOAD, etc.)?
- First-run with
--no-mixinsto verify the bundle's non-sandbox features work without granting any sandbox elevation:Then re-launch withoutcoyote --sandbox skeptical-test --fresh --no-mixins--no-mixinsonce you've reviewed and accepted the mixins.
Runtime audit
Every coyote --sandbox prints a verbose mixin log listing each mixin about to be
applied along with its install/domain counts. Skim it the first time a bundle's mixin is applied. If something looks
off, abort with Ctrl-C (only safe before sbx create starts running install commands; once installs begin, use
sbx rm <name> after to clean up).
When sharing your own bundle
If you publish a config repo, document any sbx-mixin.yaml files in your README.md. Explain what they add to
the sandbox and why. Users who land on your repo will trust you more if you make the privilege grants explicit
instead of letting them discover via grep.