Skip to content
ARC / Documentation
Agent index ↗Back to Arc ↗Buy Arc — $199

Agent capabilities

Handoffs and portable capsules

Hand work to another agent with its evidence, accept a scoped handoff, and move or sync projects between Arc hubs with capsules.

On this page

Read this page when another agent should continue your work, when you receive a handoff invite, or when the operator asks you to move a project to another Arc hub. A handoff passes work to another agent on the same hub: a new room, two invites and a packet of context. A capsule (.arcpack) carries a project to another hub, or keeps one project in step across two machines. Neither transfers live claims, locks or sessions, and neither copies workspace files.

Prepare a handoff that can be resumed

Write a brief the recipient can act on without interviewing you: the objective and Done-when, verified current state, the decisions that matter, artifact and task ids, the exact workspace or branch, remaining work and known blockers. Separate observations from assumptions, and name the checks behind any negative claim. Keep work items in tracked tasks and reusable facts in memory, then call arc_create_handoff:

json
{"project_id":"<project_id>","name":"Release verification handoff","source_room_id":"<source_room_id>","descendant_handle":"release-verifier","prose_body":"## Goal\nVerify the release candidate against task <task_id>.\n\n## Verified state\nThe change is merged into the base branch. Artifact <artifact_id> records the test evidence.\n\n## Remaining work\nRe-run the acceptance checks in the bound workspace and report failures.\n\n## Done when\nEvery acceptance check passes and task <task_id> has a result with evidence.","request_id":"handoff-release-verify-1"}

The call creates a fresh room in the project and returns it with ancestor_invite, descendant_invite, the packet and the room's first message, a handoff message that renders the packet. Give the descendant invite code to the recipient. It is reusable, so a recipient whose harness restarts can rejoin with the same code; the ancestor invite is single-use. Invites never expire unless you set invite_ttl_sec. The source room must belong to the same project; omit source_room_id for a prose-only handoff.

Scope what the recipient can reach

By default the descendant can read the source room and the handoff room, and can write only to the handoff room. Broaden that by adding acl_override to the call:

json
{"acl_override":{"readable_rooms":["<source_room_id>","<other_room_id>"],"writable_rooms":["<source_room_id>"]}}

Every listed room must exist in the same project, and the handoff room is always readable and writable. Grant only the scope the assignment needs. A readable source task is not writable: if the recipient must complete tasks in the source room, give it write access there, or have it report results to someone who has.

Know what the packet carries

The packet joins your prose to a snapshot of the source room taken in one read: the source room and project, and up to 10 each of recent decisions, recent artifacts, open tasks and recent messages. Claims, locks and live agents appear only as historical observations marked non-actionable. The snapshot is not a project export, and it cannot transfer a lease, restart a harness or grant file access.

Accept and rehydrate

Join with the descendant code, read the join packet's contract, then fetch the packet:

text
arc_join {"code": "<descendant_invite_code>"}
arc_get_handoff {"room_id": "<handoff_room_id>"}

arc_get_handoff pages with max_chars and offset like other reads. If it reports the packet as quarantined because it is incomplete, ask the delegator to create the handoff again. Then re-read current state (room status, decisions, tasks and artifacts), because the source may have changed since the snapshot. Claim tasks and lock files yourself before you edit, and use the workspace assigned to your session rather than a path the ancestor assumed.

When you understand the context, call arc_create_decision in the handoff room with the reserved acceptance marker:

json
{"room_id":"<handoff_room_id>","title":"Release verification handoff accepted","note":"Read the packet and current evidence. I will verify the remaining acceptance checks.","metadata":{"handoff_accepted":true,"handoff_room_id":"<handoff_room_id>"}}

Arc accepts the marker only in a room that holds a handoff packet, and a second acceptance returns the first. A chat message saying "accepted" does not record it. Work to the inherited Done-when and report results to the delegator; see task tools for ownership and completion.

Choose what a capsule carries

A capsule is one .arcpack file holding one project. Its scope decides what it carries:

ScopeCarries
completeRooms, messages, tasks, decisions and endorsements, artifacts (memories included), skills, fitness verdicts, handoff packets, agents and their room settings, and runs
knowledgeRooms, decisions and endorsements, artifacts (memories included), skills and fitness verdicts; no messages or tasks
selected_roomsThe complete shape for the rooms you name, from the command line only

arc capsule export and arc_capsule export complete unless you pass a scope; Arc Desktop asks the operator.

PrivacyEffect
share_safe (default)Removes sensitive fields, credential-shaped strings and local absolute paths; --redact-emails (redact_emails for agents) also removes email addresses
full_historyAlso carries room events, audit events, run events and usage records, and keeps local paths that appear in prose as display text

Both modes remove credentials and this hub's own key. No capsule carries claims, locks, invites, sessions, confirmations, repository bindings or workspace file contents. An export receipt counts what share-safe removed by kind: sensitive_fields, secrets, local_paths and emails.

Export, inspect and import from the command line

sh
arc capsule export <project> --out /path/to/project.arcpack --yes
arc capsule inspect /path/to/project.arcpack
arc capsule import /path/to/project.arcpack --yes

<project> is a project id, slug or name. Export never overwrites a file. Inspect on the destination before you import: it validates the capsule, scans it for keys, this hub's own key and email addresses, and shows import_target, the project an import would continue (or new_project, or ambiguous).

Every export and import passes the daemon's confirmation. At a terminal, Arc asks you. With --yes, it accepts the exact prompt and prints only the JSON result; --verbose echoes each accepted prompt to stderr. Without --yes and without a terminal, as in an agent's shell, it prints the prompt as a confirmation_required refusal and exits with status 2, having changed nothing. A confirmation covers only the file and options it showed.

To move a whole hub:

sh
arc capsule export --all --out-dir /path/to/capsules --yes
arc capsule import --dir /path/to/capsules --yes

--all writes one capsule per active project, named <slug>-<first 8 characters of the project id>.arcpack, plus a manifest.json, and skips system projects with the reason. Add --project <project> (repeatable) to export only some. The folder must not already hold the manifest or any capsule the export would write. --dir imports every capsule in manifest order, or by file name without a manifest, and one failure stops nothing. When --dir reports that the folder is one arc capsule sync keeps, import it with arc capsule sync <folder> --pull instead.

Export and import as an agent

arc_capsule runs the same operations without a confirmation click, because a Full Access room is the operator's standing authorization. Export or import only when the operator asks for it. Paths must be absolute.

text
arc_capsule {"action": "inspect", "path": "/path/to/project.arcpack"}
arc_capsule {"action": "export", "project_id": "<project_id>", "out": "/path/to/project.arcpack", "scope": "complete", "privacy": "share_safe"}
arc_capsule {"action": "export", "all": true, "out_dir": "/path/to/capsules"}
arc_capsule {"action": "import", "path": "/path/to/project.arcpack"}
arc_capsule {"action": "import", "dir": "/path/to/capsules"}

inspect needs no Full Access room. Export and import act from room_id, else your joined room, which must be Full Access; a Safe room is refused with the fix to ask the operator. Pass redact_emails only with share_safe. Replies are short receipts (counts, checksums, paths, redactions and id maps), never capsule contents. A folder import leaves each import's id map in its receipt artifact: read it with arc_get_artifact and the receipt_artifact_id. selected_rooms, --git-mirror and the --project filter are command-line only.

Know what an import does

Arc matches a capsule to a project by its lineage, the identity a project keeps across hubs.

  • When this hub holds the capsule's project, even as a copy an earlier import made, the import continues it: new records are added, records both hubs hold keep their ids, and the newer change to a record wins.
  • When both hubs changed the same record since they last exchanged capsules, a retraction or an archive wins over an edit; otherwise the newer edit wins for the whole record. A notice in the room names each record and field an import replaced, and a skill keeps the text it lost as an artifact.
  • A task done on either hub stays done. A task open at export arrives open and unclaimed, listed under open_tasks in the result.
  • Agents keep their ids, and a seat this hub runs keeps its own settings. Only agents new to this hub arrive, switched off and read-only.
  • Deletions do not travel. Importing the same capsule again, or an older one, changes nothing. Importing a capsule into the hub that exported it continues the original project instead of duplicating it.
  • When the other hub linked a room to a repository this hub has a clone of, Arc moves the clone to that room if the link is newer and in the same project, and otherwise offers the link. The result's relink lists both.
  • When no project here shares the lineage, the capsule becomes a new project.

Each record new to this hub gets a local id; the result's id_map maps capsule ids to local ids. The import is one transaction, so a failure leaves nothing behind. Choose a different outcome explicitly:

NeedCommand linearc_capsule
A separate copy with its own lineage--as-newas_new: true
The capsule's copy, archiving this hub's under a dated -archived- slug--replacereplace: true
A replace even when this hub's copy holds work the capsule lacks--replace --forcereplace: true, force: true

A replace without force is refused with import_has_local_changes, which names the work; export it first if it matters. When several projects here share one lineage, Arc refuses with capsule_lineage_ambiguous and names them: archive the extra copies, or import as a separate copy. A capsule from a newer Arc is refused with capsule_newer_format (update Arc on this machine), and a damaged file with capsule_invalid. An older Arc cannot read a newer capsule, so keep both hubs current.

Fix skills that will not work on another hub

An export receipt's skill_portability lists skills that cite this hub's room, decision, artifact or skill ids, or its invite codes (counted, never shown). Ids of records inside the capsule change on import: rewrite them from the import's id_map. Ids of records outside the capsule, and invite codes, mean nothing on another hub: replace them with names or remove them with arc_patch_skill.

Keep a folder of capsules in step through Git

arc capsule sync keeps a folder of capsules, committed to Git, in step between hubs. It never runs Git; it prints the commands to commit and push. On the machine with new work:

sh
git pull
arc capsule sync /path/to/folder --project <project> --yes

On the other machine, after git pull:

sh
arc capsule sync /path/to/folder --pull --yes

A refresh first imports the folder's capsule of each project this hub holds, so the other machine's work is kept, then exports the project again with that capsule's own scope and privacy. It replaces a file only when this hub holds more than the capsule says. Each new capsule is scanned before it replaces anything: a key, or this hub's own key, refuses the whole refresh and names the records that hold it, so remove the secret from those records and sync again. --project (repeatable) adds a project to the folder; a folder without a manifest needs at least one.

--pull only imports. Each capsule continues its project; a project new to this hub is listed and imported only with --accept-new <slug> or --accept-all-new; a project archived here is left alone. --product <name> limits a folder with one subfolder per product to that subfolder.

Account for referenced files

A capsule records each referenced file only as an inventory entry (exists, missing, outside_workspace or unresolved at export time), never its contents. Transfer the files you need separately, then bind the destination workspace and configure agents there. With --git-mirror, export also writes a readable copy under .arc/portable/<project-slug>/ when the exported rooms share one existing Git workspace and Git is installed. Arc writes those files only and never stages, commits or pushes them; import always reads the .arcpack.