hostctl
v0.1.42
Published
hostctl is a tool that runs task scripts against hosts.
Readme
hostctl
hostctl is a modern task runner for managing fleets of hosts. It executes TypeScript or JavaScript automations locally or over SSH while keeping inventories, tags, and secrets in one place.
Why hostctl
- Treat remote automation like regular code: tasks are modules with strong typing and structured logging.
- First-class inventory and secrets management built around AGE.
- Layered runtime cleanly separates CLI parsing, orchestration, and execution for easy extension.
System Requirements
- Node.js 24+ (CLI runs through
tsx). agefor encrypting secrets.- Git (recommended) for cloning packages and publishing tasks.
Check your toolchain:
node -v
npm -v
age --versionInstall hostctl
Clone & Develop
git clone https://github.com/monopod/hostctl.git
cd hostctl
npm installUse ./hostctl during development or npm run build && ./dist/bin/hostctl.js ... to test the bundled CLI.
Global CLI
npm install -g hostctl
hostctl --helpOne-off Execution
Run straight from npm without installing globally:
npx hostctl run core.echo message:helloBootstrap identities, inventory, and secrets
- Generate AGE identities
mkdir -p ~/.hostctl/age age-keygen -o ~/.hostctl/age/you.priv age-keygen -y ~/.hostctl/age/you.priv > ~/.hostctl/age/you.pub - Author an inventory at
~/.hostctl/hostctl.yaml:hosts: ubuntu-vm: hostname: 192.168.56.15 user: vagrant password: !secret vagrant-password tags: [ubuntu, testvm] secrets: vagrant-password: ids: you value: vagrant ids: you: age1... - Manage the file
Sethostctl inventory encrypt # wrap with AGE recipients hostctl inventory decrypt # view/edit locally hostctl inventory list # inspect hosts & tagsAGE_IDS="~/.hostctl/age/*.priv"before running commands if the file is encrypted.
Running tasks
- Local script
npm run build ./dist/bin/hostctl.js run example/echo.ts args:hello - Local package
hostctl run ./my-package hello name:Sam - Remote orchestration
hostctl run -r -t ubuntu core.net.interfaces --json-r/--remotetargets hosts selected by tags via SSH.-t/--tagis greedy; use--before positional args when needed.
- From npm or git
hostctl run hostctl-hello greet name:Phil hostctl run https://github.com/monopod/hostctl-example echo args:hello,world - Install Docker anywhere
The task follows Docker’s official installation guides for Ubuntu/Debian and Fedora/RHEL/Rocky (matching the currenthostctl run -r -t ubuntu core.docker.install users:hostctlxcpng-e2etemplates), so the same invocation works across your lab images. - Run containers
The first task streams container output back to the CLI; the detached variant returns the created container ID/name so you can manage it later.hostctl run core.docker.run-container image:alpine command:'["/bin/sh","-c","echo from container"]' hostctl run core.docker.run-container-detached image:redis name:ci-cache
Passing parameters
key:valuepairs after the task name.--params '{"key":"value"}'for JSON blobs.--file params.jsonto load structured arguments.
Managing task packages
hostctl pkg commands wrap the npm-only package manager:
hostctl pkg create my-task --lang typescript
hostctl pkg install hostctl-hello
hostctl pkg list
hostctl pkg remove hostctl-helloInstalled packages live under ~/.hostctl/packages and can be run offline once cached.
Designing tasks
Define tasks with the task helper and a typed TaskContext:
import { task, type TaskContext } from 'hostctl';
interface EchoParams { message: string }
interface EchoResult { repeated: string }
async function run(context: TaskContext<EchoParams>): Promise<EchoResult> {
const { params, info } = context;
info(`Echo: ${params.message}`);
return { repeated: params.message };
}
export default task(run, { name: 'example.echo', description: 'Prints a message' });Key TaskContext capabilities (see docs/task-api.md for details):
- Structured logging via
info,warn,error,debug, orlog(level, ...). - Command execution with
exec(command, { sudo, env, cwd, stdin, pty }). - Remote fan-out using
ssh(tags, remoteFn). - Subtask orchestration with
run(otherTask(params)). - Secrets & credentials via
getSecret(name)andgetPassword(). - Inventory helpers:
inventory(tags)andselectedInventory(tags?). - File helpers:
file.read,file.write,file.exists,file.mkdir,file.rmthat respect local vs. remote runtime.
Building & testing task packages
- Scaffold:
hostctl pkg create awesome-firewall --lang typescript. - Install deps:
cd awesome-firewall && npm install. - Build:
npm run build(defaults totsc). - Test locally without publishing:
npx hostctl run . args:foo. - Add unit tests with Vitest if needed, or invoke tasks directly in scripts.
Publishing task packages
- Update
package.jsonmetadata (name,version,description,files). - Build artifacts (
npm run buildor rely onprepublishOnly). - Authenticate with npm (
npm loginorNPM_TOKEN). - Publish:
npm version patch # or minor/major npm publish --access public - Tag releases in git or automate with tools like
release-it(this repo shipsrelease.shas an example flow). - Verify:
npm info your-package version.
Consuming published packages
- One-off:
npx hostctl run your-package taskName param:value. - Cache locally:
hostctl pkg install [email protected]then run offline. - Compose in other codebases by adding the package to
dependenciesand importing its exported tasks.
Troubleshooting
- Task not found: confirm the package exports the task name and that
exportsexposes it. - Version mismatch: keep
package.json,src/version.ts, andjsr.jsonin sync before releasing. - SSH failures: verify inventory entries (hostname, user, auth) and only pass
-rwhen you intend remote execution. - Secrets: when inventories are encrypted, ensure
AGE_IDSincludes the private keys sohostctlcan decrypt secrets. - Environment drift: run
hostctl runtimeto inspect prerequisites orhostctl runtime installto bootstrap them.
Developer workflow
- Format & typing:
npm run format(Prettier) andnpm run lint(tsc --noEmit). - Build artifacts:
npm run build(tsup) producesdist/bundles for the CLI and published package. - Tests:
npm run test→ unit + functional suites.npm run test:unit,npm run test:functional,npm run test:e2efor focused runs.
- VM helpers (
npm run vm:*) are legacy while XCP-ng provisioning matures; seedocs/xcp-ng-operations.md. - Releases rely on
npm run release+release-it; seeNPM_MIGRATION_PLAN.mdfor npm-only context.
Documentation map
- Task API reference:
docs/task-api.md. - Operational guides:
docs/*.md(process, package, system management, etc.). - Architecture & design:
ARCHITECTURE.mdand supporting design docs. - Contributor guide:
CONTRIBUTING.mdandAGENTS.md. - Issue tracking: https://github.com/monopod/hostctl/issues.
Explore the examples under example/, get familiar with the task API, and share automations with the community via npm-compatible packages.
