Skip to content

Hypernote interactivity: submit disable, button variants, checklists, response suppression#302

Merged
futurepaul merged 6 commits intomasterfrom
hypernote
Feb 26, 2026
Merged

Hypernote interactivity: submit disable, button variants, checklists, response suppression#302
futurepaul merged 6 commits intomasterfrom
hypernote

Conversation

@futurepaul
Copy link
Copy Markdown
Collaborator

@futurepaul futurepaul commented Feb 25, 2026

Hypernote: Project Overview (This Branch)

Hypernote is the branch’s answer to “generative UI” for Pika: an LLM can emit interactive UI as message content, and clients render/respond without a custom SPA runtime per feature.

The model is intentionally hypermedia-first:

  • UI is carried by messages, not by long-lived client-side app state.
  • Interactions are explicit response messages linked back to a target note.
  • The protocol surface is small and inspectable.

Why this exists

The goal is to let bots/agents ship useful UI on demand (forms, checklists, polls, confirmations) while keeping:

  • predictable transport semantics,
  • low Swift complexity,
  • shared behavior in Rust,
  • and straightforward bot ergonomics in OpenClaw.

Core protocol

Hypernote v1 is two message kinds:

  • 9467: Hypernote note (MDX + optional metadata tags).
  • 9468: Hypernote action response ({"action":"...","form":{...}}) with e tag pointing to the target note.

Important behavior:

  • 9468 is hidden from chat timeline UI.
  • Tallies/state are derived from 9468 in Rust.
  • Signed-action publishing has been removed from this branch to reduce complexity.

End-to-end architecture

  1. Bot/agent emits content (plain text or Hypernote block).
  2. OpenClaw channel routes fenced Hypernote blocks to send_hypernote.
  3. Sidecar/daemon publish 9467 with optional title/state tags.
  4. iOS renders Hypernote from parsed MDX/AST-backed data.
  5. User presses SubmitButton (or poll option).
  6. Client sends 9468 action response.
  7. Rust core processes responses (dedupe + declared-action validation + tallying).
  8. OpenClaw receives message_received with kind, so action responses can be handled explicitly.

This keeps the interaction loop message-native and avoids introducing a parallel imperative UI protocol.

Code ownership boundaries

  • hypernote-mdx: parsing/AST layer.
  • crates/hypernote-protocol: canonical protocol contract in Rust (kinds, component registry, action registry, catalog helpers, response helpers, poll builder).
  • Rust core (rust/): message semantics, response processing, unread/chat-list correctness.
  • SwiftUI (ios/): rendering and obvious local interaction state only.
  • OpenClaw plugin: inbound/outbound bot integration and routing.

A central theme of this branch is lowering ambiguous logic out of Swift and into shared Rust definitions.

Current v1 capabilities

  • Canonical component registry (layout, typography, interactive primitives) plus catalog design principles.
  • Canonical action registry (submit family via SubmitButton).
  • Daemon/CLI catalog query (hypernote_catalog, hypernote-catalog).
  • Optional default form state via Hypernote state tag.
  • Polls implemented as plain Hypernotes + actions (same protocol path, no special polling protocol).
  • OpenClaw support for outbound Hypernote fenced blocks:
    • pika-hypernote
    • hypernote
    • hnmd
  • Chat correctness fixes for hidden response kinds and Hypernote previews.

Bot interaction extensions (Waffle request)

To support richer bot participation in group UX (including bot-to-bot hypernote flows), this branch now includes:

  • New daemon command react:
    • { cmd: "react", nostr_group_id, event_id, emoji }
    • Publishes kind-7 reaction with e tag to target event.
  • New daemon command submit_hypernote_action:
    • { cmd: "submit_hypernote_action", nostr_group_id, event_id, action, form }
    • Publishes kind-9468 response with e tag to target hypernote event.
  • message_received now includes event_id (raw Nostr event id hex) in addition to legacy message_id, so bots can reliably target reactions/action submissions.
  • OpenClaw sidecar TS protocol and wrappers updated:
    • sendReaction(...)
    • submitHypernoteAction(...)
  • OpenClaw inbound context now propagates EventId, so agent/tool layers can act on exact target events.

This closes a key interoperability gap: bots can acknowledge with lightweight emoji reactions and can participate in hypernote interactions authored by users or other bots.

Simplicity / complexity posture in this branch

This branch intentionally trades breadth for clarity:

  • Keeps one explicit response path (9468).
  • Removes cryptographic signed-action path as premature complexity for v1.
  • Centralizes “what components/actions exist” in one Rust source of truth.
  • Reuses existing message/response primitives instead of inventing a separate stateful UI subsystem.

What’s mature vs. what’s still early

Mature enough for practical bot UI:

  • protocol shape,
  • catalog introspection,
  • poll/form submission loop,
  • OpenClaw interoperability,
  • core timeline/unread semantics,
  • bot-triggered reactions and hypernote action submissions.

Still early / expected follow-ups:

  • richer action families beyond submit,
  • more component primitives,
  • better authoring ergonomics (e.g., emoji handling and additional MDX affordances),
  • further consolidation of client-only behavior into shared Rust where appropriate.

Canonical spec

docs/hypernote-bot-guide.md is now the branch’s canonical v1 spec and prompt guidance source for bots.

futurepaul and others added 5 commits February 25, 2026 22:08
…sts, response suppression

- Replace formState with interactionState in HypernoteRenderer; disable all
  inputs/buttons after submit with "Response sent" confirmation
- Add SubmitButton variants (primary/secondary/danger) with post-submit
  visual feedback (checkmark on selected, fade on unselected)
- Add ChecklistItem JSX component with name/checked attributes bound to
  form state
- Add HYPERNOTE_ACTION_RESPONSE_KIND (kind 9468) so chat action responses
  are stored by MDK but hidden from the chat timeline
- Track kind in LocalOutgoing so local outbox also suppresses 9468 messages
- Add default_state support: "state" tag on hypernotes seeds interactionState
  on appear, wired through daemon SendHypernote and CLI --state flag
- Add defaultState param threading from Rust HypernoteData through Swift
- Update hypernote-bot-guide.md with ChecklistItem docs, button variants,
  response suppression, default state, and "one form per hypernote" guidance

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@futurepaul futurepaul marked this pull request as ready for review February 26, 2026 04:13
@futurepaul futurepaul merged commit 0248ac0 into master Feb 26, 2026
14 checks passed
@futurepaul futurepaul deleted the hypernote branch February 26, 2026 04:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant