macosctl
v0.6.0
Published
Interactive CLI for managing macOS LaunchAgents.
Readme
macosctl
Interactive CLI for managing user-level macOS LaunchAgents.
macosctl stores editable job descriptions and scripts under
~/.config/macosctl, generates property lists in ~/Library/LaunchAgents, and
uses modern launchctl bootstrap, bootout, and kickstart commands.
Install
npm install -g macosctl
macosctl init
macosctlNode.js 22.17 or newer and macOS are required. System LaunchDaemons and sudo
workflows are not supported.
Features
The interactive menu can:
- list loaded user LaunchAgents and their current launchd state
- add, edit, and delete jobs
- start, stop, and restart jobs
- sync all managed jobs from
launchd/*.json - launch executables,
.appbundles, or bash/zsh scripts - configure arguments, a working directory, environment variables,
RunAtLoad,KeepAlive, and schedules
Application bundles are opened through /usr/bin/open. KeepAlive is disabled
for application jobs because open exits after handing the request to macOS.
Data directory
~/.config/macosctl/
launchd/ # One editable JSON file per job
scripts/ # User-managed .sh and .zsh scripts
logs/ # Job stdout and stderrWhen creating a script job, choose an existing script or create a new bash/zsh
script directly from the menu. New scripts are stored in
~/.config/macosctl/scripts/. Scripts are invoked explicitly with /bin/bash
or /bin/zsh, so executable permissions are not required.
Example ~/.config/macosctl/launchd/worker.json:
{
"id": "worker",
"name": "Background worker",
"type": "executable",
"path": "/usr/local/bin/worker",
"args": ["--serve"],
"workingDirectory": "/Users/me/Projects/worker",
"environment": {
"MODE": "production"
},
"runAtLoad": true,
"keepAlive": true,
"schedule": {
"type": "daily",
"hour": 4,
"minute": 30
}
}Each entry in args is passed directly to the executable — no shell interpretation
occurs. Do not use quotes around values; they would be passed literally to the
process and are not stripped.
Machine-specific environment overrides can live in
~/.config/macosctl/launchd/<id>.env. When present, this file is merged over
the shared environment object before macosctl generates the plist. The data
directory .gitignore is managed automatically and includes *.env.
Job ids use lowercase letters, numbers, and hyphens. Their launchd labels are
generated as dev.shura.macosctl.<id>.
Edits made through the menu are applied immediately. Starting or restarting a job also regenerates its plist from the current JSON file. Stopping leaves all managed files in place. Deleting removes the job JSON and generated plist while keeping scripts and logs.
Development
npm install
npm run typecheck
npm test
npm run build
npm run dev