feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add Server Redirect CEP draft - #47

Open
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect
Open

feat: add Server Redirect CEP draft#47
ContextVM-org wants to merge 4 commits into
masterfrom
cep-42-server-redirect

Conversation

@ContextVM-org

@ContextVM-orgContextVM-org commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

CEP-47: Server Redirect

Summary

Adds a draft Standards Track CEP defining a request redirection mechanism for ContextVM. A server can instruct a client to re-issue a request to a different address (a public key, with optional relay hints) by returning a JSON-RPC error response (-32044 "Redirect").

Motivation

There is currently no way for a ContextVM server to hand a client a different address mid-exchange. This blocks two common patterns, both reducible to "use this address instead":

  • Load distribution: a well-known entry point points clients at a backend instead of proxying traffic.
  • Privacy: a server rotates clients onto a different (possibly unannounced) address so its announced identity carries no subsequent traffic.

The reason for a redirect is a server-side concern; the protocol carries only the address hand-off and never represents intent on the wire. Full motivation, rationale, and security discussion live in the tracking issue.

What this PR contains

Per the CEP guidelines, this PR holds the specification-side document only:

  • src/content/docs/reference/ceps/cep-47.md — abstract, specification, security considerations, backward compatibility, dependencies, reference implementation
  • astro.config.mjs — sidebar registration

The tracking issue carries the comprehensive proposal (motivation, rationale, security implications); its Specification section should link back to this PR to keep the spec in a single place.

Design

  • One JSON-RPC error: -32044 "Redirect" in a kind-25910 response, e-tag correlated to the original request.
  • error.data: target (required pubkey), relays (optional inline hints; absent ⇒ CEP-17 lookup), instructions (optional, agent-readable).
  • Server emits it unconditionally per its own policy — no capability negotiation, no branching on client support.
  • Client re-issues the same request (method/params) to target; caps redirect chains (≤5) to prevent loops; surfaces unknown codes as ordinary errors (safe degradation, not silent failure).
  • Session state is established directly with target on re-issue, so no state transfer is needed and redirect works at any point in an exchange.
  • Follows the same "intercept special error → extract retry directive → re-issue" pattern as CEP-8's -32042 payment-gating error, but is independent of it.

Backward compatibility

Additive. No new event kind is introduced (redirects are normal kind-25910 responses); servers that do not redirect are unaffected; clients that do not recognize -32044 surface it as a normal error and are no worse off than with any other server refusal.

Dependencies

  • CEP-6 (target identity verification)
  • CEP-17 (relay discovery fallback when relays is absent)

CEP-4 (channel security) and CEP-8 (error-pattern sibling) are referenced inline only, not listed as dependencies.

@vercel

vercelBot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
contextvm-docsReadyReadyPreview, CommentJul 22, 2026 3:09pm

@abhayguptas

Copy link
Copy Markdown

Pulled the branch and went through the spec. Core design is solid, follows the same intercept-error-reissue pattern as CEP-8 which makes the SDK implementation straightforward. A few things that would be worth tightening before merge:

target format

The spec says target is "the public key of the server" but doesn't specify the format. Hex, npub, nprofile? If nprofile is allowed it carries relay hints inline, which overlaps with the relays field. Worth pinning this down explicitly, something like "64-character lowercase hex public key."

Relay fallback order when relays is provided

The spec covers the case where relays is absent (fall back to CEP-17). But when relays IS provided and the target is unreachable on those relays, should the client fall back to CEP-17 discovery or treat it as a failure? A sentence covering the priority would help implementers.

Redirect arriving during an in-flight CEP-8 payment

Security considerations mention that the target becomes the payment processor on redirect. But what about the case where a redirect arrives after a payment_required notification was already received in transparent mode (invoice displayed, waiting for settlement)? Should the client abandon the in-flight payment with the original server? Probably worth a note saying redirect cancels any pending payment state for that request.

Hop counter scope

"At most 5 hops" but is this per original request or per session? If a client sends 10 different tool calls and each gets one redirect, that's 10 total hops but only 1 per request. I'd suggest clarifying as "at most 5 consecutive redirects for the same original request."

Self-redirect

A server redirecting to its own pubkey creates a trivial 1-hop loop. The hop cap catches it eventually but burns through retries. A "servers SHOULD NOT redirect to their own public key" would be a cheap guard.

Unreachable target

No guidance on what to do if the target is simply offline or can't be reached. Should the client surface the redirect as an error to the caller, or retry the original server? Probably the former to avoid silent fallback confusion.

Minor: branch name is still cep-42-server-redirect but the spec content is CEP-47.

@1amKhush

1amKhush commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Some additional findings

+1 on all of Abhay's points. A few things not yet covered:

  1. Add _meta to error.data — CEP-8's error responses include _meta as an extension namespace. CEP-47 omits it. Adding it now avoids a breaking change if future extensions are needed (redirect reason hints, TTL, capability equivalence hashes via CEP-15).

  2. Redirect during CEP-41 open streams — if a redirect arrives for a request with an active open-ended stream, the client would need to abort and restart with target. Worth a note: "A redirect MUST NOT be emitted for a request with an active open-ended stream (CEP-41); the server SHOULD complete or abort the stream first."

  3. instructions example value — agents should treat -32044 as the actionable signal, not parse instructions for routing logic. An example like "Re-issue your request to the target address." would help implementers.

  4. Structured field table for error.data — for parity with CEP-8, a quick table (field / required / type) would improve scannability over the current prose-after-JSON-block format.

@ContextVM-org

Copy link
Copy Markdown
ContributorAuthor

Thanks @abhayguptas and @1amKhush . Attached your feedback in my latest commit. Please share your thoughts

@abhayguptas

Copy link
Copy Markdown

All points addressed cleanly. The field table, _meta namespace, hop scope clarification, CEP-41 interaction rule, and relay fallback order are all solid. One remaining gap I noticed:

Client behavior when server violates the CEP-41 MUST NOT

Line 75 says the server MUST NOT emit a redirect for a request with an active open-ended stream. That's the right constraint. But the spec doesn't say what a client should do if a buggy server does it anyway. The client receives a -32044 while the stream is still open (no close or abort frame), which leaves ambiguous state: does it follow the redirect with the stream still active? Does it ignore the redirect because it violates the spec?

Suggesting something like: "If a client receives a -32044 during an active CEP-41 stream, it SHOULD treat the stream as failed, release local stream state, and follow the redirect normally." That gives clients a clear defensive rule without over-specifying.

Everything else looks ready.

…rationale
- Client Behavior: define recovery when a server emits -32044 without
first terminating an active CEP-41 stream (treat as failed, release
state, follow redirect; stricter client MAY refuse).
- Server Behavior: correct the MUST NOT rationale — the stream needs its
terminal close/abort frame before the single final JSON-RPC response;
a mid-stream redirect strands it, rather than a double-final collision.
Sign up for freeto 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.

3 participants

@ContextVM-org@abhayguptas@1amKhush