Collaborative Human-Agent Protocol (CHAP) The protocol for humans and agents doing real work together. When a bot drafts something and a human edits it, where does that edit live? In CHAP, it lives in an envelope you can query, replay, and verify six months later. Install · The 90-second tour · Twelve scenarios · About this repo · Paper
Why CHAP exists
You have agents doing real work. Drafting code reviews, triaging tickets, suggesting settlements, reviewing contracts. A human approves, edits, or rejects each one. Right now, that decision lives in your application code, your chat threads, your ticket comments, and your head. When something goes wrong six weeks later, reconstructing what happened costs you forty-five minutes and is half guesswork.
CHAP gives you one place to put those decisions and one shape to put them in. The agent's draft is an artefact. The human's edit is a structured override with a diff, a rationale, and tags you control. The whole thing chains together by content hash. You query the chain instead of grepping logs across four UIs.
That's the whole pitch.
The 90-second tour
A solo developer using Cursor to review pull requests. The bot flags a "warning" the developer disagrees with. Here is the whole exchange, end to end. The clip below runs in about 23 seconds across six labelled steps; the matching code is right underneath.
And here is the code, every line of it. The narrative below is one continuous story in two languages; pick whichever stack you actually use.
1. Spin up a workspace. An embedded coordinator with SQLite persistence, two participants, a workspace:
TypeScript Python import { Coordinator } from "@brightbeamai/chap-coordinator" ; import { SqliteStore } from "@brightbeamai/chap-coordinator/storage/sqlite" ; const coord = new Coordinator ( { store : new SqliteStore ( "./chap.db" ) , } ) ; coord . api . workspace . create ( { workspace : "wsp_pr_reviews" , profiles : [ "core/1.0" , "review/1.0" ] , } ) ; coord . api . participant . join ( { workspace : "wsp_pr_reviews" , from : "human:me@local" , type : "human" , } ) ; coord . api . participant . join ( { workspace : "wsp_pr_reviews" , from : "agent:cursor#v1" , type : "agent" , } ) ; from chap_coordinator import Coordinator from chap_coordinator . storage . sqlite \ import SqliteStore coord = Coordinator ( store = SqliteStore ( "./chap.db" )) def send ( method , params ): return coord . dispatch ({ "jsonrpc" : "2.0" , "id" : method , "method" : method , "params" : params , }) send ( "workspace.create" , { "workspace" : "wsp_pr_reviews" , "profiles" : [ "core/1.0" , "review/1.0" ], }) send ( "participant.join" , { "workspace" : "wsp_pr_reviews" , "from" : "human:me@local" , "type" : "human" , }) send ( "participant.join" , { "workspace" : "wsp_pr_reviews" , "from" : "agent:cursor#v1" , "type" : "agent" , })
... continue reading