Architecture
How Nodevisor packages compose into a complete infrastructure automation platform.
Layered Package Model
Nodevisor is organized into five layers. Each layer builds on the one below it.
1. Execution Layer
The foundation. Handles command execution, SSH connections, and output parsing.
| Package | Purpose |
|---|---|
@nodevisor/shell | Shell proxy, command builder, connections, module base class |
@nodevisor/endpoint | Network endpoint definitions (ports, protocols) |
2. System Layer
Cross-platform abstractions for common system operations.
| Package | Purpose |
|---|---|
@nodevisor/os | Hostname, arch, uptime, command detection |
@nodevisor/fs | File read/write, permissions, temp files |
@nodevisor/packages | Package install/remove (apt, yum, brew, winget) |
@nodevisor/services | systemd service start/stop/restart |
@nodevisor/env | Environment variables, env files |
@nodevisor/pwsh | PowerShell command execution |
3. Security Layer
User management, authentication, and access control.
| Package | Purpose |
|---|---|
@nodevisor/users | Create/remove system users |
@nodevisor/groups | Manage groups and membership |
@nodevisor/auth | Set user passwords |
@nodevisor/authorized-keys | Manage SSH authorized_keys |
@nodevisor/ssh | Install/configure OpenSSH server |
@nodevisor/ufw | UFW firewall management |
4. Orchestration Layer
Container management, multi-node deployment, and cloud integrations.
| Package | Purpose |
|---|---|
@nodevisor/cluster | Abstract cluster primitives (nodes, services, users) |
@nodevisor/docker | Docker, Compose, Swarm, pre-built services |
@nodevisor/aws | AWS CLI and ECR integration |
@nodevisor/registry | Abstract container registry interface |
@nodevisor/builder | Abstract image builder interface |
5. Aggregator
| Package | Purpose |
|---|---|
nodevisor | Umbrella package that re-exports everything |
@nodevisor/cli | CLI for setup, deploy, connect, run |
@nodevisor/schema | Shared Zod schemas for admin/runner configs |
Core Patterns
The Shell Proxy ($)
The $ function is a Proxy that supports multiple calling conventions:
import $ from 'nodevisor';
// 1. Template literal → execute command
await $`echo hello`;
// 2. $.connect() → create remote shell proxy
const $remote = $.connect({ host: '10.0.0.10', username: 'root' });
// 3. $(Module) → instantiate module with current shell
const packages = $(Packages);
// 4. $remote(Module) → instantiate module on remote shell
const remotePackages = $remote(Packages);
// 5. $.as(user) → switch execution user
const $runner = $.as('runner');
Modules
Every functional package (Users, Packages, FS, Docker, etc.) exports a class that extends Module. Modules receive the shell context and execute commands through it:
import { Module } from '@nodevisor/shell';
class MyModule extends Module {
async doSomething() {
// this.$ is bound to the shell context
return this.$`my-command --flag`.text();
}
}
// Use it locally
const result = await $(MyModule).doSomething();
// Use it remotely
const remoteResult = await $remote(MyModule).doSomething();
Command Builder
Every template literal call returns a CommandBuilder with a fluent API for output transformation:
// Chain transforms
const name = await $`hostname`.trim().toLowerCase().text();
// Parse different formats
const data = await $`cat config.json`.json();
const lines = await $`cat /etc/hosts`.lines();
const ok = await $`ping -c1 google.com`.noThrow().boolean();
// Control execution
await $`long-command`.timeout(5000);
await $`risky-command`.noThrow();
Package & Service Base Classes
Installable software extends Package. Services (which can be started/stopped) extend Service:
Module → Base class for all modules
└─ Package → Adds install/uninstall/isInstalled
└─ Service → Adds start/stop/restart/isRunning
Dependency Graph
@nodevisor/shell (foundation)
├── @nodevisor/os → pwsh
├── @nodevisor/fs → pwsh, users, os
├── @nodevisor/env
├── @nodevisor/packages → os
├── @nodevisor/services
├── @nodevisor/users
├── @nodevisor/groups
├── @nodevisor/auth → fs, users
├── @nodevisor/authorized-keys → fs, env
├── @nodevisor/ssh → services, packages
├── @nodevisor/ufw → packages, endpoint
├── @nodevisor/pwsh
├── @nodevisor/docker → groups, packages, services, fs, ufw, cluster, builder, registry
├── @nodevisor/cluster → auth, authorized-keys, users, packages, services, ssh, ufw, builder, registry
├── @nodevisor/aws → packages, fs, os, registry
├── @nodevisor/registry
├── @nodevisor/builder → registry
└── @nodevisor/endpoint
Typical Deployment Flow
import $, {
Packages, Users, Auth, AuthorizedKeys,
SSH, UFW, Docker, DockerSwarm, endpoints
} from 'nodevisor';
const $server = $.connect({ host: 'server', username: 'root' });
// 1. System setup
await $server(Packages).updateAndUpgrade();
// 2. User setup
await $server(Users).add('runner');
await $server(Auth).setPassword('runner', 'secure-password');
await $server(AuthorizedKeys).writeFromFile('~/.ssh/id_ed25519.pub');
// 3. Security hardening
await $server(SSH).disablePasswordAuthentication();
await $server(UFW).install();
await $server(UFW).allow([endpoints.ssh, endpoints.web, endpoints.webSecure]);
await $server(UFW).start();
// 4. Container runtime
await $server(Docker).install();
await $server(Docker).allowUser('runner');
await $server(DockerSwarm).start();