Specify a webhook-driven task for OpenClaw
Describe event inputs, validation, deduplication, and intended actions before integration work.
5,003,842 AI resources indexedWorking toward the world’s largest AI resource index.
Setup and configure oh-my-droid (the ONLY command you need to learn)
---
name: omd-setup-e0fbf61e1b79
description: Setup and configure oh-my-droid (the ONLY command you need to learn)
---
# OMD Setup
This skill is a **setup wizard**. Ignore unrelated context (open files, pending code changes, git/commits, etc.).
**When you need to ask the user anything, use the `AskUser` tool and ONLY ask the wizard questions below.**
This is the **only command you need to learn**. After running this, everything else is automatic.
## Graceful Interrupt Handling
**IMPORTANT**: This setup process saves progress after each step. If interrupted (Ctrl+C or connection loss), the setup can resume from where it left off.
### State File Location
- `.omd/state/setup-state.json` - Tracks completed steps
### Resume Detection (Step 0)
Before starting any step, check for existing state:
```bash
# Check for existing setup state
STATE_FILE=".omd/state/setup-state.json"
# Cross-platform ISO date to epoch conversion
iso_to_epoch() {
local iso_date="$1"
local epoch=""
# Try GNU date first (Linux)
epoch=$(date -d "$iso_date" +%s 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$epoch" ]; then
echo "$epoch"
return 0
fi
# Try BSD/macOS date
local clean_date=$(echo "$iso_date" | sed 's/[+-][0-9][0-9]:[0-9][0-9]$//' | sed 's/Z$//' | sed 's/T/ /')
epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "$clean_date" +%s 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$epoch" ]; then
echo "$epoch"
return 0
fi
echo "0"
}
if [ -f "$STATE_FILE" ]; then
# Check if state is stale (older than 24 hours)
TIMESTAMP_RAW=$(jq -r '.timestamp // empty' "$STATE_FILE" 2>/dev/null)
if [ -n "$TIMESTAMP_RAW" ]; then
TIMESTAMP_EPOCH=$(iso_to_epoch "$TIMESTAMP_RAW")
NOW_EPOCH=$(date +%s)
STATE_AGE=$((NOW_EPOCH - TIMESTAMP_EPOCH))
else
STATE_AGE=999999 # Force fresh start if no timestamp
fi
if [ "$STATE_AGE" -gt 86400 ]; then
echo "Previous setup state is more than 24 hours old. Starting fresh."
rm -f "$STATE_FILE"
else
LAST_STEP=$(jq -r ".lastCompletedStep // 0" "$STATE_FILE" 2>/dev/null || echo "0")
TIMESTAMP=$(jq -r .timestamp "$STATE_FILE" 2>/dev/null || echo "unknown")
echo "Found previous setup session (Step $LAST_STEP completed at $TIMESTAMP)"
fi
fi
```
If state exists, use `AskUser` to prompt **exactly**:
1. [question] Found a previous setup session. What should I do?
[topic] Resume
[option] Resume from last step
[option] Start fresh (clear saved state)
If user chooses "Start fresh":
```bash
rm -f ".omd/state/setup-state.json"
echo "Previous state cleared. Starting fresh setup."
```
### Step 0.5: Always Ask Parallelism (Required)
**MANDATORY:** Regardless of whether the user resumes or starts fresh, you MUST ask for `maxBackgroundTasks` in this run.
If resuming, try to infer the scope from the state file:
```bash
# Optional: infer scope from state file
CONFIG_TYPE=$(jq -r '.configType // empty' ".omd/state/setup-state.json" 2>/dev/null || true)
```
Interpretation:
- If `CONFIG_TYPE` starts with `local` → scope = `Local (this project)`
- If `CONFIG_TYPE` starts with `global` → scope = `Global (all projects)`
- Otherwise, ask Step 1 (scope) again.
### Save Progress Helper
After completing each major step, save progress:
```bash
# Save setup progress (call after each step)
# Usage: save_setup_progress STEP_NUMBER
save_setup_progress() {
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": $1,
"timestamp": "$(date -Iseconds)",
"configType": "${CONFIG_TYPE:-unknown}"
}
EOF
}
```
### Clear State on Completion
After successful setup completion (Step 7/8), remove the state file:
```bash
rm -f ".omd/state/setup-state.json"
echo "Setup completed successfully. State cleared."
```
## Usage Modes
This skill handles three scenarios:
1. **Initial Setup (no flags)**: First-time installation wizard
2. **Local Configuration (`--local`)**: Configure project-specific settings (.factory/FACTORY.md)
3. **Global Configuration (`--global`)**: Configure global settings (~/.factory/FACTORY.md)
## Mode Detection
Check for flags in the user's invocation:
- If `--local` flag present → Skip to Local Configuration (Step 2A)
- If `--global` flag present → Skip to Global Configuration (Step 2B)
- If no flags → Run Initial Setup wizard (Step 1)
**IMPORTANT:** Always run Step 1.1 (parallelism) even when `--local` or `--global` is used.
## Step 1: Initial Setup Wizard (Default Behavior)
**Note**: If resuming and lastCompletedStep >= 1, skip to the appropriate step based on configType.
Immediately use `AskUser` to prompt **exactly**:
1. [question] Where should I configure oh-my-droid?
[topic] Scope
[option] Local (this project)
[option] Global (all projects)
## Step 1.1: Configure Parallelism (maxBackgroundTasks)
**IMPORTANT:** Always run this step (even if `maxBackgroundTasks` is already set, and even when resuming).
Use `AskUser` to prompt:
1. [question] How many background tasks should I allow in parallel?
[topic] Parallelism
[option] Keep current
[option] 2
[option] 5
[option] 10
[option] 20
If the user chooses **Keep current**, skip updating settings.
Otherwise, update BOTH:
1) **Factory Droid global settings**: `~/.factory/settings.json` → top-level `maxBackgroundTasks`
2) **oh-my-droid config** (so OMD can read it):
- If scope is **Local** → `./.factory/droid.jsonc` → `permissions.maxBackgroundTasks`
- If scope is **Global** → `${XDG_CONFIG_HOME:-~/.config}/oh-my-droid/config.jsonc` → `permissions.maxBackgroundTasks`
Rules:
- Default to **5** if the user provides an invalid value
- Clamp to **1..20**
```bash
python3 - <<'PY'
import json
import os
import re
from pathlib import Path
MIN_V = 1
MAX_V = 20
DEFAULT_V = 5
def strip_jsonc(text: str) -> str:
out: list[str] = []
i = 0
in_str = False
str_ch = ''
while i < len(text):
c = text[i]
if in_str:
out.append(c)
if c == '\\' and i + 1 < len(text):
i += 1
out.append(text[i])
elif c == str_ch:
in_str = False
i += 1
continue
if c in ('"', "'"):
in_str = True
str_ch = c
out.append(c)
i += 1
continue
if c == '/' and i + 1 < len(text) and text[i + 1] == '/':
i += 2
while i < len(text) and text[i] not in ('\n', '\r'):
i += 1
continue
if c == '/' and i + 1 < len(text) and text[i + 1] == '*':
i += 2
while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'):
i += 1
i += 2
continue
out.append(c)
i += 1
return ''.join(out)
def parse_jsonc_file(path: Path) -> dict:
if not path.exists():
return {}
raw = path.read_text('utf-8')
cleaned = strip_jsonc(raw)
cleaned = re.sub(r',\s*([}\]])', r'\1', cleaned)
cleaned_s = cleaned.strip()
if not cleaned_s:
return {}
return json.loads(cleaned_s)
factory_settings_path = Path.home() / '.factory' / 'settings.json'
factory_settings_path.parent.mkdir(parents=True, exist_ok=True)
try:
factory_data = json.loads(factory_settings_path.read_text('utf-8')) if factory_settings_path.exists() else {}
except Exception:
factory_data = {}
current = int(factory_data.get('maxBackgroundTasks', DEFAULT_V) or DEFAULT_V)
raw = "USER_CHOICE" # replace with chosen value (or user's custom answer)
scope = "SCOPE_CHOICE" # replace with: "Local (this project)" | "Global (all projects)" (or flags)
raw_s = str(raw).strip().lower()
if raw_s.startswith('keep'):
v = current
else:
try:
v = int(raw_s)
except Exception:
v = current
if v < MIN_V:
v = MIN_V
if v > MAX_V:
v = MAX_V
# 1) Factory Droid settings (global)
factory_data['maxBackgroundTasks'] = v
factory_settings_path.write_text(json.dumps(factory_data, indent=2) + '\n', encoding='utf-8')
print('Set Factory maxBackgroundTasks to', v, 'in', factory_settings_path)
# 2) OMD config (local or global)
scope_s = str(scope).strip().lower()
if scope_s.startswith('local'):
omd_config_path = Path.cwd() / '.factory' / 'droid.jsonc'
else:
xdg = Path(os.environ.get('XDG_CONFIG_HOME') or (Path.home() / '.config'))
omd_config_path = xdg / 'oh-my-droid' / 'config.jsonc'
omd_config_path.parent.mkdir(parents=True, exist_ok=True)
try:
omd_data = parse_jsonc_file(omd_config_path)
except Exception as e:
print('Warning: could not parse OMD config; skipping update:', omd_config_path, '-', e)
omd_data = None
if isinstance(omd_data, dict):
perms = omd_data.get('permissions')
if not isinstance(perms, dict):
perms = {}
perms['maxBackgroundTasks'] = v
omd_data['permissions'] = perms
omd_config_path.write_text(json.dumps(omd_data, indent=2) + '\n', encoding='utf-8')
print('Set OMD permissions.maxBackgroundTasks to', v, 'in', omd_config_path)
PY
```
## Step 2A: Local Configuration (--local flag or user chose LOCAL)
**CRITICAL**: This ALWAYS downloads fresh FACTORY.md from GitHub to the local project. DO NOT use the Write tool - use bash curl exclusively.
### Create Local .factory Directory
```bash
# Create .factory directory in current project
mkdir -p .factory && echo ".factory directory ready"
```
### Download Fresh FACTORY.md
```bash
# Extract old version before download
OLD_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "none")
# Backup existing FACTORY.md before overwriting (if it exists)
if [ -f ".factory/FACTORY.md" ]; then
BACKUP_DATE=$(date +%Y-%m-%d)
BACKUP_PATH=".factory/FACTORY.md.backup.${BACKUP_DATE}"
cp .factory/FACTORY.md "$BACKUP_PATH"
echo "Backed up existing FACTORY.md to $BACKUP_PATH"
fi
# Download fresh FACTORY.md from GitHub
curl -fsSL "https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md" -o .factory/FACTORY.md && \
echo "Downloaded FACTORY.md to .factory/FACTORY.md"
# Extract new version and report
NEW_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
if [ "$OLD_VERSION" = "none" ]; then
echo "Installed FACTORY.md: $NEW_VERSION"
elif [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo "FACTORY.md unchanged: $NEW_VERSION"
else
echo "Updated FACTORY.md: $OLD_VERSION -> $NEW_VERSION"
fi
```
**Note**: The downloaded FACTORY.md includes Context Persistence instructions with `<remember>` tags for surviving conversation compaction.
**Note**: If an existing FACTORY.md is found, it will be backed up to `.factory/FACTORY.md.backup.YYYY-MM-DD` before downloading the new version.
**MANDATORY**: Always run this command. Do NOT skip. Do NOT use Write tool.
**FALLBACK** if curl fails:
Tell user to manually download from:
https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md
### Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
### Confirm Local Configuration Success
After completing local configuration, save progress and report:
```bash
# Save progress - Step 2 complete (Local config)
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 2,
"timestamp": "$(date -Iseconds)",
"configType": "local"
}
EOF
```
**OMC Project Configuration Complete**
- FACTORY.md: Updated with latest configuration from GitHub at ./.factory/FACTORY.md
- Backup: Previous FACTORY.md backed up to `.factory/FACTORY.md.backup.YYYY-MM-DD` (if existed)
- Scope: **PROJECT** - applies only to this project
- Hooks: Provided by plugin (no manual installation needed)
- Agents: 28+ available (base + tiered variants)
- Model routing: Haiku/Sonnet/Opus based on task complexity
**Note**: This configuration is project-specific and won't affect other projects or global settings.
If `--local` flag was used, clear state and **STOP HERE**:
```bash
rm -f ".omd/state/setup-state.json"
```
Do not continue to HUD setup or other steps.
## Step 2B: Global Configuration (--global flag or user chose GLOBAL)
**CRITICAL**: This ALWAYS downloads fresh FACTORY.md from GitHub to global config. DO NOT use the Write tool - use bash curl exclusively.
### Download Fresh FACTORY.md
```bash
# Extract old version before download
OLD_VERSION=$(grep -m1 "^# oh-my-droid" ~/.factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "none")
# Backup existing FACTORY.md before overwriting (if it exists)
if [ -f "$HOME/.factory/FACTORY.md" ]; then
BACKUP_DATE=$(date +%Y-%m-%d)
BACKUP_PATH="$HOME/.factory/FACTORY.md.backup.${BACKUP_DATE}"
cp "$HOME/.factory/FACTORY.md" "$BACKUP_PATH"
echo "Backed up existing FACTORY.md to $BACKUP_PATH"
fi
# Download fresh FACTORY.md to global config
curl -fsSL "https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md" -o ~/.factory/FACTORY.md && \
echo "Downloaded FACTORY.md to ~/.factory/FACTORY.md"
# Extract new version and report
NEW_VERSION=$(grep -m1 "^# oh-my-droid" ~/.factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
if [ "$OLD_VERSION" = "none" ]; then
echo "Installed FACTORY.md: $NEW_VERSION"
elif [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo "FACTORY.md unchanged: $NEW_VERSION"
else
echo "Updated FACTORY.md: $OLD_VERSION -> $NEW_VERSION"
fi
```
**Note**: If an existing FACTORY.md is found, it will be backed up to `~/.factory/FACTORY.md.backup.YYYY-MM-DD` before downloading the new version.
### Clean Up Legacy Hooks (if present)
Check if old manual hooks exist and remove them to prevent duplicates:
```bash
# Remove legacy bash hook scripts (now handled by plugin system)
rm -f ~/.factory/hooks/keyword-detector.sh
rm -f ~/.factory/hooks/stop-continuation.sh
rm -f ~/.factory/hooks/persistent-mode.sh
rm -f ~/.factory/hooks/session-start.sh
echo "Legacy hooks cleaned"
```
Check `~/.factory/settings.json` for manual hook entries. If the "hooks" key exists with UserPromptSubmit, Stop, or SessionStart entries pointing to bash scripts, inform the user:
> **Note**: Found legacy hooks in settings.json. These should be removed since the plugin now provides hooks automatically. Remove the "hooks" section from ~/.factory/settings.json to prevent duplicate hook execution.
### Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
### Confirm Global Configuration Success
After completing global configuration, save progress and report:
```bash
# Save progress - Step 2 complete (Global config)
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 2,
"timestamp": "$(date -Iseconds)",
"configType": "global"
}
EOF
```
**OMC Global Configuration Complete**
- FACTORY.md: Updated with latest configuration from GitHub at ~/.factory/FACTORY.md
- Backup: Previous FACTORY.md backed up to `~/.factory/FACTORY.md.backup.YYYY-MM-DD` (if existed)
- Scope: **GLOBAL** - applies to all Factory Droid sessions
- Hooks: Provided by plugin (no manual installation needed)
- Agents: 28+ available (base + tiered variants)
- Model routing: Haiku/Sonnet/Opus based on task complexity
**Note**: Hooks are now managed by the plugin system automatically. No manual hook installation required.
If `--global` flag was used, clear state and **STOP HERE**:
```bash
rm -f ".omd/state/setup-state.json"
```
Do not continue to HUD setup or other steps.
## Step 3: Setup HUD Statusline
**Note**: If resuming and lastCompletedStep >= 3, skip to Step 3.5.
The HUD shows real-time status in Factory Droid's status bar. **Invoke the hud skill** to set up and configure:
Use the Skill tool to invoke: `hud` with args: `setup`
This will:
1. Install the HUD wrapper script to `~/.factory/hud/omd-hud.mjs`
2. Configure `statusLine` in `~/.factory/settings.json`
3. Report status and prompt to restart if needed
After HUD setup completes, save progress:
```bash
# Save progress - Step 3 complete (HUD setup)
mkdir -p .omd/state
CONFIG_TYPE=$(cat ".omd/state/setup-state.json" 2>/dev/null | grep -oE '"configType":\s*"[^"]+"' | cut -d'"' -f4 || echo "unknown")
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 3,
"timestamp": "$(date -Iseconds)",
"configType": "$CONFIG_TYPE"
}
EOF
```
## Step 3.5: Resolve Active Plugin Install
Use Factory's installation metadata rather than sorting cache directory names,
which are content hashes rather than semantic versions:
```bash
PLUGIN_DIR=$(node --input-type=module - <<'NODE'
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
const registries = [
{ path: join(process.cwd(), ".factory/plugins/installed_plugins.json"), scope: "project" },
{ path: join(homedir(), ".factory/plugins/installed_plugins.json"), scope: "user" },
];
for (const registry of registries) {
try {
const metadata = JSON.parse(readFileSync(registry.path, "utf-8"));
const installs = metadata.plugins?.["oh-my-droid@oh-my-droid"] ?? [];
const install = installs.find((item) => item.scope === registry.scope) ?? installs[0];
if (install?.installPath) {
console.log(install.installPath);
process.exit(0);
}
} catch {}
}
console.log("");
NODE
)
if [ -n "$PLUGIN_DIR" ]; then
echo "Active plugin install: $PLUGIN_DIR"
else
echo "No active plugin install found (normal for new installs)"
fi
```
## Step 3.6: Check for Updates
Notify user if a newer version is available:
```bash
# Detect installed version
INSTALLED_VERSION=""
PLUGIN_DIR=$(node --input-type=module - <<'NODE'
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
const registries = [
{ path: join(process.cwd(), ".factory/plugins/installed_plugins.json"), scope: "project" },
{ path: join(homedir(), ".factory/plugins/installed_plugins.json"), scope: "user" },
];
for (const registry of registries) {
try {
const metadata = JSON.parse(readFileSync(registry.path, "utf-8"));
const installs = metadata.plugins?.["oh-my-droid@oh-my-droid"] ?? [];
const install = installs.find((item) => item.scope === registry.scope) ?? installs[0];
if (install?.installPath) {
console.log(install.installPath);
process.exit(0);
}
} catch {}
}
console.log("");
NODE
)
# Try the metadata-resolved plugin directory first
if [ -n "$PLUGIN_DIR" ] && [ -f "$PLUGIN_DIR/package.json" ]; then
INSTALLED_VERSION=$(node -p "require(process.argv[1]).version" "$PLUGIN_DIR/package.json" 2>/dev/null)
fi
# Try .omd-version.json second
if [ -z "$INSTALLED_VERSION" ] && [ -f ".omd-version.json" ]; then
INSTALLED_VERSION=$(grep -oE '"version":\s*"[^"]+' .omd-version.json | cut -d'"' -f4)
fi
# Try FACTORY.md header third (local first, then global)
if [ -z "$INSTALLED_VERSION" ]; then
if [ -f ".factory/FACTORY.md" ]; then
INSTALLED_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | sed 's/^v//')
elif [ -f "$HOME/.factory/FACTORY.md" ]; then
INSTALLED_VERSION=$(grep -m1 "^# oh-my-droid" "$HOME/.factory/FACTORY.md" 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | sed 's/^v//')
fi
fi
# Check npm for latest version
LATEST_VERSION=$(npm view oh-my-droid version 2>/dev/null)
if [ -n "$INSTALLED_VERSION" ] && [ -n "$LATEST_VERSION" ]; then
# Simple version comparison (assumes semantic versioning)
if [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then
echo ""
echo "UPDATE AVAILABLE:"
echo " Installed: v$INSTALLED_VERSION"
echo " Latest: v$LATEST_VERSION"
echo ""
echo "To update, run: droid /plugin install oh-my-droid@oh-my-droid"
else
echo "You're on the latest version: v$INSTALLED_VERSION"
fi
elif [ -n "$LATEST_VERSION" ]; then
echo "Latest version available: v$LATEST_VERSION"
fi
```
## Step 3.7: Enable Background Processes (Required)
Background processes are required for true parallel shell execution (e.g., running multiple long `Execute` commands concurrently).
This must be set globally in `~/.factory/settings.json` (there is no per-project equivalent).
```bash
python3 - <<'PY'
import json
from pathlib import Path
settings_path = Path.home() / '.factory' / 'settings.json'
settings_path.parent.mkdir(parents=True, exist_ok=True)
try:
data = json.loads(settings_path.read_text('utf-8')) if settings_path.exists() else {}
except Exception:
data = {}
data['allowBackgroundProcesses'] = True
settings_path.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8')
print('Enabled allowBackgroundProcesses in', settings_path)
print('NOTE: You may need to restart Droid (or start with --allow-background-processes) for it to take effect.')
PY
```
If the user wants to use background processes immediately in the current session and it still reports "Fire and forget is disabled", instruct them to restart Droid.
## Step 3.8: Set Default Execution Mode
Use `AskUser` to prompt:
1. [question] Which execution mode should be the default when I interpret requests like "fast" / "parallel"?
[topic] Default-Mode
[option] ultrawork
[option] ecomode
Store the preference in `~/.factory/.omd-config.json`:
```bash
# Read existing config or create empty object
CONFIG_FILE="$HOME/.factory/.omd-config.json"
mkdir -p "$(dirname "$CONFIG_FILE")"
if [ -f "$CONFIG_FILE" ]; then
EXISTING=$(cat "$CONFIG_FILE")
else
EXISTING='{}'
fi
# Set defaultExecutionMode (replace USER_CHOICE with "ultrawork" or "ecomode")
echo "$EXISTING" | jq --arg mode "USER_CHOICE" '. + {defaultExecutionMode: $mode, configuredAt: (now | todate)}' > "$CONFIG_FILE"
echo "Default execution mode set to: USER_CHOICE"
```
**Note**: This preference ONLY affects generic keywords ("fast", "parallel"). Explicit keywords ("ulw", "eco") always override this preference.
## Step 3.9: Install CLI Analytics Tools (Optional)
The OMD CLI provides standalone token analytics commands (`omd stats`, `omd agents`, `omd tui`).
Ask user: "Would you like to install the OMD CLI for standalone analytics? (Recommended for tracking token usage and costs)"
**Options:**
1. **Yes (Recommended)** - Install CLI tools globally for `omd stats`, `omd agents`, etc.
2. **No** - Skip CLI installation, use only plugin skills
### CLI Installation Note
The CLI (`omc` command) is **no longer supported** via npm/bun global install.
All functionality is available through the plugin system:
- Use `/help` for guidance
- Use `/doctor` for diagnostics
Skip this step - the plugin provides all features.
## Step 4: Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
## Step 5: Offer MCP Server Configuration
MCP servers extend Factory Droid with additional tools (web search, GitHub, etc.).
Ask user: "Would you like to configure MCP servers for enhanced capabilities? (Context7, Exa search, GitHub, etc.)"
If yes, invoke the mcp-setup skill:
```
/mcp-setup
```
If no, skip to next step.
## Step 6: Detect Upgrade from 2.x
Check if user has existing configuration:
```bash
# Check for existing 2.x artifacts
ls ~/.factory/commands/ralph-loop.md 2>/dev/null || ls ~/.factory/commands/ultrawork.md 2>/dev/null
```
If found, this is an upgrade from 2.x.
## Step 7: Show Welcome Message
### For New Users:
```
OMD Setup Complete!
You don't need to learn any commands. I now have intelligent behaviors that activate automatically.
WHAT HAPPENS AUTOMATICALLY:
- Complex tasks -> I parallelize and delegate to specialists
- "plan this" -> I start a planning interview
- "don't stop until done" -> I persist until verified complete
- "stop" or "cancel" -> I intelligently stop current operation
MAGIC KEYWORDS (optional power-user shortcuts):
Just include these words naturally in your request:
| Keyword | Effect | Example |
|---------|--------|---------|
| ralph | Persistence mode | "ralph: fix the auth bug" |
| ralplan | Iterative planning | "ralplan this feature" |
| ulw | Max parallelism | "ulw refactor the API" |
| eco | Token-efficient mode | "eco refactor the API" |
| plan | Planning interview | "plan the new endpoints" |
**ralph includes ultrawork:** When you activate ralph mode, it automatically includes ultrawork's parallel execution. No need to combine keywords.
MCP SERVERS:
Run /mcp-setup to add tools like web search, GitHub, etc.
HUD STATUSLINE:
The status bar now shows OMD state. Restart Factory Droid to see it.
CLI ANALYTICS (if installed):
- omc - Full dashboard (stats + agents + cost)
- omd stats - View token usage and costs
- omd agents - See agent breakdown by cost
- omd tui - Launch interactive TUI dashboard
That's it! Just use Factory Droid normally.
```
### For Users Upgrading from 2.x:
```
OMD Setup Complete! (Upgraded from 2.x)
GOOD NEWS: Your existing commands still work!
- /ralph, /ultrawork, /plan, etc. all still function
WHAT'S NEW in 3.0:
You no longer NEED those commands. Everything is automatic now:
- Just say "don't stop until done" instead of /ralph
- Just say "fast" or "parallel" instead of /ultrawork
- Just say "plan this" instead of /plan
- Just say "stop" instead of /cancel
MAGIC KEYWORDS (power-user shortcuts):
| Keyword | Same as old... | Example |
|---------|----------------|---------|
| ralph | /ralph | "ralph: fix the bug" |
| ralplan | /ralplan | "ralplan this feature" |
| ulw | /ultrawork | "ulw refactor API" |
| eco | (new!) | "eco fix all errors" |
| plan | /plan | "plan the endpoints" |
HUD STATUSLINE:
The status bar now shows OMD state. Restart Factory Droid to see it.
CLI ANALYTICS (if installed):
- omc - Full dashboard (stats + agents + cost)
- omd stats - View token usage and costs
- omd agents - See agent breakdown by cost
- omd tui - Launch interactive TUI dashboard
Your workflow won't break - it just got easier!
```
## Step 8: Ask About Starring Repository
First, check if `gh` CLI is available and authenticated:
```bash
gh auth status &>/dev/null
```
### If gh is available and authenticated:
Use `AskUser` to prompt:
1. [question] Would you like to star the oh-my-droid GitHub repo?
[topic] Star
[option] Yes, star it
[option] No
[option] Maybe later
If user chooses "Yes, star it!":
```bash
gh api -X PUT /user/starred/MeroZemory/oh-my-droid 2>/dev/null && echo "Thanks for starring! ⭐" || true
```
**Note:** Fail silently if the API call doesn't work - never block setup completion.
### If gh is NOT available or not authenticated:
```bash
echo ""
echo "If you enjoy oh-my-droid, consider starring the repo:"
echo " https://github.com/MeroZemory/oh-my-droid"
echo ""
```
### Clear Setup State on Completion
After Step 8 completes (regardless of star choice), clear the setup state:
```bash
# Setup complete - clear state file
rm -f ".omd/state/setup-state.json"
echo "Setup completed successfully!"
```
## Keeping Up to Date
After installing oh-my-droid updates (via npm or plugin update), run:
- `/omd-setup --local` to update project config
- `/omd-setup --global` to update global config
This ensures you have the newest features and agent configurations.
## Help Text
When user runs `/omd-setup --help` or just `--help`, display:
```
OMD Setup - Configure oh-my-droid
USAGE:
/omd-setup Run initial setup wizard
/omd-setup --local Configure local project (.factory/FACTORY.md)
/omd-setup --global Configure global settings (~/.factory/FACTORY.md)
/omd-setup --help Show this help
MODES:
Initial Setup (no flags)
- Interactive wizard for first-time setup
- Configures FACTORY.md (local or global)
- Sets up HUD statusline
- Checks for updates
- Offers MCP server configuration
Local Configuration (--local)
- Downloads fresh FACTORY.md to ./.factory/
- Backs up existing FACTORY.md to .factory/FACTORY.md.backup.YYYY-MM-DD
- Project-specific settings
- Use this to update project config after OMC upgrades
Global Configuration (--global)
- Downloads fresh FACTORY.md to ~/.factory/
- Backs up existing FACTORY.md to ~/.factory/FACTORY.md.backup.YYYY-MM-DD
- Applies to all Factory Droid sessions
- Cleans up legacy hooks
- Use this to update global config after OMC upgrades
EXAMPLES:
/omd-setup # First time setup
/omd-setup --local # Update this project
/omd-setup --global # Update all projects
For more info: https://github.com/MeroZemory/oh-my-droid
```
---
name: omd-setup-e0fbf61e1b79
description: Setup and configure oh-my-droid (the ONLY command you need to learn)
---
# OMD Setup
This skill is a **setup wizard**. Ignore unrelated context (open files, pending code changes, git/commits, etc.).
**When you need to ask the user anything, use the `AskUser` tool and ONLY ask the wizard questions below.**
This is the **only command you need to learn**. After running this, everything else is automatic.
## Graceful Interrupt Handling
**IMPORTANT**: This setup process saves progress after each step. If interrupted (Ctrl+C or connection loss), the setup can resume from where it left off.
### State File Location
- `.omd/state/setup-state.json` - Tracks completed steps
### Resume Detection (Step 0)
Before starting any step, check for existing state:
```bash
# Check for existing setup state
STATE_FILE=".omd/state/setup-state.json"
# Cross-platform ISO date to epoch conversion
iso_to_epoch() {
local iso_date="$1"
local epoch=""
# Try GNU date first (Linux)
epoch=$(date -d "$iso_date" +%s 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$epoch" ]; then
echo "$epoch"
return 0
fi
# Try BSD/macOS date
local clean_date=$(echo "$iso_date" | sed 's/[+-][0-9][0-9]:[0-9][0-9]$//' | sed 's/Z$//' | sed 's/T/ /')
epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "$clean_date" +%s 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$epoch" ]; then
echo "$epoch"
return 0
fi
echo "0"
}
if [ -f "$STATE_FILE" ]; then
# Check if state is stale (older than 24 hours)
TIMESTAMP_RAW=$(jq -r '.timestamp // empty' "$STATE_FILE" 2>/dev/null)
if [ -n "$TIMESTAMP_RAW" ]; then
TIMESTAMP_EPOCH=$(iso_to_epoch "$TIMESTAMP_RAW")
NOW_EPOCH=$(date +%s)
STATE_AGE=$((NOW_EPOCH - TIMESTAMP_EPOCH))
else
STATE_AGE=999999 # Force fresh start if no timestamp
fi
if [ "$STATE_AGE" -gt 86400 ]; then
echo "Previous setup state is more than 24 hours old. Starting fresh."
rm -f "$STATE_FILE"
else
LAST_STEP=$(jq -r ".lastCompletedStep // 0" "$STATE_FILE" 2>/dev/null || echo "0")
TIMESTAMP=$(jq -r .timestamp "$STATE_FILE" 2>/dev/null || echo "unknown")
echo "Found previous setup session (Step $LAST_STEP completed at $TIMESTAMP)"
fi
fi
```
If state exists, use `AskUser` to prompt **exactly**:
1. [question] Found a previous setup session. What should I do?
[topic] Resume
[option] Resume from last step
[option] Start fresh (clear saved state)
If user chooses "Start fresh":
```bash
rm -f ".omd/state/setup-state.json"
echo "Previous state cleared. Starting fresh setup."
```
### Step 0.5: Always Ask Parallelism (Required)
**MANDATORY:** Regardless of whether the user resumes or starts fresh, you MUST ask for `maxBackgroundTasks` in this run.
If resuming, try to infer the scope from the state file:
```bash
# Optional: infer scope from state file
CONFIG_TYPE=$(jq -r '.configType // empty' ".omd/state/setup-state.json" 2>/dev/null || true)
```
Interpretation:
- If `CONFIG_TYPE` starts with `local` → scope = `Local (this project)`
- If `CONFIG_TYPE` starts with `global` → scope = `Global (all projects)`
- Otherwise, ask Step 1 (scope) again.
### Save Progress Helper
After completing each major step, save progress:
```bash
# Save setup progress (call after each step)
# Usage: save_setup_progress STEP_NUMBER
save_setup_progress() {
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": $1,
"timestamp": "$(date -Iseconds)",
"configType": "${CONFIG_TYPE:-unknown}"
}
EOF
}
```
### Clear State on Completion
After successful setup completion (Step 7/8), remove the state file:
```bash
rm -f ".omd/state/setup-state.json"
echo "Setup completed successfully. State cleared."
```
## Usage Modes
This skill handles three scenarios:
1. **Initial Setup (no flags)**: First-time installation wizard
2. **Local Configuration (`--local`)**: Configure project-specific settings (.factory/FACTORY.md)
3. **Global Configuration (`--global`)**: Configure global settings (~/.factory/FACTORY.md)
## Mode Detection
Check for flags in the user's invocation:
- If `--local` flag present → Skip to Local Configuration (Step 2A)
- If `--global` flag present → Skip to Global Configuration (Step 2B)
- If no flags → Run Initial Setup wizard (Step 1)
**IMPORTANT:** Always run Step 1.1 (parallelism) even when `--local` or `--global` is used.
## Step 1: Initial Setup Wizard (Default Behavior)
**Note**: If resuming and lastCompletedStep >= 1, skip to the appropriate step based on configType.
Immediately use `AskUser` to prompt **exactly**:
1. [question] Where should I configure oh-my-droid?
[topic] Scope
[option] Local (this project)
[option] Global (all projects)
## Step 1.1: Configure Parallelism (maxBackgroundTasks)
**IMPORTANT:** Always run this step (even if `maxBackgroundTasks` is already set, and even when resuming).
Use `AskUser` to prompt:
1. [question] How many background tasks should I allow in parallel?
[topic] Parallelism
[option] Keep current
[option] 2
[option] 5
[option] 10
[option] 20
If the user chooses **Keep current**, skip updating settings.
Otherwise, update BOTH:
1) **Factory Droid global settings**: `~/.factory/settings.json` → top-level `maxBackgroundTasks`
2) **oh-my-droid config** (so OMD can read it):
- If scope is **Local** → `./.factory/droid.jsonc` → `permissions.maxBackgroundTasks`
- If scope is **Global** → `${XDG_CONFIG_HOME:-~/.config}/oh-my-droid/config.jsonc` → `permissions.maxBackgroundTasks`
Rules:
- Default to **5** if the user provides an invalid value
- Clamp to **1..20**
```bash
python3 - <<'PY'
import json
import os
import re
from pathlib import Path
MIN_V = 1
MAX_V = 20
DEFAULT_V = 5
def strip_jsonc(text: str) -> str:
out: list[str] = []
i = 0
in_str = False
str_ch = ''
while i < len(text):
c = text[i]
if in_str:
out.append(c)
if c == '\\' and i + 1 < len(text):
i += 1
out.append(text[i])
elif c == str_ch:
in_str = False
i += 1
continue
if c in ('"', "'"):
in_str = True
str_ch = c
out.append(c)
i += 1
continue
if c == '/' and i + 1 < len(text) and text[i + 1] == '/':
i += 2
while i < len(text) and text[i] not in ('\n', '\r'):
i += 1
continue
if c == '/' and i + 1 < len(text) and text[i + 1] == '*':
i += 2
while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'):
i += 1
i += 2
continue
out.append(c)
i += 1
return ''.join(out)
def parse_jsonc_file(path: Path) -> dict:
if not path.exists():
return {}
raw = path.read_text('utf-8')
cleaned = strip_jsonc(raw)
cleaned = re.sub(r',\s*([}\]])', r'\1', cleaned)
cleaned_s = cleaned.strip()
if not cleaned_s:
return {}
return json.loads(cleaned_s)
factory_settings_path = Path.home() / '.factory' / 'settings.json'
factory_settings_path.parent.mkdir(parents=True, exist_ok=True)
try:
factory_data = json.loads(factory_settings_path.read_text('utf-8')) if factory_settings_path.exists() else {}
except Exception:
factory_data = {}
current = int(factory_data.get('maxBackgroundTasks', DEFAULT_V) or DEFAULT_V)
raw = "USER_CHOICE" # replace with chosen value (or user's custom answer)
scope = "SCOPE_CHOICE" # replace with: "Local (this project)" | "Global (all projects)" (or flags)
raw_s = str(raw).strip().lower()
if raw_s.startswith('keep'):
v = current
else:
try:
v = int(raw_s)
except Exception:
v = current
if v < MIN_V:
v = MIN_V
if v > MAX_V:
v = MAX_V
# 1) Factory Droid settings (global)
factory_data['maxBackgroundTasks'] = v
factory_settings_path.write_text(json.dumps(factory_data, indent=2) + '\n', encoding='utf-8')
print('Set Factory maxBackgroundTasks to', v, 'in', factory_settings_path)
# 2) OMD config (local or global)
scope_s = str(scope).strip().lower()
if scope_s.startswith('local'):
omd_config_path = Path.cwd() / '.factory' / 'droid.jsonc'
else:
xdg = Path(os.environ.get('XDG_CONFIG_HOME') or (Path.home() / '.config'))
omd_config_path = xdg / 'oh-my-droid' / 'config.jsonc'
omd_config_path.parent.mkdir(parents=True, exist_ok=True)
try:
omd_data = parse_jsonc_file(omd_config_path)
except Exception as e:
print('Warning: could not parse OMD config; skipping update:', omd_config_path, '-', e)
omd_data = None
if isinstance(omd_data, dict):
perms = omd_data.get('permissions')
if not isinstance(perms, dict):
perms = {}
perms['maxBackgroundTasks'] = v
omd_data['permissions'] = perms
omd_config_path.write_text(json.dumps(omd_data, indent=2) + '\n', encoding='utf-8')
print('Set OMD permissions.maxBackgroundTasks to', v, 'in', omd_config_path)
PY
```
## Step 2A: Local Configuration (--local flag or user chose LOCAL)
**CRITICAL**: This ALWAYS downloads fresh FACTORY.md from GitHub to the local project. DO NOT use the Write tool - use bash curl exclusively.
### Create Local .factory Directory
```bash
# Create .factory directory in current project
mkdir -p .factory && echo ".factory directory ready"
```
### Download Fresh FACTORY.md
```bash
# Extract old version before download
OLD_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "none")
# Backup existing FACTORY.md before overwriting (if it exists)
if [ -f ".factory/FACTORY.md" ]; then
BACKUP_DATE=$(date +%Y-%m-%d)
BACKUP_PATH=".factory/FACTORY.md.backup.${BACKUP_DATE}"
cp .factory/FACTORY.md "$BACKUP_PATH"
echo "Backed up existing FACTORY.md to $BACKUP_PATH"
fi
# Download fresh FACTORY.md from GitHub
curl -fsSL "https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md" -o .factory/FACTORY.md && \
echo "Downloaded FACTORY.md to .factory/FACTORY.md"
# Extract new version and report
NEW_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
if [ "$OLD_VERSION" = "none" ]; then
echo "Installed FACTORY.md: $NEW_VERSION"
elif [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo "FACTORY.md unchanged: $NEW_VERSION"
else
echo "Updated FACTORY.md: $OLD_VERSION -> $NEW_VERSION"
fi
```
**Note**: The downloaded FACTORY.md includes Context Persistence instructions with `<remember>` tags for surviving conversation compaction.
**Note**: If an existing FACTORY.md is found, it will be backed up to `.factory/FACTORY.md.backup.YYYY-MM-DD` before downloading the new version.
**MANDATORY**: Always run this command. Do NOT skip. Do NOT use Write tool.
**FALLBACK** if curl fails:
Tell user to manually download from:
https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md
### Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
### Confirm Local Configuration Success
After completing local configuration, save progress and report:
```bash
# Save progress - Step 2 complete (Local config)
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 2,
"timestamp": "$(date -Iseconds)",
"configType": "local"
}
EOF
```
**OMC Project Configuration Complete**
- FACTORY.md: Updated with latest configuration from GitHub at ./.factory/FACTORY.md
- Backup: Previous FACTORY.md backed up to `.factory/FACTORY.md.backup.YYYY-MM-DD` (if existed)
- Scope: **PROJECT** - applies only to this project
- Hooks: Provided by plugin (no manual installation needed)
- Agents: 28+ available (base + tiered variants)
- Model routing: Haiku/Sonnet/Opus based on task complexity
**Note**: This configuration is project-specific and won't affect other projects or global settings.
If `--local` flag was used, clear state and **STOP HERE**:
```bash
rm -f ".omd/state/setup-state.json"
```
Do not continue to HUD setup or other steps.
## Step 2B: Global Configuration (--global flag or user chose GLOBAL)
**CRITICAL**: This ALWAYS downloads fresh FACTORY.md from GitHub to global config. DO NOT use the Write tool - use bash curl exclusively.
### Download Fresh FACTORY.md
```bash
# Extract old version before download
OLD_VERSION=$(grep -m1 "^# oh-my-droid" ~/.factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "none")
# Backup existing FACTORY.md before overwriting (if it exists)
if [ -f "$HOME/.factory/FACTORY.md" ]; then
BACKUP_DATE=$(date +%Y-%m-%d)
BACKUP_PATH="$HOME/.factory/FACTORY.md.backup.${BACKUP_DATE}"
cp "$HOME/.factory/FACTORY.md" "$BACKUP_PATH"
echo "Backed up existing FACTORY.md to $BACKUP_PATH"
fi
# Download fresh FACTORY.md to global config
curl -fsSL "https://raw.githubusercontent.com/MeroZemory/oh-my-droid/main/docs/FACTORY.md" -o ~/.factory/FACTORY.md && \
echo "Downloaded FACTORY.md to ~/.factory/FACTORY.md"
# Extract new version and report
NEW_VERSION=$(grep -m1 "^# oh-my-droid" ~/.factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
if [ "$OLD_VERSION" = "none" ]; then
echo "Installed FACTORY.md: $NEW_VERSION"
elif [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo "FACTORY.md unchanged: $NEW_VERSION"
else
echo "Updated FACTORY.md: $OLD_VERSION -> $NEW_VERSION"
fi
```
**Note**: If an existing FACTORY.md is found, it will be backed up to `~/.factory/FACTORY.md.backup.YYYY-MM-DD` before downloading the new version.
### Clean Up Legacy Hooks (if present)
Check if old manual hooks exist and remove them to prevent duplicates:
```bash
# Remove legacy bash hook scripts (now handled by plugin system)
rm -f ~/.factory/hooks/keyword-detector.sh
rm -f ~/.factory/hooks/stop-continuation.sh
rm -f ~/.factory/hooks/persistent-mode.sh
rm -f ~/.factory/hooks/session-start.sh
echo "Legacy hooks cleaned"
```
Check `~/.factory/settings.json` for manual hook entries. If the "hooks" key exists with UserPromptSubmit, Stop, or SessionStart entries pointing to bash scripts, inform the user:
> **Note**: Found legacy hooks in settings.json. These should be removed since the plugin now provides hooks automatically. Remove the "hooks" section from ~/.factory/settings.json to prevent duplicate hook execution.
### Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
### Confirm Global Configuration Success
After completing global configuration, save progress and report:
```bash
# Save progress - Step 2 complete (Global config)
mkdir -p .omd/state
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 2,
"timestamp": "$(date -Iseconds)",
"configType": "global"
}
EOF
```
**OMC Global Configuration Complete**
- FACTORY.md: Updated with latest configuration from GitHub at ~/.factory/FACTORY.md
- Backup: Previous FACTORY.md backed up to `~/.factory/FACTORY.md.backup.YYYY-MM-DD` (if existed)
- Scope: **GLOBAL** - applies to all Factory Droid sessions
- Hooks: Provided by plugin (no manual installation needed)
- Agents: 28+ available (base + tiered variants)
- Model routing: Haiku/Sonnet/Opus based on task complexity
**Note**: Hooks are now managed by the plugin system automatically. No manual hook installation required.
If `--global` flag was used, clear state and **STOP HERE**:
```bash
rm -f ".omd/state/setup-state.json"
```
Do not continue to HUD setup or other steps.
## Step 3: Setup HUD Statusline
**Note**: If resuming and lastCompletedStep >= 3, skip to Step 3.5.
The HUD shows real-time status in Factory Droid's status bar. **Invoke the hud skill** to set up and configure:
Use the Skill tool to invoke: `hud` with args: `setup`
This will:
1. Install the HUD wrapper script to `~/.factory/hud/omd-hud.mjs`
2. Configure `statusLine` in `~/.factory/settings.json`
3. Report status and prompt to restart if needed
After HUD setup completes, save progress:
```bash
# Save progress - Step 3 complete (HUD setup)
mkdir -p .omd/state
CONFIG_TYPE=$(cat ".omd/state/setup-state.json" 2>/dev/null | grep -oE '"configType":\s*"[^"]+"' | cut -d'"' -f4 || echo "unknown")
cat > ".omd/state/setup-state.json" << EOF
{
"lastCompletedStep": 3,
"timestamp": "$(date -Iseconds)",
"configType": "$CONFIG_TYPE"
}
EOF
```
## Step 3.5: Resolve Active Plugin Install
Use Factory's installation metadata rather than sorting cache directory names,
which are content hashes rather than semantic versions:
```bash
PLUGIN_DIR=$(node --input-type=module - <<'NODE'
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
const registries = [
{ path: join(process.cwd(), ".factory/plugins/installed_plugins.json"), scope: "project" },
{ path: join(homedir(), ".factory/plugins/installed_plugins.json"), scope: "user" },
];
for (const registry of registries) {
try {
const metadata = JSON.parse(readFileSync(registry.path, "utf-8"));
const installs = metadata.plugins?.["oh-my-droid@oh-my-droid"] ?? [];
const install = installs.find((item) => item.scope === registry.scope) ?? installs[0];
if (install?.installPath) {
console.log(install.installPath);
process.exit(0);
}
} catch {}
}
console.log("");
NODE
)
if [ -n "$PLUGIN_DIR" ]; then
echo "Active plugin install: $PLUGIN_DIR"
else
echo "No active plugin install found (normal for new installs)"
fi
```
## Step 3.6: Check for Updates
Notify user if a newer version is available:
```bash
# Detect installed version
INSTALLED_VERSION=""
PLUGIN_DIR=$(node --input-type=module - <<'NODE'
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
const registries = [
{ path: join(process.cwd(), ".factory/plugins/installed_plugins.json"), scope: "project" },
{ path: join(homedir(), ".factory/plugins/installed_plugins.json"), scope: "user" },
];
for (const registry of registries) {
try {
const metadata = JSON.parse(readFileSync(registry.path, "utf-8"));
const installs = metadata.plugins?.["oh-my-droid@oh-my-droid"] ?? [];
const install = installs.find((item) => item.scope === registry.scope) ?? installs[0];
if (install?.installPath) {
console.log(install.installPath);
process.exit(0);
}
} catch {}
}
console.log("");
NODE
)
# Try the metadata-resolved plugin directory first
if [ -n "$PLUGIN_DIR" ] && [ -f "$PLUGIN_DIR/package.json" ]; then
INSTALLED_VERSION=$(node -p "require(process.argv[1]).version" "$PLUGIN_DIR/package.json" 2>/dev/null)
fi
# Try .omd-version.json second
if [ -z "$INSTALLED_VERSION" ] && [ -f ".omd-version.json" ]; then
INSTALLED_VERSION=$(grep -oE '"version":\s*"[^"]+' .omd-version.json | cut -d'"' -f4)
fi
# Try FACTORY.md header third (local first, then global)
if [ -z "$INSTALLED_VERSION" ]; then
if [ -f ".factory/FACTORY.md" ]; then
INSTALLED_VERSION=$(grep -m1 "^# oh-my-droid" .factory/FACTORY.md 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | sed 's/^v//')
elif [ -f "$HOME/.factory/FACTORY.md" ]; then
INSTALLED_VERSION=$(grep -m1 "^# oh-my-droid" "$HOME/.factory/FACTORY.md" 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | sed 's/^v//')
fi
fi
# Check npm for latest version
LATEST_VERSION=$(npm view oh-my-droid version 2>/dev/null)
if [ -n "$INSTALLED_VERSION" ] && [ -n "$LATEST_VERSION" ]; then
# Simple version comparison (assumes semantic versioning)
if [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then
echo ""
echo "UPDATE AVAILABLE:"
echo " Installed: v$INSTALLED_VERSION"
echo " Latest: v$LATEST_VERSION"
echo ""
echo "To update, run: droid /plugin install oh-my-droid@oh-my-droid"
else
echo "You're on the latest version: v$INSTALLED_VERSION"
fi
elif [ -n "$LATEST_VERSION" ]; then
echo "Latest version available: v$LATEST_VERSION"
fi
```
## Step 3.7: Enable Background Processes (Required)
Background processes are required for true parallel shell execution (e.g., running multiple long `Execute` commands concurrently).
This must be set globally in `~/.factory/settings.json` (there is no per-project equivalent).
```bash
python3 - <<'PY'
import json
from pathlib import Path
settings_path = Path.home() / '.factory' / 'settings.json'
settings_path.parent.mkdir(parents=True, exist_ok=True)
try:
data = json.loads(settings_path.read_text('utf-8')) if settings_path.exists() else {}
except Exception:
data = {}
data['allowBackgroundProcesses'] = True
settings_path.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8')
print('Enabled allowBackgroundProcesses in', settings_path)
print('NOTE: You may need to restart Droid (or start with --allow-background-processes) for it to take effect.')
PY
```
If the user wants to use background processes immediately in the current session and it still reports "Fire and forget is disabled", instruct them to restart Droid.
## Step 3.8: Set Default Execution Mode
Use `AskUser` to prompt:
1. [question] Which execution mode should be the default when I interpret requests like "fast" / "parallel"?
[topic] Default-Mode
[option] ultrawork
[option] ecomode
Store the preference in `~/.factory/.omd-config.json`:
```bash
# Read existing config or create empty object
CONFIG_FILE="$HOME/.factory/.omd-config.json"
mkdir -p "$(dirname "$CONFIG_FILE")"
if [ -f "$CONFIG_FILE" ]; then
EXISTING=$(cat "$CONFIG_FILE")
else
EXISTING='{}'
fi
# Set defaultExecutionMode (replace USER_CHOICE with "ultrawork" or "ecomode")
echo "$EXISTING" | jq --arg mode "USER_CHOICE" '. + {defaultExecutionMode: $mode, configuredAt: (now | todate)}' > "$CONFIG_FILE"
echo "Default execution mode set to: USER_CHOICE"
```
**Note**: This preference ONLY affects generic keywords ("fast", "parallel"). Explicit keywords ("ulw", "eco") always override this preference.
## Step 3.9: Install CLI Analytics Tools (Optional)
The OMD CLI provides standalone token analytics commands (`omd stats`, `omd agents`, `omd tui`).
Ask user: "Would you like to install the OMD CLI for standalone analytics? (Recommended for tracking token usage and costs)"
**Options:**
1. **Yes (Recommended)** - Install CLI tools globally for `omd stats`, `omd agents`, etc.
2. **No** - Skip CLI installation, use only plugin skills
### CLI Installation Note
The CLI (`omc` command) is **no longer supported** via npm/bun global install.
All functionality is available through the plugin system:
- Use `/help` for guidance
- Use `/doctor` for diagnostics
Skip this step - the plugin provides all features.
## Step 4: Verify Plugin Installation
```bash
grep -q "oh-my-droid" ~/.factory/settings.json && echo "Plugin verified" || echo "Plugin NOT found - run: droid /plugin install oh-my-droid@oh-my-droid"
```
## Step 5: Offer MCP Server Configuration
MCP servers extend Factory Droid with additional tools (web search, GitHub, etc.).
Ask user: "Would you like to configure MCP servers for enhanced capabilities? (Context7, Exa search, GitHub, etc.)"
If yes, invoke the mcp-setup skill:
```
/mcp-setup
```
If no, skip to next step.
## Step 6: Detect Upgrade from 2.x
Check if user has existing configuration:
```bash
# Check for existing 2.x artifacts
ls ~/.factory/commands/ralph-loop.md 2>/dev/null || ls ~/.factory/commands/ultrawork.md 2>/dev/null
```
If found, this is an upgrade from 2.x.
## Step 7: Show Welcome Message
### For New Users:
```
OMD Setup Complete!
You don't need to learn any commands. I now have intelligent behaviors that activate automatically.
WHAT HAPPENS AUTOMATICALLY:
- Complex tasks -> I parallelize and delegate to specialists
- "plan this" -> I start a planning interview
- "don't stop until done" -> I persist until verified complete
- "stop" or "cancel" -> I intelligently stop current operation
MAGIC KEYWORDS (optional power-user shortcuts):
Just include these words naturally in your request:
| Keyword | Effect | Example |
|---------|--------|---------|
| ralph | Persistence mode | "ralph: fix the auth bug" |
| ralplan | Iterative planning | "ralplan this feature" |
| ulw | Max parallelism | "ulw refactor the API" |
| eco | Token-efficient mode | "eco refactor the API" |
| plan | Planning interview | "plan the new endpoints" |
**ralph includes ultrawork:** When you activate ralph mode, it automatically includes ultrawork's parallel execution. No need to combine keywords.
MCP SERVERS:
Run /mcp-setup to add tools like web search, GitHub, etc.
HUD STATUSLINE:
The status bar now shows OMD state. Restart Factory Droid to see it.
CLI ANALYTICS (if installed):
- omc - Full dashboard (stats + agents + cost)
- omd stats - View token usage and costs
- omd agents - See agent breakdown by cost
- omd tui - Launch interactive TUI dashboard
That's it! Just use Factory Droid normally.
```
### For Users Upgrading from 2.x:
```
OMD Setup Complete! (Upgraded from 2.x)
GOOD NEWS: Your existing commands still work!
- /ralph, /ultrawork, /plan, etc. all still function
WHAT'S NEW in 3.0:
You no longer NEED those commands. Everything is automatic now:
- Just say "don't stop until done" instead of /ralph
- Just say "fast" or "parallel" instead of /ultrawork
- Just say "plan this" instead of /plan
- Just say "stop" instead of /cancel
MAGIC KEYWORDS (power-user shortcuts):
| Keyword | Same as old... | Example |
|---------|----------------|---------|
| ralph | /ralph | "ralph: fix the bug" |
| ralplan | /ralplan | "ralplan this feature" |
| ulw | /ultrawork | "ulw refactor API" |
| eco | (new!) | "eco fix all errors" |
| plan | /plan | "plan the endpoints" |
HUD STATUSLINE:
The status bar now shows OMD state. Restart Factory Droid to see it.
CLI ANALYTICS (if installed):
- omc - Full dashboard (stats + agents + cost)
- omd stats - View token usage and costs
- omd agents - See agent breakdown by cost
- omd tui - Launch interactive TUI dashboard
Your workflow won't break - it just got easier!
```
## Step 8: Ask About Starring Repository
First, check if `gh` CLI is available and authenticated:
```bash
gh auth status &>/dev/null
```
### If gh is available and authenticated:
Use `AskUser` to prompt:
1. [question] Would you like to star the oh-my-droid GitHub repo?
[topic] Star
[option] Yes, star it
[option] No
[option] Maybe later
If user chooses "Yes, star it!":
```bash
gh api -X PUT /user/starred/MeroZemory/oh-my-droid 2>/dev/null && echo "Thanks for starring! ⭐" || true
```
**Note:** Fail silently if the API call doesn't work - never block setup completion.
### If gh is NOT available or not authenticated:
```bash
echo ""
echo "If you enjoy oh-my-droid, consider starring the repo:"
echo " https://github.com/MeroZemory/oh-my-droid"
echo ""
```
### Clear Setup State on Completion
After Step 8 completes (regardless of star choice), clear the setup state:
```bash
# Setup complete - clear state file
rm -f ".omd/state/setup-state.json"
echo "Setup completed successfully!"
```
## Keeping Up to Date
After installing oh-my-droid updates (via npm or plugin update), run:
- `/omd-setup --local` to update project config
- `/omd-setup --global` to update global config
This ensures you have the newest features and agent configurations.
## Help Text
When user runs `/omd-setup --help` or just `--help`, display:
```
OMD Setup - Configure oh-my-droid
USAGE:
/omd-setup Run initial setup wizard
/omd-setup --local Configure local project (.factory/FACTORY.md)
/omd-setup --global Configure global settings (~/.factory/FACTORY.md)
/omd-setup --help Show this help
MODES:
Initial Setup (no flags)
- Interactive wizard for first-time setup
- Configures FACTORY.md (local or global)
- Sets up HUD statusline
- Checks for updates
- Offers MCP server configuration
Local Configuration (--local)
- Downloads fresh FACTORY.md to ./.factory/
- Backs up existing FACTORY.md to .factory/FACTORY.md.backup.YYYY-MM-DD
- Project-specific settings
- Use this to update project config after OMC upgrades
Global Configuration (--global)
- Downloads fresh FACTORY.md to ~/.factory/
- Backs up existing FACTORY.md to ~/.factory/FACTORY.md.backup.YYYY-MM-DD
- Applies to all Factory Droid sessions
- Cleans up legacy hooks
- Use this to update global config after OMC upgrades
EXAMPLES:
/omd-setup # First time setup
/omd-setup --local # Update this project
/omd-setup --global # Update all projects
For more info: https://github.com/MeroZemory/oh-my-droid
```
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.