Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/saf/surface/03-usb-hands.md
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00

122 lines
5.8 KiB
Markdown

# USB Hands
The phone may become a keyboard and pointer for the host on its USB cable.
That reach has three states with three owners; collapsing them is what made the
first surface confusing.
## The wire, the surface, the hand
`UsbState.mode` says what sessiond and usb-signaller have made the port. HID or
KVM means the wire is armed. Developer or charging-only means it is not.
QuickShell never writes configfs and the page never opens `/dev/hidg*`.
`HidController.active` says the trackpad surface is open. It is not another
name for an armed port. Power Options is the human place that arms or disarms
the wire; a separate child action opens or closes the trackpad, and opening is
refused until HID or KVM is already armed.
`HidController.ready` says its one persistent `usb-hid-inject stream` helper
has acknowledged the endpoint. Pointer motion is batched to the display clock;
text, keys, clicks, and release reports go through that one writer.
These are deliberately different facts. A composed gadget with no open
surface is safe and useful. An open surface with no composed gadget is a dead
control and is refused. A helper process that has not said `ready` is not
dressed up as a usable hand.
The resulting state graph is small:
```
developer/charging -> no trackpad
HID or KVM armed -> trackpad may be opened
trackpad active -> dock yields; Face routes gestures and words
disarm or lock -> helper releases, trackpad closes
```
Arming the wire alone changes no shell furniture. The dock leaves only while
the conditional trackpad is actually on the glass.
## Authority and mechanism
The path has one owner at each layer:
- QuickShell asks sessiond for `set_usb_mode`; `UsbState` only projects the
answer and never writes the gadget.
- Sessiond records the USB mode action and asks usb-signaller to compose the
port. The supported postures are developer, HID, KVM, and charging-only.
- `HidController` alone owns the live stream helper. The Face page emits
intent into that controller; it never opens `/dev/hidg*` itself.
- The substrate's `body hand` verb returns to QuickShell's `usbHands` IPC. It
does not create a second HID writer merely because the caller is an agent.
The present route is not yet the final authority seam. `attached_identity`
and `probe_owner` are explicit unknowns, and a locally permitted caller can
still reach usb-signaller's system D-Bus mechanism around sessiond. Joining an
unlocked surface and arming it in Power Options are useful local gates, not a
credential or known-peer policy. The seam is complete only when the mutation
mechanism admits the attested/sessiond path alone and sessiond can distinguish
a known scoped peer from an unknown attachment. Charging-only remains the
always-available safe contraction.
Mode failure must return a refusal and leave or restore a usable USB posture.
It must not strand the management lane, a bound UDC, a held key, or a pointer
button. Closing Hands, disarming, and secure lock all release reports and stop
the helper; a mode switch stops the writer before usb-signaller changes the
endpoints beneath it.
## One conversation
Hands is a limb of the existing Face/Souveraine connection, not a compact
second chat client. Opening it resumes the current agent's latest conversation
only when no conversation is attached. Conversation selection and creation
belong to the agent pane, so the Hands header carries no mystery back-arrow or
new-thread button.
The joined surface currently exposes agent text/voice, trackpad, scroll,
left/right click, and a held Ctrl+Alt+Delete. It does not advertise a keyboard
pane merely because an HTML input can emit key reports. A real on-glass
keyboard needs its own QML surface and focus contract before it earns a button.
## The agent's reach
While Hands is joined, the ambient skill points at the substrate's typed
`body` tool: `verb: hand` with `status`, `type`, `key`, `click`, or `pointer`.
It does not teach a second raw `qs` command vocabulary.
A direct request to type ordinary user-authored text is authorization to type
that text, including creative, intimate, or unusual prose. Odd tone is not a
state refusal. The hand still sends nothing Casey did not ask to place on the
attached host, and readiness/state refusals remain visible to the agent.
## Beyond HID
HID can send input and cannot truthfully return a terminal's output. Learned
administration or tunnel payloads therefore belong to a separate, auditable
capability path: named/versioned recipes, an explicit scope and lease, and a
management transport that returns stdout, stderr, and exit status as typed
events. Do not infer success from keystrokes and do not turn an RMM or reverse
tunnel into an opaque keyboard macro.
The NCM control lane can carry that future return path. Its authority,
identity, rollback, and evidence contract must exist before a learned payload
is treated as a skill rather than an unaudited script.
## Proof boundary
Source agreement is only the first line of proof. USB Hands is operational on
a phone only when the signed usb-signaller package contains the persistent
stream helper, the installed Souveraine surface and face assets are the same
revision, and the following motion is observed on glass and on the attached
host:
1. Power Options arms HID while another management path remains reachable.
2. Opening the trackpad starts one helper and receives its `ready` reply.
3. Motion, scroll, left/right click, requested text, a named key, and held
Ctrl+Alt+Delete reach the host without a second writer.
4. A rejected character sends none of that command; leaving and locking leave
no held report.
5. Returning to developer mode restores the control lane cleanly.
KVM adds separate display, storage, NCM, and touch-return acceptance. A green
shell reload, a packaged binary, or the first successful keystroke proves only
its own layer; none of them silently stands in for that cable exercise.