Web gateway for Sorcery Desktop that bridges HTTPS URLs to the local srcuri:// protocol handler.
Sorcery Server enables srcuri links to work in web contexts (Jira, Slack, Teams, web browsers) where custom protocols face limitations. It provides public-facing HTTPS endpoints that redirect to the local srcuri protocol handler.
The server operates on two subdomains with distinct purposes:
| Path Format | Purpose | User Action |
|---|---|---|
srcuri.com/<provider-url> |
Remote URL Translator | Prefix GitHub/GitLab/etc. URLs with https://srcuri.com/ |
srcuri.com/<workspace-path> |
Direct Protocol Gateway | Replace srcuri:// with https://srcuri.com/ for direct protocol links |
Prefix provider URLs with https://srcuri.com/:
Before: https://github.com/owner/repo/blob/main/src/lib.rs#L42
After: https://srcuri.com/github.com/owner/repo/blob/main/src/lib.rs#L42
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The path-based translator:
- Parses GitHub, GitLab, Bitbucket, Gitea, Codeberg, and Azure DevOps URLs
- Preserves line numbers from
#L42fragments (handled client-side) - Redirects to
srcuri://protocol to open in your editor
Replace srcuri:// with https://srcuri.com/:
Before: srcuri://myrepo/src/lib.rs:42?branch=main
After: https://srcuri.com/myrepo/src/lib.rs:42?branch=main
Supports all major Git hosting providers:
# GitHub
https://srcuri.com/github.com/owner/repo/blob/main/file.rs#L42
# GitLab
https://srcuri.com/gitlab.com/group/project/-/blob/master/file.py#L10
# Self-hosted GitLab
https://srcuri.com/gitlab.mycompany.com/team/app/-/blob/dev/main.go#L100
# Bitbucket
https://srcuri.com/bitbucket.org/workspace/repo/src/main/file.py#lines-5
# Gitea/Codeberg
https://srcuri.com/codeberg.org/user/repo/src/branch/main/file.go#L24
# Azure DevOps
https://srcuri.com/dev.azure.com/org/project/_git/repo?path=/src/file.ts&line=12
# Optional escape hatch (URL-encoded provider URL)
https://srcuri.com/?remote=https://github.com/owner/repo/blob/main/file.rs#L42For sharing direct srcuri links:
# Workspace-relative paths
https://srcuri.com/myrepo/src/lib.rs:42?branch=main&remote=https://github.com/owner/myrepo
# With remote for cloning
https://srcuri.com/myrepo/src/lib.rs:42?branch=main&remote=https://github.com/owner/myrepoEnterprise tenants get their own subdomain:
https://acme.srcuri.com/internal-tools/src/auth.rs:42
- Provider Passthrough (
srcuri.com/<provider-url>) - Convert GitHub/GitLab URLs to srcuri links - Direct Protocol Gateway (
srcuri.com) - 1:1 mapping from srcuri:// to https:// - Enterprise Subdomains - Multi-tenant support for organizations
- Line Number Preservation - Client-side JS preserves
#L42fragments - Link Unfurling - OpenGraph tags for Slack/Teams previews
- www Redirect -
www.srcuri.comredirects tosrcuri.com
- Rust 1.75+
- Cargo
cargo runThe server starts on http://localhost:3000.
Use the ?_subdomain= query parameter to simulate subdomains:
# Test enterprise tenant
curl "http://localhost:3000/myrepo/file.rs:42?_subdomain=acme"
# Test www redirect
curl "http://localhost:3000/?_subdomain=www"PORT- Server port (default: 3000)TENANTS_DIR- Directory containing tenant configs (default:sorcery-server/tenants)RUST_LOG- Logging level (default:sorcery_server=debug)
cargo test111 tests covering URL parsing, subdomain detection, and integration scenarios.
# Health check
curl http://localhost:3000/health
# Tenant config
curl http://localhost:3000/.well-known/srcuri.json
# Direct protocol mode (root)
curl http://localhost:3000/
# Provider passthrough
curl "http://localhost:3000/github.com/owner/repo/blob/main/file.rs"docker build -t sorcery-server .
docker run -p 8080:8080 -e PORT=8080 sorcery-serversrcuri.com → A/CNAME to server
*.srcuri.com → A/CNAME to server (enterprise subdomains)
Compatible with: Fly.io, Railway, AWS ECS, Google Cloud Run, or any Docker host.
Request with Host header
↓
Subdomain Detection
↓
┌─────────────────────────────────────────┐
│ www.srcuri.com → 301 to srcuri.com │
│ srcuri.com → Direct Protocol │
│ acme.srcuri.com → Enterprise Tenant │
└─────────────────────────────────────────┘
User shares: https://srcuri.com/github.com/owner/repo/blob/main/file.rs#L42
↓
Server returns: HTML page with JavaScript
↓
Browser JS reads: window.location (including #L42 fragment)
↓
JS parses: GitHub URL → extracts repo, branch, file, line
↓
JS builds: srcuri://repo/file.rs:42?branch=main&remote=https://github.com/owner/repo
↓
JS redirects: window.location.href = srcuri://...
↓
OS launches: Sorcery Desktop
↓
Editor opens: file.rs at line 42
User shares: https://srcuri.com/repo/src/lib.rs:42?branch=main
↓
Server returns: HTML with OpenGraph tags + JavaScript
↓
JS redirects: srcuri://repo/src/lib.rs:42?branch=main
↓
OS launches: Sorcery Desktop
URL fragments (#L42) are never sent to servers - this is standard browser behavior. The provider passthrough uses client-side JavaScript to read the fragment and include line numbers in the srcuri:// redirect.
This means:
- OG unfurling cannot include line numbers (Slack/Teams only see the server response)
- Line numbers work because JavaScript preserves them client-side
Create tenant config files in tenants/ directory:
{
"tenant_id": "acme",
"require_auth": false,
"allowed_paths": ["src/**", "lib/**"],
"fallback_viewer_url": "https://github.com/acme/repo/blob/main/{path}#L{line}"
}Subdomain mapping:
srcuri.com→tenants/default.jsonacme.srcuri.com→tenants/acme.json
- Fragment-based privacy: For
/openendpoint, file paths stay in browser - Client-side parsing: Sensitive data processed in JavaScript
- Local validation: srcuri client validates paths before opening
- CORS enabled: Allows cross-origin requests for embedding
- URL Design Rationale:
dev/srcuri-website-url-design.md - Translator Mode Spec:
dev/translator-mode.md - Server Spec:
dev/server-spec.md
github.com/sorcery-app/sorcery-server
AGPL-3.0 License