Overview

Let Bots collaborate, run on a schedule, and recover safely

Bot-to-Bot: Direct chats and Groups#

Direct#

Direct only connects two active Bots, and both definitions must satisfy, simultaneously:

  • allow_direct is turned on.
  • The other Bot is already listed in its own allowed_peers.

This is a reciprocal allowlist. You can open a Conversation and submit a task, but you can never impersonate a Bot to send a Direct message as it. If either side is paused, archived, trashed, or edited to no longer allow the other, any new dispatch fails closed.

Bot Group#

A Group has 2 to 6 active Bots, plus one designated active moderator.

  • An instruction from you with no @mention goes to the moderator for the first round of orchestration.
  • An explicit @Bot dispatches only to that mentioned active member.
  • @everyone dispatches to every active member.
  • The moderator can't be removed while it still holds that role.
  • Every member keeps using its own revision, permission snapshot, budget, and Approval policy — nothing merges into a shared permission set.

Every member in a Group is a Bot. This isn't chat software, and it doesn't offer multiple human identities, invites, presence, read state, or a human ACL.

The asynchronous collaboration loop#

A peer request persists in this order:

  1. Write the Conversation Message.
  2. Create a Delivery, and optionally a CollaborationTask, for the target member.
  3. A background dispatcher creates an independent BotRun for the receiving Bot.
  4. The receiving Bot settles its Task and writes a structured response back to the Conversation.
  5. The response closes the source Task — it never spawns another response task automatically, so there's no request/response ping-pong.

A timeline notice only records state — it never triggers a new Run. Message and Task identities let you safely retry the same request without duplicate dispatch; the same identity with different content gets rejected.

Stopping and limits#

Stopping a Conversation blocks new dispatches and moves any unfinished collaboration to an explicit terminal state. It can't undo a side effect that already happened in an external system — an uncertain side effect moves into Recovery instead of being auto-retried as an ordinary failure.

The platform also limits child tasks, delegation depth, and message hops; a Bot definition can tighten these limits further. An ArtifactRef only references an immutable Artifact — it never carries the sending Bot's own access rights.

Bot Routine: trigger BotRuns on a schedule#

Bots -> Routine repeatedly runs one active Bot. A Routine only stores the trigger policy — every occurrence resolves and locks in a Bot revision first, then creates an ordinary durable BotRun.

Creating one#

When you create a Routine, you specify:

  • The active Bot and the Routine's name.
  • A cron expression.
  • An IANA timezone, e.g. Asia/Dubai.
  • The input for each run.
  • Context mode: isolated or continue_conversation.
  • Revision mode: follow_current or pinned.
  • A consecutive-failure auto-pause threshold.

Once created, you can pause, resume, edit, or Run now.

Context mode#

isolated creates an independent context for every occurrence and never reads Conversation history — it fits daily reports, periodic checks, and maintenance tasks.

continue_conversation must bind to an active Conversation, and the Bot must still be an active member of it. It fits periodic tasks that need to continue a Bot-to-Bot working state; if the membership or Conversation lifecycle doesn't hold, the Routine doesn't run around the check.

Revision mode#

  • follow_current resolves the Bot's currently published revision at the moment an occurrence is due, then locks that result into the BotRun.
  • pinned always uses the revision selected when you created or last updated the Routine.

Either way, a BotRun already queued never changes revision because of a later publish.

Scheduling and recovery#

An occurrence's identity is generated deterministically from the Routine and its scheduled time. A repeated tick or an app restart never creates a second Run for the same occurrence.

Once consecutive failures hit the configured threshold, the Routine auto-pauses, so a broken task doesn't repeat indefinitely. If a Bot enters an inactive lifecycle state, its associated Routines pause too. Before resuming, check failed or UNKNOWN evidence in Runs & Recovery first.

How it differs from Session Schedule#

Schedule periodically delivers a message into a specific Session. Bot Routine directly triggers an independent Bot definition, constrained by its revision, permission snapshot, Memory, contract, and Bot-to-Bot Conversation.

Both only run for as long as the kxen runtime is up — neither is an OS-level cron job, and neither spins up a shared cloud execution environment once the app quits.

Runs & Recovery#

Bots -> Runs shows the durable state of every BotRun. Bots -> Recovery rolls up every Bot, Run, Conversation, and Routine that can't be safely judged as succeeded or failed.

BotRun#

Every Run locks in a snapshot of:

  • The Bot identity and its immutable revision.
  • Capability, resource grants, Approval policy, and budget.
  • Trigger, input contract, and its Conversation/Task associations.
  • Provider-neutral context, turns, usage, the tool journal, results, and the artifact manifest.

Transient stream deltas only refresh the UI. After an app restart, the durable Run and event stream are the source of truth — kxen never guesses execution results from frontend cache.

Waiting operations#

A Run can enter two kinds of explicit wait:

  • Approval: shows a summary of the operation, and you Allow or Deny it. Side-effect approvals are bound to an exact operation identity.
  • Input: shows what information is missing, submitted against a stable request identity bound to the original Run.

Cancel records a durable cancellation request first, then interrupts execution. A later ordinary success/failure that the model or a tool reports can't override a cancellation you already submitted.

Tool journal and UNKNOWN#

Tool calls with side effects are recorded through Prepare → Started → OutcomeKnown or OutcomeUnknown → Settled. Only pure operations that never crossed a side-effect boundary are eligible for automatic retry under the Bot's failure policy.

An operation that reached Started but whose result can't be proven is UNKNOWN. The system never rewrites it to plain Failed, and never automatically replays it — the external system may already have completed the write.

Artifact#

A Bot can submit an immutable Artifact. The Runs page shows its name, media type, size, and content hash, and verifies content on read:

  • Text and JSON preview directly in the UI.
  • Binary files only report verified size and type — they're never executed or rendered in the preview pane.
  • Trash and Restore only change an Artifact's lifecycle — they never modify content already submitted.

What a Conversation shares is an ArtifactRef, never a mutable file or the sending Bot's own permissions.

Recovery Center#

Recovery Center distinguishes two decisions you can make:

  • repair: you've verified and fixed the evidence externally, moving the aggregate back to a manageable paused state.
  • clear: you're explicitly abandoning unfinished work and closing the recovery record — never faking success or failure, and never retrying the UNKNOWN effect.

Check the reason, evidence, Run journal, and external system state first, then choose an action. When you can't prove whether an external side effect happened, keeping it UNKNOWN is safer than re-running it.

Updated

Was this page helpful?