Swarm Network OpenClaw v2026.8.2
Skills you pick in the dashboard now land on your agent automatically. Install, update or remove one, and the agent always ends up matching exactly what you chose.
What shipped on the platform, and every new release of the agent templates you can deploy.
Skills you pick in the dashboard now land on your agent automatically. Install, update or remove one, and the agent always ends up matching exactly what you chose.
Skills you pick in the dashboard now land on your agent automatically. Install, update or remove one, and the agent always ends up matching exactly what you chose.
Skills you pick in the dashboard now land on your agent automatically. Install, update or remove one, and the agent always ends up matching exactly what you chose.
Skills you pick in the dashboard now land on your Nova automatically, and always end up matching exactly what you chose.
The Files area works again.
Every action in the chat's Files area — list, upload, rename, delete — was failing with a permission error, so the area was effectively dead. Signing in now covers your files too.
The create, rename and delete dialogs are also real dialogs now: the name is checked before anything happens, Enter confirms, a rename keeps the file extension, and a delete tells you exactly what it's about to remove.
Merged in #33. Three faults behind one symptom: Nova answering "I don't see an attachment yet" to a message that visibly had one.
It was never sent
assistant-ui does not merge attachment parts into message.content. The composer builds
{ content: [text], attachments: [...] } and each attachment keeps its own content. The code that
collected files for the send scanned message.content, so it found nothing — every time, in both web
chats, for as long as attachments have existed. Only the Telegram file path ever worked.
It failed silently, which is why it lasted: the chip renders, the send succeeds, the model simply never receives a file.
Only some files could be attached
The stock adapters took images plus a handful of text types, and turned the latter into an
<attachment name=…> blob of TEXT — which can never be written back to the drive as the file it came
from. One NovaAttachmentAdapter now accepts any file (4 MB each) and carries it through with its
real filename and MIME type.
A web upload never reached the drive
Telegram stashed uploads into inbox/; the web composers did not. A file sent from a browser lived
only inside one chat turn — Nova's own tools had nothing to open, and "save this in my files" had
nowhere to save to.
orchestrate now stashes for the owner and tells the model the path, exactly as the Telegram path
does. Two exclusions, both deliberate:
inbox/…" note inside the
text it persists before the run starts. It signals this with a {nova:"inbox"} data part rather
than a flag on the call, so the fact travels with the message and a retry or replay cannot write
the same file twice.Also
Reloading a chat that had an attachment crashed the page (createObjectURL: Overload resolution failed) — a persisted transcript rehydrates file from JSON as a plain object, not a File.
Upgrade: no config or data changes. Web uploads begin appearing under files/inbox/.
Patch on v0.31.0. Merged in #32.
Picking a file in the hosted chat's composer crashed the whole surface with:
`Tooltip` must be used within `TooltipProvider`
The vendored chat components use Radix tooltips, and the attachment chip opens a bare <Tooltip> with
no provider above it. Radix's context helper throws on a missing provider rather than degrading, so
the error propagates to the nearest boundary and the chat goes with it.
It survived this long because TooltipIconButton wraps its own provider — every other tooltip in the
bundle works, and the chip was the only bare one. The thread root now provides one for everything
under it, which also keeps the bundle self-sufficient rather than depending on whatever a host wraps
it in.
Synced from the control plane's chat-ui:export, where the fix and its regression test live.
Upgrade: no config or data changes.
Three things that turned out to be one thing: Nova can format a reply properly, move files in both directions, and keep those files somewhere everyone can reach them.
Merged in #31.
Rich replies (Bot API 10.1/10.2)
sendRichMessage is a method, not a parse_mode — the reply goes out as raw GFM and Telegram
renders real tables, checkboxes, heading levels and nested lists.
Used selectively: a plain answer still goes out as a plain message, because mixing the two
surfaces makes font weight and spacing jump mid-conversation. needsRich() decides per message,
after stripping code fences — a fence is not a reason to escalate.
Three failure modes, three behaviours. The rule that matters is never re-send a transient failure, which is how a user ends up with the same answer twice:
| Failure | Response |
|---|---|
| Method unknown (older Bot API) | latch off for the process, fall back to plain |
| Content rejected (bad markup) | fall back to plain, once |
| Transient (429/5xx) | honour retry_after, retry the same send |
Also fixes a pre-existing truncation: chunk() dropped everything past 4000 characters of a line
containing no newline, so a long paragraph lost most of the answer. It now hard-splits and re-opens
straddled code fences.
Files, both directions
In — photos, albums, video, audio, voice notes, documents. An album arrives as ONE turn, debounced
by media_group_id: answering the first item treated item #2 as a new question and interrupted the
run item #1 had started. Images and PDFs reach the brain as native file parts, text-ish files
inline. Anything over Telegram's 20 MB bot-download cap is reported to the model rather than silently
dropped. Every upload also lands in the drive's inbox/.
Out — attach_file sends a real file: a rich media block for images/video/audio, a native
document bubble otherwise, a file card in both web chats.
Chat action is held for the whole run (Telegram expires it after 5 s) and switches to
upload_photo / upload_voice / upload_video / upload_document for what is about to arrive.
Nova Drive
One folder — $DATA_DIR/files. The pre-drive workspace/ is renamed into it on boot, so Nova's tools
and the user's files are one tree: a chart bash renders is a file the user downloads a second later.
Three doors, one implementation:
| Door | Who | Proof | Reach |
|---|---|---|---|
/drive/api/* | the owner | hosted-chat cookie, or CONTROL_TOKEN when the dashboard proxies | everything |
/nova/drive/* | a mesh agent | its own mesh-signed credential | only what a grant covers |
/d/<token> | anyone | the link | one file or folder, within its limits |
A grant is authorization — the credential already proves identity. Scoping is prefix+separator, so a
grant on shared/ deliberately does not cover shared-notes/. Public links take any combination of
expiry, download cap (1 = one-time) and argon2 password; answering the password sets a cookie scoped
to that one link, so a folder share does not ask per file.
Every mutation and every download records its actor (user / nova / agent:<id> /
share:<token> / telegram) — the only way a shared drive answers "did that link get used?". Text
overwrites and deletes keep bounded snapshots, so an edit is restorable; a rename carries its history.
Path safety is one tested function: lexical .. rejection plus a realpath check on the deepest
existing ancestor, because string cleaning never catches link -> /etc. HTML and SVG always download
— serving attacker-authored markup inline from the agent's own origin is stored XSS. Range is
honoured everywhere, so video scrubs.
Nova's own tools are ungated, since NOVA_SYSTEM_TOOLS is about giving it a shell, not about reading
a CSV the user just uploaded: list_drive, read_drive_file, write_drive_file, move_drive_file,
delete_drive_file, share_file, grant_agent_access.
Backups are a hand-written streaming ZIP — no dependency, no zip in the image, one file in memory at
a time.
Attachments in chat
Both web chats show a file card: glyph and tint by type, name, size, image thumbnail, click to
download. The bytes still never ride the reply — a 20 MB attachment would be re-serialized on every
poll of the task — but the reference now carries the file's size and drive path, which is the
difference between prose and a file the user can take.
The hosted chat fetches from its transcript row rather than the drive path: the row is what the reply was, so the download survives Nova moving or deleting the original.
Upgrade notes
$DATA_DIR/workspace is renamed to $DATA_DIR/files once, on boot. Anything referring to
workspace/ is stale.TELEGRAM_RICH=0 disables rich replies without a rollback.size and path.Your agent can now generate videos and send them to you, and there is a new channel to reach it on. Photos and files on Telegram now land reliably.
Opening your Nova's own domain now gives you the same chat as the dashboard — the same components, not a lookalike — with one history shared across every surface.
The dashboard's chat, verbatim
web/vendor/chat-ui/ is the control plane's own component set plus its design tokens, generated by its chat-ui:export and synced by CI. This repo supplies only the host glue (runtime adapters over the linear store, roster, schedules). Composer, message layout, action bars, animations and scrolling are therefore identical, and future dashboard changes arrive as a sync PR instead of a re-implementation.
Light and dark
Both themes from the same token file the dashboard uses, applied before first paint. The toggle in the rail follows the OS until you pin a choice.
What the chat gained
@mention tags for mesh agents (replies used to arrive as raw markdown text).‹ 2/3 › picker; the tree is persisted per session as the web view of the conversation.One history across surfaces
Sessions carry the contextId their turns run under, and turns arriving over /nova/message — the dashboard's chat — are mirrored into this Nova's own store. A conversation held in the dashboard now shows up here (badged with where it came from), and continuing it here continues the same conversation and the same memory rather than starting a parallel one. Telegram threads and scheduled runs are in the same list.
API
/chat/api gains roster, capability flags, session delete, the transcript blob, and the memory / tasks / cron routes — which now share one handler with /setup/api, so the control channel and the chat can't drift apart.
Fixes
peers.json pins the package versions the vendored bundle is built against, checked by typecheck: a react-lexical minor bump had silently killed the composer (Send disabled, Enter inserting a newline) with no build error.The first reply arrives much sooner, and models that think out loud show their thinking live. There are new models to choose from, fewer interruptions for routine actions, and finished answers are kept safe even if the agent restarts.
Maintenance and reliability improvements.
Maintenance and reliability improvements.
Your Telegram bot now recognises you from your first message, anyone you've approved stays approved across updates, and connecting Telegram is faster.
Your Telegram bot now recognises you from your first message. Everyone else still needs your approval before it will answer.
Nova's Telegram bot answered anyone who found its username: no allowlist, no pairing. A stranger could hold a full conversation and spend the owner's balance.
Nova now takes an allowlist with its credentials (runtime push, plus TELEGRAM_ALLOWED_USERS as a boot seed) and checks the sender before anything else — an unauthorized one gets a single plain refusal and no session, transcript, or model call. The control plane fills it with the account Telegram says created the bot.
An empty list stays open, so a Nova connected before this keeps working unchanged.
Fixes an issue where your own Telegram bot might not recognise you. Update to the next release, which includes a better version of this fix.
Telegram queues updates for a bot that has no webhook yet. The child bot exists for minutes before its token reaches Nova, and Telegram shows a START button the moment the user opens the chat — so pressing it queued the /start, and drop_pending_updates discarded that queue on arrival.
Telegram never offers the button twice, so first contact was lost: the generated welcome never came and the bot only replied once the user typed something by hand. The pending queue is now kept.
Your agent now recovers from problems on its own, reports ready only when it truly is, and keeps your approved users, conversations and connections across restarts.
Connecting Telegram no longer restarts the Nova, and first contact is answered by Nova itself.
Runtime Telegram credentials
POST /setup/api/telegram { token, webhookSecret, botUsername? } (bearer CONTROL_TOKEN) installs the child-bot credentials, persists them in Nova's own SQLite (app_config), and calls setWebhook immediately — the bot answers seconds after the QR scan, with no env push and no redeploy.DELETE disconnects (drops the webhook before clearing), GET reports {connected, botUsername, webhookUrl} and never returns the token.TELEGRAM_BOT_TOKEN / TELEGRAM_WEBHOOK_SECRET are now a boot seed only; stored config wins, so Novas connected the old way keep working.setWebhook sends drop_pending_updates (a reconnected bot doesn't replay its old queue) and setMyCommands gives a fresh chat a menu.Personalized welcome
/start is answered by an introduction the model writes at that moment from the live roster, the enabled persistent capabilities and the global-memory digest — static fallback if the gateway is down. It's mirrored into the hosted-chat transcript and never routed through orchestrate().
Full changelog: https://github.com/Swarm-Agent-Aggregator/Swarm-Network-Nova/compare/v0.24.0...v0.25.0
Follow along by RSS. The feed carries platform entries only.