# Proposal: an `info:` URI for client-local OSC 8 content

Status: draft for discussion with Mudlet and other MUD client implementers  
Author: Sammer from PetriaMud  
Date: 2026-09-01  
Copyright (c) 2026 Sammer for PetriaMud. All rights reserved.

## Summary

OSC 8 extensions can attach tooltips, styles, spoilers, visibility rules and
selection state to text. Today, a server must also provide an actionable URI
such as `send:`, `prompt:` or HTTP even when the content is intentionally
local to the client. This proposal adds an `info:` URI whose only purpose is to
host client-local presentation and interaction. Activating it may change local
state, but must never send text to the game, modify the input line or open an
external resource.

The proposal is built around one boundary:

```text
send:  = the MUD must receive an action
info:  = the base interaction ends entirely in the client
```

This distinction concerns transport, not appearance. An `info:` item may use
the same colors, states and interactive presentation as a `send:` item. The
difference is that activating the `info:` item itself has no server-visible
effect. A menu entry nested in its configuration remains a separate URI and
follows that entry's own scheme.

Interactive companion:
[English OSC 8 `info:` simulator](osc8_info_extension_simulator_en.html).
It contrasts `send:` with `info:` and demonstrates local spoilers, visibility,
radio color selection and checkboxes across capability profiles.

Example:

```text
ESC ] 8 ;; info:?config={"tooltip":"Requires a silver key"} ESC \
sealed door
ESC ] 8 ;; ESC \
```

## Motivation

The distinction is useful to builders and generators:

- `send:` means “execute this game command”.
- `prompt:` means “place this text in the editable input”.
- HTTP(S)/FTP means “navigate to an external resource”.
- `info:` means “present local context; there is no navigation target”.

Without that distinction, authors either invent a harmless command, expose an
empty command as clickable, or omit useful client-side features. An explicit
type also lets clients produce correct keyboard and screen-reader semantics
instead of announcing every styled annotation as a link.

## Relationship between `info:` and `selection`

`info:` and `selection` answer different questions and are not alternatives:

- The URI scheme defines what happens outside the rendered item. `send:` sends
  input, `prompt:` edits the input line, and `info:` does neither.
- The `selection` configuration defines local state: grouping, radio versus
  checkbox behavior, initial state and `style.selected` presentation.

They are independent dimensions. This proposal does not replace or modify the
existing `OSC_HYPERLINKS_SELECTION` contract.

| URI and configuration | Local behavior | Server-visible result |
|---|---|---|
| `info:` without `selection` | Tooltip, style, spoiler or visibility as configured | None |
| `info:` with `selection` | Radio/checkbox state changes locally | None; no `selected=` callback is sent |
| `send:` with `selection` | State changes locally | The base command is sent with `selected=true` or `selected=false` |
| `prompt:` with `selection` | State changes locally | The modified action is placed in the input line for review |

Consequently, a local color picker that the game does not need should use
`info:` plus `selection`. A vote or preference that the game must receive
should use `send:` plus `selection`. Both may look identical; their transport
semantics differ.

Examples:

```text
info:?config={"selection":{"group":"color","value":"red"}}
send:react?type=like&config={"selection":{"group":"post","value":"like"}}
```

Activating the first URI only updates client state. Activating the second URI
selects it locally and sends the equivalent of:

```text
react?type=like&selected=true
```

Capability checks remain independent as well. `info:` plus selection requires
both `OSC_HYPERLINKS_INFO=1` and `OSC_HYPERLINKS_SELECTION=1`. `send:` plus
selection requires `OSC_HYPERLINKS_SEND=1` and
`OSC_HYPERLINKS_SELECTION=1`; it does not require `OSC_HYPERLINKS_INFO`.

## Proposed contract

The scheme is the exact ASCII string `info:`. Its payload is empty in version
1; reserved query parameters follow the existing Mudlet OSC 8 extension rules:

```text
info:?preset=<name>&config=<JSON object>
```

Clients MUST NOT execute, prompt or externally open any part of an `info:` URI.
Local interaction such as spoiler reveal, visibility changes or selection is
permitted and does not make the URI actionable at the protocol transport
level.
Unknown query parameters MAY be retained for forward compatibility but MUST
NOT become commands. Existing limits for OSC 8 command length, configuration
size, nesting and menu entries continue to apply.

The configuration remains capability-gated. In particular, accepting `info:`
does not imply support for style, tooltip, visibility, spoiler or selection.

## Capability negotiation

Servers request this NEW-ENVIRON `USERVAR` alongside the current Mudlet OSC 8
variables:

```text
OSC_HYPERLINKS_INFO
```

A client returns `1` only when it recognizes `info:` and guarantees that it is
client-local. `0`, omission and unknown values mean unsupported. The variable
can be updated with NEW-ENVIRON `INFO` during a session. Servers must not infer
it from `OSC_HYPERLINKS=1` or from a client version.

## Interaction and accessibility

Presentation must be derived from behavior, not from the blue/underlined visual
convention of a hyperlink:

- Tooltip or style only: static text, optionally exposed as a note or accessible
  description. It should not be announced as a link and should not add a Tab
  stop.
- Spoiler or click-driven visibility: button semantics, keyboard activation
  with Enter/Space, and an expanded/hidden state.
- Exclusive selection: radio semantics with checked state.
- Non-exclusive selection: checkbox semantics with checked state.
- Disabled local interaction: disabled semantics and no activation.

The visible text must remain understandable when OSC 8 is ignored. Tooltips
must supplement rather than replace it. Clients should avoid repeatedly
announcing the same logical item when ANSI styling divides its visible text
into multiple rendering spans.

## Backward-compatible server behavior

A server can safely support older Mudlet versions as follows:

1. Emit native `info:` only after `OSC_HYPERLINKS_INFO=1`.
2. For a client that supports `send:`, `disabled` and every requested config
   feature, emit `send:?config=<config plus disabled=true>`.
3. Otherwise emit only the visible text.

The disabled fallback represents passive tooltip/style/spoiler presentation
without sending an empty command. It cannot reproduce every local interaction;
selection and click-driven visibility should remain native-`info` features or
use a genuine, safe `send:`/`prompt:` action when that behavior is required on
older clients.

Clients may temporarily recognize Petria's historical empty-base form
`?config=...`, but new producers should use explicit `info:` and negotiation.

## Security considerations

- `info:` is never a transport for commands or external URLs.
- Menu actions inside its config retain their own scheme allowlist and
  capability checks; supporting `info:` must not bypass them.
- Reserved parameter names are the exact raw lowercase names `config` and
  `preset`.
- Parsers should delimit raw or percent-encoded JSON structurally so an `&`
  inside a JSON string is not mistaken for a query separator.
- Unsupported or malformed configuration should degrade to visible text, not
  to an actionable empty link.

## Suggested conformance cases

1. Passive tooltip: no command, no external navigation and no Tab stop.
2. Styled text: normal, hover and focus states without changing the payload.
3. Spoiler: first activation reveals locally; no network output.
4. Radio and checkbox selection: state changes locally with accessible checked
   state; no network output.
5. Visibility reveal/conceal and expiry on input, prompt or output.
6. ANSI style changes inside one OSC 8 open/close pair: all fragments behave as
   one logical item.
7. Malformed JSON, unsupported capability and overlong OSC sequence: readable
   plain text remains.
8. Screen reader review: passive information is not announced as clickable;
   interactive local controls expose their actual role and state.

## Adoption request

We invite Mudlet, LociTerm, web clients and other MUD client authors to review
the scheme name, NEW-ENVIRON variable and accessibility mapping, then implement
the conformance cases above. The essential interoperability guarantee is small:
`info:` is explicit, capability-negotiated and can never perform navigation or
send user input.
