Tlon Skill
Use the tlon command for reading data, managing channels/groups/contacts, and administration.
OpenClaw
When running as an OpenClaw skill, use the built-in message tool for sending outbound messages (DMs and channel posts). The tlon command is for reading data, administration, and management — not for sending messages. The message tool routes through the proper delivery infrastructure (threading, bot profile, rate limiting).
Diary / Notebook Thread Replies
Tlon diary/notebook channels are special: a channel-level send creates a new notebook post/note. Do not use message with action: "send" in a diary channel unless you intentionally want to create a new notebook post.
For normal conversation inside an existing diary/notebook post, use the message tool with action: "reply" and reply to the parent diary post id, not the newest reply id.
Working pattern:
{
"action": "reply",
"channel": "tlon",
"target": "diary/~host/slug",
"messageId": "170.141.184.507.950.303.933.087.606.997.052.817.408",
"message": "Reply text here"
}
Important details:
- Use the dotted
@udpost id format when available. messageIdshould be the parent notebook post/thread id.- After sending, verify with
tlon messages post <diary-nest> <parent-post-id>when correctness matters. - If the tool reports success but the reply is not visible under the parent post, treat it as a delivery/plugin issue and do not claim success until verified.
Installation
npm (Node.js):
npm install @tloncorp/tlon-skill
tlon channels groups
Direct binary (no Node required):
curl -L https://registry.npmjs.org/@tloncorp/tlon-skill-darwin-arm64/-/tlon-skill-darwin-arm64-0.4.0.tgz | tar -xz
./package/tlon channels groups
Replace darwin-arm64 with darwin-x64, linux-x64, or linux-arm64 as needed.
Configuration
CLI Flags (highest priority):
# Cookie-based auth (fastest - ship parsed from cookie name)
tlon --url https://your-ship.tlon.network --cookie "urbauth-~your-ship=0v..." <command>
# Cookie-based auth with explicit ship and code fallback
tlon --url https://your-ship.tlon.network --ship ~your-ship \
--cookie "urbauth-~your-ship=0v..." --code sampel-ticlyt-migfun-falmel <command>
# Code-based auth (requires url + ship + code)
tlon --url https://your-ship.tlon.network --ship ~your-ship --code sampel-ticlyt-migfun-falmel <command>
# Use skill-dir or cached credentials for one ship
tlon --ship ~your-ship <command>
# Or load from a JSON config file
tlon --config ~/ships/my-ship.json <command>
Valid CLI credential forms are --config <file>, --url <url> --cookie <cookie> with optional --ship and fallback --code, --url <url> --ship <ship> --code <code>, and --ship <ship> when available in TLON_SKILL_DIR or cache. Incomplete or conflicting credential flag sets fail locally instead of merging with environment variables.
Config file format:
// Cookie-based (ship derived from cookie)
{"url": "...", "cookie": "urbauth-~ship=..."}
// Code-based
{"url": "...", "ship": "~...", "code": "..."}
Environment Variables:
# Cookie-based (ship derived from cookie)
export URBIT_URL="https://your-ship.tlon.network"
export URBIT_COOKIE="urbauth-~your-ship=0v..."
# Code-based
export URBIT_URL="https://your-ship.tlon.network"
export URBIT_SHIP="~your-ship"
export URBIT_CODE="sampel-ticlyt-migfun-falmel"
URBIT_* aliases take precedence over TLON_* aliases for the same field. Partial ambient credentials fail locally except ship-only env, which is used for TLON_SHIP + TLON_SKILL_DIR or cache lookup.
Skill directory: When TLON_SHIP and TLON_SKILL_DIR are set, the CLI loads ships/<ship>.json from that skill directory before checking cached credentials.
OpenClaw: If configured with a Tlon channel, credentials load automatically from JSON config. The default path is ~/.openclaw/openclaw.json; OPENCLAW_CONFIG can point to an explicit JSON config path and is parsed as JSON regardless of extension.
Resolution order: CLI credential flags → TLON_CONFIG_FILE → URL + cookie env → URL + ship + code env → TLON_SHIP + TLON_SKILL_DIR → ship-only cache lookup → OpenClaw JSON → single cached ship.
Cookie vs Code:
- Cookie-based: Uses pre-authenticated session cookie. Ship is parsed from the cookie name (
urbauth-~ship=...). Fastest option. - Code-based: Performs login to get a fresh session cookie. Requires URL + ship + code.
You can provide both cookie and code — cookie is used first, code serves as fallback if cookie expires.
Cookie Caching
The skill caches fresh auth cookies from code login and code fallback to ~/.tlon/cache/<ship>.json. Provided-cookie flows validate the cookie but do not copy that cookie into cache. This makes subsequent invocations much faster by skipping the login request.
How it works:
# First time - authenticates and caches
$ tlon --url https://zod.tlon.network --ship ~zod --code abcd-efgh contacts self
~zod
Note: Credentials cached for ~zod. Next time run: tlon --ship ~zod <command>
# After that - select the cached ship
$ tlon --ship ~zod contacts self
~zod
# With multiple cached ships - specify which one
$ tlon --ship ~zod contacts self
$ tlon --ship ~bus contacts self
Cache behavior:
- Cached cookies are URL-specific (won't use a cookie for the wrong host)
- If only one ship is cached, it's auto-selected (no flags needed)
- If multiple ships are cached, you'll be prompted to specify with
--ship - Code login and code fallback cache fresh cookies; provided-cookie flows do not copy cookies into cache
Clear cache: rm ~/.tlon/cache/*.json
Multi-Ship Usage
If you have credentials for multiple ships, you can use this skill to operate on behalf of any of them. This is useful for:
- Managing multiple identities — switch between ships without changing environment variables
- Bot operations — act as a bot ship while authenticated as yourself
- Moon management — operate moons from their parent planet
Simply pass the target ship's credentials via CLI flags:
# Read channels as ~other-ship
tlon --url https://other-ship.tlon.network --ship ~other-ship --code their-access-code \
channels groups
# Or keep credentials in config files
tlon --config ~/ships/bot.json channels groups
tlon --config ~/ships/moon.json contacts self
Commands
Help and usage errors are handled locally before credential lookup, so tlon <command> --help works without a configured ship.
Activity
Check recent notifications and unread counts. Ships are shown with nicknames when available.
tlon activity mentions --limit 10 # Recent mentions (max 25)
tlon activity replies --limit 10 # Recent replies (max 25)
tlon activity all --limit 10 # All recent activity (max 25)
tlon activity unreads # Unread counts per channel
Channels
List and manage channels. DMs show nicknames when available.
tlon channels dms # List DM contacts (with nicknames)
tlon channels groups # List subscribed groups
tlon channels all # List everything
tlon channels info chat/~host/slug # Get channel details
tlon channels create ~host/slug "Projects" --kind chat # Create a group channel
tlon channels rename chat/~host/slug "New Title" # Rename a channel
tlon channels update chat/~host/slug --title "New Title" # Update metadata
tlon channels delete chat/~host/slug # Delete a channel
# Writers (who can post)
tlon channels add-writers chat/~host/slug admin member # Add write access
tlon channels del-writers chat/~host/slug member # Remove write access
# Readers (who can view - requires group flag)
tlon channels add-readers ~host/group chat/~host/slug admin # Restrict viewing
tlon channels del-readers ~host/group chat/~host/slug admin # Open viewing
Help works for both the command and subcommands:
tlon channels --help
tlon channels create --help
tlon channels rename --help
Notes on permissions:
- Empty writers list = anyone in the group can post (default for chat)
- Empty readers list = anyone in the group can view (default)
- Diaries default to admin-only writers
- Roles must exist in the group (use
tlon groups add-rolefirst)
Contacts
Manage contacts and profiles.
tlon contacts list # List all contacts
tlon contacts self # Get your own profile
tlon contacts get ~sampel # Get a contact's profile
tlon contacts sync ~ship1 ~ship2 # Fetch/sync profiles
tlon contacts add ~sampel # Add a contact
tlon contacts remove ~sampel # Remove a contact
tlon contacts update-profile --nickname "My Name" # Update your profile
Options: --nickname, --bio, --status, --avatar, --cover
Groups
Full group management.
# Basics
tlon groups list # List your groups
tlon groups info ~host/slug # Get group details
tlon groups create "Name" [--description "..."] # Create a group
tlon groups create-owned "Name" --owner ~ship [--description "..."] # Create group, invite owner, make owner admin
tlon groups join ~host/slug # Join public/invited group, or request invite if private
tlon groups request-invite ~host/slug # Request invite to a private group
tlon groups accept-invite ~host/slug # Accept an existing group invite
tlon groups reject-invite ~host/slug # Reject an existing group invite
tlon groups cancel-join ~host/slug # Cancel a pending join
tlon groups rescind-request ~host/slug # Cancel an invite request
tlon groups leave ~host/slug # Leave a group
tlon groups delete ~host/slug # Delete (host only)
tlon groups update ~host/slug --title "..." [--description "..."]
# Members (shown with nicknames when available)
tlon groups invite ~host/slug ~ship1 ~ship2 # Invite members
tlon groups revoke-invite ~host/slug ~ship1 # Revoke pending member invite
tlon groups kick ~host/slug ~ship1 # Kick members
tlon groups ban ~host/slug ~ship1 # Ban members
tlon groups unban ~host/slug ~ship1 # Unban members
tlon groups accept-join ~host/slug ~ship1 # Approve a member join request
tlon groups reject-join ~host/slug ~ship1 # Deny a member join request
tlon groups set-privacy ~host/slug public|private|secret # Set privacy
# Roles
tlon groups add-role ~host/slug role-id --title "..." # Create a role
tlon groups delete-role ~host/slug role-id # Delete a role
tlon groups update-role ~host/slug role-id --title "..." # Update a role
tlon groups assign-role ~host/slug role-id ~ship1 # Assign role
tlon groups remove-role ~host/slug role-id ~ship1 # Remove role
# Admin
tlon groups promote ~host/slug ~ship1 [~ship2 ...] # Promote member(s) to admin
tlon groups demote ~host/slug ~ship1 [~ship2 ...] # Demote member(s) from admin
Roles vs Admin:
- Regular roles are for organizing members and controlling channel read/write permissions.
- Admin is a special privilege on top of a role. Admins can manage group settings,
channels, members, and roles.
- `promote` creates an "admin" role (if one doesn't exist), grants it admin privileges,
and assigns it to the specified members. `demote` removes that role from them.
- To grant admin to members who already share a role, use `set-admin` on that role
via the backend directly (not yet exposed in the Tlon app UI).
# Channels
tlon groups add-channel ~host/slug "Name" [--kind chat|diary|heap]
tlon groups add-channel remains supported, but for agent/tool use prefer the more discoverable channel-centric form:
tlon channels create ~host/slug "Projects" --kind chat
Help works here too:
tlon groups --help
tlon groups add-channel --help
Group format: ~host-ship/group-slug
Join behavior:
joinfirst checks whether you are already a member, then checks foreign/unjoined group state for a valid invite.- Invited groups and public groups use the backend join action.
- Private groups without an invite use the invite-request action.
- Secret groups require an invite.
Hooks
Manage channel hooks — functions that run on triggers (posts, replies, reactions, crons).
# List and inspect
tlon hooks list # List all hooks
tlon hooks get 0v1a.2b3c4 # Get hook details and source
# Manage hooks
tlon hooks init my-hook --type on-post # Create starter template (on-post|cron|moderation)
tlon hooks add my-hook ./my-hook.hoon # Add a new hook from file
tlon hooks edit 0v1a.2b3c4 --name "New Name" # Rename a hook
tlon hooks edit 0v1a.2b3c4 --src ./updated.hoon # Update source
tlon hooks delete 0v1a.2b3c4 # Delete a hook
# Configure for channels
tlon hooks order chat/~host/slug 0v1a 0v2b 0v3c # Set execution order
tlon hooks config 0v1a chat/~host/slug key1=val1 # Configure hook instance
# Scheduled execution
tlon hooks cron 0v1a ~h1 # Run hourly (global)
tlon hooks cron 0v1a ~m30 --nest chat/~host/slug # Run every 30m for channel
tlon hooks rest 0v1a # Stop cron job
Notes:
- Hook IDs are @uv format (e.g.,
0v1a.2b3c4...) - Schedules use @dr format:
~h1(1 hour),~m30(30 minutes),~d1(1 day) - Hooks run in order when triggered; use
orderto set priority - Use
configto pass channel-specific settings to a hook instance
Writing Hooks: See references/hooks.md for full documentation on writing hooks, including:
- Event types (
on-post,on-reply,cron,wake) - Bowl context (channel, group, config access)
- Effects (channel actions, group actions, scheduled wakes)
- Config handling with clam (
;;)
Examples: See references/hooks-examples/ for starter templates:
auto-react.hoon— React to new posts with emojidelete-old-posts.hoon— Cron job to clean up old messagesword-filter.hoon— Block posts containing banned words
Messages
Read and search message history. Authors are shown with nicknames when available.
tlon messages dm ~sampel --limit 20 # DM history (max 50)
tlon messages channel chat/~host/slug --limit 20 # Channel history (max 50)
tlon messages search "query" --channel chat/~host/slug # Search messages
tlon messages context chat/~host/slug 170.141... --limit 5 # Messages around a post
tlon messages post chat/~host/slug 170.141... # Fetch single post with replies
Options: --limit N, --resolve-cites
The context command fetches N messages before and after a given post ID — useful for
finding surrounding conversation when you have a post from search or activity.
For DMs, use the ship name as the channel: tlon messages context ~sampel 170.141...
The post command fetches a single post with its replies/thread. For DM posts,
pass --author ~ship (required for DM lookups).
Tip: Use search to find a message, then context with its ID to see the surrounding conversation.
DMs
Manage direct messages — reactions, invites, and deletions.
# Management
tlon dms react ~sampel ~author/170.141... "👍" # React to a DM
tlon dms unreact ~sampel ~author/170.141... # Remove reaction
tlon dms delete ~sampel ~author/170.141... # Delete a DM
tlon dms accept ~sampel # Accept DM invite
tlon dms decline ~sampel # Decline DM invite
Expose
Publish Tlon content to the clearweb via the %expose agent.
tlon expose list # List all exposed content
tlon expose show chat/~host/slug/170.141... # Expose a post publicly
tlon expose hide chat/~host/slug/170.141... # Hide an exposed post
tlon expose check diary/~host/blog/170.141... # Check if a post is exposed
tlon expose url diary/~host/blog/170.141... # Get the public URL
Cite path formats:
- Simplified:
chat/~host/channel/170.141...(auto-expands) - Full:
/1/chan/chat/~host/channel/msg/170.141...
Channel kinds map to content types: chat→msg, diary→note, heap→curio
Posts
Manage channel posts (reactions, edits, deletes).
tlon posts react chat/~host/slug 170.141... "👍" # React to a post
tlon posts unreact chat/~host/slug 170.141... # Remove reaction
tlon posts edit chat/~host/slug 170.141... "New text" # Edit with plain text
tlon posts edit diary/~host/slug 170.141... --title "T" --image <url> --content story.json # Edit notebook
tlon posts delete chat/~host/slug 170.141... # Delete a post
Edit options for notebooks: --title, --image (cover URL), --content (Story JSON file for rich formatting).
Notebook
Post to diary/notebook channels.
tlon notebook diary/~host/slug "Title" # Post with no body
tlon notebook diary/~host/slug "Title" --content story.json # Post with Story JSON
tlon notebook diary/~host/slug "Title" --markdown post.md # Post with Markdown
cat post.md | tlon notebook diary/~host/slug "Title" --markdown-stdin
tlon notebook diary/~host/slug "Title" --image <url> # Post with cover image
The --content file should be Urbit Story JSON: an array of verses accepted by the ship's story-json decoder. Use --markdown for Markdown files instead of passing Markdown or editor-export JSON through --content.
Working examples:
[{"inline": ["Hello world"]}]
[{"block": {"header": {"tag": "h1", "content": ["Title"]}}}]
[{"inline": ["Use ", {"inline-code": "ha-q"}, " for entity queries."]}]
Important gotcha:
- Do not assume newer block-editor JSON shapes or arbitrary markdown-export JSON will work.
- If posting fails with a
channel-action-2cast error mentioningcontent -> add -> post -> action -> channel, the first thing to check is whether the content file matches the ship's Story JSON shape. - When debugging, post a minimal one-verse story first so you do not create duplicate full notebook posts.
See the ship-side decoder and types here:
tlon-apps/desk/lib/story-json.hoon- Story types in tlon-apps
Upload
Upload files to Tlon storage from a URL, local path, or stdin.
tlon upload https://example.com/image.png # Upload from URL
tlon upload ./photo.jpg # Upload local file
tlon upload ~/Pictures/screenshot.png # Upload with absolute path
tlon upload ./mystery-file -t image/webp # Override content type
cat image.png | tlon upload --stdin -t image/png # Upload from stdin
Options: -t/--type (override MIME type), --stdin (read from stdin)
Content type is auto-detected from file extension for local files. For stdin, -t is recommended (defaults to application/octet-stream).
Returns the uploaded URL for use in posts, profiles, etc.
Settings (OpenClaw)
Manage OpenClaw's Tlon plugin config via Urbit settings-store. Changes apply immediately without gateway restart.
tlon settings get # Show all settings
tlon settings set <key> <json-value> # Set a value
tlon settings delete <key> # Delete a setting
# DM allowlist
tlon settings allow-dm ~ship # Add to DM allowlist
tlon settings remove-dm ~ship # Remove from allowlist
# Channel controls
tlon settings allow-channel chat/~host/slug # Add to watch list
tlon settings remove-channel chat/~host/slug # Remove from watch list
tlon settings open-channel chat/~host/slug # Set channel to open
tlon settings restrict-channel chat/~host/slug [~ship1] # Set restricted
# Authorization
tlon settings authorize-ship ~ship # Add to default auth
tlon settings deauthorize-ship ~ship # Remove from auth
Notes
- Ship names should include
~prefix - Post IDs are @ud format with dots (e.g.
170.141.184.507...) - DM post IDs include author prefix (
~ship/170.141...) - Channel nests:
<kind>/~<host>/<name>(chat, diary, or heap)
Limits
- Activity: max 25 items
- Messages: max 50 items