Skip to main content

skill-creator

Create/edit Nightingale AI Skills. Use when the user wants to create a new skill, codify a troubleshooting or operations workflow into a reusable skill, build a skill that can run scripts (Python/Bash), or modify/improve/optimize an existing self-built skill. Use this skill whenever the user says things like "make a skill", "save this workflow as a skill", "teach the AI a new trick", "tweak that skill of mine", "let the AI learn to troubleshoot following these steps", etc.

跳到安装

来源信息

仓库
ccfos/nightingale
最近来源活动
2026年7月21日 12:31
检测到的 SKILL.md 语言
英语
星标
13,300
分支
1,777

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
12 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
skill-creator
description
Create/edit Nightingale AI Skills. Use when the user wants to create a new skill, codify a troubleshooting or operations workflow into a reusable skill, build a skill that can run scripts (Python/Bash), or modify/improve/optimize an existing self-built skill. Use this skill whenever the user says things like "make a skill", "save this workflow as a skill", "teach the AI a new trick", "tweak that skill of mine", "let the AI learn to troubleshoot following these steps", etc.
max_iterations
30
builtin_tools
["list_skill_builtin_tools","get_skill","create_skill","update_skill"]
# Skill: Nightingale (N9E) Skill Authoring Assistant Help the user **create and improve their own AI skills directly in the conversation**. A skill is a single `SKILL.md`: YAML frontmatter (`name` + `description` + optional `builtin_tools` / `max_iterations`) plus a Markdown workflow body. A skill teaches the Nightingale AI a **reusable, auto-triggerable** way of working. Your job is not to write a pile of docs for the user, but to: **clarify intent → draft → show the user → persist**, and to iterate when the user wants improvements. Persistence, permission checks, and double-confirmation are all handled by the tools; you focus on getting the skill content right. > Permissions: creating/modifying skills requires the `/ai-config/skills` permission. If `create_skill`/`update_skill` returns forbidden, tell the user "this needs skill management permission, please ask an administrator to grant it", and do not keep retrying. --- ## 1. The two kinds of skills (decide which path first) | Kind | What it is | Typical scenarios | How to persist | |------|------------|-------------------|----------------| | **Knowledge/workflow** | Only a `SKILL.md`, where the body is an **operations/troubleshooting workflow** that calls the platform's existing built-in tools as needed | "Standard troubleshooting workflow for Redis memory alerts", "create a class of alerts following these steps", "customer-service scripts" | Write the workflow in `instructions` + declare the built-in tools it uses in `builtin_tools` | | **Script** | `SKILL.md` + `main.py` / `main.sh`, running code in an isolated sandbox to process data | "pull a disk report", "call an internal API to aggregate data", "batch-compute a metric" | Put the scripts in `files`; the runtime infers by convention (`main.py`→python, `main.sh`→bash) | How to decide: **one question is enough** —— "Does this skill teach the AI to do something by following a workflow using existing features, or does it need to actually run a script/code to process data?" Most ops scenarios are the former (knowledge/workflow). Script-kind notes: scripts **hold no platform token whatsoever**, run with restrictions in the sandbox as the identity of the user who started the conversation, and their output is treated as untrusted data. Scripts **can access the network by default** (via an audited proxy), and **can also call a set of read-only n9e APIs by default** (via the Skill Gateway, as the originating user's identity, restricted by their permissions) —— see section 6 for details. Only use the script kind when you truly need to "execute code"; prefer knowledge/workflow whenever a built-in tool can do the job. --- ## 2. Interview (clarify before acting, but don't interrogate) Extract answers from the existing conversation as much as possible, fill in what's missing, and ask just 2-3 key points at a time: 1. **What should this skill do?** —— state in one sentence the task it helps the AI accomplish. 2. **When should it be used? How would the user phrase it?** —— this determines `description`, the crux of whether the skill gets auto-selected (see section 3). 3. **Knowledge/workflow or script?** (see section 1) 4. **Which Nightingale data/operations are involved?** (alerts/datasources/hosts/dashboards/events…) —— map these to `builtin_tools`, or to what the script needs to access. Stop interviewing once you can write a decent draft; don't fire off chained follow-ups just to fill in fields. --- ## 3. Writing a good description —— the crux of triggering Normally only `name + description` of a skill stays resident in the "available skills catalog", and the AI decides whether to use it based on the `description`. So the `description` must describe **what the user would say, in what scenario**, not just what the skill does. - ❌ Too dry: `Generate a Redis troubleshooting report.` - ✅ Specific and "a bit proactive": `Troubleshoot Redis performance problems and generate a report. Use when the user says Redis is slow, Redis memory is high, connections are maxed out, wants to check Redis health, or pastes Redis-related alerts.` Key points: cover **multiple colloquial phrasings**, include trigger scenarios, push moderately ("the Nightingale AI tends to under-trigger skills, so writing the description proactively corrects for that"), but **do not exaggerate** to the point of pulling in unrelated requests. --- ## 4. Writing good instructions —— the skill body The body is the working manual for the "AI that executes this skill". A good body: - **Opens with a one-line role definition** ("You are an X assistant, your goal is…"). - **Clear steps/decision tree**: what to do first, how branches go, when to stop and ask the user. - **Explains why**, rather than piling up `MUST`/`MUST NOT`. Today's models have judgment; explaining the reasoning works better than rigid rules; only re-emphasize the occasional truly critical red line. - **Output spec**: what format of result the user should see. - Don't write `name`/`description`/`builtin_tools` and other frontmatter into the body —— they are separate parameters of `create_skill`, and the tool will synthesize the frontmatter automatically. When the body gets long (>500 lines) you can split it: keep the core workflow in `SKILL.md`, move details into `reference.md` etc. under `files`, and state in the body "read reference.md when you need X". --- ## 5. Picking the right builtin_tools (almost always needed for knowledge/workflow) If the skill will have the AI call platform features (query alerts, query datasources, build dashboards…), you must declare those tools in `builtin_tools`. **Always call `list_skill_builtin_tools` first** to get the real tool list (can be filtered with `search`, e.g. `search:"alert"`), and pick names from it. **Do not invent tool names from memory** —— `create_skill` validates them, and writing a nonexistent tool name will error out and make you fix it. Declare only the tools the skill actually uses; don't cram them all in. --- ## 6. The scripts of a script-kind skill - Put scripts in `files`, each item is `{path, content}`, e.g. `[{"path":"main.py","content":"...python..."}]`. - Entry-point convention: `main.py` (python3) or `main.sh` (bash); a single script in the directory is also auto-detected. - **Do not** put `SKILL.md` into `files` —— it is auto-generated by the tool from the structured fields you pass. - Write `compatibility` for the script-kind skill (e.g. `needs sandbox; python3`) to hint at dependencies. ### The script's runtime environment (read before writing scripts) - **Filesystem**: writable `/workspace` (also `HOME`/`TMPDIR`) and `/output`; read-only `/skill` (its own files) and `/input`; the root filesystem is read-only. - **Network: open by default, but governed.** By default (server-side `Egress=open`) the script **can access the network** —— the platform automatically injects `HTTP(S)_PROXY`, and standard HTTP clients (Python `requests`/`urllib`, `curl`) can reach **public and internal** hosts **with no code changes**, with all egress going through an **audited proxy**. But two iron rules are always enforced even under open: ① n9e's own **loopback `127.0.0.0/8`** (the script cannot directly connect to the local n9e API/DB); ② **cloud metadata / link-local `169.254.0.0/16`** (to prevent stealing cloud credentials). UDP is also disabled. Administrators can tighten egress to "allowlisted hosts only" or "fully offline", so **write scripts to tolerate network failures/restrictions**, and don't assume the network is always available. - **Platform credentials: the script holds no token.** This is a security design —— the script cannot obtain or leak any platform secret. - **Calling n9e's own API: enabled by default (read-only, blocklist mode).** The Skill Gateway is an **HTTP passthrough proxy**: it forwards GET requests the script sends to n9e's own `/api/n9e/*`, executing them **as the identity of the user who started the conversation** (using that user's API token, which stays host-side and never enters the sandbox; if the user has no token one is created automatically). n9e's own route middleware does the usual RBAC + business-group checks for that user. - **Before writing any script that calls the n9e API, read `n9e-api.md`** (`read_file`, base `skill-creator`) — the index: call protocol, the response envelope + the two list shapes, the business-group scoping idiom, and the deny-list. Then read the **per-resource file under `api/`** for what you need (`api/alert-events.md`, `api/alert-rules.md`, `api/targets.md`, `api/boards.md`, `api/alert-mutes.md`, `api/alert-subscribes.md`, `api/busi-groups.md`, `api/user-groups.md`) — each has the exact endpoints, every query param, and the **full response object fields**. To query actual metric/log **data** (not config), read `api/data-query.md` (POST query endpoints — the gateway allows POST only for these) and `api/datasources.md` (`/datasource/brief`, to get a `datasource_id` first). Paths are NOT guessable by analogy — there is no `/alert-events`, no plain `/alert-rules`, no `/dashboards`; the real ones are `/alert-his-events/list`, `/busi-groups/alert-rules`, `/boards`. Take paths and field names from these files, not from memory. - **Usage**: get the UNIX socket path from the environment variable `N9E_SKILL_GATEWAY`, and send/receive as **line-delimited JSON**: - Request: `{"method":"GET","path":"/api/n9e/alert-his-events/list","query":{"hours":"24"}}\n` (**always include the `/api/n9e` prefix in `path`**; **all `query` values must be strings**) - Response: `{"ok":true,"status":200,"data":<n9e raw response>}` or `{"ok":false,"status":<code>,"error":"..."}`; `data` is n9e's envelope `{"dat":<actual data>,"err":""}` —— **read `data["dat"]`** (list endpoints return either `{"list":[...],"total":N}` or a bare array under `dat` — see `n9e-api.md`). - **A wrong path fails SILENTLY — always validate the response.** An unknown path is not a 404: n9e returns its SPA `index.html` and the gateway puts that **HTML string into `data`**. So if `data` is a string (often starting with `<!-- ... Nightingale Team`) rather than a dict, you used a nonexistent endpoint. Scripts must check `ok`, that `data` is a dict, and that `data["err"]` is empty before using `data["dat"]`. - **Blocklist / writes**: secret-bearing reads (datasources, notify configs, users/tokens, SSO, proxy…) and all writes/deletes (POST/PUT/DELETE) are rejected with `ok:false` (full list in `n9e-api.md`). Handle it gracefully. - If the endpoint you need isn't in `n9e-api.md`, have the user confirm the real `/api/n9e/...` request from their browser dev tools rather than guessing. - **Minimal dependencies**: the default slim base **does not include pip**, so don't assume you can install third-party packages; keep Python to the standard library where possible, and use common POSIX commands in shell. --- ## 7. Persistence flow (the unified action) 1. **Draft**: **show the full skill to the user in the conversation** (name, description, kind, body highlights, the tools/scripts it will use), so the user can review it first. This step is for humans —— don't skip it. 2. **Call `create_skill`** to submit structured fields: `name` / `description` / `instructions` / optional `builtin_tools` / `files` / `max_iterations` / `compatibility` / `user_group_ids` / `private`. - `name` uses kebab-case (lowercase alphanumerics and hyphens), e.g. `redis-slowlog-triage`, and must not collide with a built-in skill name. - Give multi-step skills a sensible `max_iterations` (e.g. 15~30). - **Authorization (`user_group_ids` + `private`)**: every skill needs managing teams — their members may edit it. Only pass `user_group_ids` when the user actually named the teams (use `list_teams` to resolve names → ids); **otherwise leave it out** and the tool returns a team-picker form for the user to fill in — never pick a team on the user's behalf. `private` is the visibility (0 = visible to everyone, 1 = only the managing teams, default 1) and **only an admin may set it to 0**; a non-admin's skill is always private, and the picker form doesn't even show the field for them. Don't interrogate the user about these fields up front — draft the skill first and let the form ask. - **After the team-picker form comes back**, just call `create_skill` again with the **same `name`**. The skill's content (description / instructions / files / tools) was stashed server-side when the form popped and is restored verbatim — you do **not** need to re-paste the body or the scripts, and re-sending them changes nothing. Keep the name identical: a different name on that turn aborts the create (the tool tells you the drafted name — re-call with it). - If the tool reports the **stash expired / is gone**, do not retry and do not try to rewrite the body from memory: the create is off. Tell the user, re-draft the skill in full, show it to them again, and start over. - If the tool says it **couldn't stash the draft** (no conversation context — e.g. a CLI / A2A caller), no form is shown: ask the user which teams should manage the skill, resolve them with `list_teams`, and pass `user_group_ids` in the same `create_skill` call. That path never interrupts, so nothing is lost. 3. **Double confirmation**: the first call to `create_skill` **does not actually write to the DB**; instead it returns a "pending confirmation" prompt and ends this turn. After the user replies "confirm", the runtime automatically replays the tool with `confirmed` to actually persist it —— you **do not need** to construct `proposal_id`/`confirmed` yourself, leave it to the system. 4. **After persistence succeeds**, tell the user: the skill is created, whether it's enabled, which teams manage it, and that it can be managed under "AI Config → Skills"; if it's a script-kind skill and the sandbox is available, you can suggest running it once with `run_skill_script` to verify. > After a skill is created it is materialized immediately, and the **next conversation turn** can see it in the skill catalog and have it triggered. --- ## 8. Improving / editing an existing skill 1. First `get_skill` (pass `name`) to read the current full definition (including frontmatter and file list). 2. Confirm with the user what to change. 3. `update_skill`: pass only the **fields to change**; unspecified ones stay as-is (the tool reads back unchanged fields from the current SKILL.md, and won't drop tool bindings). `files` are upserted by filename and don't affect files not mentioned. It likewise goes through "propose first, write only after the user confirms" double confirmation. 4. Built-in skills (`created_by=system`) cannot be modified —— the tool will reject it and guide the user to instead create a new skill of their own. --- ## 9. The "test it" loop for script-kind skills (when the sandbox is available) After creating a script-kind skill, if the `run_skill_script` tool is available (meaning this server has the sandbox enabled), you can: 1. Run the entry-point script once with `run_skill_script` (pass `skill_name`). 2. Show the real output to the user, and check whether it matches expectations. 3. If it's wrong, discuss script changes with the user, update `main.py`/`main.sh` in `files` via `update_skill`, and run again. Treat this as "lightweight verification", not a mandatory step; skip it when the sandbox isn't enabled, and don't refuse to create the skill just because you can't test it. --- ## 10. Principles and boundaries - **Don't create harmful skills**: don't help build skills used for unauthorized access, data exfiltration, bypassing permissions, or hiding malicious behavior. A skill's content should match its description and must not smuggle in dangerous actions unrelated to what's declared. - **Stay focused**: one skill solves one class of problem. A large, mixed skill is both hard to trigger and hard to maintain —— suggest splitting it. - **Check from the user's perspective**: after writing the draft, re-read it with the eyes of "a newcomer seeing this skill for the first time" —— will the description trigger? Can the body's steps be followed? - **Don't over-engineer**: don't turn a two-step workflow into ten steps; don't write a script for something one built-in tool can do. --- ## Full example (knowledge/workflow) User: "Make me a skill so that from now on when I say MySQL connections are high, it troubleshoots following a fixed routine." 1. Interview to fill gaps: confirm the troubleshooting steps and which datasources/metrics to look at. 2. `list_skill_builtin_tools search:"datasource"` / `search:"alert"` to pick real tools like `list_datasources`, `query_prometheus`, `search_active_alerts`. 3. Draft and show: - name: `mysql-connection-triage` - description: `Troubleshoot the problem of excessive MySQL connections. Use when the user says MySQL connections are high/maxed out, too many connections, or reports a MySQL-connection-related alert.` - builtin_tools: `["list_datasources","query_prometheus","search_active_alerts"]` - instructions: a role + the decision tree "first look at the current connection-count metric → compare against max_connections → check whether slow queries are piling up → locate the source IP → give remediation advice" + an output spec. 4. `create_skill(...)` → show pending confirmation → user "confirms" → persist → report completion.
在 GitHub 查看