88
99![ agentproof overview] ( assets/agentproof-hero.svg )
1010
11- ` agentproof ` is a Python library for agent-oriented verification challenges .
12- It lets a service issue a structured challenge, lets an agent solve it , and verifies the result
13- deterministically on the server.
11+ ` agentproof ` is a Python library for LLM-capability CAPTCHA flows .
12+ It issues obfuscated public challenges, expects a structured answer back , and verifies the answer
13+ deterministically against the private server-side copy .
1414
1515Install:
1616
@@ -24,180 +24,168 @@ Import:
2424import agentproof
2525```
2626
27- ## What problem it solves
27+ ## What it is
2828
29- Traditional CAPTCHA asks "are you human?" .
29+ Traditional CAPTCHA asks whether the client is human.
3030
3131` agentproof ` asks a different question:
3232
33- " Can this client complete an agent-friendly, machine-checkable challenge?"
33+ > Can this client recover and execute an obfuscated instruction in an LLM-like way?
3434
35- That is useful when you want to :
35+ That makes it useful for :
3636
37- - gate agent-focused endpoints
38- - prototype reverse-CAPTCHA style flows
39- - add a structured verification step before allowing API access
40- - experiment with challenge-response systems for LLM agents
37+ - LLM-first endpoints
38+ - reverse-CAPTCHA experiments
39+ - capability gates before access to an API
40+ - local testing of challenge-response flows for agents
4141
4242## How it works
4343
44- 1 . Your server generates a challenge JSON payload .
45- 2 . The agent reads it and produces a structured response .
46- 3 . Your server verifies the response .
47- 4 . Verification returns ` ok: true ` or a deterministic failure reason.
44+ 1 . Your server generates a challenge and keeps the private verification copy .
45+ 2 . You send the public challenge JSON to the client .
46+ 3 . The client returns structured JSON with ` payload.answer ` .
47+ 4 . Your server verifies the response and gets ` ok: true ` or an exact failure reason.
4848
49- ## Smallest example
49+ ## Quickest real example
5050
5151``` python
52- from agentproof import ChallengeSpec, generate_challenge, solve_challenge , verify_response
52+ from agentproof import AgentResponse, ChallengeSpec, generate_challenge , verify_response
5353
5454challenge = generate_challenge(
55- ChallengeSpec(challenge_type = " proof_of_work" , difficulty = 8 , ttl_seconds = 60 )
55+ ChallengeSpec(
56+ challenge_type = " obfuscated_text_lock" ,
57+ difficulty = 2 ,
58+ options = {" template" : " amber_sort" },
59+ )
60+ )
61+
62+ public_challenge = challenge.to_dict()
63+
64+ # Send public_challenge to an LLM-capable client.
65+ # The client responds with structured JSON.
66+ response = AgentResponse(
67+ challenge_id = challenge.challenge_id,
68+ challenge_type = challenge.challenge_type,
69+ payload = {" answer" : " EMBER-HARBOR-SIGNAL" },
5670)
57- response = solve_challenge(challenge)
58- result = verify_response(challenge, response)
5971
72+ result = verify_response(challenge, response)
6073assert result.ok
6174```
6275
63- ## What a real challenge looks like
64-
65- Example ` proof_of_work ` challenge:
76+ ## What the public challenge looks like
6677
6778``` json
6879{
69- "challenge_id" : " 6f2c8e4a91d3b5c1" ,
70- "challenge_type" : " proof_of_work" ,
71- "prompt" : " Find a nonce such that sha256_hex(payload + ':' + nonce) starts with 8 leading zero bits." ,
72- "issued_at" : " 2026-03-07T01:10:00+00:00" ,
73- "expires_at" : " 2026-03-07T01:11:00+00:00" ,
74- "version" : " 1" ,
80+ "challenge_id" : " bb28567e201b35aa" ,
81+ "challenge_type" : " obfuscated_text_lock" ,
82+ "prompt" : " gl1tch//llm-cap-v1::d2\n frag@f8 // D3c0d3 the driFted Br13f ANd 4N5w3r tHrOUgH Payload.answer 0NLY\n frag@d8 %% d3CK: slOt5 v10l37 cIndEr\n frag@f6 %% d3ck: sloT2 4Mb3R h4Rb0r\n frag@c9 || task: 0rD3R thE kept 5h4Rd WOrdS By 5l07 numBer fr0m loW to h1gh\n frag@b3 %% dEcK: slOt3 C0b4L7 sabLe\n frag@d3 %% AnswEr ruLe: R37urn ThE 5H4rd W0rd5 in UpPercaSe aScii J01N3D WIth hYpheNs\n frag@e2 || d3Ck: SLot4 4mb3R 51gn4L\n frag@e5 ^^ tasK: keEp onLy ShArds cArrying the 4MB3r TAg\n frag@e4 :: d3CK: slot1 4mB3r 3Mb3R\n reply via payload.answer only // structured-json" ,
83+ "issued_at" : " 2026-03-07T02:58:20.639623+00:00" ,
84+ "expires_at" : " 2026-03-07T03:00:20.639623+00:00" ,
7585 "data" : {
76- "algorithm" : " sha256" ,
77- "difficulty" : 8 ,
78- "salt" : " a14d22b8f91c77e2" ,
79- "payload" : " 6f2c8e4a91d3b5c1:a14d22b8f91c77e2"
80- }
86+ "difficulty" : 2 ,
87+ "profile" : " llm_capability_v1" ,
88+ "response_contract" : {
89+ "payload.answer" : " UPPERCASE ASCII words joined with hyphens" ,
90+ "payload.decoded_preview" : " optional free-form notes"
91+ }
92+ },
93+ "version" : " 1"
8194}
8295```
8396
84- Example agent response:
97+ The matching client response looks like :
8598
8699``` json
87100{
88- "challenge_id" : " 6f2c8e4a91d3b5c1 " ,
89- "challenge_type" : " proof_of_work " ,
101+ "challenge_id" : " bb28567e201b35aa " ,
102+ "challenge_type" : " obfuscated_text_lock " ,
90103 "payload" : {
91- "nonce " : " 223 " ,
92- "hash " : " 00bf9b61a372cbd81bef570069b655fd02ef299cc29e9e59d5739e86f5fb6974 "
104+ "answer " : " EMBER-HARBOR-SIGNAL " ,
105+ "decoded_preview " : " kept amber shards ordered by slot "
93106 }
94107}
95108```
96109
97- Example verification result :
110+ And verification returns :
98111
99112``` json
100113{
101114 "ok" : true ,
102115 "reason" : " ok" ,
103116 "details" : {
104- "hash" : " 00bf9b61a372cbd81bef570069b655fd02ef299cc29e9e59d5739e86f5fb6974" ,
105- "nonce" : " 223"
117+ "answer" : " EMBER-HARBOR-SIGNAL" ,
118+ "template_id" : " amber_sort" ,
119+ "difficulty" : 2
106120 }
107121}
108122```
109123
110- ## Why this fits agents
111-
112- These challenges are good for agents because they are:
113-
114- - machine-readable
115- - automatable
116- - exact
117- - easy to verify on the server
118-
119- Agents are typically better than humans at:
120-
121- - reading structured JSON
122- - following exact constraints
123- - iterating until a condition is satisfied
124- - returning properly formatted machine output
125-
126124## Built-in challenge types
127125
128- | Challenge type | What the agent does | How it is verified |
126+ | Challenge type | Role | Built-in solver |
129127| --- | --- | --- |
130- | ` proof_of_work ` | Search for a nonce | Recompute hash and check difficulty |
131- | ` semantic_math_lock ` | Produce constrained text | Check required words, exact word count, and initial-letter sum |
132-
133- ## Semantic example
134-
135- ``` python
136- from agentproof import ChallengeSpec, generate_challenge, solve_challenge, verify_response
137-
138- challenge = generate_challenge(
139- ChallengeSpec(
140- challenge_type = " semantic_math_lock" ,
141- ttl_seconds = 90 ,
142- options = {" topic" : " security" , " word_count" : 7 },
143- )
144- )
145- response = solve_challenge(challenge)
146- result = verify_response(challenge, response)
147-
148- print (response.payload[" text" ])
149- print (result.to_dict())
150- ```
151-
152- Typical response text:
128+ | ` obfuscated_text_lock ` | Primary LLM-capability challenge | No |
129+ | ` proof_of_work ` | Deterministic compute baseline | Yes |
130+ | ` semantic_math_lock ` | Readable exact-constraint baseline | Yes |
153131
154- ``` text
155- security demands careful metrics metrics metrics metrics
156- ```
157-
158- ## API shape
159-
160- ``` python
161- from agentproof import ChallengeSpec, generate_challenge, solve_challenge, verify_response
162- from agentproof import Challenge, AgentResponse, VerificationResult
163- ```
132+ ` obfuscated_text_lock ` is the main product path. It is meant to be solved by an external
133+ LLM-capable client, not by a bundled reference solver.
164134
165135## CLI
166136
167- Generate, solve, and verify from the command line :
137+ Baseline challenge roundtrip :
168138
169139``` bash
170140agentproof generate proof_of_work --difficulty 16 --output challenge.json
171141agentproof solve challenge.json --output response.json
172142agentproof verify challenge.json response.json
173143```
174144
175- ## Demo
145+ Obfuscated challenge flow:
176146
177- A runnable local demo lives in [ ` demo/ ` ] ( https://github.com/bnovik0v/agentproof/tree/main/demo ) .
147+ ``` bash
148+ agentproof generate obfuscated_text_lock \
149+ --difficulty 2 \
150+ --template amber_sort \
151+ --output challenge.internal.json \
152+ --public-output challenge.public.json
153+ ```
154+
155+ Use ` challenge.public.json ` for the client and keep ` challenge.internal.json ` server-side for
156+ verification.
157+
158+ ## Demo
178159
179- Run it with :
160+ Run the local demo :
180161
181162``` bash
182163uv run python demo/app.py
183164```
184165
185- Then open:
166+ Then open ` http://127.0.0.1:8765 ` .
186167
187- ``` text
188- http://127.0.0.1:8765
189- ```
168+ The demo centers the obfuscated challenge flow and lets you paste a real LLM response into the
169+ browser before verifying it.
170+
171+ ## What this proves
172+
173+ ` agentproof ` is best used to prove:
174+
175+ - the client can recover intent from obfuscated text
176+ - the client can return exact structured output
177+ - the response can be checked deterministically on your server
190178
191179## What this does not prove
192180
193181` agentproof ` does not prove:
194182
195- - model provenance
196- - provider identity
183+ - model identity
184+ - provider provenance
197185- hardware-backed execution
198- - protection against determined custom automation
186+ - protection against every scripted solver
199187
200- It is a challenge-response library, not an identity system.
188+ It is an LLM-capability CAPTCHA library, not an identity system.
201189
202190## Development
203191
@@ -218,5 +206,3 @@ uv run mkdocs build --strict
218206- Contributing: [ CONTRIBUTING.md] ( CONTRIBUTING.md )
219207
220208## License
221-
222- MIT
0 commit comments