zudo-text

検索したい単語を入力

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

Inline AI command

The Inline AI command is a lightweight prompt surface that lives inside the editor itself. Instead of context-switching to a chat panel, you stay on the line you are writing, type a short instruction, and the writing app streams the response back into the same document — either as ghost text you bake in with Tab, or into a small floating panel you can review before keeping.

It is designed for the small, in-the-flow edits you do dozens of times a day while drafting: rewriting a sentence, translating a paragraph, expanding a bullet point, summarising a quote. Free-form prompts work, but you can also save reusable instructions as skills — see Skill authoring for that.

By default, each request also carries a bounded, line-aligned window around the command from the current note. The setting can turn that surrounding context off when the command and selection are enough.

Triggering the command

There are two ways to enter capture mode:

1. Type the prefix

In the editor, start a line with the trigger sequence (default @@ followed by a space) and the writing app drops you into capture mode. A small pill renders at the trigger position so you can see the surface is armed:

@@ summarise the paragraph above in one line

The prefix only counts at the start of a line (leading whitespace is allowed). A literal @@ mid-sentence such as foo @@ bar is ignored, and the prefix is also ignored inside fenced code blocks.

2. Press the keyboard shortcut

The default shortcut is Cmd+J (Mod-j, set as inlineAiCommandTrigger in shortcuts). Pressing it inserts @@ at the cursor — or on a fresh line just above when the cursor is mid-line — and immediately enters capture mode. The shortcut is the fastest path when you are already typing and do not want to backspace to the line start.

You can rebind it from Settings → Shortcuts like any other shortcut.

Output modes

Once the command is captured, two gestures decide where the response goes:

Tab — bake inline

Pressing Tab runs the command and streams the result as ghost text directly under the trigger line. You can keep watching it stream in, then press Tab again to bake the result into the document — at which point the @@ … line is replaced with the generated content.

This mode is the right default for short, deterministic edits where you trust the model: rewrites, translations, fills, list expansions. Round trips are minimal because the result lands in place.

Cmd+Enter — open the mini panel

Pressing Cmd+Enter instead opens a small floating mini panel anchored to the trigger line. The response streams into the panel, you can read it without committing to anything, and only then decide to:

  • Insert at cursor to replace the @@ … line with the most recent answer, or

  • Apply to note when a selection was captured. This opens the shared diff review so you can compare the selected text with the answer before replacing it, or

  • Promote to thread to prefill a new AI Assistant composer with the exchange, or

  • Dismiss the panel and keep the editor untouched, or

  • send one follow-up from the panel.

The panel mode is the right default for longer or higher-stakes generations — drafts, summaries, anything you want to glance at before it lands in the document.

The panel accepts one follow-up. It sends the original request, first answer, and follow-up together, and carries the same surrounding context window into that request. After the follow-up, the input is disabled; promote the exchange to AI Assistant when you need a continuing conversation. Insert at cursor always uses the most recent answer.

The panel's Apply to note and the assistant's existing-note proposals use the same diff review. Apply writes the replacement, Discard closes the review without writing, and its X button or Escape dismisses the review without choosing either outcome. A dismissed review leaves the panel or proposal available.

The panel starts at up to 720 × 480 pixels (or 60% of the viewport height), is kept above the status bar, and can be dragged or resized. Its geometry is saved per workspace and is clamped again after a window or status-bar resize so the actions and resize grip remain reachable.

Selection-aware behaviour

If you have a selection in the editor when you trigger the command, the prompt is treated as an instruction applied to the selected text rather than a free-form generation:

  • Without a selection, @@ translate to English produces an English passage from scratch (whatever the model decides to write).

  • With the previous paragraph selected, @@ translate to English produces an English translation of that paragraph.

This matches the way you usually want to work — select the chunk you mean, then describe what to do with it. Selection handling is identical for both Tab (inline) and Cmd+Enter (panel) gestures, and identical whether you are running a free-form prompt or a /skill-name skill.

When a selection is present, Tab and Insert at cursor still replace the trigger line and leave the selected text in place. To replace the selected text, use Apply to note in the mini panel. It revalidates the range before opening the diff and before applying, then makes one transaction and one undo step. If the selection moved or changed, the replacement is refused and the command can be run again.

Settings overview

A dedicated Inline AI Command section in Settings (added in the Sub 11 wiring; opens via the settings dialog or the command palette) collects the feature's preferences. The main fields are:

  • Enabled — master toggle. When off, the trigger sequence, the keyboard shortcut, and every command-palette entry for the feature become no-ops.

  • Trigger sequence — which prefix preference is stored for the editor. The default is @@. /ai currently follows the same @@ detector; setting it to off disables the inline command extension, including its keyboard shortcut, until you choose @@ or /ai again.

  • Default mode — the stored preference for the two output surfaces. inline (Tab) bakes ghost text directly into the document; panel (Cmd+Enter) opens the mini panel. The submit gesture currently decides the output surface.

  • Insert on line start only — a stored preference for the keyboard trigger. The current shortcut behavior inserts @@ at the cursor or on a fresh line above when the cursor is mid-line; the setting is retained for the editor's future line-start policy.

  • Trust workspace skills — gates whether skill files in the workspace-scoped directory (<workspace>/.zudotext/skills/) are loaded at all. It defaults to off, which means workspace skills are not loaded — only the user-scoped layer is active. Turn it on only after you have reviewed the workspace's skill files. See The workspace skill security gate below.

  • Reveal Skills folder — a button that opens the workspace's .zudotext/skills/ directory in Finder. This is the workspace-scoped layer where your custom skills live; see Skill authoring.

Surrounding note context

With Surrounding note context set to Send a bounded window (the default), the command carries up to 12 KiB of surrounding note text, measured as UTF-8 bytes. The window is line-aligned around the @@ line, prefers nearby lines, and marks omitted text with […]. The selected text, when present, is sent separately and remains available even when surrounding context is off.

The assembled request is preflighted against a 48 KiB UTF-8 body budget. If a request is too large, only the surrounding window is reduced; the command, selection, and skill instructions stay intact. If those fixed fields alone do not fit, the command is refused with a message asking for shorter input.

The model is @cf/meta/llama-3.3-70b-instruct-fp8-fast on Cloudflare Workers AI — the same model the AI assistant panel uses, served by the same agent-server Worker but through its one-shot /inline route rather than a durable Flue conversation. No per-machine model setup is required; access is gated by your cloud workspace sign-in. See AI Provider for quota details.

The workspace skill security gate

Skill files live in two places: a user-scoped directory (~/.config/zudotext/<appname>/skills/, private to you) and a workspace-scoped directory (<workspace>/.zudotext/skills/, committed alongside the workspace and easy to clone from somewhere else). Because a skill's body becomes the system prompt that the AI model runs, an untrusted workspace skill is effectively arbitrary instructions for the AI — so the workspace layer is gated behind an explicit opt-in.

The gate is the Trust workspace skills setting (inlineAiCommand.trustWorkspaceSkills in the settings file). It defaults to false.

  • When the setting is off (the default), the workspace skill layer is skipped entirely. The loader does not even scan <workspace>/.zudotext/skills/ and does not watch it for changes — no workspace file is loaded, parsed, or surfaced in autocomplete. This is stronger than shadowing: a workspace skill is not "hidden behind" a user skill, it simply never enters the registry. Only user-scoped skills are available.

  • When you turn it on, the workspace layer is loaded and merges with the user layer using the usual precedence (workspace wins on a name collision; the shadowed user file is reported). See Skill authoring → Override rules.

Turn this on only after you have opened the workspace's .zudotext/skills/ directory and read the skill bodies — treat them the way you would treat any script you are about to run. If a skill you expect to use does not appear in autocomplete and it lives in the workspace directory, check this setting first: an off gate is the most common reason a workspace skill is invisible.

Free-form vs skill commands

The text after the trigger is interpreted in one of two ways:

  • Free-form prompt — anything that does not start with / is sent to the LLM as a plain instruction. Example: @@ rewrite this in a friendlier tone.

  • Skill command — a /skill-name token resolves against the loaded skills (workspace dir, then user dir). Example: @@ /translate-en こんにちは. If the slug matches a skill, the rest of the line is passed as the skill's argument and the skill's body becomes the system prompt. If the slug does not match anything, the input falls back to free-form — /notaskill is sent verbatim, no error pop-up.

For how to write your own skills, see Skill authoring.

Troubleshooting

Nothing happens when I type @@ or press Cmd+J

A handful of things can swallow the trigger:

  • The feature is disabled. Check Settings → Inline AI Command → Enabled. The toggle is on by default, but a previous session or settings sync may have flipped it.

  • The trigger sequence is set to off. That setting disables the inline command extension, including the keyboard shortcut. Pick @@ or /ai to enable it again.

  • The cursor is mid-sentence. Cmd+J inserts a fresh @@ line above the cursor. The saved "Insert on line start only" preference does not change this current behavior.

  • You are inside a fenced code block. The trigger detector deliberately ignores ``` blocks so the prefix you wrote in a code sample does not arm the surface.

The pill appears but pressing Tab does nothing

The inline command requires a signed-in cloud workspace session. If you are not signed in, requests fail silently at the network layer. Open Settings → Sync and sign in, then retry.

The response is gibberish, wrong language, or stops mid-sentence

This is almost always a transient server or quota issue rather than a writing-app problem:

  • Check that the daily quota has not been exhausted. The AI provider page describes the 100-turn daily limit.

  • If the response truncates, try shortening the selection or running the command on a smaller chunk — very long context windows occasionally time out.

The shortcut conflicts with another binding

Cmd+J is a relatively safe default on macOS, but if it collides with something you have already bound (a Vim command, another app command, etc.), open Settings → Shortcuts and rebind inlineAiCommandTrigger to anything else. Chord bindings (e.g. Mod-k Mod-i) are supported too.

A skill I just edited still produces the old output

Skill files are watched at runtime — saving the file should trigger a hot-reload. If the new prompt does not seem to apply:

  • Confirm the file's frontmatter still validates. Invalid frontmatter is logged with a console.warn and the file is skipped silently. Open the developer console and look for [inline-command-skills] skipped ….

  • Confirm you are not editing a shadowed copy. A workspace-scoped skill takes precedence over a user-scoped one with the same name. The loader emits a shadowed event when this happens; details in the skill authoring guide.

  • As a last resort, restart the writing app — that always rebuilds the registry from disk.