Clankdar
Run a check

Your first check.

Run a check locally, connect your own solver, and keep the signed result.

Run a complete check.

To see a puzzle before installing anything, try one in your browser. To get a signed receipt, install Bun 1.3.14 and run:

git clone https://github.com/hraness/clankdar.git
cd clankdar
bun install --frozen-lockfile --ignore-scripts
bun run try

The demo creates four fresh ALGAL puzzles, solves them with an included script, and signs and independently verifies the result. It saves receipt.json and verification.json in a new results/try-…/ directory and prints the paths and verification command.

It needs no credentials and calls no model. A script answers the puzzles and a temporary key signs the result, so the score only shows that the flow works. It is not a model score, and the receipt does not come from the hosted service.

Use your own solver

Export solve(challenges, signal) from a JavaScript or TypeScript module, then run:

bun run try --solver ./my-solver.mjs

Your function receives public challenge objects and an AbortSignal. Return an object that maps each challengeId you received to its answer string. For example, connect your existing agent in my-solver.mjs:

import { askAgent } from "./your-agent.mjs";

export async function solve(challenges, signal) {
  const answers = {};
  for (const challenge of challenges) {
    answers[challenge.challengeId] = await askAgent(challenge.prompt, { signal });
  }
  return answers;
}

askAgent is your application function, not a Clankdar API. Return only each requested answer, forward the signal to provider requests, and set your own model and spending limits. Loading your module runs its code and can incur your provider costs. The default policy requires three of four correct answers within 180 seconds.

Read the local result.

bun run try prints PASS or FAIL with how many answers passed against the three-of-four policy. Both results can have a valid signature and correctly verified scores, so a valid receipt does not mean the solver passed. The command exits with status 0 for a passing check, 1 for a completed failing check, and 2 when it cannot finish or save the result.

Use the printed verification command to recheck the saved receipt with the same issuer key, session, context, and SHA-256 value. Do not substitute the temporary demo key for an issuer your application trusts.

When your solver cannot finish

Check that the module exports solve(challenges, signal), returns answer strings keyed by the supplied challengeId values, and finishes within 180 seconds. Forward signal to its asynchronous work. Custom code runs with your local permissions, so review the module before you run it. If saving fails, check write access to results/.

Use the API from your server.

The hosted API is an experimental staging service, open by invitation. Request hosted access, then store your token privately as CLANKDAR_TOKEN.

Use ordinary HTTP, or download the small JavaScript helper. It runs on Node 22+ or Bun and needs no repository checkout:

curl -fsS https://clankdar.com/clankdar-client.mjs -o clankdar-client.mjs

Connect the same solve function from the local example in your server code:

import { writeFile } from "node:fs/promises";
import { check } from "./clankdar-client.mjs";
import { solve } from "./my-solver.mjs";

const result = await check({
  baseUrl: "https://clankdar-hosted-staging.972abc65.workers.dev",
  token: process.env.CLANKDAR_TOKEN,
  solve,
});
await writeFile("receipt.json", result.receiptText);
console.log(result.receiptUrl);

The helper issues a check, passes its prompts to your solver, submits the answers, and downloads the signed receipt. You choose the provider your solver calls and pay its costs. Keep the token, and the one-time ticket each check returns, out of browser code. Submitted answers and any context you send become public.

The helper checks that the receipt it downloads matches the result returned when you submitted. Before accepting the result, verify it against an issuer key you trust and check that it passed your required policy.

Recover a submission after a connection failure

The first accepted submission fixes the result, even when it fails. Retry that submission to recover the result; creating another check consumes another quota slot. Use the helper’s optional onIssued(record) and checkpoint(record) callbacks to save the ticket privately before solving and the answers before submitting. The helper source and API contract describe the records and retry behavior.

Verify before you rely on a result.

From the repository checkout, use the offline verifier with an issuer key from your trusted application configuration:

bun cloudflare/examples/verify-receipt.mjs receipt.json \
  --issuer="$EXPECTED_ISSUER_PUBLIC_KEY"

The checker verifies the signature and replays the recorded answers. Your app still has to check three things itself: the receipt uses the policy you expect, it is recent enough for your purpose, and it passed. A valid receipt can record a failed check. For the local demo, use the exact verification command printed by bun run try.

Issuer key, expected context, and replay details

Never take the expected issuer key from the receipt you are checking. Optional --context, --session, and --sha256 assert your integration’s expected context, check ID, and exact file hash. See the verifier source for its output.

Present, well-formed answers produce challenge receipts with seeds that let a checker regenerate and rescore those puzzles. Missing or malformed answers count as nonpassing without a challenge receipt or seed reveal. A check submitted with every answer blank still verifies, as zero of four passing.

Three places to start.

Agent preflight
Request a fresh result before offering a job. Use it alongside your existing sign-in and your own rules for accepting agents.
Release checks
Compare a changed model endpoint under the same declared conditions. Keep receipts with your release record.
Listing evidence
Show a recent result with its policy, date, and sample size. Let readers inspect the receipt.
Schedule checks in your own app

Your cron job or agent loop can call the same API. You choose cadence, budgets, how to treat missed runs, and alerting. A single check says nothing about whether an agent stays available.

Three HTTP calls.

POST /v1/checks
Send {} with your bearer token. Receive fresh challenges, their deadline, a scoped ticket, and the future receipt URL.
POST /v1/checks/:id/responses
Send {"ticket":"…","responses":{"actualChallengeId":"answer"}}. Receive the score, signed receipt, URL, and exact-byte hash. No issue token is needed.
GET /v1/checks/:id
Download the receipt as immutable JSON. This read needs no token.

The default algal-floor-v1 policy asks four puzzles, requires three passes, and allows 180 seconds. Every answer is checked exactly; there is no judge model.

Policy selection and optional fields

Set policyId when issuing if you need a particular policy. List hosted policies and check the prompts, required passes, and deadline before selecting one.

Optional context is a nonempty, non-sensitive string up to 256 characters. It becomes part of the public result.

Bind a check to a subject key

Include subjectPublicKey when issuing and the matching subjectProof when submitting. This binds a key to the check, not the identity of its solver. Most integrations can start without it. The API contract defines the proof format.

Exercise the HTTP flow with curl and jq

This optional walkthrough uses your invitation token and one quota slot. These commands never call a model; they submit blank answers to show a failed check.

Create a check and inspect its prompts.

export CLANKDAR_URL="https://clankdar-hosted-staging.972abc65.workers.dev"
# Set CLANKDAR_TOKEN privately to your invitation token.
umask 077
curl -fsS "$CLANKDAR_URL/v1/checks" \
  -H "Authorization: Bearer $CLANKDAR_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"policyId":"algal-floor-v1"}' > check.json
jq -r '.challenges[] | "\(.challengeId)\n\(.prompt)\n"' check.json

check.json contains the challenge IDs and prompts, expiresAt, and a private ticket for this check. The default algal-floor-v1 policy gives you four ALGAL program puzzles, requires three passing answers, and allows 180 seconds.

Build the answer map and submit once.

jq '.challenges | map({key: .challengeId, value: ""}) | from_entries' \
  check.json > answers.json

This creates blank answers under the real challenge IDs. Submit them unchanged for an intentionally failed-check demo. To test capability, replace each blank value with your solver’s answer before expiresAt. Failed answers consume the attempt just as passing answers do.

jq -n --slurpfile check check.json --slurpfile answers answers.json \
  '{ticket: $check[0].ticket, responses: $answers[0]}' > submission.json
curl -fsS "$CLANKDAR_URL/v1/checks/$(jq -r '.id' check.json)/responses" \
  -H "Content-Type: application/json" \
  --data-binary @submission.json > result.json
jq '{id, pass, passed, required, receiptUrl, sha256}' result.json

The response includes pass, the passing and required counts, a content hash, a receipt URL, and the signed receipt itself. Submission uses the scoped ticket, so your main issue token stays with your server. Retrying submission recovers the first result; it cannot replace the answers. Retrying creation makes a new check and consumes another quota slot.

Download the exact JSON receipt.

curl -fsS "$CLANKDAR_URL$(jq -r '.receiptUrl' result.json)" > receipt.json

The receipt is signed JSON in the clankdar-gate-v1 format, with protocol, payload, and signature fields. It stays readable after the ticket expires. Save the file; see Limits for how long receipts are kept.

Full API contract: fields, errors, limits, and retries

See the benchmark and puzzle design.

See the model benchmark for recorded scores, test conditions, and downloadable evidence.

How Clankdar uses ALGAL

A program with a checkable answer.

ALGAL’s official Rust evaluator, compiled to WebAssembly, calculates the reference answer for each program puzzle. The CLI and Worker use the same pinned evaluator. Clankdar supplies fresh inputs, deadlines, exact scoring, and signed receipts.

Programs compose filtering and arithmetic, coupled recurrences, and matrix transitions. They have a 10,000-unit work budget and no network, filesystem, or model access. Your solver returns the final integer; Clankdar does not execute code supplied in a response.

bun run algal:example

Run this worked example from the repository after installing dependencies. Inspect the program contract, evaluator pin, and solution.

Inspect a harder puzzle

Public practice · a harder logic puzzle

Solve this system of linear equations over GF(2): every variable is 0 or 1 and ⊕ is XOR (addition modulo 2). The system has exactly one solution.

x0 ⊕ x1 ⊕ x2 = 1
x0 ⊕ x1 ⊕ x2 ⊕ x5 = 1
x1 ⊕ x3 = 1
x1 ⊕ x5 = 1
x0 ⊕ x1 ⊕ x2 ⊕ x4 = 1
x2 ⊕ x3 ⊕ x5 = 1
x1 ⊕ x3 ⊕ x4 = 1
x0 ⊕ x2 ⊕ x4 ⊕ x5 = 0

Reply with only the 6-digit assignment as bits, in order x0 first through x5 last.
Reveal the reference answer111000

Subtracting XOR equations gives x5 = 0 and x4 = 0. Then x1 = 1, x3 = 0, x2 = 1, and x0 = 1.

This practice puzzle does not issue a receipt. Recorded source and conditions.

How Clankdar compares.

Choose according to the decision you need to make: assess traffic, verify a signed request, or evaluate answers to tasks. Clankdar records which generated puzzles were solved and gives you a signed result to rescore.

ApproachWhat it tells youUse it when
Turnstile / reCAPTCHABrowser and interaction risk signals for legitimate traffic versus automation.You want to keep automated traffic out of a form meant for people.
Proof-of-workThe requester spent computation, such as finding a hash nonce.You want to slow bulk scraping without accounts.
Web Bot AuthA registered agent key signed the request.You need to verify a request against a registered agent key.
Reverse CAPTCHAs: HATCHA, imrobotSoftware answered a quick challenge, such as multiplying two large numbers, before a timer ran out.You want agents through a signup form with a drop-in widget.
LiveBenchScores for public models on regularly released new questions.You want a broad comparison of public models.
Reasoning GymGenerated reasoning tasks with answer checkers, built for reinforcement learning.You need training data or many task families.
ClankdarSpecific fresh tasks passed, with signed evidence you can independently replay.You need a record of which puzzles your agent solved.

For integration requirements, follow each project’s documentation. Clankdar’s local demo runs from source; its hosted API is an experimental staging service, open by invitation.

Limits, storage, and boundaries.

Shared staging allows 1,024 issued checks over its lifetime and at most 60 issues per fixed UTC minute. These are service-wide limits, not a quota for every token. Request bodies are limited to 128 KiB and receipts to 256 KiB. Your application supplies any inference and pays its own provider costs.

Each finished check is stored once, as a signed JSON file. Receipts aren’t deleted automatically, but this experimental service doesn’t promise to keep them. Download any receipt you need.

Keep credentials separate from results.

Keep the issue token server-side. The ticket is a private credential scoped to one check until it is consumed or expires. A recorded failed check fixes the result too; retry only to recover that first result. A receipt stays readable after the ticket expires. Results are public, so do not put private information in context or responses.

What a check establishes.

A receipt measures the submitted responses under a recorded policy and deadline. It does not prove model identity, human presence, autonomy, uniqueness, safety, ongoing availability, or permission to act, and it does not record what the answers cost. A puzzle can be solved with code or handed to someone else. Hosted checks draw new random seeds from the public puzzle generators; none of the hosted policies uses a private puzzle set. Whoever runs an issuer can sign any result it wants, so decide which issuers you trust.

Source and deeper references.