Files
cthulhu/README-REMOTE-CONTROLLER.md
Storm Dragon 05a4f90af2 Add local development infrastructure and documentation
Add essential development tools and documentation for Cthulhu development:

Development Scripts:
- build-local.sh: Local build and install to ~/.local
- clean-local.sh: Clean build artifacts and local installation
- test-local.sh: Test local installation

Documentation:
- README-REMOTE-CONTROLLER.md: D-Bus service API documentation
- README-DEVELOPMENT.md: Development workflow documentation
- .gitignore: Updated with local build artifact patterns

These tools enable efficient local development without system-wide installation
and provide proper documentation for the D-Bus remote control capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-31 14:03:48 -04:00

12 KiB

Cthulhu Remote Controller (D-Bus Interface)

STABLE: This D-Bus interface has been successfully ported from Orca v49.alpha and integrated into Cthulhu. The API is functional and ready for use, providing external control and automation capabilities for the Cthulhu screen reader.

[TOC]

Overview

Cthulhu exposes a D-Bus service at:

  • Service Name: org.stormux.Cthulhu.Service
  • Main Object Path: /org/stormux/Cthulhu/Service
  • Module Object Paths: /org/stormux/Cthulhu/Service/ModuleName (e.g., /org/stormux/Cthulhu/Service/SpeechAndVerbosityManager)

Dependencies

The D-Bus interface requires:

  • dasbus - Python D-Bus library used by Cthulhu for the remote controller implementation. (Installation instructions)
  • python-dasbus package (available on most distributions)

Service-Level Commands

Commands available directly on the main service (/org/stormux/Cthulhu/Service):

Get Cthulhu's Version

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service GetVersion

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service \
    --method org.stormux.Cthulhu.Service.GetVersion

Returns: String containing the version (and revision if available)

Example output: s "Cthulhu screen reader version 2025.06.05-plugins (rev 408fb85)"

Present a Custom Message in Speech and/or Braille

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service PresentMessage s "Your message here"

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service \
    --method org.stormux.Cthulhu.Service.PresentMessage "Your message here"

Parameters:

  • message (string): The message to present to the user

Returns: Boolean indicating success

List Available Service Commands

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service ListCommands

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service \
    --method org.stormux.Cthulhu.Service.ListCommands

Returns: List of (command_name, description) tuples

List Registered Modules

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service ListModules

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service \
    --method org.stormux.Cthulhu.Service.ListModules

Returns: List of module names

Interacting with Modules

Each registered module exposes its own set of operations. Based on the underlying Cthulhu code, these are categorized as Commands, Runtime Getters, and Runtime Setters:

  • Commands: Actions that perform a task. These typically correspond to Cthulhu commands bound to a keystroke (e.g., IncreaseRate).
  • Runtime Getters: Operations that retrieve the current value of an item, often a setting (e.g., GetRate).
  • Runtime Setters: Operations that set the current value of an item, often a setting (e.g., SetRate). Note that setting a value does NOT cause it to become permanently saved.

You can discover and execute these for each module.

Discovering Module Capabilities

List Commands for a Module

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ListCommands

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ListCommands

Replace ModuleName with an actual module name from ListModules.

Returns: List of (command_name, description) tuples.

List Runtime Getters for a Module

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ListRuntimeGetters

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ListRuntimeGetters

Replace ModuleName with an actual module name from ListModules.

Returns: List of (getter_name, description) tuples.

List Runtime Setters for a Module

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ListRuntimeSetters

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ListRuntimeSetters

Replace ModuleName with an actual module name from ListModules.

Returns: List of (setter_name, description) tuples.

Executing Module Operations

Execute a Runtime Getter

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ExecuteRuntimeGetter s 'PropertyName'

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ExecuteRuntimeGetter 'PropertyName'

Parameters:

  • PropertyName (string): The name of the runtime getter to execute.

Returns: The value returned by the getter as a GLib variant (type depends on the getter).

Example: Get the current speech rate
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/SpeechAndVerbosityManager \
    org.stormux.Cthulhu.Module ExecuteRuntimeGetter s 'Rate'

This will return the rate as a GLib Variant.

Execute a Runtime Setter

busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ExecuteRuntimeSetter s 'PropertyName' v <value>

Alternative using gdbus:

gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ExecuteRuntimeSetter 'PropertyName' <value>

Parameters:

  • PropertyName (string): The name of the runtime setter to execute.
  • <value>: The value to set, as a GLib variant (type depends on the setter).

Returns: Boolean indicating success.

Example: Set the current speech rate
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/SpeechAndVerbosityManager \
    org.stormux.Cthulhu.Module ExecuteRuntimeSetter s 'Rate' v '<90>'

Execute a Module Command

# With user notification
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ExecuteCommand s 'CommandName' b true

# Without user notification (silent)
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/ModuleName \
    org.stormux.Cthulhu.Module ExecuteCommand s 'CommandName' b false

Alternative using gdbus:

# With user notification
gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ExecuteCommand 'CommandName' true

# Without user notification (silent)
gdbus call --session --dest org.stormux.Cthulhu.Service \
    --object-path /org/stormux/Cthulhu/Service/ModuleName \
    --method org.stormux.Cthulhu.Module.ExecuteCommand 'CommandName' false

Parameters (both required):

  • CommandName (string): The name of the command to execute
  • notify_user (boolean): Whether to notify the user of the action (see section below)

Returns: Boolean indicating success

Please Note

Setting notify_user=true is not a guarantee that feedback will be presented. Some commands inherently don't make sense to announce. For example:

# This command should simply stop speech, not announce that it is stopping speech.
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service/SpeechAndVerbosityManager \
    org.stormux.Cthulhu.Module ExecuteCommand s 'InterruptSpeech' b true

In those cases Cthulhu will ignore the value of notify_user.

Setting notify_user=false is a guarantee that Cthulhu will remain silent. If Cthulhu provides any feedback when notify_user=false, it should be considered a bug.

Integration with Cthulhu's Plugin System

The D-Bus Remote Controller integrates seamlessly with Cthulhu's pluggy-based plugin system. Plugins can:

  • Register their own D-Bus commands using the @cthulhu_hookimpl decorator
  • Expose plugin-specific functionality via the remote controller
  • Access the D-Bus service through the dynamic API manager

See the main CLAUDE.md file for more details on plugin development with D-Bus integration.

Troubleshooting

Service Not Available

If you get "The name is not activatable" or similar errors:

  1. Check if Cthulhu is running:

    ps aux | grep cthulhu
    
  2. Check if the D-Bus service is registered:

    busctl --user list | grep -i cthulhu
    
  3. Verify dasbus is installed:

    python3 -c "import dasbus; print('dasbus available')"
    
  4. Check Cthulhu debug output:

    DISPLAY=:0 ~/.local/bin/cthulhu --debug 2>&1 | grep -i dbus
    

Common Issues

  • Timing Issues: The D-Bus service starts after ATSPI initialization. Wait a few seconds after Cthulhu startup before attempting D-Bus calls.
  • Permissions: Ensure you're using --user with busctl/gdbus for session bus access.
  • Display: Make sure DISPLAY=:0 is set when running Cthulhu in terminal sessions.

Examples

Quick Test Script

#!/bin/bash
# Test Cthulhu D-Bus Remote Controller

echo "Testing Cthulhu D-Bus Remote Controller..."

# Get version
echo "Version:"
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service GetVersion

# Present a message
echo "Presenting message..."
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service PresentMessage s "Hello from D-Bus!"

# List available modules
echo "Available modules:"
busctl --user call org.stormux.Cthulhu.Service \
    /org/stormux/Cthulhu/Service \
    org.stormux.Cthulhu.Service ListModules

echo "D-Bus test complete!"

Integration Status

  • Core D-Bus service: Fully integrated with Cthulhu
  • Service lifecycle: Automatic start/shutdown with Cthulhu
  • Message presentation: PresentMessage() method working
  • Version info: GetVersion() method working
  • Deferred startup: D-Bus service starts after ATSPI initialization to prevent crashes
  • Error handling: Proper exception handling and logging
  • 🔄 Module registration: Ready for individual managers to register D-Bus commands
  • 🔄 Plugin integration: Plugins can expose D-Bus commands using decorators

Future Development

  • Add more speech configuration commands, getters, and setters
  • Expose Cthulhu's plugin system commands via D-Bus
  • Integrate with Cthulhu's advanced features (indentation audio, self-voicing, etc.)
  • Progressively expose all of Cthulhu's commands and settings via the remote controller interface
  • src/cthulhu/dbus_service.py - Main D-Bus service implementation
  • src/cthulhu/cthulhu.py - Integration and startup logic
  • CLAUDE.md - Main development guide with plugin integration details