Updated documentation, will have to change again later.
This commit is contained in:
1 parent
785569abdd
commit
ba5876f57c
2 files changed
+352
-6
No files matched your search
@@ -7,11 +7,21 @@ Repository material and Hello World are licensed under GPL-3.0-or-later; see
|
||||
|
||||
`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 verified native packages for Linux amd64 and arm64. Prepared
|
||||
release artifacts live in `dist/`; they become downloadable only after publication.
|
||||
The catalog lists native packages for Linux amd64 and arm64. Hello World 0.1.0 is
|
||||
available from the [release page](https://git.stormux.org/storm/cthulhu-tentacles/releases/tag/hello-world-v0.1.0).
|
||||
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](#create-and-release-your-own-tentacle).
|
||||
|
||||
## Build and check
|
||||
|
||||
Keep the matching experimental `cthulhu-go` checkout beside this directory.
|
||||
@@ -86,6 +96,342 @@ 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 publication and an
|
||||
explicit reader restart. For source-only local testing, the development launch
|
||||
procedure remains in [Hello World](hello-world/README.md#local-launch).
|
||||
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](hello-world/README.md#local-launch).
|
||||
|
||||
## 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:
|
||||
|
||||
```sh
|
||||
mkdir -p greeting-tentacles/greeting/src
|
||||
cd greeting-tentacles
|
||||
git init -b main
|
||||
```
|
||||
|
||||
Create these files:
|
||||
|
||||
```text
|
||||
greeting-tentacles/
|
||||
repository.toml
|
||||
catalog.toml
|
||||
go.mod
|
||||
.gitignore
|
||||
greeting/
|
||||
tentacle.toml
|
||||
README.md
|
||||
LICENSE
|
||||
src/main.go
|
||||
```
|
||||
|
||||
Use this `go.mod`:
|
||||
|
||||
```go
|
||||
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`:
|
||||
|
||||
```toml
|
||||
format-version = 1
|
||||
id = "example.greeting-tentacles"
|
||||
name = "Greeting Tentacles"
|
||||
description = "A small example Tentacle repository."
|
||||
```
|
||||
|
||||
Create the initial `catalog.toml`:
|
||||
|
||||
```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:
|
||||
|
||||
```toml
|
||||
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`:
|
||||
|
||||
```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](hello-world/README.md) for cancellation, the 30-second
|
||||
protection bound and speech backend limitations.
|
||||
|
||||
### 4. Build and test before packaging
|
||||
|
||||
From `greeting-tentacles`:
|
||||
|
||||
```sh
|
||||
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`:
|
||||
|
||||
```sh
|
||||
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](hello-world/README.md#local-launch),
|
||||
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](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 currently target Hello World specifically. They do not automatically
|
||||
discover or package a new folder. Its checker also pins the current example
|
||||
version. 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:
|
||||
|
||||
```sh
|
||||
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.
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```text
|
||||
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`:
|
||||
|
||||
```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` lists only Hello World
|
||||
and must not overwrite a larger catalog.
|
||||
|
||||
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.
|
||||
Reference in new issue
Block a user