A small pixel-art spark that lives on your desktop wallpaper, mirrors what Claude Code is doing, and opens a compact chat when you click it. If Claude Code is not installed or you are not signed in yet, it walks you through both.
Click the spark, ask a question, watch it think, get the answer. Recorded from the
plugin's own QML and scripts running in an isolated Quickshell window (no real desktop
in the frame); the answer is a real claude -p response.
Unofficial. Claude Companion is a community plugin. It is not made, endorsed or reviewed by Anthropic. "Claude" and "Claude Code" are Anthropic's names; the spark is an original drawing, not Anthropic's logo.
It is a Ryoku desktop-widget plugin (Quickshell on Hyprland): QML plus four small bash scripts. No resident app, no compiled code, no account of its own.
- Shows what Claude is doing. One spark, nine animations: sleeping, waking up, thinking, working (while a tool runs), waiting for you, done, error, needs attention, idle. It follows every Claude Code session you have running, in any terminal or editor.
- Chats. Click it for a small panel; ask something and the answer streams in. The conversation survives closing the panel and restarting the shell. new starts over.
- Sets itself up. First time here? It checks for Claude Code, points you to the install guide, and signs you in without leaving the widget. See First run.
- Dresses for the season. Christmas, Halloween, summer, spring and autumn outfits, each with its own falling or flying details. Auto (the default) follows the calendar and stays plain outside the seasons.
| What | Why |
|---|---|
| Ryoku (Hyprland + Quickshell) | the widget host |
claude (Claude Code CLI) |
does all the talking to Claude; the widget guides you to install it |
jq, inotify-tools (inotifywait) |
read the CLI's JSON output; watch session files without polling |
| A Claude plan with Claude Code access (Pro, Max, Team, Enterprise) or an Anthropic Console account | needed to sign in; the free claude.ai plan does not include Claude Code |
From Ryostore, once listed: open Ryoku Hub > Plugins and install Claude Companion. From this repository, anytime:
ryoku plugin add https://github.com/AdriLabTech/claude-companion --yes
Then turn it on under Ryoku Settings > Desktop > Widgets > Plugins and drag it where you
want it; docs/enable.md walks through it with screenshots, including how to
choose the seasonal outfit. The host remembers the position per monitor (Ctrl + wheel or the
corner handle resizes it). Remove it with
ryoku plugin remove claude-companion.
Nothing to configure. The widget checks on start and tells you what is missing; the spark shows a ? while it needs you.
| You see | It means | What to do |
|---|---|---|
| Claude Code is not installed | no claude command was found |
Install guide opens the official instructions; install, then Check again. |
| One helper tool is missing | jq is not installed |
Install it with your package manager, then Check again. |
| Sign in to Claude | Claude Code is installed but has no account | Sign in: your browser opens the official Claude page. |
| Finish signing in | the browser step is running | Approve in the browser. If the page shows a code instead of finishing by itself, paste it in the field and press send. Open link / Copy link are there if no browser opened. |
Sign-in is done by claude auth login, the official command. The widget only shows its
link and forwards a pasted code to it; it never sees your password or token, and the
tokens are stored by Claude Code in its own config directory, not by the plugin. If you
use an Anthropic Console account instead of a Claude plan, set Sign-in account type in
the settings first. If your login later expires, the next question brings you back to
the sign-in screen instead of failing silently.
More detail, including how to test every setup state on a machine that is already signed in, in docs/first-run.md.
| Do | Result |
|---|---|
| Click the spark | opens or closes the chat panel and wakes the spark up |
Type, Enter |
sends the message; stop cancels the turn (and the model call) |
Esc |
closes the panel |
| new | forgets the conversation and starts a fresh one |
What the spark means:
| State | When |
|---|---|
| Sleeping (zzz) | nothing happened for a while; any activity wakes it |
| Idle | awake and calm; blinks, looks around |
| Thinking (dots) | Claude is composing an answer |
| Working (sparks) | Claude is running a tool (Bash, Read, Edit...) |
| Waiting for you (?) | a session waits for input, or setup needs you |
| Needs attention (!) | a session is blocked on a permission prompt |
| Done | a turn finished: a short celebration |
| Error | a turn ended in an error, or the connection to Claude Code failed |
Set Seasonal outfit to Auto and it follows the calendar (pick the Northern or the Southern hemisphere variant), or pin one. Christmas: Santa hat and snow. Halloween: witch hat and bats. Summer: sunglasses, a small sun, glints. Spring: flower crown, petals, a butterfly. Autumn: a beanie and falling leaves. Details and dates in docs/seasons.md. Reduced motion turns the particles off and holds the first frame of each animation; it also follows your desktop's reduced-animation setting, read at start and after each setup check.
~/.claude/sessions + transcripts ─ companion-watch ─┐
├─ ClaudeState ─ state machine ─ sprite
claude -p (stream-json) ─ companion-chat ───────────┘
companion-check / companion-login ── first-run setup ──┘
service/Main.qml: all logic (setup, sign-in, merge of sources, state machine, chat).content/Widget.qml: the spark, the chat panel and the setup screens.content/PixelSprite.qml,content/SeasonFx.qml: sprite sheets and seasonal particles.bin/gen-sprites.py: draws every sheet and the generatedSpriteDefs.qml/SeasonDefs.qml(needs python-pillow; not run by the plugin).
Docs: turn it on · first run · seasons · Claude integration · character design.
Right-click the widget for the quick ones (the same list is under QS Bar Settings >
Community). Developers can also set debugOverlay, debugState (force an animation)
and debugCycle (step through all of them) in ~/.config/ryoku/plugins.json; they are
kept out of the menu so it stays short.
| Setting | Default | What it does |
|---|---|---|
| Pixel size of the companion | 3 | scale of the spark (1-8) |
| Fall asleep after idle | 120 s | when it starts sleeping |
| Reduced motion | off | static poses, no particles |
| Seasonal outfit | auto | off, auto (northern or southern hemisphere), or one season |
| Claude Code activity | follow | Off disables the session watcher (chat only) |
| Chat working folder | (empty) | empty = a private state folder with no project files; set a folder to let Claude work on a project |
| Chat permissions | ask | default (tools needing approval are denied), plan, or acceptEdits |
| Sign-in account type | Claude account | or Anthropic Console (API billing) |
Written for the Ryoku plugin rules (R6 to R11); the same facts, in one place.
- Runs (all from
bin/, never through a shell string built from your input):companion-check:claude --version,claude auth status,command -v jq,command -v inotifywait, andgsettings get ... enable-animationsif present. Prints one JSON line. The account email and organisation thatclaude auth statusalso prints are discarded before anything reaches the widget.companion-watch:inotifywait,jq. Read-only.companion-chat:claude -p --output-format stream-jsonwith your message as one argument after--.companion-login:claude auth login, only after you press Sign in.
- Reads:
~/.claude/sessions/*.jsonand the tail of~/.claude/projects/*/*.jsonl(or$CLAUDE_CONFIG_DIR) to tell thinking from running a tool. It looks at status fields and the name of the running tool; it does not store or transmit transcript text. That folder layout is observed behaviour of Claude Code, not a documented API (see docs/claude-integration.md). - Writes: the plugin itself writes only
$XDG_STATE_HOME/ryoku/plugins/claude-companion/(the id of your current chat, a few bytes) and temporary files; never~/.claude, never shell config. Theclaudeprocesses it starts write their usual session data (and the credentials after sign-in) in Claude Code's own config directory, and with theacceptEditspermission they can edit files in the chat working folder. - Network: none of its own.
claudetalks toapi.anthropic.com; signing in involvesclaude.ai/claude.com/platform.claude.com; the install guide button openscode.claude.comin your browser. They are declared incapabilities.network. - No privileged commands. No
sudo, nopkexec. - Validator note.
ryoku plugin validatereports fiveoutside-writewarnings. They are false positives from the pattern$HOME/...appearing in scripts: thePATHline that makes~/.local/bin/claudefindable (Quickshell often starts without your shellPATH) and reads of~/.claude. Nothing outside the state folder is written.
- The chat is headless: a tool that needs approval is denied and Claude says so. Pick
planoracceptEditsin the settings if you want something else. - Success and error are inferred (Claude Code publishes no "outcome" event): a turn that ends after a failed tool can still read as success.
- The widget lives on the wallpaper layer, so windows cover it; opening the panel grows the tile downward, so keep the spark a panel's height above the screen edge.
- The host starts the service once per screen surface, so with two monitors you will see
several
companion-watchprocesses; each just blocks on inotify.
claude-companion/
manifest.json # id, entry points, hosts, settings schema
service/Main.qml # main: setup, sign-in, state machine, chat
content/Widget.qml # content: spark, chat panel, setup screens
content/PixelSprite.qml # sprite-sheet player
content/SeasonFx.qml # seasonal particles
content/*Defs.qml # generated by bin/gen-sprites.py
bin/companion-* # check, login, chat, watch (bash)
bin/gen-sprites.py # draws every sheet (python-pillow)
assets/ # sheets, particles, preview-widget.png
docs/ # first run, seasons, integration, design, GIFs
Regenerate the art with python3 bin/gen-sprites.py --preview /tmp/preview.
AdriLabTech labs.lownoise@gmail.com: community-made (official is false). MIT, see
LICENSE.



