Example setup
Purpose: show exactly how two KyberBot users go from "ARP installed" to "agents talking under policy" — with the real commands, the real browser steps, and the real wire-level flow.
Cast: Anna runs KyberBot agent Atlas on her Mac. Bob runs KyberBot agent Mythos on his. Both want Mythos to be able to ask Atlas about a project named alpha — and only that project.
1. Provision the agent in the cloud — browser
Each user, independently, on their own machine:
- Open
cloud.arp.runand sign up with a passkey - Claim a
<name>.agentdomain — Anna picksatlas.agent, Bob picksmythos.agent - Provision the agent — the cloud generates the agent's key pair, the principal binding, and a handoff bundle
- Click Download handoff →
arp-handoff.jsonlands in the browser's Downloads folder
The handoff bundle is the credential the local bridge uses to authenticate to gateway.arp.run. It contains the agent did:web, the principal did:key, and the gateway WebSocket URL.
2. Drop the handoff into the agent folder — terminal
The agent folder is the KyberBot folder — the one that holds identity.yaml, .env, data/, skills/. Anything that runs kyberbot on your machine is already pointed at one.
mv ~/Downloads/arp-handoff.json ~/atlas/ # Anna
mv ~/Downloads/arp-handoff.json ~/mythos/ # Bob
3. Install the ARP CLI — terminal, one-time per machine
npm i -g @kybernesis/arp@latest
Brings arpc onto PATH. Doesn't touch the KyberBot install — they're independent npm packages.
4. Initialize ARP in the agent folder — terminal
cd ~/atlas
arpc init --framework kyberbot
Creates arp.json declaring "framework": "kyberbot" plus a "kyberbot": { "root": "." } block. The bridge reads this on startup to know which adapter to load.
5. Install the bridge service — terminal, one-time per machine
arpc service install
Registers a macOS LaunchAgent (or systemd unit on Linux) that runs the bridge in the background, dialing gateway.arp.run with the handoff credentials. The bridge pings KyberBot's /health endpoint on startup so a misconfigured install fails fast.
Verify:
arpc service status # → installed · loaded · pid <N>
arpc host status # → running · pid <N> (via launchd)
Both Anna and Bob now have the bridge running. Atlas and Mythos can be reached over ARP, but no connection has been formed between them yet.
6. Tag memories on the source side — KyberBot's remember skill
This is the part that makes policy meaningful. Tagging is the gate. An untagged memory is private; a --project alpha memory is shareable through alpha-scoped connections.
The remember skill (shipped with KyberBot) tells the LLM to set tags whenever the user clearly names a project or sensitivity context. Atlas's LLM, talking to Anna, runs:
kyberbot remember "Sarah Chen joined the project alpha team as ML lead" \
--project alpha \
--tag hiring
kyberbot remember "Weekly sync notes — alpha v1 ships March 15" \
--response "Slipped from Feb 28 due to QA cycle" \
--project alpha \
--tag roadmap
kyberbot remember "Internal team list for project alpha" \
--project alpha \
--classification internal
Each row lands in ~/atlas/data/messages.db, entity-graph.db, and ChromaDB metadata with project_id='alpha' stamped. Memories without --project alpha (or with --project beta) will not match an alpha-scoped peer query — by construction, not by trust.
| Flag | When it fires |
|---|---|
--project <slug> | Memory is specifically about a named project |
--tag <name> (repeatable) | Cross-cutting themes |
--classification public|internal|confidential|pii | Sensitivity tier — drives default obligations |
7. Pair Atlas → Mythos in the browser — issuer side
Anna opens cloud.arp.run/pair, picks Atlas as the issuer, types did:web:mythos.agent as the audience.
Now picks scopes — this is where policy is set:
- Preset: Project collaboration
project_id:alpha
The cedar policies generated by the picker read like:
permit (
principal == Agent::"did:web:mythos.agent",
action == Action::"search",
resource is NotesCollection
) when {
resource.project_id == "alpha"
};
Anna clicks Generate invitation → gets a cloud.arp.run/pair/accept#<payload> URL → shares it with Bob over a trusted channel.
For two-way communication, Anna can also pick scopes for the reverse direction in the "WHAT YOU GRANT THEM IN RETURN" picker — or Bob can on the accept screen (whoever sets it first).
8. Accept the invitation in the browser — audience side
Bob opens the URL on his machine. The accept screen shows two panels:
- What they ask from you — Atlas wants Mythos to be able to search project alpha notes
- What you grant them in return — Bob picks scopes for the reverse direction (or leaves empty for one-way)
Bob clicks Approve + countersign. The cloud writes the connection row on both tenants. Both bridges receive the new connection_id over their WS.
9. Mythos asks Atlas a question — typed action over ARP
Bob asks Mythos: "Ask Atlas what we know about project alpha hiring."
Mythos's LLM, using the contact skill (already installed), composes a typed action request:
arpc request atlas notes.search \
--param collection_id=alpha \
--param query="hiring" \
--param limit=10
What happens, step by step:
- Mythos's bridge signs a DIDComm envelope with body
{ action: 'notes.search', collection_id: 'alpha', query: 'hiring', connection_id: 'conn_…' }and POSTs it to the gateway - Cloud gateway verifies the signature, finds the connection row, calls
dispatchInbound - PDP evaluates Cedar policies against
principal=Mythos, action=search, resource.project_id=alpha. The pairing policies match → allow - Audit entry written to the cloud (hash-chained) with
decision=allow - Cloud forwards the inbound to Atlas's tenant; Atlas's bridge receives via WS
- Atlas's adapter sees
body.action === 'notes.search', dispatches toPOST /api/arp/notes.searchon Atlas's local KyberBot - Atlas's typed handler runs
SELECT … FROM facts WHERE project_id='alpha' AND content MATCHES 'hiring'— by construction, only project alpha rows are returned. ChromaDB semantic search runs the samewhere: { project_id: 'alpha' }filter - Obligation enforcer applies any obligations attached to the connection (rate limit, redact_fields_except, max_size_mb) to the result set
- Atlas's bridge ships the typed JSON response back to Mythos's tenant via DIDComm
- Mythos's bridge receives, the
arpc requestCLI prints the JSON, Mythos's LLM parses the response and answers Bob in plain English: "Atlas says Sarah Chen joined as ML lead. Notes also reference a recruiter intro to a senior MLE candidate."
What's enforced where
| Layer | What it guarantees |
|---|---|
| Cloud PDP | Mythos can only invoke notes.search if the Cedar policy (set during pairing) permits it for the claimed project |
| KyberBot data filter | Even if Cedar allowed, only rows with project_id='alpha' come back from SQL/ChromaDB |
| Obligation enforcer | Rate limits, redactions, size caps applied as code before returning |
| Audit | Every inbound + decision logged on the cloud with a verifiable hash chain |
What Bob and Mythos can never see
- A memory Anna stored with
--project beta(different project) - A memory Anna stored without
--project(untagged) - A memory Anna stored with
--classification confidentialif the connection's policy excludes it
Untagged memories are invisible — by design
This is the most important property to internalize: tagging is the gate. An untagged memory is private to Atlas. A --project alpha memory is shareable through alpha-scoped connections. A --classification pii memory is excluded by any policy that doesn't explicitly grant pii.
The remember skill's discipline — only tag when context is clear — directly maps to the privacy story for the user. Set tags conservatively; broaden later by re-pairing with wider scopes if the relationship warrants it.
Two-way conversations
The walkthrough above is one-way (Mythos asking Atlas). For two-way, Anna and Bob each grant the other on accept. Cedar evaluates each direction independently against its own policy set. PDP doesn't care which side initiated — principal is whoever signed the inbound envelope, and the matching policy fires.
Free-form chat still works
Plain arpc send mythos "hi" continues to work for free-form questions — the kyberbot adapter falls through to KyberBot's /api/web/chat endpoint when the message body has no structured action. The connection context is folded into the system prompt, and the LLM composes a reply normally. Use typed actions when you want deterministic data-layer enforcement; use chat when you want flexibility.