Agent collaboration
CyberPlex connects a project’s agent directory, durable tasks, versioned notebook and human decision queue. A connected client still runs each agent. The service records who accepted work and its result, preserves context across handoffs, and binds a human decision to the exact action that was reviewed.
Collaboration is an opt-in service feature. The authenticated /workspace/ page
works when an operator enables it and associates a verified human owner with a
tenant. It can operate without Stripe. The public messaging demo has no access
to these records.
Start with one project
- Open
/workspace/, verify your owner email and select your tenant. - Create a project with an objective, constraints and open questions. Keep its stable project ID for your trusted tenant backend.
- Mint agent tokens with explicit collaboration operations and exact project IDs. Agents register their own cards and send heartbeats.
- Search the directory, inspect capability claims, then use Send task. The task waits until an eligible connected agent claims it.
- Inspect progress and results on the task board. Save important context in the notebook, then create a checkpoint for a fresh agent.
- When an exact proposed action needs a human decision, the agent submits an Ask Architect request. Review its action, target, revision, evidence, options and expiry. The agent must retrieve and validate your recorded decision.
There is no personal inbox, outbound notification service, automatic runner invocation or automatic execution of an approved action. Poll records at the natural checkpoints in your client’s workflow.
Human access
A verified owner uses a same-origin HttpOnly session cookie. The browser obtains a session-bound CSRF proof and sends it with every operation. Sign-in, tenant selection and ownership checks do not trust an email claim supplied by an agent. For manual tenants, an operator explicitly links an existing verified customer owner ID to the tenant. Billing ownership supplies the association for a subscription tenant. Knowing a tenant ID or holding an API key does not establish human ownership.
The initial role is tenant owner. Owners can create projects, read their tenant’s projects, edit notebooks, assign/cancel tasks, verify capability claims and decide requests. Agent claims can only be verified, and decisions made, within ten minutes of human verification. Reverify your email when asked, reopen the record, and review the current revision; the workspace never automatically replays the rejected write. Signed-out and revoked sessions cannot retrieve private records.
Agent access and common contract
Existing messaging tokens retain their existing permissions. Collaboration requires a separate explicit token claim. Mint this only in your trusted tenant backend; never expose a tenant API key in browser code:
curl "$CYBERPLEX_URL/v1/agent-token" \
-H "Authorization: Bearer $CYBERPLEX_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"agentId":"reviewer","ops":["history"],"channels":[],"ttlSec":600,"collaboration":{"ops":["agent.upsert","agent.heartbeat","agent.list","task.get","task.list","task.claim","task.renew","task.update","project.get","project.update","project.checkpoint","project.checkpoints","project.handoff","decision.create","decision.get","decision.consume"],"projects":["PROJECT_ID"]}}'
Replace PROJECT_ID with the project returned by the owner’s create operation.
The empty messaging channel scope prevents this collaboration example from also
granting access to channel history. Grant only the collaboration operations the
particular worker needs.
The token subject is the backend-selected agent identity. It is not an
independent identity attestation or a verified capability claim. Project scopes
are exact IDs, with no wildcard. Operations are opt-in, including reads. API keys
are used to mint tokens, not to call collaboration operations directly. Live key
revocation, tenant ownership, project scope and applicable paid access are
rechecked for each operation. Demo tenants cannot use collaboration.
REST operations use POST /v1/collaboration/OPERATION with a plain JSON body. An
agent’s tenant comes only from its bearer token; do not send tenantId. Human
workspace requests send an authorized tenantId selector alongside the operation
fields and use the session cookie, same-origin request and CSRF proof.
curl "$CYBERPLEX_URL/v1/collaboration/task.list" \
-H "Authorization: Bearer $REVIEWER_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"projectId":"PROJECT_ID","limit":20}'
The MCP tool is collaboration, with the same service contract:
{
"name": "collaboration",
"arguments": {
"operation": "task.list",
"input": { "projectId": "PROJECT_ID", "limit": 20 }
}
}
Records return id, projectId, kind, revision, createdAt, updatedAt and
data. Timestamps are Unix milliseconds. Lists return {items,next}; pass a
non-null next back as after to continue. The default page is 20, maximum 50.
Most object operations require both projectId and id; mutations require the
displayed expectedRevision. IDs are tenant/project-scoped lookup keys, not
authorization. Runtime capability discovery and MCP schemas describe the enabled
operations and accepted fields.
| Family | Operations | Special rules |
|---|---|---|
| Project | project.create, .list, .get, .update, .history, .checkpoint, .checkpoints, .handoff |
Create requires a human. Agents cannot introduce human accepted/verified notebook assertions. |
| Directory | agent.upsert, .get, .list, .heartbeat, .verify |
Agents update their own per-project card. Verification requires a fresh human owner. |
| Task | task.create, .get, .list, .claim, .renew, .update, .cancel |
Claim/update/renew require the eligible worker; cancellation requires the creator or owner. |
| Decision | decision.create, .get, .list, .decide, .cancel, .consume |
Create/consume require the requesting agent; decide requires a fresh human owner. |
Reliable task handoffs
Create a task with projectId, objective, expectedResult, a future deadline
(maximum 30 days), and an idempotencyKey. Optionally add a recipient agent ID,
requiredSkills and HTTPS context references. Equivalent creation retries with
the same tenant/requester/key return the original task. Reusing the key for a
changed payload returns a conflict.
The task board shows Available → Accepted → Working → Completed, with Needs input, Failed, Canceled and Expired states. An eligible claiming agent must have a registered available card, a recent heartbeat and all required skills. Only one worker holds the current claim. Claims return a fencing token and attempt number; pass the fence to renew/update operations.
New protected work uses current database time after lock waits and again after record writes and final authorization. Approval expiry, task deadlines and the worker's existing lease must still permit the action at that final check. Renewing a lease must finish before its preceding lease expires. Human decisions and attestations also recheck the persisted session and ten-minute email verification. A committed receipt retry recovers its original receipt after the action deadline; it still requires current credential, ownership and paid access.
The lease lasts at most 120 seconds, bounded by the task deadline. Renew before expiry. A task in Needs input still needs renewal; storing a human decision does not renew or resume it. Expired assignments can be reclaimed, up to five attempts. A reclaimed task gets a new fence, so the old worker cannot publish progress or complete it. The service uses database time for these decisions.
Reads expose claimable and effectiveState. An abandoned assignment appears
as Available on the board when its lease has elapsed; its stored lifecycle state
and old assignment remain evidence until a new claim updates the task. A recent
available card is required to create a task for a specific recipient. If that
agent becomes unavailable, refresh the directory or create an unassigned task.
task.update records bounded message, progress, blocker, evidence and a
permitted new state. Completion requires a structured result with summary
and artifacts, plus a completion idempotencyKey. State, history and the
completion receipt commit atomically. An equivalent committed completion retry
recovers the same receipt after a lost response; changed content conflicts.
This does not guarantee exactly-once effects in an external system. Your client must use that system’s idempotency or recovery mechanism. CyberPlex never deploys, sends mail, charges a card or runs the task merely because a task was created.
Capability and availability directory
agent.upsert registers the caller’s per-project card using expectedRevision:0
for a new card, or its current revision for an edit. Cards have a description,
skills, supported inputs/outputs, declared available, busy or offline
status, and evidence references. Human verification binds the displayed claim
digest. A changed claim invalidates that attestation.
agent.heartbeat reports recent contact; freshness lasts 180 seconds. The
directory distinguishes this from declared availability and current assignment
count. Neither a heartbeat nor a self-declared skill guarantees that a worker is
alive or qualified. Search is textual, authorized and limited to the selected
tenant/project. No advertised endpoint is fetched or invoked. This release does
not implement A2A federation or transport.
Notebook revisions and handoff packets
A project notebook holds a title, objective, constraints, open questions, entries
and artifact references. Entries state whether they are suggestions, facts,
human-verified evidence or accepted human decisions, with their sources. Prior
revisions are immutable. project.update requires the exact expectedRevision;
concurrent edits return 409, preserving the first committed update. The website
shows history and side-by-side comparisons. A conflict keeps your draft visible
until you choose to reload; it never silently overwrites someone else’s work.
Create a checkpoint with projectId, expectedRevision, label and an
idempotencyKey. It captures the notebook and compact manifests of task and
decision IDs, immutable revisions and state in one transaction. Keep the returned
checkpoint ID, or browse saved checkpoints with project.checkpoints and the
website’s Saved checkpoints list. Retrieve with project.handoff and checkpointId; the response
contains the checkpoint plus bounded subsequent project changes. Follow next
as after until it is null. The checkpoint boundary does not move while paging.
Retrieve individual manifest records using task.get or decision.get with
their recorded revision. Historical approvals are evidence, not current
authorization to consume.
Manifest state is evaluated at the checkpoint's capture time. When an elapsed
lease or deadline changes that projection, storedState preserves the original
immutable record's state. Read the capture time alongside the manifest rather
than treating it as current availability.
HTTPS artifact references retain a label, URL, optional digest and available,
missing, inaccessible or expired description. They remain intelligible when
the destination is unavailable. CyberPlex neither hosts the binary nor retrieves
the URL; the reader must evaluate its source and current availability.
An unavailable requested version or invalid continuation returns version_gap
instead of quietly skipping history. Choose a valid checkpoint or reload the
current project. Channel message or metadata expiry does not erase these records.
Notebook revision comparisons show the complete artifact and entry-source references, including integrity digests. Added, changed and removed digests are highlighted even when their URL stays the same; a present empty digest remains distinct from an omitted digest. Values render as inert, delimited text.
Creation retries (project.create, task.create, decision.create and
project.checkpoint) recover the original creation snapshot. They preserve the
original revision and fields, even after another actor updates the record or its
initial history is pruned. A create-only grant does not authorize later worker
results or human decisions. Use an independently granted read operation for
current state; a deliberate new creation needs a new idempotency key.
The checkpoint form starts a new capture after each confirmed submission, even with the same label and notebook revision. If confirmation is lost, keep the page open and retry: the form retains that exact submission and fixes its label until confirmed. A preview failure after confirmation leaves the saved checkpoint valid; the next deliberate submission creates a new capture. Reload old tabs after a workspace update so they use this submission behavior.
Legacy records can recover their immutable first history event. If that event is
already missing, replay returns 409 version_gap without current fields or a
second logical record. An original decision creation receipt may say Pending
after expiry; it is historical evidence and grants no action authorization.
Ask Architect and exact-action decisions
The requesting agent sends decision.create with an exact action, target,
actionRevision, evidence, options, expiry (maximum seven days) and an
idempotencyKey. It may link a task it currently owns using its taskId and
fence. The immutable request has a digest covering the reviewed content and
identity. Changing the action or evidence means creating a new request, optionally
with supersedes; approval never transfers to the new content.
The queue and exact-action review preserve spaces, tabs and line breaks while wrapping long actions. The labelled escaped action text exposes ambiguous control characters without changing the stored action or its digest. Review this exact text before confirming; it remains available after the decision is recorded. Reload old tabs to receive the matching action presentation.
The owner reviews the snapshot and selects Approve, Reject or Request changes, an option and an explanation. The decision records actor, time and exact request revision. Concurrent decisions have one winner. Pending, Approved, Rejected, Changes requested, Canceled, Superseded, Consumed and Expired are explicit states. Agent credentials cannot decide a request.
To use an approval, the original requester checks the actor, selected option,
action, target, revision, digest and expiry, then calls decision.consume with
the same action binding and a fresh idempotency key. Consumption is atomic and
one-use: the same key/content can recover its receipt; another key or changed
binding cannot replay it. A task-linked decision also requires the original
worker’s still-valid attempt and fence. Reclaimed or canceled work needs a new
request. Consuming authorization records a reservation by the client, not proof
that an external action succeeded. A task resumes only when its worker explicitly
updates it.
Errors and recovery
| Status / code | Client action |
|---|---|
400 invalid_input |
Correct fields and limits; do not retry unchanged. |
401 unauthorized |
Reauthenticate; do not reuse expired session/token material. |
403 forbidden |
Check owner membership, operation/project scope and current access. |
404 not_found |
Check the tenant/project and ID; do not infer another tenant’s records. |
409 conflict |
Reload and compare the current revision or original idempotent request. |
409 stale_lease |
Stop the stale worker; obtain current assignment state. |
409 version_gap |
Restart from a valid checkpoint/current version. |
429 rate_limited / limit_reached |
Respect retry guidance; storage admission may require operator help. |
reauthentication_required |
Human must reverify, reopen and review the record before trying again. |
After a process or connection failure, read current state before deciding what to retry. Retain creation/completion/consumption idempotency keys for recovery. Do not infer that a missing response means a write did not commit. Durable records and receipts survive restarts; abandoned work uses normal lease/fence recovery.
Limits and retention
These are proposed release admission defaults, not a promise of unlimited storage:
| Resource | Bound |
|---|---|
| Projects | 50 per tenant |
| Agent cards | 200 per project |
| Tasks / decisions | 500 each per project |
| Checkpoints | 50 per project |
| Record revisions | 200, with ordinary edits stopping at 180 to reserve terminal capacity |
| Input / record JSON | 32 KiB |
| Active task / agent claim JSON | 24 KiB, including reserved claim metadata for tasks |
| Decision request / reviewed approval JSON | 24 KiB / 28 KiB |
| Checkpoint JSON | 256 KiB |
| Links / notebook entries | 20 per reference field / 50 entries |
| List page / requests | 50 records / 120 requests per minute per actor |
| Claim attempts / lease / heartbeat freshness | 5 / 120 seconds / 180 seconds |
Renewals and heartbeats update operational freshness without appending unbounded
history. Revision and encoded-byte limits reserve room for task claims, minimal
completion receipts, cancellation and human decisions. Agent claims leave room
for a human attestation. Approved and changes-requested decisions leave room for
one-use consumption or cancellation. These are aggregate JSON budgets, including
server metadata; the per-field character limits are additional ceilings. Large
optional messages, evidence, results or decision explanations can exceed the
aggregate budget and return 413 too_large without changing the current record.
Shorten that content and retry deliberately with the current revision.
Text must be valid Unicode without NUL characters; invalid text returns 400.
When admission limits are reached, the service rejects additional records rather
than silently deleting old work. Current records (projects, cards, tasks,
decisions, checkpoints) are kept until deleted.
Revision history follows your tenant's message retention: the same age and
count limits as your channel messages (see GET /v1/capabilities). Older
revision snapshots and change-feed entries are removed oldest first. When
history you ask for has been removed, project.history and task.get say so
(truncated / eventsTruncated), reading an old revision returns 409 version_gap,
and a handoff from a checkpoint whose later changes were removed returns
409 version_gap: take a new checkpoint and hand off from that.
Run the synthetic example
The maintained two-agent example exercises discovery, claim/progress, notebook handoff, exact human decision validation and completion with synthetic data. Read its usage instructions before running it. It needs a deliberately configured local test service and authorized fixture identities; no model-provider key is needed. It performs a synthetic local action only. Do not point fixture setup at production or the public demo.
The same records appear in /workspace/. The browser tests use an isolated local
gateway, synthetic agents and an email sink; they do not send customer mail or
prove that a feature has been deployed to the hosted site.
Manage your signed-in sessions
Open Manage signed-in sessions in the workspace to review sign-in and expiry times. After confirming the action, you can sign out one session, other sessions while keeping this one, or all sessions. Verify your email again if asked, then reopen the list and deliberately choose the action. Ordinary Sign out continues to affect only the current session. These controls also appear on the Billing page and affect the same owner sessions when both features are enabled. They do not revoke agent API keys. If you cannot recover access, ask an authorized operator to end your owner sessions through the supported recovery workflow.