Skip to content

artemy/semaphore

Repository files navigation

Semaphore CLI

MIT License

🚦 CLI for a USB-HID traffic-light device that turns your desk light into a live session indicator for Claude Code, Codex, and Opencode.

Features

  • Control red, yellow, and green LEDs individually or all at once
  • Three modes per LED: off, on, and blink with configurable speed
  • solo command lights one LED and clears the other two
  • status query reads current device state
  • boot plays a startup animation
  • Claude Code, Codex, and Opencode hook integration — the light follows session events automatically where supported

Getting started

Prerequisites

  • Node.js 18+
  • The semaphore device (VID 0x1209, PID 0x0001) connected via USB

Installing

npm install -g semaphore-cli

Or from source:

git clone https://github.com/artemy/semaphore
cd semaphore/software
npm install
npm install -g .

Usage

semaphore <led> off
semaphore <led> on
semaphore <led> blink [half_period_ms]
semaphore solo <color> on
semaphore solo <color> blink [half_period_ms]
semaphore status
semaphore boot
  • <led>: red | yellow | green | all
  • <color>: red | yellow | green (solo turns off the other two)
  • blink half-period: 20–5000 ms (default 500)
  • --soft / -s: silently exit 0 on device-connectivity errors (for hooks)

Examples

semaphore red on             # turn red LED on
semaphore green blink 250    # fast-blink green (250 ms half-period)
semaphore solo yellow on     # yellow on, red and green off
semaphore all off            # turn everything off
semaphore status             # read and print current device state

Hooks installation

⚠️ Every hook command uses --soft. This keeps the LED best-effort when the device is unplugged, and suppresses stdout so hook output is not injected into the model's context.

Claude Code

Claude Code hooks lifecycle

Claude Code support uses the documented lifecycle hooks in hooks/hooks.json:

LED state Meaning Hook events
green solid Idle / waiting for input SessionStart, Stop
red solid Claude is busy UserPromptSubmit, PostToolUse
yellow blink Needs human attention PermissionRequest, Notification
all off No active session SessionEnd

Plugin (recommended)

Make sure the package is installed globally first, then run from inside Claude Code:

/plugin marketplace add artemy/semaphore
/plugin install semaphore-hooks@semaphore

Manual

Merge the hooks key from hooks/hooks.json into your .claude/settings.json.

OpenAI Codex

Codex hooks lifecycle

Codex support uses the documented Codex lifecycle hooks in hooks/codex-hooks.json:

LED state Meaning Hook events
green solid Idle / waiting for input Stop
red solid Codex is busy UserPromptSubmit, PostToolUse
yellow blink Needs human attention PreToolUse (on request_user_input)
yellow blink Needs human approval PermissionRequest

Plugin (recommended)

Make sure the package is installed globally first, then run from your terminal:

codex plugin marketplace add artemy/semaphore
codex plugin add semaphore-hooks@semaphore

⚠️ Codex will prompt you to review the newly installed hooks after you run it next time.

Manual

Copy the contents of hooks/codex-hooks.json into your .codex/hooks.json.

Opencode

Opencode hooks lifecycle

Opencode support uses the native plugin system — the plugin at .opencode/plugins/semaphore-hooks.js is auto-discovered and maps Opencode lifecycle events to the semaphore device:

LED state Meaning Opencode events
green solid Idle / waiting for input session.created, session.idle
red solid Opencode is busy message.updated (role=user), tool.execute.after
yellow blink Needs human attention permission.asked, tool.execute.before (on question)
all off No active session session.deleted, dispose

Plugin

TODO: Installation

Built With

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

License

This project is licensed under the MIT License — see the LICENSE.md file for details