deep-links

GitHub

ToolHive Studio深度链接实现指南,涵盖toolhive-gui://协议解析、路由导航及IPC通信机制,用于开发、调试或添加新的深度链接功能。

.codex/skills/deep-links/SKILL.md stacklok/toolhive-studio

Trigger Scenarios

实现深度链接功能 调试深度链接跳转问题 添加新的深度链接意图 理解深度链接架构

Install

npx skills add stacklok/toolhive-studio --skill deep-links -g -y
More Options

Non-standard path

npx skills add https://github.com/stacklok/toolhive-studio/tree/main/.codex/skills/deep-links -g -y

Use without installing

npx skills use stacklok/toolhive-studio@deep-links

指定 Agent (Claude Code)

npx skills add stacklok/toolhive-studio --skill deep-links -a claude-code -g -y

安装 repo 全部 skill

npx skills add stacklok/toolhive-studio --all -g -y

预览 repo 内 skill

npx skills add stacklok/toolhive-studio --list

SKILL.md

Frontmatter
{
    "name": "deep-links",
    "description": "Deep links in ToolHive Studio. Use when implementing, debugging, or asking about deep link features (toolhive-gui:\/\/ protocol), adding new deep link intents, understanding the deep link architecture, IPC model, or platform\/packaging support.",
    "allowed-tools": "Read, Grep, Glob, Bash"
}

Deep Links in ToolHive Studio

Deep links allow external systems (browsers, terminals, other apps) to trigger navigation inside ToolHive Desktop via the toolhive-gui:// custom protocol.

About this document: Much of the content in the reference docs is the result of research into how other Electron apps implement deep links. Some design decisions are implemented; others describe the intended direction but are not yet in the codebase. The base skill reflects the current implementation. The reference docs reflect the research and design intent — read them with that in mind, and update them when relevant implementation decisions change.


URL Schema

toolhive-gui://v1/<intent>[?<query>]

Examples:

  • toolhive-gui://v1/open-registry-server-detail?serverName=fetch — open a registry server detail page
  • toolhive-gui://v1/open-registry-server-install?serverName=fetch — open the registry server detail page and auto-open the install dialog
  • toolhive-gui://v1/open-registry-skill-detail?namespace=io.github.stacklok&skillName=skill-creator — open a registry skill detail page
  • toolhive-gui://v1/open-registry-skill-install?namespace=io.github.stacklok&skillName=skill-creator&version=v1.0.0 — open the skill detail page and auto-open the install dialog with the reference (and optional ?version tag) prefilled. Tag-only — OCI digests (sha256:…) are intentionally not supported because safeIdentifier rejects colons; users wanting digest pinning can paste it into the dialog directly.

The v1 segment is the version. The intent is a kebab-case action name. Query params carry intent-specific data.


Current Implementation

Key Files

File Role
common/deep-links.ts Single source of truth. All deep link definitions: intent name, Zod param schema, navigation target.
main/src/deep-links/parse.ts Parses and validates a raw URL string using the schemas from common/deep-links.ts.
main/src/deep-links/index.ts Entry point: extracts URL from argv (Windows/Linux), waits for window ready, dispatches via IPC.
main/src/deep-links/squirrel.ts Squirrel.Windows-specific protocol registration.

IPC Channel

deep-link-navigation — sent main → renderer as a NavigateTarget ({ to: string; params?: Record<string, string> }).

The renderer receives this and calls the TanStack Router navigate() directly.

How It Works (Current)

  1. Protocol registration: On app start, app.setAsDefaultProtocolClient('toolhive-gui') registers the protocol. On Windows with Squirrel, registerProtocolWithSquirrel() is called instead (see squirrel.ts).
  2. URL extraction: On Windows/Linux, the URL arrives in process.argv. extractDeepLinkFromArgs() scans for the first toolhive-gui:// argument (safe against argv injection — see patterns doc).
  3. Parse + validate: parseDeepLinkUrl() parses the URL and runs it through the Zod discriminated union schema defined in common/deep-links.ts. Invalid links resolve to showNotFound.
  4. Window ready: waitForMainWindowReady() polls until the window is visible and not loading before dispatching.
  5. Dispatch: resolveDeepLinkTarget() converts the validated intent to a NavigateTarget, which is sent to the renderer via the deep-link-navigation IPC channel.
  6. Renderer: The renderer listens for deep-link-navigation and calls navigate(target).

Current Limitations vs. Design Intent

The current implementation only supports read (navigate) operations. The design doc proposes a confirmation flow for write/destructive operations (C/U/D), but this is not yet implemented. The IPC sends a pre-resolved NavigateTarget rather than a raw parsed intent — this simplified the initial implementation. See design doc for the full intended model.


How to Add a New Deep Link

All changes happen in common/deep-links.ts:

// 1. Define the new intent using v1DeepLink()
export const myNewIntent = v1DeepLink({
  intent: 'my-new-intent', // kebab-case, matches URL path segment
  params: z.object({
    someParam: safeIdentifier, // use safeIdentifier for user-supplied strings
  }),
  navigate: (params) => ({
    to: '/some-route/$id', // TanStack Router route
    params: { id: params.someParam },
  }),
})

// 2. Add to allDeepLinks array
const allDeepLinks = [
  openRegistryServerDetail,
  showNotFound,
  myNewIntent,
] as const

// 3. Add to deepLinkSchema discriminated union
export const deepLinkSchema = z.discriminatedUnion('intent', [
  openRegistryServerDetail.schema,
  showNotFound.schema,
  myNewIntent.schema, // ← add here
])

Test manually:

./node_modules/.bin/electron . "toolhive-gui://v1/my-new-intent?someParam=value"

safeIdentifier is defined as z.string().regex(/^[a-zA-Z0-9_.-]+$/) — use it for any param that could be user-supplied to prevent injection.


Reference Documents

For deeper background, see:

  • OS & Packaging Support — Platform-specific registration requirements (Windows, Linux, macOS) and packaging format considerations (Squirrel, Flatpak, .deb, .rpm, .dmg, AppImage, MSIX, etc.). Largely research/prior art.
  • Observed Patterns — Patterns from VS Code, GitHub Desktop, Mattermost, Element, and others: URL sanitization, argv injection, security confirmations, waiting-for-readiness patterns, telemetry.
  • Design & Decisions — Full design rationale, IPC model, error handling strategy, queue management, testing approach, and the decisions log. Some sections describe planned future behaviour not yet implemented.

Version History

  • 12a6ab3 Current 2026-08-20 10:47

Same Skill Collection

.claude/skills/bug-fix-tdd/SKILL.md
.claude/skills/deep-links/SKILL.md
.claude/skills/security-vuln-remediation/SKILL.md
.claude/skills/skill-creator/SKILL.md
.claude/skills/skill-editor/SKILL.md
.claude/skills/testing-api-assertions/SKILL.md
.claude/skills/testing-api-overrides/SKILL.md
.claude/skills/testing-with-api-mocks/SKILL.md
.codex/skills/bug-fix-tdd/SKILL.md
.codex/skills/security-vuln-remediation/SKILL.md
.codex/skills/skill-creator/SKILL.md
.codex/skills/skill-editor/SKILL.md
.codex/skills/testing-api-assertions/SKILL.md
.codex/skills/testing-api-overrides/SKILL.md
.codex/skills/testing-with-api-mocks/SKILL.md
.cursor/skills/bug-fix-tdd/SKILL.md
.cursor/skills/deep-links/SKILL.md
.cursor/skills/security-vuln-remediation/SKILL.md
.cursor/skills/skill-creator/SKILL.md
.cursor/skills/skill-editor/SKILL.md
.cursor/skills/testing-api-assertions/SKILL.md
.cursor/skills/testing-api-overrides/SKILL.md
.cursor/skills/testing-with-api-mocks/SKILL.md

Metadata

Files
0
Version
9d42989
Hash
d728d7f4
Indexed
2026-08-20 10:47

inicio - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-17 05:18
浙ICP备14020137号-1