surface

Creating custom nodes with Penny.

Create a reusable node with Penny. Define its interface, review generated code and warnings, test known cases, and revise it while preserving its contract.

Written for
Anyone asking Penny to create or adapt a node in Studio.

When an existing node does not provide the operation you need, ask Penny to create one. It can write a custom node's Python and interface, save the script, and add an instance to your graph. You can describe the behavior in plain language; you still need to review and test what was built.

Decide what belongs in the node

Ask Penny to check available nodes first. A custom node is useful for a specific transformation, calculation, service integration, or reusable tool with its own controls. If existing steps already do the job, connecting them may be enough; see Building and editing graphs with Penny.

Keep the first version focused. Describe one operation and its inputs and outputs before adding a complex interface, network calls, or several optional behaviors. This makes the result easier to test and reuse.

Open the right authoring context

Use Assistant in the graph toolbar. Say whether you want a new node, a separate variation, or an edit to an existing custom node. For an edit, identify both the graph instance and its script path; ask Penny to confirm the active script before changing it.

Assistant node generation and manual code editing are separate capabilities. Depending on your account, Penny may be able to generate a node even when raw code editing is unavailable. The desktop graph toolbar's Code control and a node's Edit script action provide code access where supported. Built-in nodes offer a clone-and-edit flow; cloning creates a user copy. Mobile Penny does not expose every desktop authoring tool.

Write a brief with a testable contract

Specify input types, required or optional inputs, controls with defaults and ranges, outputs, and clear failure behavior. Include whether the node may use network services or install dependencies. For example:

Create a separate “Frame an image” node. It takes one required image and adds a solid border outside it, keeping the original pixels. Add an integer inset control from 0 to 64 pixels, default 24, and a frame-color control. Return a PNG image and a short settings summary. Missing images or invalid inset values must fail clearly without a success image. Use no model or network service. Save it in a new package, add one instance, and report its actual script path. Build only; do not run it.

State which settings should be editable after creation. Avoid relying on a value buried in the generated code when you need to change it regularly.

Review the proposed interface

Explore an example custom node's interface, intended output, and missing-input behavior.

The illustrative Frame an image contract has a required image input, an inset control from 0 to 64 pixels with default 24, a frame-color control, and image and summary outputs. Interface describes the operation before testing. Expected output illustrates an outside border, with the original image preserved. Missing image expects a clear failure and no success image. Every state describes intended behavior, not a completed run.

Authored artwork and concept cards are not actual Studio panels or a measured pixel preview. The controls create no node and execute no code.

Inspect names, types, defaults, ranges, and the declared outputs on the actual node. Check that required inputs and error behavior match the brief. A wire supplies a connected input's value; an input that looks different from the brief may need a schema correction, rather than just another prompt.

Keep the script and graph identities clear

Ask Penny to report the saved script path and the node instance it added. A saved script and a placed graph node are different outcomes. If saving succeeds but placement fails, have Penny inspect the saved node's catalog entry before creating another script. A filename conflict may produce a suffixed name; use the path actually returned by the tool.

Before modifying reused code, preserve a copy of the source or ask for a new package. Instances can refer to the same script path. Do not assume that selecting one instance, renaming its label, or copying a graph isolates the script you are about to overwrite. Preserve the graph separately through Saving and recovery.

Read source checks and warnings

Generated node saves apply source and contract checks. If a save is rejected, read its error, line information, and suggested correction; ask Penny to fix that specific problem and save again. Do not assume the proposed code became the saved version after an error.

Successful saves can also carry implementation warnings for patterns such as unfinished code, placeholder bodies, or exception handling that returns replacement content as success. Ask Penny to explain any warning. Static checks do not execute the node, and absence of warnings does not prove its behavior is complete or correct.

Use the supported node contract and runtime

For ordinary Python nodes, preserve comment-based metadata, input and output declarations, and a top-level run() function. Return an output dictionary with keys matching the declared outputs. Renaming a pin or changing its type can break an existing connection; keep the interface stable unless the change is intentional. See Writing custom nodes for code.

Ask Penny to use supported runtime helpers for files, output media, package assets, and service requests. User-node policy restricts direct filesystem access and backend internals; copying built-in Python may need adaptation. Declare needed packages through supported requirements metadata and handle unavailable dependencies visibly. Keep credentials out of source; configure services through the intended integration settings.

Plan the smallest useful tests

Use Manual evaluation on the test node and other affected nodes when you want to control execution; eligible Auto nodes can run after changes. Keep the construction request explicit about whether running is allowed. Building can still use a paid assistant model, even if the node needs no model call. Provider tests can incur separate usage; see Credits and billing.

Choose a small known input and write down the expected output before running. Include a boundary value and a failure case. For media, inspect the produced file as well as its path or preview; a valid-looking filename is not evidence that useful media exists.

Compare expected test outcomes

Compare a known input, a boundary value, and an invalid value for the example frame node.

These are independent planned tests, not recorded results. With an 800 × 600 image, Known input uses a 24-pixel outside border and expects 848 × 648. Boundary value uses zero and expects 800 × 600, with no added border. Invalid value uses −1 and expects a clear error without a success image. Also test a missing image, as shown above. A control's minimum does not replace checking values that can arrive through a wire or code.

The figure computes no media, executes no Python, and makes no provider call. Use the actual node's results to decide whether its implementation passes.

Run and inspect the actual result

Ask Penny to run the specific test node with the agreed inputs. Its required upstream dependencies may be included, and eligible cached results can be reused. Identify what executed, what was reused, and what remains unverified; see Runs.

Compare actual dimensions, format, content, and the summary with the expected values. A successful execution can still return the wrong result. For a failure case, check that it reports the problem instead of silently creating sample content. Save useful output through Files and results.

Revise and reuse deliberately

Give Penny the observed result, expected result, exact error, and relevant script path. Ask for a narrow fix that preserves working inputs, outputs, and connections. After saving, inspect the actual node interface and repeat the relevant tests. Add a fresh instance if you need to compare its current schema with an older instance; do not delete the working copy first.

Save the graph and retain the intended source/package and required assets. Creating a private node does not publish it to the community or guarantee that another account has its dependencies, services, or permissions. Verify those requirements before sharing or relying on it elsewhere.

Last reviewed against Kaitoi on 24 October 2026. View this page as Markdown

Type at least two characters.