← Receivers

agent:handover-accept

agent family

The person an agent was offered to accepts it, in their own session or human key — a compare-and-set on the agent's ownership; the Own press re-proves the link (owner · seat · vault) and lands seat → owner → chain, reverting on any refusal

Effect
ask
Awaits an outcome — the call returns the response below.
Caller
owner
The class of authority the caller must already hold, decided from the attested context with no round trip.
Cost
free
What one call costs, so you can budget before acting.
Reversible
no
This cannot be undone. Dry-run it first where the contract allows.
Idempotent
no
Not safe to blind-retry — dedupe on the envelope idempotencyKey.

Send it with your agent

One click hands your coding agent a prompt that registers the substrate, reads this contract, and makes the call. Launch opens the app; the others copy the prompt.

Claude Code
Codex
Cursor
Gemini CLI
Claude Desktop
ChatGPT
curl -X POST https://one.ie/api/ask/agent:handover-accept \
  -H "Authorization: Bearer $ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data": { "agent": "scout", "nonce": "<nonce>" }}'

The key is never in a link. npx -y @oneie/cli login writes it to ~/.config/oneie/key on your machine.

Request

Validated before dispatch — an invalid payload is refused with the fix, never half-applied.

  • agent string optional The agent's actor id. Required person-to-person; the Own press (/get-key?own=<offer>) knows only the offer, which names its agent
  • nonce any required The offer's nonce
  • address string optional The Own press: the Sui address of the key the redeemer kept
  • signature any optional The Own press: { publicKey, signature } (hex) by that key over the 'ONE vault handover' statement

Response

What comes back from the call.

  • ok boolean
  • accepted boolean
  • agent string
  • owner string
  • previousOwner string
  • next string
  • vault string
  • address string
  • chain any The vault facade's answer to transferOwner: { digest } or { error } — never a claimed digest. { owner, confirmedBy: 'read' } when the transfer's answer was lost — or when the AGENT signed it in its own runtime — and the vault read back names the new owner. { error: 'agent_signs', vault, to, net } on a published vault: the server holds no key, the agent signs transfer_owner(vault, to) itself (round 7 repair 1)
  • workspace object The workspace owner seat the link carried, granted on the Own press before the owner and the chain moved
  • undo any On a refusal only: a revert that itself did not land, named — { owner?: 'failed', seat?: <verdict>, offer?: 'failed', seatPending?: string[], residual: ('owner_revert_failed' | 'seat_revoke_failed' | 'seat_unproven' | 'seat_pending' | 'offer_unreserve_failed' | 'saga_unrecorded')[] }. Absent, nothing moved: every half was read back absent and every recorded seat attempt has settled. offer_unreserve_failed: the offer stayed spent, so the same redeemer cannot press again — the agent mints a new link (nothing else moved only when it is the sole residual). seat_revoke_failed: the seat is recorded on the offer row and the next press takes it back. seat_unproven: a seat write was not answered and the read-back ran too soon to prove it absent (a write the gateway aborts may still commit and take ~0.5s to become readable) — the attempt is APPENDED to the offer row's attempts with the time the write was sent and the time it answered or aborted, never overwritten by a later press; every later refusal reads every attempt back by its own times and drops it only once settled absent or taken back, and a press that lands clears them all. seat_pending: a recorded seat is on a gid (named in seatPending) where ANOTHER press of this agent is reserved and not yet landed — that press may hold the seat or still be refused, so the record is kept, never dropped and never reverted, and a later press settles it by the read-back once that press lands (explained, dropped), lapses or is refused (read back and reverted). saga_unrecorded: the row could not be written, so the next press cannot see the residual; a press held at the chain this way is found by the next press from the owner record and resumed. The agent has been warned
  • pending boolean chain_pending: the chain was asked and could not be read back — seat and owner stay, the offer stays reserved, the row records the target; the redeemer's next press resolves it (finishes, retries, or reverts). agent_signs: the vault is published and the server never signs — the agent signs transfer_owner to the recorded address in its own runtime; seat and owner are NOT held moved while it waits, the offer stays reserved for the redeemer, and the next press lands both halves once the chain names the kept key (round 7 repair 1)
  • cause string On reserve_failed | link_unreadable | seat_failed | owner_failed | vault_unreachable | chain_pending: the message of the call that threw, so the press names what it could not do
  • closed mark | warn | dissolve
  • error string offer_invalid | human_presence_required | offer_not_found | not_offered_to_you | offer_already_accepted | offer_expired | offer_stale | invite_not_redeemed | redeemer_unresolved | owner_proof_invalid | reserve_failed | seat_lost | seat_unreadable | seat_failed | vault_not_held | vault_unreadable | vault_refused | agent_signs | link_unreadable | owner_failed | vault_unreachable | chain_pending — every refusal after the reservation reverted what had landed and gave the offer back (an unanswered write is read back first, never counted 'did not land'; one that answered ok with zero rows did not land); undo names a revert that did not; chain_pending is the one named pending state, resolved by the next press; redeemer_unresolved: the link was opened by an account that has no slug yet

Traffic

Every call to agent:handover-accept, counted where it is dispatched — over HTTP or in-process alike. Aggregate only — no actor, no payload, no workspace.

Counting…

Wiring

Every place in the open source that names agent:handover-accept, and the file that answers it. Read from the tree at build time — a receiver is reached by NAME through one door, so there is no import edge to follow and a grep is the honest shape of the question. Structure, not volume — the count is in Traffic above.

Called from

UI 1
  • one.ie/web/src/components/key/KeyFlowBlocks.tsx:508
API route 2
  • one.ie/web/src/lib/receiver-index.generated.ts:22
  • one.ie/web/src/lib/training/scenarios.ts:196
→

Answered by

agent:handover-accept one.ie/web/src/lib/resolvers/agent-handover.ts:1270 Dispatched through POST /api/ask/agent:handover-accept, after the envelope validates the payload.
JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "agent": {
      "description": "The agent's actor id. Required person-to-person; the Own press (/get-key?own=<offer>) knows only the offer, which names its agent",
      "type": "string"
    },
    "nonce": {
      "description": "The offer's nonce"
    },
    "address": {
      "description": "The Own press: the Sui address of the key the redeemer kept",
      "type": "string"
    },
    "signature": {
      "description": "The Own press: { publicKey, signature } (hex) by that key over the 'ONE vault handover' statement"
    }
  },
  "required": [
    "nonce"
  ]
}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "accepted": {
      "type": "boolean"
    },
    "agent": {
      "type": "string"
    },
    "owner": {
      "type": "string"
    },
    "previousOwner": {
      "type": "string"
    },
    "next": {
      "type": "string"
    },
    "vault": {
      "type": "string"
    },
    "address": {
      "type": "string"
    },
    "chain": {
      "description": "The vault facade's answer to transferOwner: { digest } or { error } — never a claimed digest. { owner, confirmedBy: 'read' } when the transfer's answer was lost — or when the AGENT signed it in its own runtime — and the vault read back names the new owner. { error: 'agent_signs', vault, to, net } on a published vault: the server holds no key, the agent signs transfer_owner(vault, to) itself (round 7 repair 1)"
    },
    "workspace": {
      "description": "The workspace owner seat the link carried, granted on the Own press before the owner and the chain moved",
      "type": "object",
      "properties": {
        "gid": {
          "type": "string"
        },
        "role": {
          "type": "string"
        },
        "landed": {
          "type": "boolean",
          "const": true,
          "description": "Always true on an ok answer: the Own press lands seat → owner → chain or reverts every write — an ok answer cannot carry a seat that did not land"
        },
        "verdict": {
          "type": "string"
        }
      },
      "required": [
        "gid",
        "role",
        "landed",
        "verdict"
      ]
    },
    "undo": {
      "description": "On a refusal only: a revert that itself did not land, named — { owner?: 'failed', seat?: <verdict>, offer?: 'failed', seatPending?: string[], residual: ('owner_revert_failed' | 'seat_revoke_failed' | 'seat_unproven' | 'seat_pending' | 'offer_unreserve_failed' | 'saga_unrecorded')[] }. Absent, nothing moved: every half was read back absent and every recorded seat attempt has settled. offer_unreserve_failed: the offer stayed spent, so the same redeemer cannot press again — the agent mints a new link (nothing else moved only when it is the sole residual). seat_revoke_failed: the seat is recorded on the offer row and the next press takes it back. seat_unproven: a seat write was not answered and the read-back ran too soon to prove it absent (a write the gateway aborts may still commit and take ~0.5s to become readable) — the attempt is APPENDED to the offer row's attempts with the time the write was sent and the time it answered or aborted, never overwritten by a later press; every later refusal reads every attempt back by its own times and drops it only once settled absent or taken back, and a press that lands clears them all. seat_pending: a recorded seat is on a gid (named in seatPending) where ANOTHER press of this agent is reserved and not yet landed — that press may hold the seat or still be refused, so the record is kept, never dropped and never reverted, and a later press settles it by the read-back once that press lands (explained, dropped), lapses or is refused (read back and reverted). saga_unrecorded: the row could not be written, so the next press cannot see the residual; a press held at the chain this way is found by the next press from the owner record and resumed. The agent has been warned"
    },
    "pending": {
      "description": "chain_pending: the chain was asked and could not be read back — seat and owner stay, the offer stays reserved, the row records the target; the redeemer's next press resolves it (finishes, retries, or reverts). agent_signs: the vault is published and the server never signs — the agent signs transfer_owner to the recorded address in its own runtime; seat and owner are NOT held moved while it waits, the offer stays reserved for the redeemer, and the next press lands both halves once the chain names the kept key (round 7 repair 1)",
      "type": "boolean"
    },
    "cause": {
      "description": "On reserve_failed | link_unreadable | seat_failed | owner_failed | vault_unreachable | chain_pending: the message of the call that threw, so the press names what it could not do",
      "type": "string"
    },
    "closed": {
      "type": "string",
      "enum": [
        "mark",
        "warn",
        "dissolve"
      ]
    },
    "error": {
      "description": "offer_invalid | human_presence_required | offer_not_found | not_offered_to_you | offer_already_accepted | offer_expired | offer_stale | invite_not_redeemed | redeemer_unresolved | owner_proof_invalid | reserve_failed | seat_lost | seat_unreadable | seat_failed | vault_not_held | vault_unreadable | vault_refused | agent_signs | link_unreadable | owner_failed | vault_unreachable | chain_pending — every refusal after the reservation reverted what had landed and gave the offer back (an unanswered write is read back first, never counted 'did not land'; one that answered ok with zero rows did not land); undo names a revert that did not; chain_pending is the one named pending state, resolved by the next press; redeemer_unresolved: the link was opened by an account that has no slug yet",
      "type": "string"
    }
  },
  "required": [
    "ok"
  ]
}