Files
ansiblings/packages/nopy-cubes
Benjamin Diedrichsen 7e703c93b1 streamline package naming
2026-07-29 13:07:34 +02:00
..
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00
2026-07-29 13:07:34 +02:00

@bitsquare/nopy-cubes

The authoring surface for nopy cubes — the Manifest factory, the Cube class, and the types around them.

A cube manifest ships nothing but data, so it should not have to depend on a CLI to describe itself. This package is what a cube bundle depends on: no commander, no inquirer, no execa, no process spawning. @bitsquare/nopy re-exports everything here, so a manifest that already imports from @bitsquare/nopy keeps working unchanged.

Install

pnpm add @bitsquare/nopy-cubes zod

zod is a peer dependency on purpose: the manifest, the schema it builds and the Manifest factory should all see the same copy.

Writing a manifest

// cubes/net/tailscale/manifest.mjs
import { Manifest } from '@bitsquare/nopy-cubes';
import { z } from 'zod';

export default Manifest({
  id: 'net:tailscale',
  name: 'Tailscale',
  schema: z.object({
    AUTH_KEY: z.string().describe('Tailscale auth key'),
    ACCEPT_ROUTES: z.boolean().describe('Accept advertised routes').default(true),
  }),
  secrets: ['AUTH_KEY'],
  dependencies: (vars) => (vars.ACCEPT_ROUTES ? ['net:ip-forwarding'] : []),
  before: [async (ctx, vars) => ctx.exec('apt:essentials', {})],
});

Every schema field should carry a .describe() — nopy uses it as the prompt label — and a .default() wherever a sensible one exists, so --use-defaults can run the cube without prompting.

secrets names the schema keys that hold sensitive values. Nopy keeps those out of session and history files and masks them in every command it prints; it does not infer them, so a key nothing declares is recorded and printed in the clear. Each entry must be a key of schema — naming anything else is a manifest error. Give a secret a placeholder .default() rather than a real credential: a default lives in the manifest, where none of that protection reaches it.

The manifest lives next to a deploy.py in the same directory; together they make a cube. See the nopy README for the full cube contract and for how to publish a directory of cubes as a bundle.

Exports

Export What it is
Manifest(opts) Builds a manifest, filling in id, schema, secrets, before, after
createManifest / manifest Aliases of Manifest
Cube A loaded manifest plus its directory; getDefaults(), requiredKeys(), secrets, isSecret()
zodKind / zodInner Instance-agnostic zod introspection, safe across zod copies
AnyObjectSchema, CubeVariables, DependencySpec, Hook, HookContext, CubeSource, LoadResult types

License

MIT