Submit a proof
Submitting runs from your terminal.
There is one tool. It caches the task pool so browsing is instant and offline, builds the bundle without touching a key, checks it for free, and only then moves money. Paying and submitting are separate commands, on purpose.
There is no browser upload yet. Everything below works today against the live validator.
The contract
Every figure here comes from the validator, not from this page.
- Per attempt
- 0.5 τ
- Bundle format
- conjectures-submission/v1
- Bundle ceiling
- 2048 KiB
- Pinned revision
- 379fc02…379fc0298dc146df549e7061c3ede0353a5bb51f
- Tasks in the pool
- 292
- Pay to
- 5Gn2SyG6PmBstAjiPD93CTuxADqYaYqf6fKeFuezKsX7Chf9
Install
One script, then point it at a validator.
With uv it installs as a tool; without it, into a private virtualenv linked from ~/.local/bin, so Python 3.12 or newer is the only requirement. Either way it finishes by installing tab completion for your shell.
Install
./install.shPoint it at a validator
conjectures config set api_base_url https://conjectures.io
conjectures status # accepting work? queues? banner?
conjectures tasks sync # cache the allowlistYour task
The commands below are filled in for this task. A unique prefix stands in for the full id everywhere, including tab completion.
fc-379fc029-green3-green-3-d3215fe1c4-counterexample-v1
Seven steps
Check before you pay.
Step three is free, unlocks no key, and is the last thing that happens before money moves. It exits non-zero on a refusal, so `conjectures check && conjectures pay` is safe to write.
Pick a task
list and show read the local cache, so they are instant and work offline. A unique prefix or substring stands in for the full task id everywhere.
Browse the pool
conjectures tasks list --filter green3 conjectures tasks show green3Write the proof
challenge saves the statement and prints what you are proving - in particular the task mode, because a counterexample task wants the negation. Those are the same bytes hashed into the published task_bundle_sha256. Your Main.lean holds the declarations only: it is inserted between a trusted header and footer that supply the imports and the namespace, so an import line of your own is a refusal rather than a duplicate. Also refused: sorry, admit, axiom, set_option, native_decide, instance, attributes, macro, syntax, notation, and any reference to the source theorem.
Save the challenge, then write Main.lean
conjectures tasks challenge green3 # Main.lean theorem target : ¬ (fcTypeOfName% "Green3.green_3") := by ...Choose the keys
Names only. No key material belongs in the config file, the environment, or the bundle. The hotkey signs; the coldkey of the same wallet pays, and the validator checks on chain that it owns the hotkey.
Wallet names
conjectures config set wallet_name my-wallet conjectures config set wallet_hotkey my-hotkey conjectures config set bittensor_network finneyBuild
Offline, and writes two files: submission.zip, sealed once and never rebuilt, and submission.plan.json - where the archive is, what it must still hash to, a readable copy of its manifest, and the payment slot that pay fills.
Build the bundle
conjectures build --proof Main.lean --task green3Check
Free, unauthenticated, and it opens no key. This is the same admission and static policy check the validator runs, so a refusal here costs nothing to fix.
Check it
conjectures checkPay
pay takes the treasury address and the exact price from the validator, asks the chain whether your coldkey owns the submitting hotkey, sends the transfer, follows it to finality, and records the resolved reference on the plan. --dry-run runs every check and sends nothing.
Move the money
conjectures pay --dry-run conjectures paySubmit, then watch it
No --payment-ref: the plan already cites the payment. submit signs the request and spends it, after showing what is about to be spent. Verification is asynchronous, and the report is the verifier's immutable record.
Send and follow
conjectures submit conjectures submissions show <id> --watch conjectures submissions report <id>
Three statuses
None of them implies another.
Lean's verdict, the reward-policy review and the payout move independently. Once verification leaves UNVERIFIED the immutable verifier report is available, and a rejection names the gate that failed.
- verification_status
- UNVERIFIED -> VERIFIED / REJECTED
- What Lean decided. REJECTED is terminal.
- manual_review_status
- UNREVIEWED -> APPROVED / REJECTED
- Reward-policy review, where it is enabled. It can never turn a Lean-invalid proof into a valid one.
- reward_status
- INELIGIBLE -> ELIGIBLE -> REWARDED / FAILED
- Payout, at the amount frozen when the submission was written.
| Field | Values | Meaning |
|---|---|---|
| verification_status | UNVERIFIED -> VERIFIED / REJECTED | What Lean decided. REJECTED is terminal. |
| manual_review_status | UNREVIEWED -> APPROVED / REJECTED | Reward-policy review, where it is enabled. It can never turn a Lean-invalid proof into a valid one. |
| reward_status | INELIGIBLE -> ELIGIBLE -> REWARDED / FAILED | Payout, at the amount frozen when the submission was written. |
The payment reference
A position, not a hash.
A payment reference is block-extrinsic or block-extrinsic-event. A node can resolve a position; resolving a hash is an indexer's job, so the validator cannot confirm a payment from one. If the extrinsic moved TAO more than once, the event index is what names one payment, and pay resolves that for you. Paid outside the tool, or lost the reference before it was recorded? Resolve it from the position your wallet or a block explorer shows.
Recover a reference
conjectures pay reference --extrinsic 4821993-2 --plan submission.plan.jsonWhat costs money
Two commands spend, the rest do not.
tasks, status, build, check and pay reference are free. pay moves TAO on chain and submit spends it; both show you what is about to happen first, and --yes skips the prompt.
- They stay separate commands on purpose. A single command that paid and submitted would make every submission failure look like a lost transfer, and would invite a retry that pays twice.
- A plan that already cites a payment refuses a second pay, because that reference is the only local record of money that has moved.
- If the validator refuses a submission, the payment is not consumed: no submission row is written, so the same reference still works.
- The idempotency key is written to disk before the request goes out. That is what makes a retry safe - reuse it and you get the original outcome rather than a second charge. Every refusal prints whether the payment survived it.
Configuration
Only one command opens your coldkey.
Precedence, highest first: CLI flag, then environment (CONJECTURES_*), then the user config file, then the default. Wallet names live in the config; key material never does. The hotkey signs every authenticated request. pay is the one command that opens your coldkey, because a transfer has to be signed by the account holding the funds - it never leaves the process, and what goes on chain is a signed extrinsic.
Where the values came from
conjectures config path
conjectures config show --resolvedExit codes
- 1
- Refused.
- 2
- Bad configuration or input.
- 3
- The validator said no.
- 4
- The validator or the chain was unreachable.
--output json emits exactly one JSON document on stdout, so piping into jq works.
When something is refused
Every refusal is recorded with its reason code.
A paid-and-refused request can be looked up in support against your payment reference. The code tells you which gate closed.
- PAYMENT_NOT_FINALIZED
- Wait for finality, or check the recipient, the amount, and that your coldkey owns the hotkey.
- SIGNATURE_INVALID
- Check that the configured hotkey is the one the bundle names.
- TASK_NOT_ALLOWED
- Run tasks sync. The pool changes between releases.
- DUPLICATE_PROOF / DUPLICATE_PAYMENT
- Already used. There is nothing to retry.
- IDEMPOTENCY_CONFLICT
- A used key with a different request. Build a fresh plan for a genuinely new submission.
- BUNDLE_*
- Rebuild and re-run check.
- SUBMISSION_POLICY_VIOLATION
- Your Lean file uses something prohibited. The detail names it.
| reason_code | What to do |
|---|---|
| PAYMENT_NOT_FINALIZED | Wait for finality, or check the recipient, the amount, and that your coldkey owns the hotkey. |
| SIGNATURE_INVALID | Check that the configured hotkey is the one the bundle names. |
| TASK_NOT_ALLOWED | Run tasks sync. The pool changes between releases. |
| DUPLICATE_PROOF / DUPLICATE_PAYMENT | Already used. There is nothing to retry. |
| IDEMPOTENCY_CONFLICT | A used key with a different request. Build a fresh plan for a genuinely new submission. |
| BUNDLE_* | Rebuild and re-run check. |
| SUBMISSION_POLICY_VIOLATION | Your Lean file uses something prohibited. The detail names it. |
More detail