Integration — Claude Code, other agents & devices¶
Claude Code integration¶
NHJ installs four Claude Code lifecycle hooks: Stop (scans each response for [vibes:INTENT] markers and speaks the result), StopFailure (marks the session idle immediately when a turn ends with an API error, so hold music stops right away), plus UserPromptSubmit + SessionEnd (the hold-music busy/idle tracking and the secret guard). StopFailure warning vibes are opt-in with stop_failure_vibe.
NHJ also ships a Claude Code skill for changing Jan/Bazza/Karren settings from plain-language requests.
After installing hooks, verify they are registered by running /hooks in the Claude Code chat window. The NHJ events should appear with command entries and timeouts.
- Plugin install: Claude Code discovers the skill from the plugin's top-level
skills/not-happy-jan/SKILL.md. - NHJ repo checkout: the same top-level
skills/file is the canonical source used by the plugin and package build. - Wheel / non-checkout install: copy the bundled skill into Claude's personal skills dir:
Verify the skill¶
ls ~/.claude/skills/not-happy-jan/SKILL.md # wheel installs after `nhj install-skill`
nhj status # confirm the CLI is available to the skill
The skill uses nhj status, nhj set, and related CLI commands. Live overrides follow NHJ's
resource conventions: checkout .env during source use, otherwise the platform config dir
(NHJ_CONFIG_DIR override), plus the platform state dir / NHJ_STATE_FILE for runtime state.
Supersedes a shared
[vibes:]Stop hook. NHJ uses the same[vibes:]marker contract as AgentVibes (which it builds on), so if you already run AgentVibes (or another tool sharing the contract),install-hooksupersedes its Stop hook rather than stacking on top: - It first backs up~/.claude/settings.json→settings.json.pre-nhj.bak. - If it finds a legacy shared-[vibes:]-marker Stop hook, it removes that entry before adding NHJ's — otherwise both would fire and you'd hear each notification twice. - Only thesettings.jsonhook entry is touched; no other tool's files are removed. -nhj remove-hookremoves NHJ's hooks (restore from the backup to revert).If you've no prior agent-feedback Stop hook, it simply adds NHJ's.
Claude emits markers anywhere in its response:
The event contract (options)¶
The marker hook, the MCP tool (nhj_vibe), the remote dispatch, the queue, and the worker all share one option set and one validator (nhj/event.py), so an [Jan:ok|…] marker and an nhj_vibe(...) call accept, validate, and forward exactly the same options:
| Option | Type / range | Meaning |
|---|---|---|
intent |
ok\|err\|warn\|attn\|celebrate\|step |
event type (required) |
message |
text | "" → a random in-character phrase |
vibe_level |
int 1–10 | haptic intensity |
pretext |
text | spoken prefix (e.g. Node Om:) |
verbosity |
low\|medium\|high |
message detail |
emotion |
neutral\|alert\|confidential\|celebrate |
TTS delivery |
speed |
float 0.5–2.0 | TTS speed multiplier |
voice_variant |
text | per-character voice override |
character |
name | explicit override ("" routes by intent) |
Inline marker form: [Jan:err|emotion=alert|speed=1.2|Build broke] (the leading non-key=value chunk is the message; the who before the colon is the character).
- Local and remote dispatch send an identical payload — the explicit-character override (
[Jan:ok]) works the same whether it fires locally or overNHJ_REMOTE_URL. - Validation happens once, at the boundary. Out-of-range / unknown-enum values produce a clear error: the MCP tool returns
[nhj:error] …; a bad marker is logged and skipped so it never crashes the session. - Unknown options are reported, not silently accepted (logged to
/tmp/nhj-hook.log).
Other IDEs / agents¶
NHJ exposes an MCP tool nhj_vibe that works with any MCP-compatible agent:
| Agent | Integration method |
|---|---|
| Claude Code | Stop hook (marker-based) or MCP tool |
| OpenCode | MCP tool via opencode.json |
| Cursor | MCP tool via MCP server config |
| Aider | --after-completion shell hook |
| Cline | MCP tool |
| Amazon Q | Hook command |
| JetBrains AI | MCP server |
For remote agents (fleet nodes) set NHJ_REMOTE_URL to the NHJ SSE daemon on your local machine.
OpenCode integration¶
OpenCode is a CLI-based AI coding agent that uses MCP for tool integration. NHJ's MCP server works with OpenCode's stdio transport out of the box.
Quick install¶
This merges the NHJ MCP entry into your OpenCode config. Re-running is idempotent.
Manual configuration¶
// ~/.config/opencode/opencode.json
{
"mcp": {
"not-happy-jan": {
"type": "local",
"command": ["nhj", "serve-mcp"],
"enabled": true
}
}
}
Example usage¶
OpenCode calls the nhj_vibe MCP tool directly:
nhj_vibe(intent="ok", message="Task completed")
nhj_vibe(intent="err", message="Build failed")
nhj_vibe(intent="celebrate")
Verify connectivity¶
nhj test ok # fires a test vibe locally
nhj serve-mcp # start the MCP server in the foreground (stdio)
Remove¶
Security nudge — Karren catches leaked secrets¶
If you paste something secret-shaped into the chat (an API key, password, token, private key…), Karren tells you off: "Oi! You just dropped a bloody API key in the chat. NOT. HAPPY."
Off by default (opt-in). Enable with:
Important caveats — read before enabling:
- Heuristic only. The detector matches the shape of a secret with local regular expressions. It will produce false positives (normal text that happens to resemble a key format) and false negatives (real secrets that don't match any pattern). Do not rely on it as a security control.
- Local-only, no harvesting.
../src/nhj/secret_scan.pyonly returns a category string ("an API key") orNone— it never captures, returns, logs, stores, or transmits the secret value. Karren's scold names only the category, never the secret itself. - Zero network. The only effect is a local spoken nudge. It's ~40 auditable lines.
This is a convenience reminder, not a security guarantee.
Adding a notification device¶
💡 New to the hardware? See docs/devices/ — which devices are supported, and why a Ulanzi pixel clock (~AU$60, ~10-min flash) is the recommended place to start.
Implement NotificationAdapter and register it via entry points: