zudo-text

検索したい単語を入力

いつでも検索バーを開ける

Inline AI command — skill authoring

Skills are reusable prompts you invoke from the inline AI command surface as /skill-name. Each skill is a single Markdown file: YAML frontmatter declares the skill's identity, and the Markdown body becomes the system prompt the model sees when the skill runs.

This page describes the skill file format, where to put the files, how /skill-name resolution works, and how the format relates to (and differs from) Claude Code's .claude/skills/ files.

Where skills live

Skills are discovered from two directories at runtime:

  1. Workspace-scoped<workspace>/.zudotext/skills/. Anything in this directory is local to the current text app's workspace. Use it for project-specific prompts (a tone-of-voice instruction tied to one client, a glossary that only applies to one document set).

    • The settings dialog has a Reveal Skills Folder button that opens this directory in Finder. The same path is used by the standard / full presets when scaffolding a fresh workspace, so it usually exists already.

    • This layer is loaded only when you opt in. See The workspace skill security gate below — by default it is skipped entirely.

  2. User-scoped — a skills directory under the writing app's user-config dir (~/.config/zudotext/<appname>/skills/ on macOS / Linux). Skills here are shared across every workspace you open with that text app — useful for personal defaults (a /translate-en you always want available, regardless of which workspace you are in). This layer is always loaded.

The workspace skill security gate

A skill's Markdown body becomes the system prompt the local model runs. Workspace skill files travel with the workspace — they are committed, and a workspace can be cloned from anywhere — so loading them automatically would mean running someone else's instructions against your AI without your consent. To prevent that, the workspace layer is gated behind an explicit opt-in: the Trust workspace skills setting (inlineAiCommand.trustWorkspaceSkills), which defaults to false.

  • When the gate is off (the default), the workspace layer is skipped completely. The loader does not scan <workspace>/.zudotext/skills/ and does not watch it — no workspace file is read, parsed, or surfaced in autocomplete. This is not shadowing: a workspace skill is not hidden behind a user skill, it never enters the registry at all. Only user-scoped skills are available.

  • When you turn the gate on, the workspace layer is loaded and the override rules below apply.

Turn it on from Settings → Inline AI Command → Trust workspace skills, and only after you have opened the directory and read the skill bodies. If a workspace skill never appears in autocomplete, check this setting before anything else.

Override rules

These rules apply only when the workspace gate is on (otherwise there is no workspace layer to collide with).

When the same name is declared in both layers, the workspace copy wins. The user-scoped file is "shadowed" — it stays on disk untouched, but it does not appear in the registry while the workspace copy is present. Removing the workspace file promotes the user file back into the registry on the next watcher event.

The loader emits a diagnostic shadowed event in this case, which surfaces as a console.warn in the developer console — useful when you cannot work out why a skill body is not the one you just edited.

The file watcher is debounced and re-parses on every event; a save is enough to update the live registry — no restart needed.

File format

Each skill is a UTF-8 Markdown file with a YAML frontmatter block. The contract is enforced by parseSkillFile in @takazudo/inline-command-skills; an invalid file is skipped with a console.warn rather than crashing the editor, so a single broken skill never takes the surface down.

Frontmatter fields

FieldRequiredDefaultNotes
nameyesSlug-style identifier. Must match ^[a-z][a-z0-9-]*$ — lowercase letters, digits, hyphens, must start with a letter. This is the token typed after the / (e.g. name: translate-en is invoked as /translate-en).
descriptionyesShort, non-empty, human-readable string. Surfaces in the autocomplete popup as the entry's info text. Aim for one sentence.
modenoinlineHint about which submit gesture this skill is designed for. inline means the skill prefers Tab (bake into document); panel means it prefers Cmd+Enter (mini panel). It is a hint surfaced in the autocomplete popup, not a binding override — the user's actual gesture still decides where the result lands.
modelnoOptional model-override string. The parser accepts it (a non-empty string is stored on the skill), but it is currently a no-opagent-server's /inline route (the backend this surface calls, see Flue Agent Platform) has no per-request model field to forward it to, so every skill runs on the same fixed model regardless of this value. Present for forward-compatibility; safe to set, but it has no effect today.

Body

Everything after the closing frontmatter delimiter (---) is the skill body. The body is passed to the model as the system prompt for this run (systemPromptOverride on the underlying stream call). The user's text after /skill-name (whatever they typed on the trigger line, plus the editor selection if any) becomes the user message.

That separation is the model the skills assume:

  • Body — durable instruction. "You are a translator. Render the user's text into natural, idiomatic English."

  • Trigger-line argument — per-invocation parameter. @@ /translate-en こんにちは passes こんにちは as the user message.

  • Selection — when a selection is present in the editor at submit time, it is also forwarded to the stream as selection. The body is free to reference both.

Recipe — translate-en

A skill that renders the selected text into natural English.

Save as <workspace>/.zudotext/skills/translate-en.md (or under ~/.config/zudotext/<appname>/skills/ for a user-scoped version):

---
name: translate-en
description: Translate the selected text into natural, idiomatic English.
mode: inline
---

You are a careful translator. Translate the user's text into natural,
idiomatic English. Preserve the original tone (formal, casual, technical).

When a `selection` is provided, treat it as the source text to translate.
When no selection is provided, treat the user's free-form input as the
source text.

Output only the translation. Do not add commentary, do not include the
original text, do not wrap the result in quotes.

Invoke it from the editor by selecting a passage and typing:

@@ /translate-en

Then press Tab to bake the translation in place.

Recipe — summarize-bullets

A skill that turns the selected text into a short bullet summary. Designed for the mini panel — you usually want to read the summary before deciding to keep it.

Save as <workspace>/.zudotext/skills/summarize-bullets.md:

---
name: summarize-bullets
description: Summarise the selected text as 3–5 short bullet points.
mode: panel
---

You are a precise summariser. Read the user's text and produce a Markdown
bullet list with 3 to 5 items.

Each bullet must:
- Be a single short sentence (no sub-bullets, no nested lists).
- Capture one distinct idea — do not restate the same point twice.
- Stay faithful to the source. Do not add facts that are not in the text.

When a `selection` is provided, summarise the selection. When no selection
is provided, summarise whatever the user typed after the slash command.

Output only the bullet list. No preamble, no closing remark.

Invoke it by selecting a longer block of text and typing:

@@ /summarize-bullets

Press Cmd+Enter to open the mini panel. The bullet list streams in; you can read it, then bake or dismiss.

How /skill-name resolves

The resolver in @takazudo/inline-command-skills runs against whatever you typed after the @@ prefix:

  1. Empty input → no resolution. The Tab/Cmd+Enter gesture does nothing.

  2. The first whitespace-delimited token must start with /. If it does not, the input is treated as a free-form prompt — sent to the model verbatim, no skill body involved.

  3. The token is matched against ^/[a-z][a-z0-9-]*$. Malformed slugs (uppercase, leading digit, special characters, just / on its own) do not match a skill and the input falls back to free-form.

  4. The leading / is stripped and the remaining name is looked up in the loaded registry. A hit returns { skill, args }. A miss falls back to free-form.

args is whatever followed the first run of whitespace after the token, trimmed. Example: @@ /translate-en hello world resolves to skill: translate-en with args: "hello world" — inner whitespace is preserved verbatim, only the edges are trimmed.

There is no error UI for a missing skill. @@ /notaskill foo is sent as a free-form prompt (/notaskill foo) — the model deals with it however it likes. This is intentional: the surface stays out of your way, and you can always introduce a new skill name later without breaking older notes that happen to mention /notaskill.

Reusing Claude Code skill files

The skill file format is intentionally close to Claude Code's .claude/skills/ files so an existing collection of skill prompts can be ported with minimal edits. The pieces that line up directly:

  • Frontmatter shape. YAML between --- delimiters, parsed the same way.

  • Markdown body as system prompt. Same convention — what comes after the frontmatter is the durable instruction.

  • File location. Claude Code uses <workspace>/.claude/skills/; zudo-text uses <workspace>/.zudotext/skills/. Move (or symlink) the files into the inline-command directory when porting.

What is specific to the inline-command driver and must be added when porting:

  • name — required, slug-format. Claude Code skills use name too, but the inline-command resolver enforces ^[a-z][a-z0-9-]*$. Rename if you have something that does not match (uppercase, spaces, _, etc.).

  • description — required. Some Claude Code skills omit it; the inline-command parser rejects the file without one.

  • mode — specific to the inline-command driver. Optional; defaults to inline. Claude Code does not have this field.

What is ignored when porting:

  • Any frontmatter field other than name, description, mode, and model. Extra keys are silently dropped — they do not cause a validation error, but they have no effect either. (model is read but is itself a no-op against the current agent-server backend today; see the frontmatter table above.)

  • Claude Code-only directives in the body (tool-use sections, sub-agent invocations, etc.). The inline-command driver passes the body verbatim to the model as a system prompt; it does not interpret Claude Code-specific markers.

Troubleshooting

A new skill file does not appear in autocomplete

  • Frontmatter failed validation. Open the developer console and look for [inline-command-skills] skipped <path>: <reason>. The most common reasons are a missing name or description, or a name that violates the slug pattern (uppercase, leading digit, contains _ or space).

  • Filename does not end in .md. The loader only ingests .md files. Rename translate-en.markdowntranslate-en.md.

  • The directory does not exist yet. A missing directory is treated as an empty layer — no error is raised. Use the Reveal Skills Folder button in Settings → Inline AI Command to create / open it.

  • The skill is workspace-scoped and the trust gate is off. This is the most common cause for a workspace skill. Workspace skills are loaded only when Trust workspace skills is on (it is off by default); while it is off the whole workspace layer is skipped — the file is never even scanned. See The workspace skill security gate.

  • You edited the wrong layer. When the workspace gate is on, the workspace layer wins; if a workspace skill with the same name is present, your user-scoped edit is shadowed. Look for the diagnostic shadowed console.warn.

Hot-reload is not picking up edits

  • The watcher reads the file on every change event. If your editor uses an atomic-save scheme (write-to-temp → rename), some watchers see the rename as a "removed + added" pair. The loader handles that case, but the registry blip can be a few hundred milliseconds — try the skill again after a short pause.

  • Network-mounted user skill directories (SMB, NFS) sometimes do not produce inotify events at all. If your local ~/.config/zudotext/<appname>/skills/ directory resolves to a network mount, expect to restart the writing app after changing a user skill. This caveat does not describe cloud workspace storage.

Output is missing, gibberish, or in the wrong language

This is rarely a skill-file problem; most often it is the underlying model. See the Inline AI command troubleshooting section for the model and provider checks.