Start from observable behavior

Compatibility is a reviewed adaptation, not a promise that Autohand can import arbitrary Pi TypeScript. Write down what users can observe: skill invocation, commands, tool results, dialogs, status content, shortcuts, flags, hooks, model behavior, and permission decisions.

Good target: “Preserve $release-workflow, /release, the release picker, Ctrl+R, and the provider-backed summary; document that Autohand uses its own modal lifecycle and permission ordering.”

Invoke the bundled authoring skill with the source path and desired outcome:

$extension-builder adapt ./pi-release-helper for Autohand. Preserve its Agent Skill, /release command, picker, shortcut, and provider. Inspect without executing source, compile the runtime, validate it, and install at project scope only after review.

Inspect without executing the package

Read package.json, every pi.extensions and pi.skills path, referenced resources, local dependencies, build scripts, and lockfiles as data. Do not import the package or run its lifecycle scripts merely to discover registrations.

{
  "name": "pi-release-helper",
  "pi": {
    "extensions": ["./extensions/index.ts"],
    "skills": ["./skills/release-workflow/SKILL.md"]
  }
}

Record every external dependency and side effect before choosing the destination. Network calls, process spawning, filesystem mutation, credential reads, and native modules need an explicit operating and trust story.

Classify each contribution

Pi behaviorAutohand destinationTrust
SKILL.md instructions and referencescontributes.skillsDeclarative; review content and paths
Bounded shell-backed toolcontributes.toolsDeclarative; normal invocation authorization
Focused sub-agent promptcontributes.agentsDeclarative; tool list is not a permission grant
registerCommandapi.commands.registerTrusted runtime
Pi UI, renderer, menu, dialog, or editorapi.ui.registerView with host React and InkTrusted runtime
Event handlerapi.hooks.onTrusted runtime
Shortcut or startup flagapi.keybindings.register or api.cli.registerFlagTrusted runtime
Model providerapi.providers.register plus extensionProviders configTrusted runtime
Permission behaviorDeclarative tools plus api.permissions.registerPolicyTrusted policy cannot override immutable security
Long-running service or isolated integrationMCP server or Agent SDK hostSeparate process boundary

If a bounded declarative contribution preserves the behavior, prefer it. Use the runtime layer only for behavior that genuinely belongs inside the Autohand process.

Port the Agent Skill first

Copy the complete skill directory, not only its entrypoint, and declare the SKILL.md path:

{
  "schemaVersion": 1,
  "extensionApi": 1,
  "id": "company.release-helper",
  "name": "Release Helper",
  "version": "1.0.0",
  "description": "Prepare evidence-backed releases.",
  "contributes": {
    "skills": ["skills/release-workflow/SKILL.md"]
  }
}

Update host-specific command names, tool names, filesystem assumptions, and examples. Keep references relative to the skill directory. After installation, daily use is $release-workflow; $extension-builder is only for authoring and repair.

Translate runtime registrations

Write an Autohand entrypoint instead of wrapping or evaluating Pi source. Preserve intent while using Autohand's host-owned React, Ink, command routing, and cleanup.

export function activate(api) {
  const { React, Ink } = api.ui;

  function ReleasePicker({ close }) {
    Ink.useInput((_input, key) => {
      if (key.return) close('release plan selected');
    });
    return React.createElement(
      Ink.Text,
      { color: 'cyan' },
      'Press Enter to build the release plan',
    );
  }

  api.ui.registerView({
    id: 'company.release-helper.picker',
    title: 'Release picker',
    component: ReleasePicker,
  });

  api.commands.register({
    command: '/release',
    description: 'Open the release workflow',
    execute(context) {
      return context.ui.open('company.release-helper.picker');
    },
  });

  api.keybindings.register({
    key: 'ctrl+r',
    command: '/release',
    when: 'input-empty',
  });
}

Autohand owns modal pause/resume, alternate-screen cleanup, Escape, and Ctrl+C behavior. Do not bundle a second React or Ink copy. Commands, views, flags, providers, segment ids, and shortcuts must not collide with built-ins or other extensions.

Compile and declare the runtime

Autohand loads compiled JavaScript only. Use your existing build tool to emit a self-contained runtime file and declare that output, not the TypeScript source.

npm run build

# Review the emitted entrypoint and bundled dependency notices.
sed -n '1,260p' dist/extension.mjs
{
  "schemaVersion": 1,
  "extensionApi": 1,
  "id": "company.release-helper",
  "name": "Release Helper",
  "version": "1.0.0",
  "description": "Prepare evidence-backed releases.",
  "contributes": {
    "skills": ["skills/release-workflow/SKILL.md"],
    "runtime": ["dist/extension.mjs"]
  }
}

Do not rely on postinstall, dynamic TypeScript transpilation, or undeclared files. A copied install must remain functional without the original development checkout.

Document semantic differences

Create a short mapping table in the extension README. Call out intentionally changed behavior instead of implying byte-for-byte compatibility.

OriginalAdapted behaviorReason
Pi skillSame $release-workflow name and referenced rubricPortable Agent Skill contract
Pi command/release registered through Autohand routingBuilt-in commands remain reserved
Pi custom UIHost React 19 + Ink 7 viewAvoid duplicate renderers and preserve terminal cleanup
Pi permission callbackAutohand policy and normal approval pathImmutable security and session mode remain authoritative

Validate, trust, and prove lifecycle

autohand extensions validate ./company.release-helper
autohand extensions install ./company.release-helper --link --trust
autohand extensions show company.release-helper
autohand extensions doctor

# Start a fresh CLI and exercise $release-workflow, /release, and Ctrl+R.

autohand extensions disable company.release-helper
autohand extensions enable company.release-helper
autohand extensions remove company.release-helper --yes

# Release proof uses a copied install:
autohand extensions install ./company.release-helper --trust
  1. Save validation JSON and a deliberately broken-package failure.
  2. Exercise every skill, tool, agent, command, view, shortcut, flag, hook, provider, and policy under normal permissions.
  3. Prove a denied tool call cannot be bypassed.
  4. Use a real PTY/Tuistory test for modal and keyboard behavior.
  5. Confirm disable removes all registrations and enable restores them once.
  6. Verify a fresh copied install from an immutable checkout before publishing.

Never ask users to trust code they cannot review. Publish source, emitted runtime, dependency notices, build instructions, and an immutable release tag together.

Related builds