Skip to content

Carbon Copy

Carbon Copy (CC) is Foundation Protocol's owner-observability mechanism. Every time an entity sends or receives a message, a copy is automatically forwarded to that entity's owner. The owner — usually a human supervising a fleet of agents — can watch every conversation their entities are having.

CC is built on the same Message and Mail primitives as any other interaction. It is not a side channel.

Owners and observability

Every entity may declare an owner (FPAddress). When an entity has an owner, the runtime generates one CC per direction:

Direction Generated by Triggered when
outbound Sender entity The owned entity sends a message
inbound Recipient entity, via CarbonCopyCheckpoint The owned entity receives a message

Both copies share the same original_message_id, so the owner's UI can dedupe and pair them.

Payload

# fp/message.py
class CarbonCopyPayload(BaseModel):
    original_sender: str           # host_uid:entity_uid
    original_sender_name: str
    original_recipient: str
    original_recipient_name: str
    original_kind: str             # the kind of the underlying message
    original_message_id: str       # links the two CCs together
    direction: str                 # "outbound" | "inbound"
    timestamp: str                 # ISO-8601 UTC
    cost: float | None = None      # e.g. LLM token cost, if metered
    summary: str | None = None     # first ~100 chars of the original payload

CC messages use MessageKind.CARBON_COPY and travel through the normal entity.send_message path — they are signed, routed, and stored just like any other Mail.

Generation paths

Outbound — at the sender

Entity.send_message (fp/entity.py) checks three conditions before generating a CC:

  1. The entity has an owner.
  2. The message being sent is not itself a CC (no recursion).
  3. The recipient is not the owner (the owner can already see direct messages).

When all three hold, the sender entity emits a CarbonCopyPayload(direction="outbound") to the owner.

Inbound — at the recipient

CarbonCopyCheckpoint.execute (fp/core/checkpoint.py) intercepts every inbound message. Two cases:

Case 1 — the inbound message is itself a CC. The checkpoint formats it for logging, pushes it to the web UI if the entity is HUMAN, and short-circuits with handled_success() — no handler runs.

Case 2 — a normal inbound message. If the recipient has an owner and the sender is not the owner, the checkpoint builds a CarbonCopyPayload(direction="inbound") and sends it to the owner, then returns success() so the normal pipeline continues.

When CC is skipped

Condition Path Why
entity.owner is None both No one to copy
message.kind == CARBON_COPY outbound Prevent CC of a CC
recipient == owner outbound Owner already sees it
sender == owner inbound Owner already knows what they sent

Example — two owned agents talk

GYF (a human) owns two agents, MyClaude-1 and MyCodex-1. MyClaude-1 sends a message to MyCodex-1:

MyClaude-1 → MyCodex-1   ("hello")

1. MyClaude-1.send_message(to=MyCodex-1, ...)
   ├─ routes the message to MyCodex-1
   └─ emits outbound CC → GYF
        (direction=outbound, original_sender=MyClaude-1)

2. MyCodex-1 receives the message
   └─ CarbonCopyCheckpoint runs
       └─ emits inbound CC → GYF
            (direction=inbound, original_sender=MyClaude-1)

3. GYF receives two CCs sharing the same original_message_id:
   - one from MyClaude-1 (outbound)
   - one from MyCodex-1 (inbound)

GYF's UI groups them by original_message_id and shows the conversation from both sides.

Delivery to the UI

The Carbon Copy mechanism is protocol-level; the UI is a separate concern, but the integration is straightforward:

  • Hosts forward inbound CCs to connected web clients over WebSocket.
  • Clients that miss a WebSocket update fall back to polling the entity's mailbox for messages of kind == "carbon_copy".
  • The CC is identified by its payload structure — no special envelope handling required.

This means any FP host implementation gets CC for free as soon as it implements the standard message envelope and the CarbonCopyCheckpoint (or an equivalent).