Installing a GitHub skill via the API
Table of Contents

Most teams keep their internal skills in a private (or public) GitHub repo, version them with tags, and want their CI to install the latest cut onto a specific agent. The Agento public API lets you do that without ever opening the dashboard. Pass the repo URL, get back an installed-skill record, restart the agent, done.
This guide is the GitHub-source counterpart to the inline-author flow in Managing skills via the API. If you have not already, skim the Using the Public API guide first to mint a key.
When to use this
Pick the GitHub flow when:
- The skill already lives in a public GitHub repo with a
manifest.jsonat its root. - You want the same source of truth for humans and machines: pushes to the repo become installable releases.
- You want to install the same skill on many agents (or many accounts) without copy-pasting file contents.
If you would rather author files directly in the request body and skip the GitHub round-trip, use the inline flow in Managing skills via the API. Both end up as the same on-disk extension layout inside the agent container.
What the repo needs
The API fetches https://raw.githubusercontent.com/<owner>/<repo>/<branch>/manifest.json and validates it. The branch defaults to main unless you pass /tree/<branch> in the URL. The manifest must include:
| Field | Type | Notes |
|---|---|---|
name |
string | Lowercase letters, digits, hyphens. Becomes the human-readable skill name. |
version |
string | Semver. Bump it when you push a new version to the repo. |
author |
string | Free-form. |
tools |
string[] | List of tool names the skill registers. Required, may be empty. |
description |
string | Optional, surfaced in the dashboard. |
uiHints |
object | Optional schema describing user-configurable settings. |
A minimal repo layout:
my-skill/
โโโ manifest.json
โโโ SKILL.md
โโโ package.json
โโโ src/
โโโ index.ts
Anything OpenClaw needs at runtime (entrypoint, helper scripts, prompts) lives alongside the manifest. The dashboard's Custom > GitHub URL install path validates the same way, so if your repo installs from the UI it installs from the API too.
Per-agent, not per-account
POST /v1/agents/:id/skills installs the skill on one specific agent. There is no "install once for the whole account" call: each agent you want the skill on needs its own request, then its own restart. If you have ten agents and call this endpoint once, only the agent in the URL gets the skill โ the other nine see nothing change.
This is different from the inline-author flow in Managing skills via the API, where POST /v1/skills first uploads the skill to your account catalog before you install it. The GitHub flow has no upload step: the catalog entry is the GitHub repo. But the per-agent install is the same in both flows.
Installing in one call
Mint an API key with the skills scope at agento.host/app/api-keys. Then:
curl -s https://api.agento.host/v1/agents/$AGENT_ID/skills \
-H "X-Api-Key: $AGENTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"trustLevel": "github",
"githubUrl": "https://github.com/acme/agento-trello-skill"
}'
The API:
- Parses the URL and pulls
manifest.jsonfrom the right branch. - Validates the manifest fields above.
- Derives the install id from
<owner>/<repo>so the same repo cannot be double-installed on the same agent. - Records
customSourceso the orchestrator can re-sync the files on the agent's next restart.
Successful response:
{
"data": {
"id": "f9c1e2a4-7d3b-4b1f-9c0a-8d2e6b3a1c5e",
"skillId": "acme/agento-trello-skill",
"name": "trello-skill",
"installedVersion": "1.2.0",
"trustLevel": "custom",
"isEnabled": true,
"needsRestart": true
}
}
The trustLevel in the response is custom because internally GitHub installs share the same record shape as inline-authored ones. The customSource link to the GitHub URL is what distinguishes them.
Pinning a branch or tag
Point at a specific branch by appending /tree/<branch>:
curl -s https://api.agento.host/v1/agents/$AGENT_ID/skills \
-H "X-Api-Key: $AGENTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"trustLevel": "github",
"githubUrl": "https://github.com/acme/agento-trello-skill/tree/release-1.2"
}'
This is the same syntax GitHub's UI uses, so you can paste any "view this branch" URL straight in. Tags work the same way (/tree/v1.2.0).
The orchestrator stores the URL verbatim. To upgrade, uninstall the old install and install again pointing at the new tag.
Restart the agent
The install only writes the database row. The skill's files reach the container on the next restart:
curl -s -X POST https://api.agento.host/v1/agents/$AGENT_ID/restart \
-H "X-Api-Key: $AGENTO_API_KEY"
Watch the logs for the plugin to register itself:
curl -sN https://api.agento.host/v1/agents/$AGENT_ID/logs/stream \
-H "X-Api-Key: $AGENTO_API_KEY"
Verifying the install
curl -s https://api.agento.host/v1/agents/$AGENT_ID/skills \
-H "X-Api-Key: $AGENTO_API_KEY"
Look for the skillId you got back in the install response. The response includes the installed version, trust level, and whether the skill is currently enabled. If you do not see it, the most likely causes are:
- Manifest is missing one of the required fields. Check the API response body, not just the status: validation errors include the failing field.
- The repo is private. The API only fetches public raw URLs.
- You typed the URL with a trailing slash or
.gitsuffix. Both are tolerated, but mistypes (e.g. swappingtreeforblob) are not.
Uninstalling
curl -s -X DELETE https://api.agento.host/v1/agents/$AGENT_ID/skills/acme%2Fagento-trello-skill \
-H "X-Api-Key: $AGENTO_API_KEY"
The skillId is <owner>/<repo>, which contains a slash, so URL-encode it as %2F. After uninstalling, restart the agent to drop the plugin from memory.
Multi-agent rollout
A common pattern is keeping a list of agent ids in your CI and rolling out the same skill on every push:
for AGENT in $AGENT_IDS; do
curl -s https://api.agento.host/v1/agents/$AGENT/skills \
-H "X-Api-Key: $AGENTO_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"trustLevel\": \"github\", \"githubUrl\": \"https://github.com/acme/agento-trello-skill/tree/v$VERSION\" }"
curl -s -X POST https://api.agento.host/v1/agents/$AGENT/restart \
-H "X-Api-Key: $AGENTO_API_KEY"
done
Each agent gets its own install record, so you can stagger restarts and roll back individually if something looks off.
Errors you might hit
| Status | Code | Meaning |
|---|---|---|
| 400 | validation_error |
githubUrl missing, malformed, or the manifest failed validation. The message names the offending field. |
| 403 | forbidden |
Your API key is missing the skills scope. |
| 403 | limit_reached |
The agent has hit the maxSkillsPerAgent plan limit. |
| 404 | agent_not_found |
The agent id does not exist in your account. |
| 409 | conflict |
This repo is already installed on this agent. Uninstall first if you want to re-install at a new branch. |
What is next
- The full Skills API reference lives in
api.agento.host/openapi.jsonand the LLM-friendly flat version atapi.agento.host/llms-full.txt. - For inline-authored skills, see Managing skills via the API.
- For browsing the verified marketplace from the API, see the
GET /v1/skillsendpoint documented in Using the Public API.