Skip to content

Runs and events

Everything on Manykind starts with an event landing in a vault scope. The platform turns events into runs: a Job per agent and stream, with one Task per event. A workflow run is a Job too.

Events

An event is one typed message published into a scope. It is the only way work enters the platform.

Field Meaning
type What the event is, e.g. user_message, workflow.start.
context The stream it belongs to. Events with the same context form one stream, and one Job.
payload The body.
role source, user, or agent.
from Who published it, when the vault knows: a person’s key or an agent id.
target The agent the event is for, <agentServicePubkey>:<alias>.
correlationId, metadata, parents Correlation, free-form metadata, and the ids of the events that caused this one.
timestamp Set by the vault when absent.

Where events come from

Source How
A person Runs a workflow in ROC, or acts in a widget.
Your app vault.scope(name).publish({ type, context, payload }) with the Vault SDK.
A schedule The vault fires the agent’s declared schedules (cron). See Triggers.
A webhook An outside system calls the workflow’s webhook URL with a key. See Triggers.
A connector A Slack or Telegram message arrives through a vault connector.
An agent ctx.vault.publish(type, payload, { target }) from a running agent. See Event streams.

An event reaches an agent only through an active connection on that scope. Without target, an agent’s publish goes to every agent subscribed in the scope; name the recipient to hand work to one agent. An LLM agent receives another agent’s output only when it is targeted.

Jobs and Tasks

Noun What it is
Job A long-lived run, keyed by vault, agent, scope, and context. The record of a workflow run is a Job.
Task One event’s worth of work inside a Job.

When an event arrives, the platform finds or opens the Job for that agent and stream, and adds a Task. By default a Job runs one Task at a time, in order.

  • Job states: queued, throttled, processing, active, completed, failed, cancelled, dead.
  • Task states: pending, dispatched, running, completed, failed. A Task carries an attempt count and, on failure, an error with code, message, and retryable.
  • Idle timeout. A Job with no new activity for the agent’s idleTimeout (default 30m; "0s" disables it) ends with reason idle_timeout. An agent can end its own Job with ctx.close(reason).
  • Initiator. A Job records the person who started it. A Job started by a schedule or a connector has none.

Read runs from outside with the Vault SDK: vault.jobs.list(), vault.jobs.get(jobId).tasks.list(), and .tasks.logs(taskId) for the log lines your code wrote. In ROC, open a workflow to see its runs. See Monitor runs.

How a code agent runs

A code agent is a set of engagements. For a new Job the platform selects one engagement (conditions, then priority, then weight) and pins it for the Job’s life. Each Task calls the pinned engagement’s @OnEvent handler for the event’s type.

ctx.params is resolved per Job: manifest defaults, then deployment values, then the engagement’s own. ctx.settings holds the vault owner’s values from connect time.

How a workflow runs

A workflow is dispatched exactly like a code agent; its bundle is the platform’s workflow runner. A trigger event opens the run, and the runner walks the graph: each step’s output feeds the next, edges with conditions choose the path, and steps that wait (people, agents, connector actions) resume the run when their answer arrives as an event.

The sandbox

Code agents, and the runner itself, run in a JavaScript sandbox (a V8 isolate) with no Node.js runtime.

Available Not available
fetch process, Buffer
globalThis.crypto (randomUUID(), subtle.*) node:* built-in modules
TextEncoder, TextDecoder, typed arrays Database and socket clients
console.* (captured as task logs) A file system

cef build refuses an agent entry file that imports a banned module: fs, path, net, http, https, crypto, buffer, stream, os, process, child_process, and other Node built-ins (with or without the node: prefix), plus packages such as pg, redis, ws, axios, and node-fetch. The build checks the entry file only; a Node import deeper in your dependency graph fails at runtime instead. Use Web globals: globalThis.crypto.randomUUID() for ids, fetch for HTTP, Uint8Array and TextEncoder for bytes.

Three rules follow:

  • Nothing in memory survives. The same isolate may not handle the next event. Keep state in a cubby or the Memory Bank, and read it at the start of each handler.
  • A handler can run again. A failed Task is retried. Make every write idempotent: key rows with PRIMARY KEY or UNIQUE and use upserts.
  • No secrets in the bundle. Your bundle is published to content-addressed storage and is readable by whoever can resolve it. To reach an outside system with credentials, use a vault connector, whose secrets are sealed in the vault.

Limits

Limit Value When you hit it
Publish request body 1 MiB 413 PAYLOAD_TOO_LARGE. Store large data as a vault object and publish its path.
Events per publish call 100 413 PAYLOAD_TOO_LARGE. Publish in batches of 100 or fewer.
Event retention per stream 7 days Older events are dropped. Keep what you need later in a cubby or the Memory Bank.
Finished Jobs and their Tasks Kept 7 days Older runs are deleted.