Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Current rules:
- codecs: `plain`, `lz`, `deflate`, `arx`, `arx2`, and `arx3`
- fragment size budget: `8192` characters
- decoded payload budget: `200000` characters
- Discord markdown link limit: `2000` characters for the full formatted `[label](url)` string; `createGeneratedArtifactLink*` returns `discordMarkdownLinkWarning` when exceeded
- packed wire transport (`p: 1`) is allowed and must decode back to the standard envelope
- bundles must contain at least one artifact
- artifact ids must be unique within a bundle
Expand Down Expand Up @@ -118,6 +119,7 @@ If you change the payload contract, update the code, docs, examples, and the Ope
- `src/components/renderers/json-renderer.tsx`

### Payload and protocol
- `src/lib/markdown-link.ts` - markdown link formatting and Discord length warnings
- `src/lib/payload/schema.ts` - type surface, limits, fragment key, supported kinds/codecs
- `src/lib/payload/fragment.ts` - encode/decode logic and transport behavior
- `src/lib/payload/arx-codec.ts` - arx/arx2/arx3 codecs: dictionary substitution, tuple overlay, brotli, base76/base1k/baseBMP/base64url encoding
Expand Down
4 changes: 3 additions & 1 deletion docs/payload-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ Tuple fields:

- Supported fragment budget: 8,192 decoded visible fragment characters
- Supported decoded payload budget: 200,000 characters
- Discord markdown link limit: 2,000 characters for the full formatted `[label](url)` string
- Larger payloads should fail with a clear error before rendering
- Compression is selected automatically across packed/non-packed candidates; arx and arx2 optimize conservative transport length, while arx3 optimizes compact visible length for its dense Unicode wire
- Default sync codec priority is `deflate -> lz -> plain`
- Default async codec priority is `arx3 -> arx2 -> arx -> deflate -> lz -> plain`
- Optional budget-aware encoding can target strict limits like 1,500 chars and returns the shortest fragment when none fit
- Optional budget-aware encoding can target strict limits and returns the shortest fragment when none fit
- `createGeneratedArtifactLink` / `createGeneratedArtifactLinkAsync` return `url`, `markdownLink` (ready to paste verbatim in chat), `markdownLinkLength`, and `discordMarkdownLinkWarning` so agents do not need to reconstruct `[label](url)` themselves

When a payload does not fit the fragment budget or the target surface is hostile to long URLs, use UUID mode instead of weakening the fragment protocol. Current UUID mode stores the encoded payload server-side and is not zero-retention.

Expand Down
36 changes: 12 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion public/.well-known/agent-skills/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "skill-md",
"description": "Create zero-retention agent-render.com links for markdown, code, diffs, CSV, or JSON artifacts. Markdown artifacts support inline mermaid diagram rendering via fenced code blocks. Use when an agent needs to share a nicely rendered artifact in the browser instead of pasting raw content into chat. Trigger for requests like \"share this as a link\", \"make a diff link\", \"render this markdown/code/csv/json\", \"show this diagram\", or when chat rendering is weak. Agent Render is open source, hosted on Cloudflare Pages, and self-hostable. Use platform-specific linked-text syntax only on surfaces that support it cleanly, such as Discord Markdown links, Telegram HTML links, or Slack mrkdwn links; otherwise send a short summary plus the raw URL.",
"url": "https://raw.githubusercontent.com/baanish/agent-render/main/skills/agent-render-linking/SKILL.md",
"digest": "sha256:9bbbf1fbd47fa0781271bfb8cfff6bc6a4b55146ceafab607579d289b683b249"
"digest": "sha256:93826ebd4143754c284e5e6445de33bc2978e01921fd9ef8ce13c5fef028ad29"
},
{
"name": "selfhosted-agent-render",
Expand Down
26 changes: 24 additions & 2 deletions skills/agent-render-linking/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,20 @@ Example cases:

Set `activeArtifactId` to the artifact that should open first.

## Ready-to-send markdown link

Do not hand-assemble `[label](url)` when the product already formatted it for you.

When using the link helpers (`createGeneratedArtifactLink` / `createGeneratedArtifactLinkAsync`), use the returned `markdownLink` string verbatim in chat. It is the exact Discord/Slack-style markdown link the viewer would copy, including label escaping and URL wrapping for special characters.

The result also includes:
- `markdownLinkLength` — total character count of `markdownLink`
- `discordMarkdownLinkWarning` — non-null when `markdownLink` exceeds Discord's 2,000 character message limit

If you built the URL yourself and only need the formatted link, call `buildMarkdownLinkShareInfo(label, url)` and send `markdownLink` verbatim. Check `discordWarning` before posting to Discord.

Only fall back to manual `formatMarkdownLink(label, url)` when you cannot use the helpers above.

## Link construction

Construct the final URL with the compact `#<tag><payload>` fragment:
Expand Down Expand Up @@ -255,7 +269,11 @@ For `arx3`, use the same tuple, substitution, and brotli bytes as arx2, then try
Respect these limits:
- target fragment budget: about 8,192 decoded visible characters
- target decoded payload budget: about 200,000 characters
- strict Discord practical budget for linked text workflows: about 1,500 characters
- Discord message limit for a single markdown link: 2,000 characters total for the formatted `[label](url)` string

Before sharing on Discord, check `markdownLinkLength` or `discordMarkdownLinkWarning` from the link helpers. If you formatted the link yourself, use `buildMarkdownLinkShareInfo(label, url)` and inspect `discordWarning`. When the warning is non-null, split the bundle into smaller artifacts and send separate markdown links in multiple Discord messages instead of one oversized link.

When generating links programmatically via `createGeneratedArtifactLink` / `createGeneratedArtifactLinkAsync`, send `markdownLink` verbatim and inspect `discordMarkdownLinkWarning`. When it is non-null, surface that warning to the caller and split the payload before sharing on Discord.

If a link is getting too large:
1. try `arx3` first for trusted Unicode-preserving surfaces; otherwise try `arx2`, then `arx`, then `deflate`, then `lz`, then `plain`
Expand All @@ -280,12 +298,14 @@ Use platform-specific link text only on surfaces that support it cleanly.

### Discord

Prefer standard Markdown links:
Prefer standard Markdown links. When you have `markdownLink` from the link helpers, paste that string verbatim:

```md
[Short summary](https://agent-render.com/#<tag><payload>)
```

Check `markdownLinkLength` or `discordMarkdownLinkWarning` before sending. Discord rejects messages longer than 2,000 characters, so a single `[label](url)` string that exceeds that limit will probably fail. When it does, split the artifact into smaller bundles and send multiple markdown links across separate Discord messages.

Examples:
- `[Weekly report](https://agent-render.com/#<tag><payload>)`
- `[Config diff](https://agent-render.com/#<tag><payload>)`
Expand Down Expand Up @@ -331,6 +351,8 @@ When sharing a link:
- Prefer `patch` for diffs
- Prefer readable titles
- Prefer Markdown link text when supported
- Send `markdownLink` verbatim instead of reconstructing `[label](url)` yourself
- Check `discordMarkdownLinkWarning` before sharing markdown links on Discord
- Prefer shortest-by-measurement instead of human guesses
- Use budget-aware encoding for Discord-like constraints

Expand Down
22 changes: 21 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,8 @@ select {
.creator-link-frame,
.creator-result-note,
.creator-empty-state,
.creator-error-state {
.creator-error-state,
.creator-warning-state {
border: 1px solid var(--border);
border-radius: var(--radius-lg);
background: color-mix(in srgb, var(--surface-strong) 92%, transparent);
Expand Down Expand Up @@ -739,12 +740,31 @@ select {
line-height: 1.55;
}

.artifact-share-warning {
margin: 0;
padding: 0.85rem 1rem;
border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border));
border-radius: var(--radius-lg);
background: color-mix(in srgb, var(--warning) 8%, var(--surface-strong));
color: var(--warning);
font-size: 0.86rem;
line-height: 1.55;
}

.creator-error-state {
color: var(--danger);
font-size: 0.9rem;
line-height: 1.55;
}

.creator-warning-state {
color: var(--warning);
font-size: 0.9rem;
line-height: 1.55;
border-color: color-mix(in srgb, var(--warning) 35%, var(--border));
background: color-mix(in srgb, var(--warning) 8%, var(--surface-strong));
}

.artifact-first-layout {
display: grid;
grid-template-columns: minmax(0, 1fr);
Expand Down
Loading
Loading