How to Configure LifeOS Background Jobs Using launchd Service on macOS

LifeOS configures macOS background jobs as launchd agents using plist templates, the DeployComponents pipeline, and a Services.ts wrapper that handles installation, templating, and agent bootstrapping.

LifeOS provides deterministic background automation for macOS through native launchd agents. These jobs handle tasks like work sweeps, data synchronization, and system pulse monitoring. The configuration system relies on template-driven plist generation, environment-aware deployment scripts, and idempotent installation workflows that integrate with the broader LifeOS setup process.

How launchd Configuration Works in LifeOS

The Three-Layer Architecture

LifeOS implements launchd configuration through a coordinated pipeline:

This separation keeps user configuration simple while ensuring robust, repeatable installations.

Platform Detection

All launchd components are macOS-only. The codebase uses DetectEnv.display—a helper that detects GUI macOS environments—to conditionally skip launchd installation on Linux and Windows. This keeps the Setup workflow idempotent across platforms without manual intervention.

Enabling Background Jobs in settings.enhancements.json

Individual launchd agents are toggled through boolean flags in the enhancements configuration file.

// LifeOS/install/settings.enhancements.json
{
  "pulse": true,
  "worksweep": true,
  "derivedsync": false,
  "usageAggregator": true,
  "healthsync": false
}

Each key corresponds to a specific background job:

  • pulse – Dashboard and system heartbeat service
  • worksweep – Hourly work environment cleanup and synchronization
  • derivedsync – Derived data synchronization across contexts
  • usageAggregator – System usage metrics collection
  • healthsync – Health data aggregation and sync

When the Setup workflow runs, it reads these flags and constructs a deployment plan containing only enabled components.

The Deployment Pipeline

Step 1: Setup Workflow Invocation

The top-level orchestrator is the Setup workflow located at LifeOS/install/Workflows/Setup.md. Run it via:


# From the repository root

bun run LifeOS/install/Workflows/Setup.md

Step 2: DeployComponents Delegation

Inside DeployComponents.ts (lines 319-321), the pipeline iterates over selected components. For launchd services, it delegates to Services.ts according to the source code comment describing launchd handling:

// LifeOS/install/LIFEOS/TOOLS/Services.ts lines 6-13
// Handles launchd agent installation:
// 1. Reads template from LifeOS/install/LIFEOS/TOOLS/*.plist.template
// 2. Substitutes placeholders ({{HOME}}, {{BUN_PATH}})
// 3. Writes to ~/Library/LaunchAgents/com.lifeos.<label>.plist
// 4. Executes launchctl bootstrap to load into user domain

Step 3: Plist Generation and Installation

The installLaunchd() function performs four operations:

  1. Template loading – Reads the component-specific .plist.template file
  2. Placeholder substitution – Replaces {{HOME}} and {{BUN_PATH}} with resolved paths
  3. Plist deployment – Writes to ~/Library/LaunchAgents/com.lifeos.<label>.plist
  4. Agent bootstrap – Executes launchctl bootstrap "gui/$(id -u)" <plist> to activate

The operation is idempotent—subsequent runs replace existing agents without error.

Plist Template Structure

Each background job ships with a template defining schedule, execution policy, and logging. Here is the worksweep template:

<!-- com.lifeos.worksweep.plist.template -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.lifeos.worksweep</string>
  <key>ProgramArguments</key>
  <array>
    <string>{{HOME}}/.claude/LIFEOS/bin/bun</string>
    <string>run</string>
    <string>LifeOS/install/LIFEOS/TOOLS/worksweep.ts</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>StartInterval</key><integer>3600</integer>   <!-- every hour -->
  <key>StandardOutPath</key><string>{{HOME}}/.claude/LIFEOS/MEMORY/OBSERVABILITY/worksweep.log</string>
  <key>StandardErrorPath</key><string>{{HOME}}/.claude/LIFEOS/MEMORY/OBSERVABILITY/worksweep.log</string>
</dict>
</plist>

Key launchd directives used across LifeOS templates:

Directive Purpose Typical Value
RunAtLoad Execute immediately when agent loads true
StartInterval Seconds between executions 3600 (1 hour), 300 (5 min)
KeepAlive Restart if process exits false (most jobs)
StandardOutPath / StandardErrorPath Log file locations ~/.claude/LIFEOS/MEMORY/OBSERVABILITY/

Installing a Specific Job Manually

For programmatic control or custom workflows, import installLaunchd directly:

import { installLaunchd } from '../LifeOS/install/LIFEOS/TOOLS/Services';

// Install the "worksweep" background job
await installLaunchd('worksweep');

// Install Pulse dashboard service
await installLaunchd('pulse');

This bypasses the full Setup workflow while using the same underlying machinery.

Verifying launchd Agent Status

After installation, confirm proper loading with launchctl:


# General status check

launchctl print "gui/$(id -u)/com.lifeos.worksweep"

# Expected output includes:

#   PID = <number>

#   ProgramArguments = { "/Users/.../.claude/LIFEOS/bin/bun", "run", "..." }

#   State = running

#   Scheduled = <interval description>

The Setup workflow performs automatic verification at line 54, running launchctl print for each enabled label and surfacing errors before completion.

Generated Plist Example

After template processing, the resolved plist for worksweep resembles:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.lifeos.worksweep</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/daniel/.claude/LIFEOS/bin/bun</string>
    <string>run</string>
    <string>LifeOS/install/LIFEOS/TOOLS/worksweep.ts</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>StartInterval</key><integer>3600</integer>
  <key>StandardOutPath</key><string>/Users/daniel/.claude/LIFEOS/MEMORY/OBSERVABILITY/worksweep.log</string>
  <key>StandardErrorPath</key><string>/Users/daniel/.claude/LIFEOS/MEMORY/OBSERVABILITY/worksweep.log</string>
</dict>
</plist>

Bootstrapped agents appear in ~/Library/LaunchAgents/ and persist across reboots until explicitly unloaded.

Summary

  • Configuration source: settings.enhancements.json contains boolean flags for each launchd job
  • Deployment entry point: DeployComponents.ts delegates to Services.ts for launchd-specific operations
  • Template processing: Services.ts substitutes placeholders and writes plists to ~/Library/LaunchAgents/
  • Activation: launchctl bootstrap "gui/$(id -u)" <plist> loads agents into the user domain
  • Verification: launchctl print "gui/$(id -u)/com.lifeos.<label>" confirms proper operation
  • Platform guard: DetectEnv.display ensures launchd jobs install only on macOS with GUI environments

Frequently Asked Questions

Where are LifeOS launchd plists stored after installation?

LifeOS writes generated plist files to ~/Library/LaunchAgents/ following Apple's standard for user-specific launchd agents. Each file follows the naming convention com.lifeos.<component>.plist, such as com.lifeos.worksweep.plist or com.lifeos.pulse.plist.

Can I modify the schedule of a LifeOS background job?

Yes. Edit the corresponding .plist.template file in LifeOS/install/LIFEOS/TOOLS/, then rerun the Setup workflow. Modify the StartInterval integer (seconds) or replace it with StartCalendarInterval for calendar-based scheduling. Changes take effect after launchctl bootstrap reloads the agent.

What happens if I run Setup multiple times?

The installation is idempotent. Services.installLaunchd() replaces existing plists and re-bootstraps agents without error. The launchctl bootstrap command handles replacement gracefully, and log files append rather than truncate.

How do I temporarily disable a LifeOS launchd job without uninstalling?

Use launchctl directly to unload the agent while preserving the plist:

launchctl bootout "gui/$(id -u)/com.lifeos.worksweep"

To re-enable later:

launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/com.lifeos.worksweep.plist

Alternatively, set the corresponding flag to false in settings.enhancements.json and rerun Setup to remove the agent entirely.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →