authoring-magenta-scripts

star 448

How to author magenta scripts. Magenta scripts allow for programmatic orchestration of magenta threads. Use this skill when the user explicitly asks you to write a magenta script (not just a regular script).

dlants By dlants schedule Updated 6/9/2026

name: authoring-magenta-scripts description: How to author magenta scripts. Magenta scripts allow for programmatic orchestration of magenta threads. Use this skill when the user explicitly asks you to write a magenta script (not just a regular script).

Discovery and the registerScript contract

Each script package lives in its own subdirectory of a scripts directory (.magenta/scripts/<package>/ or ~/.magenta/scripts/<package>/), so multiple independent installations can coexist. A package is a directory containing an index.ts entry point.

Magenta discovers scripts by forking each <package>/index.ts file. That file is executed, and all registerScript() calls report script definitions to magenta via IPC.

The magenta-sdk symlink

Scripts import the SDK from magenta-sdk, a symlink inside each package directory (e.g. .magenta/scripts/my-package/magenta-sdk) pointing at magenta.nvim/sdk in the plugin installation. Scripts import it via ./magenta-sdk/index.ts (and ./magenta-sdk/testing.ts for the test harness).

Magenta does not create or manage this symlink for you. When authoring a script package you (the agent or the user) must create it yourself, e.g.:

ln -s <plugin>/sdk .magenta/scripts/my-package/magenta-sdk

The directory layout looks like:

.magenta/scripts/
  my-package/
    magenta-sdk -> <plugin>/sdk
    index.ts
    my-script.ts
  other-package/
    magenta-sdk -> <plugin>/sdk
    index.ts
registerScript(name, description, parameterSchema, runner);
  • name: unique script name (how agents invoke it).
  • description: shown to agents so they know when to use it.
  • parameterSchema: a JSON Schema describing the parameters the runner receives.
  • runner(parameters, thread, log): an async function that does the work.

The runner receives:

  • parameters: the validated input object.
  • thread(prompt, yieldSchema, options?): spawns a real magenta thread seeded with prompt, equipped with a yield_to_parent tool whose input schema is yieldSchema. Resolves to the structured value the agent yields. Use the generic to type the result: await thread<{ done: boolean }>(...). options may include:
    • contextFiles: absolute paths to seed into the thread's context.
    • systemReminder: a recurring system reminder injected into the thread.
    • cwd, profile, model, tools.
  • log(message): reports progress; surfaced in the magenta Scripts section.

Minimal end-to-end example

// index.ts. file
import { registerScript } from "./magenta-sdk/index.ts";

registerScript(
  "summarize-file",
  "Summarizes a file and returns a one-line summary",
  {
    type: "object",
    properties: { path: { type: "string" } },
    required: ["path"],
  },
  async (params: { path: string }, thread, log) => {
    log(`summarizing ${params.path}`);
    const result = await thread<{ summary: string }>(
      `Read ${params.path} and summarize it in one sentence.`,
      {
        type: "object",
        properties: { summary: { type: "string" } },
        required: ["summary"],
      },
    );
    log(`summary: ${result.summary}`);
  },
);

Testing a script

Use the in-process test harness from ./magenta-sdk/testing.ts. It drives your runner with test-double thread/log — no subprocess and no magenta required. Statically import your script module first so its registerScript call runs.

import { expect, it } from "vitest";
import { runScript } from "./magenta-sdk/testing.ts";
import "./summarize-file.ts"; // registers the script

it("summarizes", async () => {
  const { handle, donePromise } = runScript("summarize-file", {
    path: "README.md",
  });

  const call = await handle.nextThread();
  expect(call.prompt).toContain("README.md");
  call.yield({ summary: "It is a readme." });

  await donePromise;
  expect(handle.logs).toContain("summary: It is a readme.");
});

handle.nextThread() resolves with each pending thread() call (in order), exposing prompt, yieldSchema, options, and yield(value) / reject(error) to settle that specific call. handle.logs captures log() output.

Install via CLI
npx skills add https://github.com/dlants/magenta.nvim --skill authoring-magenta-scripts
Repository Details
star Stars 448
call_split Forks 33
navigation Branch main
article Path SKILL.md
More from Creator