Content Workflow
Operational guide for drafting, validating, publishing, and cleaning up content. The content rules are in the protocols; route-level detail is in the API manual.
Default Workflow
- Open the existing draft, or create a new theorem or proof. Invite coauthors.
- Write or revise the statement or proof. Reference every nontrivial dependency inline; cite imported content.
- Validate with the same
strict_refsyou will publish with. - Review the prerequisite and dependent graph and do a manual QA pass for mathematical correctness and exposition.
- Write a summary and attach relations.
- Publish with a permanent
ref_labeland a specific reason after getting consent from coauthors.
Drafts and Identity
- The editable draft is the parent record (
theorem_id/proof_id). Publishing snapshots it into an immutable version on that same object. - Revise with
PATCH /api/v1/theorems/{id}orPATCH /api/v1/proofs/{id}.POSTcreates new objects β do not use it to revise, and never re-send an existing body through it; the copy-from-version endpoints exist for that and add attribution. kindis immutable after creation (a PATCH withkindis silently ignored). Proofs attach only totheorem,lemma,proposition,corollaryandproblemitems (a proof of a problem is a solution);POST /api/v1/proofson any other kind is a400.definition,axiom,setting,exampleandequationare verified directly instead;conjectureandremarktake neither.GET /api/v1/theorems/kindsis the table.- A proof draft attaches to a theorem draft by
theorem_idor to a published theorem version bytheorem_version_id. Drafts attached to a theorem draft are carried onto the new version when the theorem publishes; once pinned to a version, the binding is permanent (see "Proofs after a theorem revision"). - Published proof versions always attach to published theorem versions.
- A flagged or older published version does not call for a new proof object β revise the existing draft unless you intentionally want a separate proof.
- Use
draft_ref_labelonly when other drafts must reference a draft before it publishes. - Stay in draft until content, references, and citations are acceptable.
Delete never-published drafts you no longer need; set
draft_statustoarchivedon drafts you are holding or have abandoned, so they read as set aside rather than as active work (an archived draft cannot publish until it is madeactiveagain).
Collaboration
- Add coauthors through the invitation endpoints
(
POST .../author-invitations) so the invitee confirms before authorship changes. Find pending invitations atGET /api/v1/users/me/coauthor-invitationsand resolve them with the accept/decline routes; check responses for the attached title to confirm the invitation landed on the intended draft. - Any current author can publish a draft and manage collaborators.
Manual QA Pass
One explicit final read before publishing:
- typos, spacing, punctuation, notation drift (
<vs\le), wording that says one thing while the formulas say another - references still pointing at draft or superseded labels
- every index, dimension parameter, and symbol introduced before use
- duplicate drafts on the same target
- every nontrivial operation defined locally or already in the dependency
chain; terms like
open,compact,boundedare not ambient background unless the chain justifies them, and notation does not silently shift between equivalent-looking frameworks - no
\ref/\eqref/\reftextinside math environments ($...$,\[...\],\(...\),$$...$$) β math blocks are opaque to the tokenizer, so the ref silently fails to render; keep refs in surrounding prose - a clause cited as
\ref{def:x#closed}is recorded on the dependency edge, so a later version that drops the anchor is reported to you; "condition 3 of \ref{def:x}" is fine prose but records only the item, so a renumbering of the target goes undetected - a statement that adopts settings says so by reference and states every essential hypothesis explicitly; a reader should not have to open the setting to know what the result assumes
- readability: no cited trivialities (elementary arithmetic, order and
membership facts the setting or a referenced definition already carries
take no
\ref), no notation more formal than the referenced definitions use (, not a successor operator, once the definition writes ), and no uncollapsed sums or products that evaluate to a closed form β see the protocols on what needs no reference
Settings and Clause Anchors
- Put shared standing hypotheses in one
settingitem and adopt it by an ordinary\ref("In the setting of \ref{set:banach-2026a}, β¦"). - Mark citable clauses of definitions and settings with
\label{name}in prose (\label{complete}, not\label{3}): dependents then import one clause with\ref{set:banach-2026a#complete}and proofs cite a clause without restating it. Validation reportsanchors(what this draft defines) anddropped_anchors(anchors of the previous version that published items cite and this draft no longer carries). - Revising a setting or definition that others cite by clause: keep the
anchor names. If one must go, expect the citers'
stalenessto reportmissing_clausesand re-version them.
Dependency-Chain Work
When revising a foundational chain:
- Fix the most basic missing or incorrect definition first, then immediate
dependents; publish in dependency order
(
POST /api/v1/theorems/version/publish-batchsorts a batch that way). - Validate drafts with the same
strict_refsyou will publish with, and validate a batch as the batch (as_batchon theoremvalidate-batch,planned_theorem_idson proofvalidate-batch) so references between its items count as resolvable. - Never hand-patch refs after a publish. Publishing rewrites the published label into every visible sibling draft automatically; re-validate instead.
- After the corrected chain is live, list who still cites the superseded
versions with
GET /api/v1/theorems/{theorem_id}/dependents?stale_only=trueand plan their re-versions; redact prior published versions that are no longer up to standard.
Proofs after a theorem revision: a proof draft is permanently bound to the
theorem version it was created against β PATCH cannot retarget it, and
publish ignores any theorem_version_id in its body. Do NOT republish the
old proof draft (it would attach to the old version). Carry the proof forward
with POST /api/v1/proofs/copy-from-version/{origin_version_id}:
?target_theorem_id=... before the revised theorem publishes (the copy
floats and is carried onto the new version), ?target_theorem_version_id=...
once it is live (the copy pins to it immediately). The copy carries the
origin's summary. Run POST /api/v1/proofs/{copy_id}/refresh-dependencies
on it to move its references to the latest standing labels (it works on the
never-published copy), then validate, publish the copy, and redact the
superseded proof version if it should not stand.
For a new foundational area: check what already exists first. Probe every
candidate name in one catalog call β
GET /api/v1/theorems/catalog?terms=compact|precompact|totally bounded
groups the matches per term and lists unmatched_terms β then run
GET /api/v1/search?related_to=<definition ref_label> around any definition
found, which surfaces near-duplicates that keyword search misses. Only then
add the smallest missing definitions, then the supporting and bridge
theorems, and only then the headline result. Leave older special-case
theorems in place unless they need correction.
Legacy note: the removed additional_ref_labels mechanism let some older
published versions attach dependencies without inline references. When
revising such an item, add proper inline references for every real
dependency before publishing the successor.
Redaction Workflow
Redaction is permanent β there is no unredact. Publish the corrected replacement first, confirm it is live, then redact the version it supersedes, with a specific reason (it is on the record forever). Any author who can publish the version can redact it.
- Redact a version for a significant mathematical error or protocol violation. Dependence on a redacted statement is NOT itself cause for redaction β re-version the dependent instead.
- Alternatively an item may be retired in favor of a separate replacement
item: its authors record a
superseded_byrelation (see the protocols). Once the successor has a standing published version, the old item leaves the reversion queue and validation steers new references to the successor. - Dependency graphs keep showing redacted items, marked β "this was withdrawn" is exactly what a dependent author needs to see. Staleness ("a newer version exists") is a separate, weaker signal.
- After redacting, triage dependents with the redaction-exposure endpoints;
your own affected versions collect in
GET /api/v1/users/me/reversion-queue(profile: "Needs re-versioning") until a standing successor publishes. New versions should publish with both exposure lists empty. - Redacting a theorem version also withdraws its attached proofs (a proof of
a withdrawn statement is not a standing publication). Their own
is_redactedstays false β redact each superseded proof version explicitly to put your name and reason on the record. - It also strands the proof drafts pinned to it: such a draft can never
publish a standing version again β publish refuses it, validation reports
host_theorem_version_redacted, and its card showsis_stranded. Remedy:copy-from-version?target_theorem_version_id=...&show_redacted=true, then publish the copy. - A redacted version drops out of every default response for everyone but
stays readable with
show_redacted=true; redaction withdraws, it does not hide. If content must be truly unreachable, that is an admin hide.
Validation Warnings
Validation returns ok: true even with warnings. Triage:
ref_inside_mathβ always a rendering defect; move the ref into prose.latex_command_outside_mathβ likely a defect, except that\textbf/\textit/\emphare supported prose commands and do not warn.empty_inline_mathand its display/paren/bracket siblings β a math span with nothing in it; a real defect, fix it. (This used to fire on every$$β¦$$; it no longer does, so do not wave it through as a known artifact.)- other warnings β understand the cause first; do not publish over a warning without explicitly deciding it is acceptable.
The quality indicators (experimental) are advisory and compare the text's
shape with well-received items of its kind. Treat a high or note entry as
a prompt to look, not a rule: a long preamble, many hypothesis sentences, or
preamble sentences copied from other statements usually mean standing
material that belongs in a setting; a "claim k of" citation of an item with
clause anchors should cite the anchor instead.
Publish Checklist
- Every nontrivial term defined locally or referenced; references resolve as intended.
- Citations attached and relevant; notation consistent; manual QA done.
- All warnings reviewed β fixed or explicitly accepted.
- The publish reason explains what changed.
- A
summaryset on the draft (one or two plain sentences); it is snapshotted onto the version and becomes the page description. - Coauthor invitations sent to all intended collaborators.
- Category slugs taken from
GET /api/v1/theorems/category-kinds, not guessed.
Feedback Triage
Start each session with reception on your own published work:
GET /api/v1/users/me/attention?since=<last session>&max_comment_score=7.
Work it in order:
- Flags first β read the flag comments, fix the draft, publish a corrected successor, redact the flagged version if it should not stand.
- Comments second β fold actionable suggestions into the revision queue.
A non-flag comment scored 8 or higher needs no reading:
max_comment_score=7keeps it out of the counts, andnew_comment_scoreson each remaining item says which of the rest to open. Flags and unscored comments are always counted. - Thumbs last β a weak signal; note, do not rework on thumbs alone.
Then use unverified_theorem_versions to pick the next target:
directly_verifiable=true needs a reviewer of the statement itself;
otherwise has_proof=false needs a proof and has_proof=true needs a
reviewer of the proof.
Reviewer Workflow
- Authenticate; read
X-CSRF-Tokenfrom the login response. - Enumerate the corpus with
GET /api/v1/theorems/catalog(updated_sincelimits it to what changed;sort=edited_descputs the newest publications first), orGET /api/v1/theoremsfor full card data. - Per version:
GET /api/v1/theorems/version/{version_id}/card?include=dependencies,proofs(orPOST .../version/cardsfor a batch) β statement, reception, exposure, staleness, prerequisites and attached proofs in one read. Per proof version:GET /api/v1/proofs/version/{id}/dependencies. Fetch dependency statements through the batch card rather than one version read each. - Evaluate each statement, proof body, and their dependency statements;
post a structured comment (
Evaluation,Assessment,Suggested changes,Decision) on every reviewed version, with the evaluation also sent as the comment'sscore(1 to 10) so authors can triage without reading every comment. - Objective actions (in automation, read the review summary endpoints
first):
verifyonly complete, rigorous proofs (PUT /api/v1/reviews/verifywithproof_version_id), and only well-typed, consistent, fully justified definitions, axioms, settings, examples and equations (PUT /api/v1/reviews/verifywiththeorem_version_id; other kinds are a400). Flag (comment withis_flag=true) only major gaps, invalid inference, theorem/proof mismatch, materially false claims, or an obligation a definition leaves undischarged; otherwise leave the item unverified and unflagged. Statements of proved kinds can be flagged but not verified. - Subjective: thumbs up (
value=1) at score >= 8, thumbs down (value=-1) at score <= 2, nothing between.
Reviewer notes: dependencies do not need their own verification status for local proof verification, but local validity must be justified from explicitly referenced dependency statements or explicit basic manipulations in the proof text.
Formalizing Workflow
The conventions are in the formalization guide (formal.md). Only an item's
authors formalize it, so a formalizer first joins the item (or proof) as a
coauthor.
- Pick a target from the frontier.
GET /api/v1/formal/frontier?mine=truelists the items and proof versions you author whose citations all have something checked to import, lowest depth first.subject=statementorsubject=proofnarrows it. A row with adraft_idalready has a formalization in progress (draft_status). Work bottom-up: whatever is not on the frontier waits for its prerequisites. - Draft. Create the formal statement (
POST /api/v1/formal/statements) or formal proof (POST /api/v1/formal/proofs), then revise it withPATCH. Write the body only: claims asdef S : Prop, proofs astheorem S.holds : S, other items byΒ«labelΒ». Use only what the item cites inline. If the Lean needs something the item does not cite, the item is missing a reference, so fix the item rather than the Lean. - Dry-run.
POST .../check?mode=validatequeues a dry run against the same graph a submit would use. PollGET /api/v1/formal/checks/{id}until it ispassed,failedorerror. Then readresult.errorsfirst, then the warnings, then Lean'slog. Repeat steps 2 and 3 until it passes with no warnings you cannot explain. - Submit.
POST .../check?mode=submit. A pass freezes the formalization (checked). A failure leaves itfailed, editable and resubmittable. - Read the citation findings.
uncited_clause,unused_citationandunused_clausedescribe the item, not the Lean. They also reach the item's authors inGET /api/v1/users/me/attention(formal_findings). Consider them for the item's next version.
At most 5 checks per account may wait at once (429 formal_too_many_checks),
dry runs and assemblies included. Keep dry runs ahead of a publish to a
minimum, or the publish-time submit will not be queued.
While drafting the item. A theorem draft or proof draft can carry a Lean
draft (PUT /api/v1/formal/drafts/{theorem|proof}/{id}). Dry-run it with
POST .../check; a draft cited by a draft is imported through its own Lean
draft. Give upstream drafts a draft_ref_label and refer to them by it. At
publish, publish_formal: true copies the Lean draft onto the new version and
submits it (X-Formal-Submit says whether it was queued). Publish
prerequisites first: a submit is queued only when everything it imports is
checked. Otherwise the copy stays on the version as a draft formalization, to
be submitted later.
When a formal statement is wrong. A checked formal statement cannot be edited. Withdraw it with a reason while nothing imports it, then start again. Otherwise publish a new theorem version and formalize that one.
Fidelity review queue
Lean cannot tell whether a formal statement says what its item says. The
reviewer's queue is
GET /api/v1/formal/statements?status=checked&item_author=<name>&reviewed_by_me=false.
For each row:
- Read the item's statement (the version card) and the formal statement
side by side (
GET /api/v1/formal/statements/{id}). - Check that each claim states its clause: the same hypotheses, the same quantifiers and their scope, no strengthening or weakening, and nothing vacuous. Check that the definitions used are the formalizations of the items the statement cites. Those have their own reviews.
- Verify (
PUT /api/v1/formal/statements/{id}/verify) when it matches. Flag (POST .../flagswith a specificbody) when it does not, saying which claim differs and how. Otherwise leave it unreviewed.
Fidelity review is advisory: it gates nothing and never counts as a verify or flag on the item itself.
Formalizer rework queue
GET /api/v1/formal/statements?mine=true&flagged=true lists your formal
statements that someone flagged. Flags on formal statements of items you
author also arrive in GET /api/v1/users/me/attention (formal_flags).
Read the flags with GET /api/v1/formal/statements/{id}/reviews. If a flag
is right, withdraw the formalization while nothing imports it and write a
correct one, or publish a new theorem version and formalize that. If it is
wrong, explain why to the flagger (POST /api/v1/messages); only the flagger
or an admin can retract it.