Scaffold the penpot extension directory and register it in the repo manifest #186

Closed
opened 2026-09-14 23:08:14 +00:00 by david · 1 comment
Owner

Summary

Create the initial scaffold for a new pi extension, penpot, at extensions/penpot/ in this repository — a minimal but loadable entry point, an src/ directory for the modules later issues fill in, and a placeholder README.md — and register it in the root package.json pi.extensions manifest so pi loads it.

Background

This is a brand-new extension (TypeScript) that will expose a penpot_* tool family for creating designs against Penpot's access-token RPC API (POST/GET <PENPOT_URL>/api/rpc/command/<command>, header Authorization: Token <token>). Nothing penpot-related exists in this repo yet — this step builds from scratch and is a prerequisite for every later penpot issue.

Repo conventions this step must follow:

  • Extensions are plain TypeScript modules living under extensions/<name>/, registered by path in the root package.json under "pi": { "extensions": [...] }.
  • The entry point is a default-exported factory: export default function (pi: ExtensionAPI): void { ... }. Both extensions/learn-repo/index.ts and extensions/victorialogs/index.ts show this shape.
  • extensions/learn-repo/ is the closest structural precedent: it has no per-extension package.json, no tsconfig.json, and no bundler — it is a plain module tree tested by the root npm test script with node --test (Node 24 strips TypeScript types natively; .ts imports use explicit extensions). Follow that pattern rather than the bun-based extensions/mongodb/ / extensions/victorialogs/ packages.
  • The root package.json already has typebox as a dependency, so no new dependency is needed. This extension's own runtime deps are Node built-ins (fetch, FormData, Blob, node:test).

This step deliberately registers no toolspenpot_whoami arrives in a later step of the same milestone. The entry point must still be valid and load cleanly so that /reload in pi does not error.

Documentation Required

A separate process downloads these into the listed folders before this issue is implemented. Check the folders for the actual reference material before starting.

docs/reference/pi-coding-agent/

docs/reference/typebox/

  • https://github.com/sinclairzx81/typebox — official TypeBox README: Type.Object, Type.String, Type.Optional and Type.Static<typeof T>. Needed here only to confirm the dependency is available from the root manifest; the schemas themselves arrive in later issues.

Implementation Details

Create the following under extensions/penpot/:

  1. src/index.ts — the extension entry point. A default-exported factory matching the sibling extensions:

    import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
    
    /**
     * Penpot pi extension entry point.
     *
     * Tools are registered per milestone; this scaffold intentionally registers none.
     */
    export default function (pi: ExtensionAPI): void {
      // Tools are registered by later steps in this milestone and the next ones.
    }
    

    Keep the registration site so later steps only add pi.registerTool(...) calls. Do not read PENPOT_URL/PENPOT_TOKEN or perform any network call at load time — later steps resolve configuration lazily per call so a misconfigured environment never breaks extension loading.

  2. README.md — a minimal placeholder (title plus a one-line description such as "Penpot design-creation tools for pi — create colour/typography assets, compose screens and instance library components over the Penpot RPC API."). Full content (tool reference, env vars, safety model) is written in a later documentation step.

  3. src/ — the directory the later modules (env.ts, errors.ts, client.ts, changes.ts, svg.ts, binfile.ts) will live in. It is fine for it to contain only index.ts at this stage.

Then register the entry point in the root package.json:

"pi": {
  "extensions": [
    "extensions/rg/index.ts",
    // ... existing entries, unchanged ...
    "extensions/penpot/src/index.ts"
  ],
  "skills": [
    "./skills"
  ]
}

Do not touch "skills" (a later milestone adds skills/penpot/), do not add the new test files to scripts.test yet (they do not exist — a later step registers them), and do not reorder or reformat the existing extension entries beyond appending.

Acceptance Criteria

  • extensions/penpot/src/index.ts exists and default-exports a factory that accepts an ExtensionAPI argument and registers nothing.
  • The root package.json pi.extensions array contains "extensions/penpot/src/index.ts", appended without altering existing entries.
  • extensions/penpot/src/ exists as a directory.
  • extensions/penpot/README.md exists with at least a title and a one-line description of the extension.
  • Extension loading performs no network request and reads no environment variables at load time.
  • node --test at the repo root and npm test still pass unchanged (no regressions from the manifest edit).
  • No new npm dependency is added; no per-extension package.json/tsconfig.json is introduced.

Test Plan

  1. Validate the manifest is still valid JSON and the new path is present:

    node -e "const p=require('./package.json'); console.log(p.pi.extensions)"
    # expect the array including extensions/penpot/src/index.ts
    
  2. Confirm the entry point is syntactically loadable and registers nothing:

    node --input-type=module -e "import('./extensions/penpot/src/index.ts').then(m => { const calls=[]; m.default({ registerTool: (t) => calls.push(t) }); console.log('tools:', calls.length); })"
    # expect: tools: 0, no thrown error
    
  3. Run the existing suite to confirm no regression:

    npm test
    
  4. In pi, run /reload and confirm no extension-load error is reported for penpot (no penpot tools are expected to appear yet).

## Summary Create the initial scaffold for a new pi extension, `penpot`, at `extensions/penpot/` in this repository — a minimal but loadable entry point, an `src/` directory for the modules later issues fill in, and a placeholder `README.md` — and register it in the root `package.json` `pi.extensions` manifest so pi loads it. ## Background This is a brand-new extension (TypeScript) that will expose a `penpot_*` tool family for creating designs against Penpot's access-token RPC API (`POST/GET <PENPOT_URL>/api/rpc/command/<command>`, header `Authorization: Token <token>`). Nothing penpot-related exists in this repo yet — this step builds from scratch and is a prerequisite for every later penpot issue. Repo conventions this step must follow: - Extensions are plain TypeScript modules living under `extensions/<name>/`, registered by path in the **root** `package.json` under `"pi": { "extensions": [...] }`. - The entry point is a default-exported factory: `export default function (pi: ExtensionAPI): void { ... }`. Both `extensions/learn-repo/index.ts` and `extensions/victorialogs/index.ts` show this shape. - `extensions/learn-repo/` is the closest structural precedent: it has **no** per-extension `package.json`, no `tsconfig.json`, and no bundler — it is a plain module tree tested by the root `npm test` script with `node --test` (Node 24 strips TypeScript types natively; `.ts` imports use explicit extensions). Follow that pattern rather than the bun-based `extensions/mongodb/` / `extensions/victorialogs/` packages. - The root `package.json` already has `typebox` as a dependency, so no new dependency is needed. This extension's own runtime deps are Node built-ins (`fetch`, `FormData`, `Blob`, `node:test`). This step deliberately registers **no tools** — `penpot_whoami` arrives in a later step of the same milestone. The entry point must still be valid and load cleanly so that `/reload` in pi does not error. ## Documentation Required A separate process downloads these into the listed folders before this issue is implemented. Check the folders for the actual reference material before starting. **`docs/reference/pi-coding-agent/`** - https://pi.dev/docs/latest/extensions — pi extension authoring: the `ExtensionAPI` type, the default-exported factory, `pi.registerTool`, and how extensions are discovered from a package manifest. This is the primary reference for the entry-point shape. - https://pi.dev/docs/latest/packages — pi package manifest format, including the `"pi": { "extensions": [...], "skills": [...] }` fields that must be updated here. - https://www.npmjs.com/package/@earendil-works/pi-coding-agent — package overview and install/type entry points for the `ExtensionAPI` import. **`docs/reference/typebox/`** - https://github.com/sinclairzx81/typebox — official TypeBox README: `Type.Object`, `Type.String`, `Type.Optional` and `Type.Static<typeof T>`. Needed here only to confirm the dependency is available from the root manifest; the schemas themselves arrive in later issues. ## Implementation Details Create the following under `extensions/penpot/`: 1. **`src/index.ts`** — the extension entry point. A default-exported factory matching the sibling extensions: ```ts import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; /** * Penpot pi extension entry point. * * Tools are registered per milestone; this scaffold intentionally registers none. */ export default function (pi: ExtensionAPI): void { // Tools are registered by later steps in this milestone and the next ones. } ``` Keep the registration site so later steps only add `pi.registerTool(...)` calls. Do **not** read `PENPOT_URL`/`PENPOT_TOKEN` or perform any network call at load time — later steps resolve configuration lazily per call so a misconfigured environment never breaks extension loading. 2. **`README.md`** — a minimal placeholder (title plus a one-line description such as "Penpot design-creation tools for pi — create colour/typography assets, compose screens and instance library components over the Penpot RPC API."). Full content (tool reference, env vars, safety model) is written in a later documentation step. 3. **`src/`** — the directory the later modules (`env.ts`, `errors.ts`, `client.ts`, `changes.ts`, `svg.ts`, `binfile.ts`) will live in. It is fine for it to contain only `index.ts` at this stage. Then register the entry point in the **root** `package.json`: ```jsonc "pi": { "extensions": [ "extensions/rg/index.ts", // ... existing entries, unchanged ... "extensions/penpot/src/index.ts" ], "skills": [ "./skills" ] } ``` Do not touch `"skills"` (a later milestone adds `skills/penpot/`), do not add the new test files to `scripts.test` yet (they do not exist — a later step registers them), and do not reorder or reformat the existing extension entries beyond appending. ## Acceptance Criteria - [ ] `extensions/penpot/src/index.ts` exists and default-exports a factory that accepts an `ExtensionAPI` argument and registers nothing. - [ ] The root `package.json` `pi.extensions` array contains `"extensions/penpot/src/index.ts"`, appended without altering existing entries. - [ ] `extensions/penpot/src/` exists as a directory. - [ ] `extensions/penpot/README.md` exists with at least a title and a one-line description of the extension. - [ ] Extension loading performs no network request and reads no environment variables at load time. - [ ] `node --test` at the repo root and `npm test` still pass unchanged (no regressions from the manifest edit). - [ ] No new npm dependency is added; no per-extension `package.json`/`tsconfig.json` is introduced. ## Test Plan 1. Validate the manifest is still valid JSON and the new path is present: ```bash node -e "const p=require('./package.json'); console.log(p.pi.extensions)" # expect the array including extensions/penpot/src/index.ts ``` 2. Confirm the entry point is syntactically loadable and registers nothing: ```bash node --input-type=module -e "import('./extensions/penpot/src/index.ts').then(m => { const calls=[]; m.default({ registerTool: (t) => calls.push(t) }); console.log('tools:', calls.length); })" # expect: tools: 0, no thrown error ``` 3. Run the existing suite to confirm no regression: ```bash npm test ``` 4. In pi, run `/reload` and confirm no extension-load error is reported for `penpot` (no penpot tools are expected to appear yet).
david closed this issue 2026-09-14 23:26:23 +00:00
Author
Owner

pi-loop opened and merged a pull request for this issue: #219

pi-loop opened and merged a pull request for this issue: https://git.excelera.net/david/pi-extensions-and-skills/pulls/219
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
david/pi-extensions-and-skills#186
No description provided.