<p><strong>Elyra's </strong><code>extension_write</code><strong> — self-extensibility, completed</strong></p><p>Elyra has always been "self-extensible." You can teach it new tools by writing extensions — small TypeScript files that register tools the agent can call. We've shipped dozens: Laravel tools, database tools, a YouTrack integration, Docker, and more.</p><p>But there was always an asymmetry. The <em>human</em> extended the agent. The agent itself, when it ran into a wall — "I keep needing to call this internal CLI, but I have no tool for it" — could only shell out to bash over and over.</p><p>Version 0.9.3 closes that gap. The agent can now write its own extensions. When it repeatedly needs a capability it doesn't have, it builds the tool.</p><h2>The progression</h2><p>A few releases ago we gave the agent self-writing <em>skills</em> — the ability to save hard-won knowledge as reusable markdown. This is the natural next step:</p><ul><li><p><strong>Skills</strong> are knowledge: "here's how Stripe webhooks work in this project."</p></li><li><p><strong>Extensions</strong> are capabilities: "here's a <em>tool</em> that talks to the Stripe API."</p></li></ul><p>Skills teach the agent. Extensions give it new hands. Now it can author both.</p><h2>How it works</h2><p>When the agent decides it needs a recurring capability, it calls <code>extension_write</code> with the name, a description, and the actual TypeScript source:</p><pre><code class="language-typescript">elyra.registerTool({
    name: "deploy_status",
    label: "Deploy Status",
    description: "Check the status of a deployment by ID",
    parameters: Type.Object({ id: Type.String() }),
    async execute(_id, params) {
        // ... calls your internal deploy API ...
    },
});
</code></pre><p>Elyra validates it before writing — the code must have a default export and actually register a tool, so the agent can't save something broken:</p><pre><code class="language-typescript">export function validateExtensionCode(code: string): string | null {
    if (!/export\s+default\b/.test(code)) {
        return "extension code must have a default export";
    }
    if (!/registerTool\s*\(/.test(code)) {
        return "extension code should register at least one tool";
    }
    return null;
}
</code></pre><p>Then you see a proposal:</p><pre><code>─────────────────────────────────────────────
 Elyra wants to add a new tool. Save it as an extension?

 deploy-status.ts (project)
 Check deployment status via the internal deploy API.

 Review the code before approving — extensions run with full access.

 &gt; Save extension
   Discard
─────────────────────────────────────────────
</code></pre><p>Approve, and <code>deploy-status.ts</code> lands in your extensions directory. After a <code>/reload</code>, the agent has a <code>deploy_status</code> tool it can call from then on.</p><h2>The crucial guardrail</h2><p>Extensions are <em>code that runs with full access</em>. An agent writing executable code that then runs in your environment is powerful and, handled carelessly, dangerous. So the design takes safety seriously:</p><ul><li><p><strong>Approval by default.</strong> The agent proposes; you review the code; you decide. The confirmation dialog explicitly warns you to read it.</p></li><li><p><strong>A loud reminder.</strong> "Extensions run with full access" is right there in the prompt, every time.</p></li><li><p><strong>Opt-in autonomy.</strong> Power users who trust the flow can enable "Auto-save extensions" in <code>/settings</code>, but it's off by default.</p></li></ul><p>This is the same philosophy as self-writing skills: the agent gets the magical capability, but you keep the veto until you explicitly hand it over.</p><h2>Where it fits</h2><p>The agent is told to use this sparingly — bash for one-offs, skills for knowledge, and <code>extension_write</code> only for capabilities that are <em>clearly recurring</em>. You don't want a new tool scaffolded for every passing need. You want one when the agent notices it's been doing the same awkward multi-step dance five times and could wrap it in a proper tool.</p><p>That's the dream of a self-extensible agent: not one you have to keep teaching, but one that notices its own gaps and fills them — with your sign-off.</p>