···7171 solstone-linux install-service
7272 ```
73737474-6. verify it's running and connected:
7474+6. install the system tray indicator (optional):
7575+ ```
7676+ solstone-linux install-tray
7777+ ```
7878+ this installs status icons and an XDG autostart entry so the tray app launches on login. to start it immediately: `solstone-tray &`
7979+8080+7. verify it's running and connected:
7581 ```
7682 systemctl --user status solstone-linux
7783 sol remote list
+7
contrib/solstone-tray.desktop
···11+[Desktop Entry]
22+Type=Application
33+Name=Solstone Tray
44+Comment=System tray status for solstone observer
55+Exec=solstone-tray
66+Icon=solstone-recording
77+NoDisplay=true
+66
src/solstone_linux/cli.py
···77 run Start capture loop + sync service (default)
88 setup Interactive configuration
99 install-service Write systemd user unit, enable, start
1010+ install-tray Install tray icons and XDG autostart entry
1011 status Show capture and sync state
1112"""
1213···192193 return 0
193194194195196196+def cmd_install_tray(args: argparse.Namespace) -> int:
197197+ """Install tray icons and XDG autostart desktop entry."""
198198+ binary = shutil.which("solstone-tray")
199199+ if not binary:
200200+ print("Error: solstone-tray not found on PATH", file=sys.stderr)
201201+ print(
202202+ "Install with: pipx install --system-site-packages solstone-linux",
203203+ file=sys.stderr,
204204+ )
205205+ return 1
206206+207207+ # Source icons from the installed package
208208+ icon_source = Path(__file__).resolve().parent / "icons" / "hicolor"
209209+ if not icon_source.is_dir():
210210+ print(f"Error: bundled icons not found at {icon_source}", file=sys.stderr)
211211+ return 1
212212+213213+ # Install icons to ~/.local/share/icons/hicolor/
214214+ icon_dest = Path.home() / ".local" / "share" / "icons" / "hicolor"
215215+ status_dir = icon_dest / "scalable" / "status"
216216+ status_dir.mkdir(parents=True, exist_ok=True)
217217+218218+ for svg in sorted((icon_source / "scalable" / "status").iterdir()):
219219+ if svg.suffix == ".svg":
220220+ shutil.copy2(svg, status_dir / svg.name)
221221+ print(f"Installed {status_dir / svg.name}")
222222+223223+ # Copy index.theme only if one doesn't already exist
224224+ index_dest = icon_dest / "index.theme"
225225+ if not index_dest.exists():
226226+ shutil.copy2(icon_source / "index.theme", index_dest)
227227+ print(f"Wrote {index_dest}")
228228+229229+ # Update icon cache (non-fatal if gtk-update-icon-cache is missing)
230230+ try:
231231+ subprocess.run(["gtk-update-icon-cache", str(icon_dest)], check=False)
232232+ except FileNotFoundError:
233233+ print("Warning: gtk-update-icon-cache not found. Icon cache not updated.")
234234+235235+ # Write autostart desktop entry
236236+ autostart_dir = Path.home() / ".config" / "autostart"
237237+ autostart_dir.mkdir(parents=True, exist_ok=True)
238238+ desktop_path = autostart_dir / "solstone-tray.desktop"
239239+240240+ desktop_content = f"""\
241241+[Desktop Entry]
242242+Type=Application
243243+Name=Solstone Tray
244244+Comment=System tray status for solstone observer
245245+Exec={binary}
246246+Icon=solstone-recording
247247+NoDisplay=true
248248+"""
249249+250250+ desktop_path.write_text(desktop_content)
251251+ print(f"Wrote {desktop_path}")
252252+ print("Tray will auto-start on next login.")
253253+254254+ return 0
255255+256256+195257def cmd_status(args: argparse.Namespace) -> int:
196258 """Show capture and sync state."""
197259 config = load_config()
···291353 # install-service
292354 subparsers.add_parser("install-service", help="Install systemd user service")
293355356356+ # install-tray
357357+ subparsers.add_parser("install-tray", help="Install tray icons and autostart entry")
358358+294359 # status
295360 subparsers.add_parser("status", help="Show capture and sync state")
296361···304369 "run": cmd_run,
305370 "setup": cmd_setup,
306371 "install-service": cmd_install_service,
372372+ "install-tray": cmd_install_tray,
307373 "status": cmd_status,
308374 }
309375