lil-agents-macos-dock
```markdown
What this skill does
```markdown
---
name: lil-agents-macos-dock
description: Tiny AI companions (Bruce and Jazz) that live on your macOS dock and provide Claude Code, OpenAI Codex, and GitHub Copilot CLI access via animated characters
triggers:
- "add lil agents to my dock"
- "set up dock AI companions"
- "configure lil agents"
- "add a new character or theme to lil agents"
- "integrate claude codex copilot with lil agents"
- "build lil agents from source"
- "customize lil agents appearance"
- "troubleshoot lil agents not showing"
---
# lil-agents macOS Dock AI Companions
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
lil-agents places animated AI companion characters (Bruce and Jazz) above your macOS dock. Click a character to open a themed terminal popover that shells out to your chosen AI CLI (Claude Code, OpenAI Codex, or GitHub Copilot). Characters walk, display thinking bubbles, and play sound effects — all rendered from transparent HEVC video bundled in the app.
---
## What It Does
| Feature | Detail |
|---|---|
| Characters | Bruce & Jazz walk back and forth above the dock |
| AI backends | Claude Code, OpenAI Codex CLI, GitHub Copilot CLI |
| Themes | Peach, Midnight, Cloud, Moss |
| Terminal | Themed popover with live streaming output |
| Thinking bubbles | Playful phrases while the agent runs |
| Updates | Sparkle framework for auto-updates |
| Privacy | Fully local — no telemetry, no accounts |
---
## Requirements
- macOS Sonoma 14.0+
- Xcode 15+ (to build from source)
- At least one AI CLI installed
### Install AI CLIs
```bash
# Claude Code
# Download from https://claude.ai/download and install
# OpenAI Codex
npm install -g @openai/codex
# GitHub Copilot CLI
brew install copilot-cli
```
---
## Building from Source
```bash
git clone https://github.com/ryanstephen/lil-agents.git
cd lil-agents
open lil-agents.xcodeproj
# Press ⌘R in Xcode to build and run
```
No additional package manager steps are required — dependencies (Sparkle) are resolved automatically by Xcode's Swift Package Manager integration.
---
## Project Structure
```
lil-agents/
├── lil-agents.xcodeproj/
├── lil agents/
│ ├── App/
│ │ ├── AppDelegate.swift # NSApplication entry, StatusItem, Sparkle
│ │ └── OnboardingWindowController.swift
│ ├── Characters/
│ │ ├── CharacterWindowController.swift # Transparent overlay window above dock
│ │ ├── CharacterView.swift # AVPlayer HEVC rendering
│ │ └── ThinkingBubbleView.swift
│ ├── Terminal/
│ │ ├── TerminalPopoverController.swift # Popover terminal UI
│ │ ├── AgentProcess.swift # Shells out to CLI
│ │ └── TerminalTheme.swift # Peach/Midnight/Cloud/Moss
│ ├── Settings/
│ │ └── SettingsManager.swift # UserDefaults-backed config
│ ├── Resources/
│ │ ├── bruce/ # HEVC .mov files (walk, think, idle)
│ │ ├── jazz/ # HEVC .mov files
│ │ └── Sounds/
│ └── Info.plist
└── README.md
```
---
## Core Architecture
### Transparent Window Above the Dock
Characters live in a `NSWindow` with `level = .statusBar` positioned just above the dock frame.
```swift
// CharacterWindowController.swift pattern
import AppKit
import AVKit
class CharacterWindowController: NSWindowController {
private var playerView: AVPlayerView!
private var player: AVPlayer!
override func windowDidLoad() {
super.windowDidLoad()
guard let window = window else { return }
// Make window transparent and click-through by default
window.isOpaque = false
window.backgroundColor = .clear
window.hasShadow = false
window.ignoresMouseEvents = false // false so clicks register
window.level = .statusBar // float above normal windows
// Position above the dock
positionAboveDock()
setupHEVCPlayer()
}
private func positionAboveDock() {
guard let screen = NSScreen.main else { return }
let dockHeight = getDockHeight(for: screen)
let charSize = CGSize(width: 80, height: 80)
// Start at left edge, above dock
let origin = CGPoint(
x: 100,
y: dockHeight + 4
)
window?.setFrame(CGRect(origin: origin, size: charSize), display: true)
}
private func getDockHeight(for screen: NSScreen) -> CGFloat {
// visibleFrame excludes dock and menu bar
let visible = screen.visibleFrame
let full = screen.frame
return visible.minY - full.minY // bottom inset = dock height
}
private func setupHEVCPlayer() {
guard let url = Bundle.main.url(forResource: "bruce-walk",
withExtension: "mov") else { return }
player = AVPlayer(url: url)
player.actionAtItemEnd = .none // we loop manually
NotificationCenter.default.addObserver(
self,
selector: #selector(playerDidReachEnd),
name: .AVPlayerItemDidPlayToEndTime,
object: player.currentItem
)
playerView = AVPlayerView(frame: window!.contentView!.bounds)
playerView.player = player
playerView.videoGravity = .resizeAspect
playerView.controlsStyle = .none
window?.contentView?.addSubview(playerView)
player.play()
}
@objc private func playerDidReachEnd(_ notification: Notification) {
player.seek(to: .zero)
player.play()
}
}
```
### Shelling Out to AI CLIs
```swift
// AgentProcess.swift pattern
import Foundation
enum AIBackend: String, CaseIterable {
case claude = "claude"
case codex = "codex"
case copilot = "gh" // `gh copilot suggest`
var executablePath: String {
// Resolve from common install locations
let candidates: [String]
switch self {
case .claude:
candidates = ["/usr/local/bin/claude", "/opt/homebrew/bin/claude"]
case .codex:
candidates = ["/usr/local/bin/codex", "/opt/homebrew/bin/codex",
"\(NSHomeDirectory())/.npm-global/bin/codex"]
case .copilot:
candidates = ["/usr/local/bin/gh", "/opt/homebrew/bin/gh"]
}
return candidates.first { FileManager.default.fileExists(atPath: $0) }
?? "/usr/local/bin/\(rawValue)"
}
func buildArguments(for prompt: String) -> [String] {
switch self {
case .claude:
return ["-p", prompt]
case .codex:
return ["-p", prompt]
case .copilot:
return ["copilot", "suggest", "-t", "shell", prompt]
}
}
}
class AgentProcess {
var onOutput: ((String) -> Void)?
var onComplete: (() -> Void)?
var onError: ((String) -> Void)?
private var process: Process?
func run(prompt: String, backend: AIBackend) {
let proc = Process()
proc.executableURL = URL(fileURLWithPath: backend.executablePath)
proc.arguments = backend.buildArguments(for: prompt)
// Inherit a PATH that includes Homebrew and npm globals
var env = ProcessInfo.processInfo.environment
env["PATH"] = "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:"
+ "\(NSHomeDirectory())/.npm-global/bin:"
+ (env["PATH"] ?? "")
proc.environment = env
let pipe = Pipe()
proc.standardOutput = pipe
proc.standardError = pipe
pipe.fileHandleForReading.readabilityHandler = { [weak self] handle in
let data = handle.availableData
guard !data.isEmpty,
let text = String(data: data, encoding: .utf8) else { return }
DispatchQueue.main.async { self?.onOutput?(text) }
}
proc.terminationHandler = { [weak self] _ in
DispatchQueue.main.async { self?.onComplete?() }
}
do {
Related in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.