Tlon on Urbit: Support Status and Configuration
Covers Tlon/Urbit support in OpenClaw: what the bundled plugin supports, what it does not, and how to configure it. Useful for operators linking an Urbit ship to OpenClaw.
Read this when
- Working on Tlon/Urbit channel features
Tlon is a decentralized messenger that runs on Urbit. By linking OpenClaw to your Urbit ship, you get automatic replies to direct messages and group chats. In groups, an @ mention is needed by default, and authorization rules plus an owner-approval flow sit on top of that.
Status: bundled plugin. Supported: DMs, group mentions, threads, rich text, image upload and download, and an owner approval system. Not supported: reactions and polls.
Bundled plugin
Current OpenClaw releases include Tlon as a bundled plugin, so packaged builds require no separate installation.
If you run an older build or a custom install that leaves it out, pull it from npm:
openclaw plugins install @openclaw/tlon
Tracking the current release tag means using the bare package name. Pin a version (@openclaw/tlon@x.y.z) only when you need reproducible installs.
From a local checkout:
openclaw plugins install ./path/to/local/tlon-plugin
More detail: Plugins
Setup
openclaw channels add --channel tlon --ship ~sampel-palnet --url https://your-ship-host --code lidlut-tabwed-pillex-ridrup
Alternatively, edit the config file directly:
{
channels: {
tlon: {
enabled: true,
ship: "~sampel-palnet",
url: "https://your-ship-host",
code: "lidlut-tabwed-pillex-ridrup",
ownerShip: "~your-main-ship", // recommended: your ship, always authorized
},
},
}
Your ship's web login code serves as the login code here. To print the current one, run +code in the ship's dojo. That code rotates, so read it again any time authentication begins to fail.
Ship URLs accept IPv6 literals wrapped in brackets, for example http://[::1]:8080. Loopback and private IPv6 addresses need the private-network opt-in described below.
Config changes are picked up through hot reload. Verify openclaw channels status --probe, and start the Gateway if it is offline. After that, DM the bot or @ mention it in a group channel.
Inbound durability
Accepted Tlon DM and group-chat events are persisted by OpenClaw before agent dispatch. Turns that are pending or retryable survive a Gateway restart, and work stays serialized per group channel or direct peer. Redelivered events are also suppressed by stable Urbit message IDs for as long as their queue record or retained completion record exists.
Should the connection stop delivering data or heartbeats for roughly 60 seconds, OpenClaw reconnects to the same Eyre channel so unacknowledged events can replay. Time spent processing a received event is not counted toward this idle timeout.
Across the queue-to-agent boundary, delivery is at least once: a crash during handoff may replay a turn. Agent actions with external side effects should therefore avoid duplicating those effects on retries where practical.
Private/LAN ships
For SSRF protection, OpenClaw blocks private and internal hostnames and IP ranges by default. When your ship lives on a private network (localhost, LAN IP, internal hostname), opt in explicitly:
{
channels: {
tlon: {
url: "http://localhost:8080",
network: {
dangerouslyAllowPrivateNetwork: true,
},
},
},
}
This covers targets such as http://localhost:8080, http://192.168.x.x:8080, and http://my-ship.local:8080. Enable it only for a ship URL you trust, since it turns off SSRF protection for that account's HTTP requests.
Note
channels.tlon.allowPrivateNetwork(flat key) is retired.openclaw doctor --fixmoves it tochannels.tlon.network.dangerouslyAllowPrivateNetworkautomatically.
Group channels
Pin channels by hand, or enable auto-discovery:
{
channels: {
tlon: {
groupChannels: ["chat/~host-ship/general", "chat/~host-ship/support"],
autoDiscoverChannels: true,
},
},
}
When unset in config, autoDiscoverChannels defaults to false; the setup wizard defaults the prompt to yes and writes true explicitly. With it enabled, OpenClaw scries joined groups at startup, watches new channels as group invites are accepted, and rechecks every 2 minutes.
Access control
DM allowlist (empty = no DMs allowed unless the sender is ownerShip):
{
channels: {
tlon: {
dmAllowlist: ["~zod", "~nec"],
},
},
}
Group authorization defaults to restricted per channel. For a baseline, set defaultAuthorizedShips, then override per channel nest:
{
channels: {
tlon: {
defaultAuthorizedShips: ["~zod"],
authorization: {
channelRules: {
"chat/~host-ship/general": {
mode: "restricted",
allowedShips: ["~zod", "~nec"],
},
"chat/~host-ship/announcements": {
mode: "open",
},
},
},
},
},
}
After the bot has replied inside a thread, later messages in that thread keep getting responses without another mention.
Set channels.tlon.implicitMentions.threadParticipation: false to require a new explicit mention for those follow-ups. Account overrides use channels.tlon.accounts.<id>.implicitMentions. Tlon does not currently produce replyToBot or quotedBot facts, so those flags have no effect here.
Set channels.tlon.requireMentionInBotThreads: false to accept unmentioned replies whenever this account's ship authored the thread root, including the first reply. Setting it to true requires a fresh mention in those threads even after the bot has participated. Omit it to keep the existing participation policy. The root author is read from the authenticated ship API; if the root is unavailable or foreign, the normal mention policy stays in place.
Named accounts can override it with accounts.<id>.requireMentionInBotThreads. A per-channel authorization.channelRules.<nest>.requireMentionInBotThreads overrides the account default, including rules supplied through the Urbit settings store. For this option, a saved channel rule overrides the file value only when it sets a boolean value; older access-only rules inherit the file value. Sender authorization still applies, and this option does not change top-level channel posts or DMs.
Owner and approval system
{
channels: {
tlon: {
ownerShip: "~your-main-ship",
},
},
}
The owner ship is authorized everywhere: DM invites are always auto-accepted, group invites are always auto-accepted, and channel messages always pass authorization. Being in dmAllowlist, defaultAuthorizedShips, or groupInviteAllowlist is not required for the owner.
Group DMs are the exception. Because Tlon does not verify who wrote a group DM message, group DM messages never carry owner authority: owner commands, approval replies, and admin commands work only in a 1:1 DM with the bot. A group DM message whose claimed author is on dmAllowlist still gets an answer, but as an ordinary unverified sender.
Pending DM requests saved by versions before this behavior cannot be distinguished from group DM claims. Approving one still adds the ship to dmAllowlist, but its stored message is not replayed. The approval confirmation tells the owner the message was not processed and that the sender has to send it again.
When ownerShip is set, unauthorized requests are not simply dropped: they queue a pending approval and DM the owner:
- DM requests from ships not on
dmAllowlist - Mentions in channels where the sender fails authorization
- Group invites from ships not on
groupInviteAllowlist(when auto-accept is off, or on but the inviter is not allowlisted)
The owner replies in DM to act on a request:
| Owner reply | Effect |
|---|---|
approve / deny / block | Acts on the most recent pending approval |
approve <id> / deny <id> | Acts on a specific approval by id |
block | Also blocks the ship natively so it cannot reconnect |
unblock ~ship | Reverses a native block |
blocked | Lists currently blocked ships |
pending | Lists pending approval requests |
With no ownerShip configured, unauthorized DMs and channel mentions are dropped and logged only; no approval prompt is sent.
The monitor accepts at most 100 new pending approvals. Approvals created by an older version are kept, so after an upgrade the owner's replies still point at the same request. Once the queue fills, the monitor sends the owner a single saturation notice and stops admitting unique requests until pending items are resolved. If delivering that notice fails, it is retried up to three times per full-queue episode. When capacity frees up and a new request is admitted, a new episode begins, so refilling the queue can trigger another notice during the same monitor run. Requesters who were rejected have to retry once capacity is available; pending DM and group invite updates stay retryable instead of being acknowledged.
Each group invite update applies to a single group. If an invitation is revoked, removed, or completed, duplicate suppression for that group is cleared, which lets a later invitation be processed under the current auto-accept and allowlist settings.
Auto-accept settings
To auto-accept DM invites from ships already listed on dmAllowlist (the owner is auto-accepted in every case, whatever this flag says):
{
channels: {
tlon: {
autoAcceptDmInvites: true,
},
},
}
To auto-accept group invites from an allowlist (with autoAcceptGroupInvites: true and an empty groupInviteAllowlist, no invite from a non-owner is accepted):
{
channels: {
tlon: {
autoAcceptGroupInvites: true,
groupInviteAllowlist: ["~zod"],
},
},
}
Hot-reload via Urbit settings store
On first run, most of the settings listed above (dmAllowlist, groupInviteAllowlist, groupChannels, defaultAuthorizedShips, autoDiscoverChannels, autoAcceptDmInvites, autoAcceptGroupInvites, ownerShip, showModelSignature) are mirrored into the ship's %settings agent (desk moltbot, bucket tlon) and read live from that location afterwards. As a result, edits made through a Landscape client or through the bundled skill's settings commands take effect without restarting the gateway. channelRules and pending approvals are persisted there as JSON as well. For any value that was never written to the settings store, file config remains the source of truth.
Delivery targets (CLI/cron)
Use with openclaw message send or cron delivery:
- DM:
~sampel-palnetordm/~sampel-palnet - Group:
chat/~host-ship/channelorgroup:~host-ship/channel
Bundled skill
The plugin ships with @tloncorp/tlon-skill, a CLI for running Urbit operations directly. It becomes available automatically after the plugin is installed:
- Activity: mentions, replies, unreads
- Channels: list, create, rename
- Contacts: list/get/update profiles
- Groups: create, join, invite/request flows, roles
- Hooks: manage channel hooks
- Messages: history, search
- DMs: send, react, accept/decline
- Posts: react, delete
- Notebook: post to diary channels
- Settings: hot-reload plugin config via the settings store above
Capabilities
channels.tlon.mediaMaxMb caps, in MiB, both each inbound image download and each outbound image load. A named account can override the cap through accounts.<id>.mediaMaxMb; if it does not, the channel root applies, and then agents.defaults.mediaMaxMb. Image downloads and uploads keep the existing 6 MiB ceiling. When a cap is configured, a failed size check or a failed download causes the send to fail rather than embedding an unchecked URL. If a bounded download succeeds but the upload then fails, the original URL can still be used. When no cap is configured, the existing link fallback stays available even if the image cannot be downloaded within that ceiling.
Outbound image uploads keep the downloaded filename, including names that Content-Disposition supplies. When no filename exists, Tlon falls back to the basename of the source URL or a generated name. Custom-S3 public URLs encode the path segments of the object key, so characters such as # and ? in a filename stay part of the object name.
| Feature | Status |
|---|---|
| Direct messages | Supported |
| Groups/channels | Supported (mention-gated by default) |
| Threads | Supported (keeps replying once it has joined) |
| Rich text | Markdown converted to Tlon's native format |
| Images | Downloaded inbound, uploaded outbound |
| Reactions | Only via the bundled skill |
| Polls | Not supported |
| Native commands | Owner-only by default |
Troubleshooting
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
Common failures:
- DMs ignored: the sender is absent from
dmAllowlistand noownerShipis configured for the approval flow. - Group messages ignored: the channel was not discovered or pinned, or the sender fails authorization and there is no
ownerShipwhere an approval could be queued. - Connection errors: verify the ship URL is reachable; for local ships, set
network.dangerouslyAllowPrivateNetwork. - Auth errors: login codes rotate, so copy the current code from your ship.
Configuration reference
Full configuration: Configuration
| Key | Meaning |
|---|---|
channels.tlon.enabled | Turns channel startup on or off. |
channels.tlon.ship | Urbit ship name of the bot (for example ~sampel-palnet). |
channels.tlon.url | URL of the ship (for example https://sampel-palnet.tlon.network). |
channels.tlon.code | Login code for the ship. |
channels.tlon.network.dangerouslyAllowPrivateNetwork | Permits ship URLs on localhost/LAN (SSRF opt-in). |
channels.tlon.ownerShip | Owner ship: always authorized and the recipient of approval requests. |
channels.tlon.dmAllowlist | Ships permitted to send DMs (empty = none other than the owner). |
channels.tlon.autoAcceptDmInvites | Accepts DMs automatically from ships listed in dmAllowlist. |
channels.tlon.autoAcceptGroupInvites | Accepts group invites automatically from groupInviteAllowlist. |
channels.tlon.groupInviteAllowlist | Ships whose group invites get auto-accepted. |
channels.tlon.autoDiscoverChannels | Discovers joined group channels automatically (default: false). |
channels.tlon.implicitMentions.threadParticipation | Lets follow-ups in participated threads skip mention gating. |
channels.tlon.requireMentionInBotThreads | Applies mention-gating bypass only to threads rooted by this account's ship; leaving it out keeps current behavior. |
channels.tlon.groupChannels | Channel nests pinned by hand. |
channels.tlon.defaultAuthorizedShips | Ships authorized across all channels (applied when no rule matches). |
channels.tlon.authorization.channelRules | Auth mode per channel nest, allowlist, and an optional requireMentionInBotThreads override. |
channels.tlon.showModelSignature | Adds _[Generated by <model>]_ to the end of replies. |
channels.tlon.responsePrefix | Automatic reply prefix: literal text, "auto", or a template like "[{model}]"; account-level settings take precedence, and "" turns it off. |
channels.tlon.accounts.<id> | Extra named accounts (for multi-ship setups). |
Notes
- A group reply requires an @ mention (such as
~your-bot-ship), unless thread participation or a bot-owned thread policy permits it. - Replies stay inside the thread, and the bot additionally receives the thread's last 10 messages as context prepended for the agent.
- Tlon's native format is produced from rich text (bold, italic, code, headers, lists).
- When an inbound message requests a channel summary (for instance "summarize this channel"), a built-in history summarization runs in place of the usual reply flow.
Related
- Channels Overview, every channel that is supported
- Pairing, DM authentication for channels that declare it; Tlon does not declare it and instead relies on the
dmAllowlistplusownerShipapproval flow described above - Groups, group chat behavior and mention gating
- Channel routing, session routing for messages
- Security, access model and hardening