Add Claude Artifact URL wrappers#20
Conversation
Reviewer's GuideAdds first-class support for URL-only macOS apps that wrap hosted Claude Artifacts, including new URL run templates, config parsing for external URLs, runtime tooling updates, tests, and documentation explaining the security boundary and behavior for these wrappers. Sequence diagram for URL-only Claude Artifact app launchsequenceDiagram
actor User
participant AppBundle as macOS_App
participant RunScript as run-template-url.sh
participant Wrapper as wrapper.swift
participant Claude as claude.ai_artifact
User->>AppBundle: Double-click .app
AppBundle->>RunScript: Launch Contents/MacOS/run
RunScript->>RunScript: Validate APP_URL is http(s)
RunScript->>Wrapper: exec wrapper APP_URL APP_NAME "" "" POLYFILL_PATH allow-external-hosts
Wrapper->>Claude: Load APP_URL in WKWebView
Claude-->>Wrapper: Auth redirect / artifact UI
Wrapper-->>Claude: allowExternalHosts keeps in-app navigation in-window
User->>Claude: Sign into Claude
Claude-->>User: Artifact runs inside native app window
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In the new URL-only launchers (
run-template-url.shandrun-template-url-chrome.sh), the interpolated$APP_NAMEand$APP_URLare passed directly intoosascriptalert strings; consider escaping quotes/newlines or using a here-doc AppleScript body to avoid malformed dialogs or potential injection if names/URLs contain unexpected characters. - For configs that accidentally specify both a local server (
port/start_command/backend_*) and anexternal_url/artifact_url, the build and doctor flows silently prefer the URL-only path; it may be worth emitting an explicit warning indesktop-build.shordesktop-doctor.shwhen both modes are configured to make this precedence clear to users.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the new URL-only launchers (`run-template-url.sh` and `run-template-url-chrome.sh`), the interpolated `$APP_NAME` and `$APP_URL` are passed directly into `osascript` alert strings; consider escaping quotes/newlines or using a here-doc AppleScript body to avoid malformed dialogs or potential injection if names/URLs contain unexpected characters.
- For configs that accidentally specify both a local server (`port`/`start_command`/`backend_*`) and an `external_url`/`artifact_url`, the build and doctor flows silently prefer the URL-only path; it may be worth emitting an explicit warning in `desktop-build.sh` or `desktop-doctor.sh` when both modes are configured to make this precedence clear to users.
## Individual Comments
### Comment 1
<location path="plugins/app-it/skills/app-it/templates/inspect.sh" line_range="112-121" />
<code_context>
+if command -v rg >/dev/null 2>&1; then
</code_context>
<issue_to_address>
**suggestion:** Reduce duplication and brittle quoting in Artifact detection regexes
The `rg` and `grep` branches currently duplicate the same two regexes with slightly different quoting, which risks them drifting out of sync and makes the nested quoting brittle. Consider defining the patterns once (e.g., `ARTIFACT_URL_PATTERN`, `ARTIFACT_API_PATTERN`) and reusing them in both branches, or switching to double-quoted strings with explicit backslash escaping to simplify the character class and improve maintainability.
Suggested implementation:
```
print_section "Claude Artifact signals"
ARTIFACT_URL_PATTERN="https://claude\.ai/[^ )\"'>]+"
ARTIFACT_API_PATTERN="window\.claude|window\.storage|claude\.complete|claude\.request"
if command -v rg >/dev/null 2>&1; then
```
```
ARTIFACT_URLS="$(rg --no-heading -n -E "$ARTIFACT_URL_PATTERN" \
```
```
ARTIFACT_API="$(rg --no-heading -n -E "$ARTIFACT_API_PATTERN" \
```
```
ARTIFACT_URLS="$(grep -RnE "$ARTIFACT_URL_PATTERN" . \
```
To fully remove duplication and brittle quoting, you should also:
1. Update any corresponding `grep`-based search for the artifact API signals (likely near the shown `ARTIFACT_URLS` grep) to use `"$ARTIFACT_API_PATTERN"` instead of an inlined regex.
2. Ensure any other occurrences of the same patterns elsewhere in the script are replaced with these two variables so that the regexes are defined in only one place.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
Addressed the review feedback in
Validation: |
|
Resolved the upstream conflicts by rebasing the Claude Artifact URL support onto current Notes:
Validation: |
The merged URL-only launcher (#20) is provider-neutral in code, but the docs framed it Claude-first. Neutralize the identity-defining surfaces — README headline/positioning, SKILL.md description + title + the hosted-auth principle, and the COMPATIBILITY heading — to "any hosted web app", keeping a published Claude Artifact as the named concrete example (still the common case). No behavior change; the mechanism is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Merged — thank you, @SohamKela. This is your second solid contribution to app-it and it shows: the mechanism is clean, the security boundary (no shipped credentials, each user signs into their own account) is exactly right, and you'd already addressed every review note before I looked. Two things worth calling out: I verified it on real macOS hardware before merging. The Small follow-up in c6ab3cc. Your code is already provider-neutral ( You're credited in the README's Community nudge for the URL-only launcher. Appreciate the careful work. 🙏 |
Description
Adds Claude Artifact support through a URL-only app strategy. When a project config includes
external_url,artifact_url, orurl,app-itnow builds a macOS.appthat opens the hosted Claude Artifact URL directly in the native wrapper instead of starting a local dev server.This keeps Claude authentication, artifact runtime APIs, storage, and Claude API usage inside Claude’s hosted artifact environment. The generated app does not distribute API keys, cookies, copied sessions, or shared authentication. Each person who receives the
.applaunches it, signs into Claude with their own account, and uses their own Claude subscription/plan.Raw JSX/TSX artifact source is still treated as ordinary local web app source only when it does not depend on Claude-hosted runtime APIs such as
window.claude,window.storage, MCP prompts, or Claude-provided auth. If it does depend on those APIs, the supported path is to publish/share the artifact in Claude and wrap that hosted URL.Acceptance Criteria Coverage
.apppackages can be created from existing Claude Artifacts by configuring a published/shared Claude Artifact URL viaartifact_url,external_url, orurl..applaunches locally and loads the hosted artifact in-window..appbundles do not include shared secrets; recipients must sign into Claude and use their own plan.server.port, and are handled correctly bydesktop:doctoranddesktop:quit.Changes
external_url/artifact_url/urlparsing indesktop-build.shanddesktop-doctor.sh.allow-external-hostssupport to the Swift wrapper so Claude auth redirects, hosted iframes, and API bridge navigation stay inside the app window.inspect.shto detect Claude Artifact URLs and local source that references Claude Artifact runtime APIs.Validation
./scripts/validate.shNotes
This intentionally does not implement a local clone of Claude’s Artifact runtime. That would require credential/session/API shims and would not satisfy the requirement that every user consume the artifact through their own Claude plan.
Summary by Sourcery
Add support for building macOS URL-only app wrappers around hosted Claude Artifacts while preserving Claude-hosted auth and runtime behavior.
New Features:
Enhancements:
Documentation:
Tests: