---
title: "Adapt a Pi Package"
source: https://docs.autohand.ai/guides/extensions/adapt-pi-package
---

# Adapt a Pi package

Preserve portable Agent Skills directly, translate Pi runtime registrations to Extension API v1, compile before packaging, and make every semantic difference and trust decision explicit.

## 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.

``` json
{
  "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 behavior | Autohand destination | Trust |
|---|---|---|
| SKILL.md instructions and references | contributes.skills | Declarative; review content and paths |
| Bounded shell-backed tool | contributes.tools | Declarative; normal invocation authorization |
| Focused sub-agent prompt | contributes.agents | Declarative; tool list is not a permission grant |
| registerCommand | api.commands.register | Trusted runtime |
| Pi UI, renderer, menu, dialog, or editor | api.ui.registerView with host React and Ink | Trusted runtime |
| Event handler | api.hooks.on | Trusted runtime |
| Shortcut or startup flag | api.keybindings.register or api.cli.registerFlag | Trusted runtime |
| Model provider | api.providers.register plus extensionProviders config | Trusted runtime |
| Permission behavior | Declarative tools plus api.permissions.registerPolicy | Trusted policy cannot override immutable security |
| Long-running service or isolated integration | MCP server or Agent SDK host | Separate 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:

``` json
{
  "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.

``` js
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.

``` bash
npm run build

# Review the emitted entrypoint and bundled dependency notices.
sed -n '1,260p' dist/extension.mjs
```

``` json
{
  "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.

| Original | Adapted behavior | Reason |
|---|---|---|
| Pi skill | Same $release-workflow name and referenced rubric | Portable Agent Skill contract |
| Pi command | /release registered through Autohand routing | Built-in commands remain reserved |
| Pi custom UI | Host React 19 + Ink 7 view | Avoid duplicate renderers and preserve terminal cleanup |
| Pi permission callback | Autohand policy and normal approval path | Immutable security and session mode remain authoritative |

## Validate, trust, and prove lifecycle

``` bash
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

[

### Tool + Agent Skill

Build a declarative workspace-brief package with no runtime trust.

Build the safe layer](/tutorials/extensions/workspace-brief-extension.html)[

Runtime

### Trusted runtime showcase

Build every Extension API v1 runtime registration surface.

Build the runtime layer](/tutorials/extensions/build-runtime-extension.html)