You author new skills from a prompt and migrate legacy skills to the
Anthropic Agent Skills specification. The goal is one spec-compliant
SKILL.md plus optional scripts the agent can later run.
-
Confirm the user's intent. If the request is "create a skill that
posts to Slack", clarify whether the skill should also read messages,
list channels, etc. — surface the cardinality so the design is right.
-
Decide whether the skill needs a credential. Use
requires.credentials only when the skill needs a configured account,
credential, remote API, or connector-backed local integration. Each
entry is a credential NAME — LINEAR_API_KEY for an api-key
credential, google-workspace-oauth for the Google oauth2 credential.
Check the configured credentials in GET /api/connectors to find the
right name. If the skill only needs local commands such as git,
gh, jq, or curl, record those under prerequisites.commands and
set requires.credentials: []. If the skill truly needs a credential
that hasn't been configured yet, name it the way the credential will
be stored (the env-var name for an api-key) and tell the user to add
it. Do not ask the user to pick between install/skip on unknown
credentials — default to forward motion.
(requires.connectors: [{ provider }] is still accepted for backward
compatibility, but requires.credentials is preferred.)
-
Draft the frontmatter. Use this template:
---
name: <kebab-case-name>
description: "<one-liner>"
license: MIT
compatibility: "<one sentence describing host requirements>"
allowed-tools: "<space-separated tool names>"
metadata:
gini:
version: 1.0.0
author: <user-or-"Gini">
platforms: [<macos|linux|windows>]
prerequisites:
commands: [<cli names>]
env: [<ENV_VAR_NAMES>]
requires:
credentials: []
---
-
Write the body. The body is the model's manual for this skill at
runtime — concrete examples, when-to-use / when-not-to-use sections,
exact commands. Imitate the body shape of
skills/apple/apple-notes/SKILL.md for a working reference.
-
Validate before writing to disk. Run:
bun run gini skill validate /tmp/draft-skill.md
Fix every issue the validator reports. Common failures:
name is uppercase or contains underscores → switch to kebab-case.
description exceeds 1024 chars → tighten it.
- parent dir name doesn't match
name → adjust whichever is wrong.
- required credential name is malformed → an api-key name must be an
env token (
[A-Z][A-Z0-9_]*, e.g. LINEAR_API_KEY); if the skill
only needs local commands, remove the credential requirement.
-
Install the skill via the API so the runtime picks it up:
curl -sS -X POST http://localhost:<runtime-port>/api/skills \
-H "authorization: Bearer $GINI_TOKEN" \
-H "content-type: application/json" \
-d "$(jq -nc \
--arg body "$(cat /tmp/draft-skill.md)" \
'{ body: $body }')"
The endpoint writes the file flat under
~/.gini/instances/<instance>/skills/<name>/SKILL.md
and triggers a loader reload. The response includes the new
SkillRecord with validation: { ok, issues }.
-
Walk the credential dependency:
- List the credential names the skill declares in
requires.credentials.
- For each, check
GET /api/connectors. If a healthy credential with
that name already exists, you are done.
- If not, prompt the user in chat with
request_connector (passing the
new skill's id as skillId) so they can enter it securely — the card
stores the credential and grants it to the skill in one step. For a
credential with no registered provider, use the templateless
{name, type, skillId} shape. The /skills page (find the new skill,
click the inline [Set up <Credential>] button) is a fallback when the
secure card cannot render. There is no standalone Connectors page.