Closes DOCS-AUDIT §6.1 and §5.1. **The script could not run.** It read `APP` off `host.data` and then used `SERVICE_NAME` and `AUTOSTART` as if they were in scope, so the very first statement — `if AUTOSTART:` — raised `NameError`; `server` was used in the else branch but never imported. Three lines: import `server` alongside `systemd`, read the two names next to `APP`. The logic underneath was always right. `python3 -m py_compile` passes. **The README documented a different cube.** It was titled "TypeStack Install Cube" and described cloning a git repository, `yarn install`, `yarn build`, `docker compose up -d` and PM2 — none of which this cube does, and it listed parameters (`USER`, `REPO`, `ENV`, `NODE_PATH`) the manifest does not have, carrying someone's private repository URL and username as defaults. Rewritten from the manifest and the now-working script: the three parameters that exist, and the thing the old text obscured by describing a deploy pipeline — this cube does not create the unit file, it enables and starts one that is already installed. `SERVICE_NAME` is documented as what it is, a label that never reaches systemd, so getting it wrong is cosmetic rather than a cube managing the wrong unit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DCzYTAm9QUhvLNr2EpdagJ
ansiblings
Infrastructure tooling monorepo: two published CLIs plus the pyinfra "cubes" they deploy.
| Path | Package | Binary | What it is |
|---|---|---|---|
packages/nopy |
@bitsquare/nopy |
nopy |
interactive pyinfra script management and execution |
packages/keyman |
@bitsquare/keyman |
keyman |
SSH key management with age encryption |
packages/nopy-cubes |
@bitsquare/nopy-cubes |
— | the authoring surface a cube's manifest.mjs imports |
packages/nopy-cubes-core |
@bitsquare/nopy-cubes-core |
— | the core bundle of deployment units nopy runs |
npm install -g @bitsquare/nopy @bitsquare/keyman
See each package's README for usage, and README.PUBLISH.md for how they get published.
Development
Requires Node ≥ 22 (the repo pins 24 in .nvmrc) and pnpm — the version is
pinned by packageManager, so corepack enable is enough.
pnpm install
| Command | Does |
|---|---|
pnpm run build |
compiles both packages with tsc |
pnpm run typecheck |
tsc --build across the workspace (see below) |
pnpm run lint |
Biome check |
pnpm run lint:fix |
Biome check with fixes applied |
pnpm test |
vitest, both packages |
pnpm run test:coverage |
vitest with the coverage gate |
pnpm run coverage:summary |
renders the last coverage run as a Markdown table |
typescript is on the 7.x native compiler, so tsc is the fast one — there is
no separate tsgo binary to keep in sync. typecheck is plain tsc --build,
not --noEmit: once a project has references, TypeScript rejects --noEmit
outright (TS6310), because a composite project has to emit the declarations its
dependents read. So the typecheck writes dist as a side effect — gitignored,
and it means the gate also proves the build works. Each package also has a dev-run script
(pnpm --filter @bitsquare/nopy run nopy) that executes the TypeScript sources
directly through tsx.
Git hooks
Installed by simple-git-hooks on pnpm install, configured in the root
package.json:
- pre-commit — Biome check with fixes, on staged files only, re-staging what it fixed. Fast; blocks only on problems it cannot fix itself.
- pre-push —
lint:ci→typecheck→test:coverage. This is the same gate CI runs, so a push that survives it will not surprise you on the runner.
Set SKIP_SIMPLE_GIT_HOOKS=1 to bypass either one; re-install them after
changing the config with pnpm exec simple-git-hooks.
Coverage
Both packages hold a hard 85 % branch floor, enforced by
coverage.thresholds in their vitest.config.ts rather than by a CI-only flag —
pnpm run test:coverage fails the same way locally, in the pre-push hook, and
on the runner. Barrel files and CLI argv wiring are excluded; everything with
behaviour in it is not.