Files
cthulhu/docs/tentacle-remote-keyboard.md
Chase CichorzandClaude Opus 5.5 6867d901b2 Support Remote browser and media keys and connection history UI
Accept the eighteen browser, volume, media and launch identities in the input vocabulary and both SDKs. Exercise media-key capture on the private Xorg harness, and permit only the new remember-host checkbox in the connection form integration test.

Validated: affected-package race tests, Tentacles make check, private native_remote_input.py and native_remote_keys.py. Physical input, live peer interoperability, speech and Braille acceptance remain pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 21:17:01 -05:00

161 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Experimental Remote keyboard IPC prerequisite
The protocol 1.1 host recognizes `remote.key`, with public Go types and matching
Python validation. A bounded incoming-key mailbox is attached in production
for sessions installed with `keyboard-inject`, and the external Remote command
forwards controller keys when keyboard control is approved for the session.
See the production attachment section below; live acceptance is pending.
## Wire contract
One child-to-host request carries one logical transition:
```json
{"lease":"0123456789abcdef0123456789abcdef","epoch":1,"sequence":2,
"key":{"name":"Control_R","pressed":false}}
```
All fields are required, including boolean `pressed` on release. Field names
are exact; unknown fields, duplicate keys, nulls, missing values, nonboolean
press state and invalid numeric identities are rejected. Epoch and sequence
are positive uint64 values. Lease identifiers have the existing 32-byte bound;
only the actual token issued to this process can authorize work.
`name` identifies one canonical unshifted logical key. It is neither text to
type nor an X keycode, Windows VK/scan code, script path or command. The bounded
allowlist matches the external mapper's canonical subset:
- Lowercase Latin letter names, top-row digits, F1–F24 and KP_0–KP_9.
- Left/right Shift, Control, Alt and Super; Menu, lock keys, Pause and Print.
- Backspace, Tab, Return, Escape and Space; main navigation, Insert and Delete.
- Keypad Enter, navigation, Begin, Insert, Delete and arithmetic/separator keys.
- Eighteen browser, volume, media and launch keys (`XF86Back`, `XF86Forward`,
`XF86Reload`, `XF86Stop`, `XF86Search`, `XF86Favorites`, `XF86HomePage`,
`XF86AudioMute`, `XF86AudioLowerVolume`, `XF86AudioRaiseVolume`,
`XF86AudioNext`, `XF86AudioPrev`, `XF86AudioStop`, `XF86AudioPlay`,
`XF86Mail`, `XF86AudioMedia`, `XF86MyComputer`, `XF86Calculator`), matching
Windows VK 0xA6–0xB7. Other XF86 keys, such as power and eject, stay unsupported.
- The eleven explicit punctuation identities supported by the external US
profile. The owner must resolve the destination layout; this does not grant
permission to guess a matching physical key or change the global keymap.
Aliases such as `Prior`, uppercase text, shifted character names, AltGr,
dead/IME keys, arbitrary Unicode and unrecognized names remain unsupported.
For exact case/spelling, see `input.ValidRemoteKeyName` in
`internal/input/remote_key_names.go`, used by `ValidRemoteKey` in the wire/SDK
layer. No implicit modifier transitions, text
insertion or fallback commands are synthesized.
Go exposes `RemoteKey`, `RemoteKeyRequest`, `ValidRemoteKey` and
`ValidRemoteKeyRequest` through `sdk/go/tentacle`. Python exposes
`valid_remote_key` and `valid_remote_key_request` from
`cthulhu_tentacle.session`. They validate representation, not consent or native
availability. Generic `SessionClient.Call`/`call` still permits method-specific
host errors; callers may use the validators before submitting work. Older hosts
return unsupported-operation for this addition.
## Authorization and admission
The host requires the current process session's live controlled-role lease and
the separately approved `keyboard-inject` grant. Installation grants, observer
consent, controller role, relay membership and a child's claimed origin cannot
authorize injection. Parameters contain no local-origin or consent override.
`remote.key` shares the strictly increasing operation sequence with heartbeat,
close and other lease operations. An accepted key advances it without renewing
the heartbeat deadline. Replayed, foreign, expired or cancelled operations are
denied. Invalid parameters and missing-owner errors do not consume the lease
sequence or enqueue work.
`Session.EnableRemoteKeys` is a reader API, not a child RPC. It attaches one
256-item mailbox. Retained queued plus in-flight keys are bounded by 256 items
and 256 KiB of canonical encoded request bytes, including lease/sequence
metadata. Receiving a delivery does not return capacity. Its idempotent
`Release` returns capacity after delivery or discard, only to the original
lease. A release from a retired worker cannot alter replacement accounting.
The RPC result `{}` acknowledges mailbox admission only. It does not acknowledge
XTEST, application delivery or key recovery. Saturation revokes the lease and
drains pending work rather than dropping a key-up and continuing. Heartbeat,
revocation and shutdown do not wait for a native worker.
## Ownership and retirement
`RemoteKeyDelivery` retains the original lease, operation sequence, typed key
and cancellation context. A future input owner must check that context and
`Session.RemoteContext(lease, "keyboard-inject")` immediately before applying
each effect, alongside current focus, lock/handoff and native policy. Context
alone does not replace the deadline check. No native callback is invoked while
the host session mutex is held.
Revoke, explicit close, replacement, expiry, policy cancellation, disable and
session failure cancel accepted work and clear pending keys. Local policy
cancellation invalidates the delivery context synchronously, before asynchronous
notification/drain callbacks acquire the session lock. Restoring availability
never revives the original lease. A new explicit approval creates a new epoch.
The native owner must keep its own destination key ledger, resolve repeats and
lock state, reject physical/injected collisions and guarantee cleanup even if
the Tentacle, reader or network disappears. Cleanup must not depend on this
mailbox admitting a last up. The external outgoing encoder's transport write
acknowledgements and this API's mailbox admission are separate contracts;
neither establishes actual destination input completion.
## Verification and remaining gates
Strict representation tests compare Go and Python validators, including both
transitions, all letter/digit/function ranges, uint64 boundaries, missing/null
values, exact field names and rejected metadata. Real Go/Python SDK child
processes exercise owner-unavailable, admission, permission/role/process checks,
shared heartbeat ordering, replay, malformed requests, capacity retention,
concurrent idempotent release, overflow and retirement/replacement. The external
bridge verifies that every canonical mapper result satisfies the public SDK
contract. None of these tests injects a desktop key.
An unconnected [destination-key prerequisite](testing/remote-key-target.md) now
retains native codes through layout changes and uncertain effects, with a
quarantined Xorg resolver/backend. It is not attached to this mailbox and supplies
no physical collision guarantee. A subsequent [source-built helper](testing/remote-input-helper.md)
now supplies private process-lifetime/EOF/watchdog cleanup. A quarantined
reader-side Supervisor now launches it with serialized heartbeats and an
original-epoch cleanup/process-exit barrier; unconfirmed retirement blocks
replacement. The quarantined `app.run_remote_keyboard` worker now joins this
supervisor to the authenticated mailbox with a required policy callback; see
[its lifecycle and native evidence](testing/remote-input-helper.md#quarantined-leasemailbox-worker).
`start_remote_keyboard` is now its production caller; see below.
No capture event API, production Xorg input owner or supervised helper attachment,
core escape/bypass integration or installed Remote keyboard command is
provided. Physical-source approval, physical collision/recovery, audible speech,
Braille and real NVDA/Orca interoperability remain unverified. Private IPC and
relay checks close no live release gate.
This increment passed the full wire/host/both-SDK race suites (host: about
128 seconds), focused application Remote connection/speech race tests, the
existing speech regression harness, affected-package vet, a separate reader
build and Tentacles `make check`. The lifecycle regression now checks malformed
typed keys and keeps its unsupported-operation check on Braille. No full reader
suite or native/hardware acceptance was performed; no active reader was replaced.
## Production attachment (2026-11-06)
Local launch and managed-session startup now call `start_remote_keyboard`
for every session installed with `keyboard-inject`, next to the speech owner.
It attaches the mailbox before the child becomes active and runs the existing
lease/mailbox worker with one `remoteinput.Supervisor` retained for the reader
lifetime, so the uncertainty latch survives session replacement. The helper is
`cthulhu-input-helper` beside the reader executable; `build-cthulhu.sh` and both
Arch packages now build and install it. A missing helper or a session without
the grant leaves `remote.key` owner-unavailable and does not affect startup.
Delivery-time policy adds reader lock, XTerm-handoff suspension and active
internal reader UI to the worker's lease, grant and deadline checks; a denied
key revokes the original lease. A clean helper failure retires only that lease
and is announced; unconfirmed cleanup is announced as requiring a reader
restart. Real SDK-process tests cover delivery and lock-policy retirement,
handoff denial before helper launch, and the no-grant and missing-helper cases.
This makes injection reachable from an approved controlled session. It does not
add physical-collision safety, injection provenance, lock/AltGr policy or live
acceptance, which remain required before keyboard control is declared ready.