Cthulhu Tentacles

A repository of experimental Tentacles for Cthulhu-Go, maintained by Storm Dragon. It contains Hello World and the development Wormhole tentacle. Repository material and both Tentacles are licensed under GPL-3.0-or-later; see LICENSE and CONTRIBUTING.md.

repository.toml identifies this source. catalog.toml explicitly lists its Tentacles, each in a direct top-level folder with its own tentacle.toml. The catalog lists native packages for Linux amd64 and arm64. Hello World 0.1.0 is available from the release page. Wormhole 0.1.1 requires the matching reader with interactive Tentacle support. Its release archives are prepared for upload to the Wormhole release page; installation becomes available once both archives have been uploaded. Local build artifacts live in the ignored dist/ directory. The discovery source URL is https://git.stormux.org/storm/cthulhu-tentacles.

Tentacles are independent of the Git hosting service. Discovery reads TOML files from an HTTPS Git repository; installation downloads the HTTPS URLs explicitly listed in its catalog. Packages can live in pretty much any git provider, on an HTTPS web server, or in object storage with stable public HTTPS links. The reader does not call a hosting service's release API. Keeping packages in separate downloads avoids putting binaries into Git history.

To write your own, follow the creation and release tutorial.

Build and check

Keep the matching experimental cthulhu-go checkout beside this directory. The go.mod local replacement uses its Go SDK, including the new uninterruptible presentation option. Building requires Go 1.24 or newer; checks also require Python 3.11 or newer and Make.

make build
make check

The executables are hello-world/bin/hello-world and wormhole/bin/wormhole-tentacle; both are ignored by Git. Checks validate the TOML metadata, registration and suggested bindings, and invoke both Tentacles through the actual Cthulhu-Go host. They produce no speech or Braille and leave the running reader alone.

Repository installation

With the updated reader, open global Cthulhu Preferences → Tentacles → Add repository and enter the HTTPS Git URL above. Refresh an already added source. Select Hello World or Wormhole and press Space to review its source/version and requested access, then Install and enable. Wormhole requests internal forms and focused-item/clipboard access as well as speech/Braille. Install instead downloads and saves the package disabled. The reader verifies the catalog's SHA-256 digest, package identity and native architecture before saving a launch entry. Catalogs without a published compatible release show a clear message and remain unchecked. No source builds or install scripts run during this workflow. Resource limits do not make untrusted same-user programs safe.

After installation, refresh status until Active and use Cthulhu+Alt+Shift+H. Disable retains the package; re-enabling and reader startup use installed files without network access. Removing the source retains installed Tentacles. Removing a managed Tentacle stops it and deletes its package files after shutdown. Package updates are not implemented in this slice. See the Hello World live checks.

Prepare and publish packages

make check
make package

tools/package.py cross-builds statically linked native binaries for Linux amd64 and arm64 from the matching adjacent SDK. It creates deterministic archives containing tentacle.toml, bin/hello-world, README.md and LICENSE, plus dist/SHA256SUMS and a generated dist/catalog.toml. Go builds use readonly module metadata, trim paths and omit VCS stamping. To build one architecture:

python3 -B tools/package.py --architecture amd64

Validate the actual host-architecture package through Cthulhu-Go's installer and command host, without changing the running reader:

cd ../cthulhu-go
CTHULHU_TENTACLE_RELEASE_ROOT=../cthulhu-tentacles GOCACHE=/tmp/cthulhu-go-cache go test ./internal/tentacle -run '^TestBuiltHelloWorldPackageThroughHost$' -count=1 -v

Before publication, review both repositories' changes and contributing guides. Commit the reviewed source with the matching SDK available; select that source revision for the hello-world-v0.1.0 release. In the Git hosting release page, upload dist/hello-world-0.1.0-linux-amd64.tar.gz, dist/hello-world-0.1.0-linux-arm64.tar.gz and dist/SHA256SUMS. Publish and verify the download URLs and digests before publishing the matching catalog change. Copy the reviewed dist/catalog.toml to catalog.toml, review the diff, and submit/push it explicitly. A release filename/version must never be reused for changed content; bump the version before preparing a later release.

The package command creates local artifacts only. It does not create commits, releases, tags, uploads or pushes. Prepared catalog changes are not evidence that the corresponding release is already available. Live shortcut, speech, Braille, lock/handoff and interruption checks remain necessary after installation. An explicit restart is needed when changing the reader itself. For source-only local testing, the development launch procedure remains in Hello World.

Create and release your own Tentacle

This tutorial creates a native Go Tentacle named Greeting, then makes it installable from a repository. The SDK and package format are experimental; use a matching Cthulhu-Go checkout. Currently the installer supports native Linux executables, protocol 1.0, command registration and optional presentation access. Python SDK development is separate from this native package workflow. Broader APIs and automatic package updates are still pending.

1. Set up the source repository

You need Go 1.24 or newer, Git, Python 3.11 or newer for this repository's checks, GNU tar and gzip. Keep your new repository beside cthulhu-go. From their parent directory:

mkdir -p greeting-tentacles/greeting/src
cd greeting-tentacles
git init -b main

Create these files:

greeting-tentacles/
  repository.toml
  catalog.toml
  go.mod
  .gitignore
  greeting/
    tentacle.toml
    README.md
    LICENSE
    src/main.go

Use this go.mod:

module example.org/greeting-tentacles

go 1.24.0

require git.stormux.org/storm/cthulhu-go v0.0.0

replace git.stormux.org/storm/cthulhu-go => ../cthulhu-go

The SDK import path names its source project; it does not constrain where you host your own repository or downloads. Record the tested reader/SDK revision in release notes, since this local replacement does not pin it. Add /dist/ and /greeting/bin/ to .gitignore.

Give greeting/README.md a description, shortcut, requirements and test procedure. Put the full license text in greeting/LICENSE; choose terms you have permission to distribute. For an example derived from Hello World, preserve its notices and GPL-3.0-or-later license. Include source corresponding to your executable.

Create repository.toml:

format-version = 1
id = "example.greeting-tentacles"
name = "Greeting Tentacles"
description = "A small example Tentacle repository."

Create the initial catalog.toml:

format-version = 1

[[tentacles]]
id = "greeting"
manifest = "greeting/tentacle.toml"

Manifests belong in direct top-level folders. Repository and Tentacle IDs start with a lowercase letter and contain only lowercase letters, digits, dots and hyphens, up to 128 characters. Keep IDs stable: the reader uses the source URL, repository ID and Tentacle ID to identify an installation. A catalog can list several Tentacles, each with its own manifest and releases. Entries without releases can be discovered, but cannot yet be installed.

2. Describe the package and permissions

Create greeting/tentacle.toml, replacing the example source URL with your own HTTPS Git URL before publication:

format-version = 1
id = "greeting"
name = "Greeting"
description = "Speak and braille a short greeting."
version = "0.1.0"
authors = ["Contributor"]
license = "GPL-3.0-or-later"
source = "https://example.org/projects/greeting-tentacles.git"
help = "README.md"
runtime = "native"
platforms = ["linux"]
entry-point = ["bin/greeting"]
apis = ["commands", "presentation"]
capabilities = ["presentation"]

[protocol]
major = 1
minor = 0

Paths refer to the archive's root, not the source repository's root. The entry point is an executable followed by optional literal arguments, not a shell command. Presentation access allows speech and Braille results through the reader. A command-only package uses apis = ["commands"] and capabilities = [], without requesting presentation in command registration. Other package API or capability combinations are currently unsupported.

3. Implement a command

Create greeting/src/main.go:

package main

import (
    "context"
    "encoding/json"
    "os"

    "git.stormux.org/storm/cthulhu-go/sdk/go/tentacle"
)

func say_greeting(ctx context.Context, _ json.RawMessage) (any, error) {
    if err := ctx.Err(); err != nil {
        return nil, err
    }
    return tentacle.Presentation{
        Speech: "Hello from Greeting!",
        Braille: "Hello from Greeting!",
    }, nil
}

func main() {
    command := tentacle.Command{
        ID: "greet", Title: "Greeting",
        Description: "Speak and braille a greeting", Presentation: true,
        Bindings: []tentacle.Binding{
            {Layout: "desktop", Scope: "global", Key: "Cthulhu+Ctrl+Alt+F10"},
            {Layout: "laptop", Scope: "global", Key: "Cthulhu+Ctrl+Alt+F10"},
        },
        Handle: say_greeting,
    }
    if tentacle.Serve(os.Stdin, os.Stdout, []tentacle.Command{command}) != nil {
        os.Exit(1)
    }
}

The SDK handles the JSON-RPC session and registration. Stdout belongs exclusively to that protocol; send limited diagnostics to stderr. Respect the supplied context when doing work, including network requests. The reader owns input, speech, Braille, user settings and lifecycle safeguards. Use its public SDK instead of reader internals or output backends. Core and user bindings take precedence over suggested shortcuts; users can remap Tentacle commands.

Greeting uses ordinary interruptible presentation. Hello World demonstrates Uninterruptible: true; use that deliberately, rather than for every message. See its output behavior for cancellation, the 30-second protection bound and speech backend limitations.

4. Build and test before packaging

From greeting-tentacles:

gofmt -w greeting/src/main.go
mkdir -p greeting/bin
CGO_ENABLED=0 GOCACHE=/tmp/cthulhu-go-cache go build -buildvcs=false -mod=readonly -trimpath -o greeting/bin/greeting ./greeting/src
GOCACHE=/tmp/cthulhu-go-cache go test ./...

Invoke the compiled command through the development host. From cthulhu-go:

GOCACHE=/tmp/cthulhu-go-cache go run ./cmd/tentacle-host -presentation -command greet "$PWD/../greeting-tentacles/greeting/bin/greeting"

Expect JSON containing speech and braille, both Hello from Greeting!. This runs the executable through the actual command host, but produces no speech or Braille. The harness's default mode has no resource containment; use it only with development code you trust. Protocol tests do not establish live behavior.

For a live test, follow Hello World's development launch procedure, substituting your absolute executable path and launch ID greeting, with Presentation: true in the launch JSON. --replace --tentacles replaces the current Go reader and selects the development list instead of the saved registry; run it explicitly when ready. Rebuild the reader first if its implementation changed. Production activation requires delegated cgroup resources and does not silently fall back when delegation fails.

Test the shortcut, learn mode, remapping, ordinary reading and web navigation on Xorg. Verify speech modes, interruption, screen lock, terminal handoff, disable and connected Braille where affected. See CONTRIBUTING.md for review and regression requirements; contributors remain responsible for reviewing and testing AI-assisted changes.

5. Create architecture-specific archives

The make build, make check and tools/package.py commands in this repository build/check Hello World and Wormhole. tools/package.py --tentacle wormhole packages Wormhole; the default still packages Hello World. The checker pins the current versions and expected Tentacles. Adapt those tools and checks when extending this repository, or use this standalone procedure for Greeting.

From greeting-tentacles, stage the root manifest, documentation and license:

mkdir -p dist/greeting-package/bin
cp greeting/tentacle.toml greeting/README.md greeting/LICENSE dist/greeting-package/

Run the following in Bash for version 0.1.0. Change the version together with the manifest on later releases. set -euo pipefail stops on build/archive failures.

set -euo pipefail
version=0.1.0
for architecture in amd64 arm64; do
    CGO_ENABLED=0 GOOS=linux GOARCH="$architecture" GOCACHE=/tmp/cthulhu-go-cache \
        go build -buildvcs=false -mod=readonly -trimpath -ldflags='-s -w' \
        -o dist/greeting-package/bin/greeting ./greeting/src
    tar --sort=name --mtime=@0 --owner=0 --group=0 --numeric-owner \
        -C dist/greeting-package -cf - tentacle.toml README.md LICENSE bin \
        | gzip -n > "dist/greeting-$version-linux-$architecture.tar.gz"
done
sha256sum "dist/greeting-$version-linux-amd64.tar.gz" \
    "dist/greeting-$version-linux-arm64.tar.gz" \
    | sed 's@  dist/@  @' > dist/SHA256SUMS

Each archive must have this layout, without an enclosing greeting/ folder:

tentacle.toml
README.md
LICENSE
bin/greeting

The executable must be a regular, executable Linux ELF file for the advertised architecture. Static Go builds avoid undeclared shared-library dependencies. The reader rejects unsafe paths, symbolic/hard links and special files. Current limits are 32 MiB per compressed download, 64 MiB expanded file data and 1,024 archive entries. Installation runs no install scripts or source builds. Package ID, name, version and capabilities must match the repository manifest.

Inspect each archive with tar -tzf; from dist, run sha256sum -c SHA256SUMS. Run each extracted executable through the host on its matching architecture; a cross-build alone is not an execution test. The staging executable above ends with the last architecture built, so use the appropriate extracted archive for your local test. Keep the exact archives for publication. Normalized tar/gzip metadata supports repeatable packaging; compare hashes when rebuilding with the same source and toolchain.

6. Publish downloads, then advertise them

Review the source diff and tests before committing. Push reviewed source to your chosen Git host. For later versions, use a release branch while preparing assets so the default branch's existing manifest and catalog remain consistent. Create a release/tag such as greeting-v0.1.0 targeting that source commit. If using a separate download server, record that source revision alongside the files. Upload both .tar.gz files and SHA256SUMS, and make the release public when the assets are ready. Keep dist/ and executables out of Git.

Use stable direct HTTPS download URLs. Release attachments are convenient but optional; an ordinary HTTPS file server works too. URLs cannot embed credentials or fragments, and redirects must remain HTTPS. The reader has no authenticated private-download workflow; expiring signed URLs are unsuitable for a durable catalog.

Download the published files again and check sha256sum -c SHA256SUMS against those downloads. Check the archive manifest and executable. Only then append these tables after Greeting's entry in catalog.toml:

[[tentacles.releases]]
platform = "linux"
architecture = "amd64"
url = "https://downloads.example.org/greeting/0.1.0/greeting-0.1.0-linux-amd64.tar.gz"
sha256 = "REPLACE_WITH_THE_AMD64_ARCHIVE_SHA256"

[[tentacles.releases]]
platform = "linux"
architecture = "arm64"
url = "https://downloads.example.org/greeting/0.1.0/greeting-0.1.0-linux-arm64.tar.gz"
sha256 = "REPLACE_WITH_THE_ARM64_ARCHIVE_SHA256"

Replace the URLs and placeholders with published URLs and their actual 64-character lowercase hexadecimal hashes. These tables belong to the preceding [[tentacles]]; each platform/architecture pair may appear once. Keep the manifest version equal to the version inside the packages. Include only architectures you actually publish. For several Tentacles, preserve the existing entries: this repository's generated dist/catalog.toml preserves catalog entries and prepares release metadata for the selected Tentacles. Review it before publication.

Review and push the matching catalog and manifest together to the repository's default branch, which discovery fetches. Never replace a release file with changed content: increase the version, create new archives and URLs, then publish a new catalog revision. Refresh updates available metadata, not installed packages. To test a newer version with the current reader, remove that managed Tentacle and install it again after refreshing the source.

7. Verify the published installation

Open global Preferences → Tentacles → Add repository in the matching reader and enter your HTTPS Git URL, or refresh an existing source. Select Greeting and press Space. Check source, version and presentation access in the first-use dialog, then choose Install and enable. Confirm status becomes Active and test Cthulhu+Ctrl+Alt+F10 and the live checks from step 4.

Also check Install without enabling, enable/disable, offline reader restart and removal. Disabled packages retain their files; installed packages launch offline. Removing a source retains installed packages; removing a managed Tentacle stops it and deletes its package files. Keep ordinary reader commands, keyboard navigation and speech/Braille preferences working.

For no compatible release, check architecture and refresh the source. For download/checksum errors, verify the exact public URL and digest. For package metadata errors, compare the archive manifest with the repository manifest. For activation failures, check the reader log for protocol, executable or cgroup errors. Resource limits constrain consumption; they do not sandbox access to account files or network. Install publishers you trust and state any remaining unverified live behavior in release notes.

S
Description
No description provided
Readme GPL-3.0
2.8 MiB
0 Stars 1 Watchers 0 Forks
Languages
Go 71.6%
Python 27.6%
Makefile 0.8%