Skip to content

connections: owner-configured app shortcuts on the Connect fold from a library of connection templates, with placeholders, visibility, QR codes and preset support - #27

Merged
FelineStateMachine merged 12 commits into
mainfrom
claude/nostr-connection-templates-4a1b09
Sep 5, 2026
Merged

connections: owner-configured app shortcuts on the Connect fold from a library of connection templates, with placeholders, visibility, QR codes and preset support#27
FelineStateMachine merged 12 commits into
mainfrom
claude/nostr-connection-templates-4a1b09

Conversation

@FelineStateMachine

@FelineStateMachine FelineStateMachine commented Sep 5, 2026

Copy link
Copy Markdown
Owner

What this changes

The Connect fold on a relay's page was a static sampling of nostr clients. It is now owner-configured, the way an "my apps" launcher is: a library of connection templates (connection-templates/NN-name.jsonc, one app shortcut each) feeds a quick-configuration tab, the owner picks which shortcuts show, in what order, and who sees each, and every shortcut can reveal a QR code for a phone.

A template writes its links once with placeholders the relay fills in for whoever is looking: {relay:url}, {relay:host}, {relay:web}, {relay:name}, {relay:domain}, {relay:npub}, {relay:nprofile}, {relay:naddr}, {owner:npub}, {owner:nprofile}, {user:npub}, {user:nprofile}, {input:<name>}, with an optional |enc suffix for query strings. So one good template works on any relay.

Each shortcut has a visibility: public, auth (anyone signed in), members, or owner. Visibility hides the shortcut and nothing else: who may read the events and files a shortcut leads to stays the relay's read rule, so a photo library shortcut can be the owner's alone while the notes feed is public, and on a relay anyone reads the files are still anyone's to fetch. A visitor sees the public shortcuts; signing in on the page sends a NIP-98 signature to GET /connect.json, which then answers with what that key may see and fills the {user:*} links with the viewer's own key.

The list travels with the configuration document as a top-level connections section (export, import, dry-run plan), so relay templates carry it too: the seed relay templates now set the shortcuts that match their rules, and a new Home template is the enriched one-click setup (members write, anyone reads, sites, files and Git on, with notes, blog, bookmarks, sites, repos and a photo library shortcut only the owner sees).

An input whose value lands in a URL path or a shell command names a pattern the owner's value must match; repos keeps its repository name to letters, digits, dot, dash and underscore, and setconnections refuses a value that does not match with the reason.

Screenshots

The Connect fold as the owner, on a relay with the Home template applied (desktop): the relay URL first, one Open per tile with a compact copy and QR control and More for the rest, and the doors, bridge and Git example folded under Connection details:

The Connect fold as the owner

The Connect tab in the owner's console: one compact row per shortcut (who sees it, Edit, move, remove), the row being edited open for its title and inputs, Save at the top lit while there is something unsaved, then the library:

The Connect tab

The fold at a phone width:

The Connect fold at a phone width

Connection template library, seed list

Template App Needs Starts as What it does
notes Jumble public everything posted on this relay as one feed
find-me Primal, or the viewer's own app via nostr: public the owner's profile with this relay attached, for feed apps
group Flotilla, or any group-aware app public the relay's NIP-29 group as a room, QR of the naddr
blog YakiHonne public the owner's long-form articles
repos GitWorkshop grasp public the relay's Git repositories, plus a clone command for the signed-in viewer's own repo (input: repository name, kept to [A-Za-z0-9._-])
sites nsyte sites public the owner's and the viewer's root site at https://<npub>.<domain>, and the nsyte publish command
bookmarks Listr, noStrudel auth the viewer's bookmarks and lists
photos bouquet files owner the owner's photo library on this relay's Blossom store; the read rule, not the shortcut, says who may fetch the files
files bouquet files members the relay's file store for members, with the Blossom and NIP-96 URLs
dm 0xchat public message the owner privately; the relay URL for the kind 10050 inbox list
marmot White Noise marmot public end-to-end encrypted group chat over this relay
relay-page Coracle public the relay's page: its feed and its people

URL patterns were verified against each app's source or the console's existing links; each file's comment says where. Where no verified deep link exists, the template hands over with a nostr: URI or the app's front page plus a copy link. No template carries a "Copy relay URL" link: the fold has one relay URL copy control at the top. The catalog is connection-templates/README.md.

Relay template changes

Template Shortcuts it now sets
default left alone (a rules reset, like the feature settings)
outbox notes, find-me, blog
inbox find-me, notes
chat group
media files (members), photos (owner)
search notes
articles blog, notes
dm dm
quiet none: an empty list
site sites, notes
marmot marmot
grasp repos, notes
marmot-members marmot (members)
home (new, 15-home.jsonc) notes, blog, bookmarks (auth), sites, repos, photos (owner-only shortcut), find-me, group; sites, files and grasp on; members write, anyone reads

Surface

  • src/connections.ts: the library's parser (also run by the build check), placeholder resolution, visibility, GET /connect.json.
  • connection-template.schema.json, served at the apex like the relay-config schema; relay-config.schema.json gains connections.
  • NIP-86: listconnectiontemplates, listconnections, setconnections; listpresets carries a preset's shortcuts.
  • scripts/build/build-connections.mjs folds the folder into src/gen/connections.ts; scripts/check/check-connections.mjs checks every file against the schema and the relay's parser; both run in npm run typecheck, and a file without a README row fails the build.
  • Console: the fold puts the relay URL and the app tiles first (two columns on desktop), each tile with one primary Open, a compact copy and QR control and a More disclosure for its other links, and folds the Blossom, names and bridge doors and the Git clone example under Connection details; URL and command fields scroll on one line with a fixed copy button. A tenth tab, Connect, between Identity and Data: a compact row per shortcut with Edit opening one row's title and inputs, and Save at the top of the list, lit while the list is dirty.
  • npm run dev:shot gains --nostr (sign in as the dev key) and --eval (run a snippet before the shot); the screenshots above come from it.
  • Docs: new docs/17-connection-templates.md (developer), plus the Connect sections in 00, 01, 04, 12, 13, 14, README and STYLE.

Tests

  • test/unit/connections.test.ts: fill, parseConnectionTemplate, parseConnections, the library's invariants.
  • test/object/connections.test.ts: the door for a visitor, a signed viewer, an unclaimed relay; visibility per key; owner overrides and inputs; feature gating; {user:*} handling; defaults, empty list and order; setconnections refusals, roles and the moderation log; configuration round trip with plan summaries; presets.
  • test/object/exposure.test.ts walks /connect.json as a stranger and a signed-in non-member, with a members-only and an owner-only shortcut in the fixture.

npm run typecheck passes (tsc, the generated-file staleness checks for the signer, console, templates and connections, the console start check, the celld check, every connection template against the schema and the relay's parser, every relay template) and npm test passes: 62 files, 350 tests, on the branch rebased onto main (which brought the Git capacity work and ntig 0.6.0).

@FelineStateMachine FelineStateMachine left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed this head locally: typecheck and all 329 existing tests pass. The two inline findings below were reproduced separately. The branch also currently conflicts with main.

Comment thread relay-templates/15-home.jsonc Outdated
"format": "bind.ws/relay-config/2",
"template": {
"title": "Home",
"about": "Your relay as your home on nostr. Members write, anyone reads; sites, files and Git hosting on, with notes, blog, bookmarks, sites, repos and a private photo library as shortcuts."

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] The Home preset advertises private photos while enabling public media reads

This description promises a "private photo library", but the preset sets reads: "open". I reproduced applying Home, uploading an owner file, and successfully listing it through unsigned GET /list/<owner-pubkey> and downloading its contents without authentication. visibility: "owner" only hides the shortcut in /connect.json; it does not protect the underlying library. Please describe this as an owner-only shortcut to public media, or implement actual media privacy before presenting it as a private photo library.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded rather than reimplemented, in 7f882ba and 8d55310: the Home template, the photos template, the docs and the PR description now say the photo library is a shortcut only the owner sees, and that visibility hides the shortcut and nothing else, so who may fetch the files stays the relay's read rule (members reads closes the store). Media privacy per owner is a real feature and out of this PR's scope; the wording no longer promises it.

Comment thread connection-templates/05-repos.jsonc Outdated
],
"links": [
{ "label": "Open", "href": "https://gitworkshop.dev/relay/{relay:host|enc}" },
{ "label": "Copy clone command", "copy": "git clone '{relay:web}/{user:npub}/{input:repo}.git'" },

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Encode and quote the repository name before building a shell command

parseConnections accepts repository input such as kid's-project, then this template interpolates it directly inside single quotes. The resulting git clone 'https://.../kid's-project.git' fails shell syntax validation. Other accepted characters can change the URL path or introduce additional shell syntax when the copied command is pasted. Build the canonical encoded repository path and apply shell-safe quoting to the resulting URL, rather than inserting the raw input into a quoted command.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8d55310. An input may now name a pattern its value must match (schema, parser, docs), and the repos template keeps the repository name to ^[A-Za-z0-9][A-Za-z0-9._\-]{0,63}$, which cannot carry a quote, a slash or whitespace into the quoted command or the URL path. parseConnections refuses a value outside the pattern, so setconnections answers 400 with connections[i].inputs.repo: must match ... and a configuration import drops the entry with the same warning; the console's input carries the pattern as well. Covered in the unit and object tests.

@FelineStateMachine

Copy link
Copy Markdown
Owner Author

UI suggestions from the three screenshots (non-blocking):

The owner editor and mobile Connect view use a lot of vertical space. The current colors, icons and bold outlines can stay while the layout becomes more compact.

  • Put app shortcuts first. On the phone screenshot, four endpoint cards and the Git instructions push the first app far down the page. Show the apps immediately under Connect. Put endpoints, HTTP bridge details and the generic Git example in a collapsed "Connection details" section beneath them.
  • Make the owner editor a compact list. Each shortcut currently repeats a heading, two labels and wide fields inside a separate large card. Use a row with icon/name, visibility, Edit and reorder/remove controls. Expand title overrides and template-specific inputs only for the item being edited. Keep a Save action visible while the list is dirty; it is currently below all eight cards. Retain comfortable touch targets on mobile.
  • Shorten and align app actions. The Sites tile's many stacked actions determine the entire desktop row height, leaving large blank areas in Repos and Photo library. Give each app one clear primary Open action, with compact Copy and QR controls and a secondary menu or disclosure for alternate clients and commands. A two-column desktop list would also give descriptions and actions more horizontal room.
  • Deduplicate shared instructions. "Copy relay URL" appears on nearly every tile and the generic clone instructions repeat what Repos offers. Keep one prominent relay copy control, put app-specific instructions with their app, and trim descriptions to a useful single sentence. This should reduce both empty card space and repeated visual weight.

For URL/command fields, use a single-line scrollable value with a fixed copy button so the phone view does not split ports and commands across several lines.

…s/ feeds the Connect fold; a template writes its links once with {relay:*}, {owner:*}, {user:*} and {input:*} placeholders the relay fills in at GET /connect.json for whoever asks, each shortcut has a visibility (public, auth, members, owner), and the owner's list is the connections section of the configuration document, so presets carry shortcuts too
…son as tiles with a QR reveal, signed for whoever is signed in so their own links fill in, and a tenth tab, Connect, edits the list from the library with a title, who sees it, the template's inputs and the order
…rules, quiet names none, default leaves them alone like the features, and home is one name with sites, files and Git on and notes, blog, bookmarks, sites, repos, a private photo library, find-me and group one click away
…aimed relay as their visibility and the library say, setconnections refuses what does not fit and logs what it saved, the list travels with configurations and presets, and the exposure walk knocks on /connect.json
…uns a snippet before the shot with --eval, so the owner's console and an open fold are in the picture
… format, the placeholders, the owner's list and the door, and the user docs, the HTTP reference, the methods list, the README and STYLE say what the Connect fold and tab now do
… repo name keeps to letters, digits, dot, dash and underscore since it lands inside a quoted shell command and a URL path; no template carries the relay URL as a copy text, since the fold has one copy control of its own; photos says the read rule, not the shortcut, decides who sees the files
…er sees, since visibility hides the shortcut and nothing else and anyone reads a home relay, files included
… two to a row, each with one Open, a compact copy and QR control and More for the rest, folds the doors, the bridge and the Git example under Connection details, scrolls a URL or command on one line beside a fixed copy button, and the Connect tab is a compact row per shortcut with Edit opening one row's title and inputs and Save at the top lit while the list is dirty
…tconnections with the reason, an unclaimed relay drops a shortcut whose every link names the owner, and no default carries the relay URL as a copy text
… the shortcut and not what it leads to, an input may name a pattern, and the pictures are the reworked fold, tab and phone view
@FelineStateMachine
FelineStateMachine force-pushed the claude/nostr-connection-templates-4a1b09 branch from a13c1c9 to 8198734 Compare September 5, 2026 17:22
@FelineStateMachine

Copy link
Copy Markdown
Owner Author

Rebased onto main (the Git capacity work and ntig 0.6.0) and reworked the UI along the lines of the suggestions, in 7b7e2c1; the screenshots in the description are re-rendered from it.

  • Apps first. The fold opens with the relay URL and its copy button, then the tiles, two to a row on desktop. The Blossom, names and bridge doors and the generic Git clone example wait under a collapsed Connection details at the bottom.
  • Compact editor. One row per shortcut: icon and title, the app, the visibility selector, and Edit, up, down, remove. Edit opens that row alone for its title override and inputs. Save sits at the top of the list and lights up while the list is dirty, with an "Unsaved changes" note beside it. Touch targets stay at the 30px buttons the console uses elsewhere.
  • One action leads. Each tile has one primary Open (the template's first link), the first copy text as a compact copy button beside it, a QR icon button, and More for the template's other links and commands. Descriptions are one sentence.
  • Deduplicated. No template carries "Copy relay URL" any more; the relay copy control at the top of the fold is the one place for it. The generic clone example stays under Connection details for people without a signed-in key, since the Repos tile's clone command is made for the viewer.
  • Single-line values. URL and command fields scroll horizontally on one line with the copy button fixed at the right, so a port or a command no longer wraps on a phone.

…ow the list-history table, which had been added above it without one
@FelineStateMachine

Copy link
Copy Markdown
Owner Author

The Data tab's storage bar was flush against the list-history table (the block above it was added later without a margin); fixed in a75f178, the bar now keeps a block's distance.

@FelineStateMachine
FelineStateMachine merged commit 2e65331 into main Sep 5, 2026
1 check passed
@FelineStateMachine
FelineStateMachine deleted the claude/nostr-connection-templates-4a1b09 branch September 5, 2026 17:43
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