Generating CosmWasm documentation from Rust contractsTerran One needed a conceptual guide and an exhaustive message reference. I wrote the guide for humans and generated the reference from Rust types, handler steps, warnings, and constraints.

Documentation was one of the first products I built at Terran One. CosmWasm developers needed two different things: a guide that explained how contracts work and a reference covering every message, field, constraint, and side effect in a contract.
I initially treated both as writing. That made the reference slow to produce and almost guaranteed that it would drift from the Rust source. A renamed field required someone to find and update the same fact in several pages.
I split the work by source of truth. I wrote the conceptual guide by hand because explanation requires judgment. I generated the contract reference from the code because message definitions and field types already existed there in a form a parser could read.
I started with documentation because it could ship immediately
The CosmWasm developer experience had several problems. New developers lacked a usable starting guide, and the contract-development loop was slow. Improving the loop required tools such as LocalTerra and the simulator. Documentation could describe the platform that already existed.
That independence made it the first deliverable. I did not need a new language, VM, or chain API before I could explain how to instantiate a Rust contract, execute messages, query state, and inspect the response.
This constraint kept the guide honest. It described the contracts developers could write at the time, using the Rust types and commands they actually had.
The guide and reference have different sources of truth
The guide explains concepts and workflows: how CosmWasm execution works, how to structure a contract, and how to move from a message definition to a deployed instance. Its accuracy depends on whether the explanation matches the platform and whether a reader can follow it.
The reference answers narrower questions: which messages does this contract accept, which fields are required, what types do they use, and what does each handler do? Those facts already live in Rust enums, structs, function signatures, and handler code.
Writing the reference by hand would create a second copy of the same interface. Every source change would then require a matching documentation change that the compiler could not enforce.
I assigned the two documents accordingly:
| Document | Authoritative input | Production method |
|---|---|---|
| Conceptual guide | platform behavior and developer workflow | written and edited by a person |
| Contract reference | Rust messages, fields, handlers, and annotations | generated from source |
This did not eliminate human writing. It put human effort where interpretation mattered and let the parser handle exhaustive repetition.
I wrote the guide in separate passes
My first attempts mixed research, organization, drafting, and line editing. I would polish a paragraph before I knew whether it belonged in the final structure, then rewrite it when the surrounding section changed.
I separated the work into four passes:
brain dump → outline → rough draft → edit
collect organize connect improveThe brain dump collected everything I might need without ordering it. The outline grouped that material around a reader's task. The rough draft connected the sections. Editing handled accuracy, clarity, and sentence quality after the coverage had stabilized.
The separation gave each artifact a clear standard. I did not judge the brain dump for organization or the outline for prose. I also stopped adding whole new topics during line editing. If editing exposed a missing section, I returned to the outline instead of forcing it into the nearest paragraph.

This made collaboration easier. Another person could review the structure before either of us spent time polishing it.
I organized the guide around what the developer is doing
A feature list assumes the reader already understands the system well enough to map a feature to their problem. A beginner does not know that "submessages" are relevant when they are trying to call another contract and handle its result.
I organized the guide around developer tasks: create a contract, define messages, store state, execute another contract, handle a reply, test locally, and deploy. The table of contents used language a developer could recognize before learning CosmWasm's internal vocabulary.
The reference used the opposite organization. Someone opening a reference already knows the message or field they need. I indexed those pages by contract interface: instantiate messages, execute variants, query variants, responses, events, and errors.
The same content therefore appeared through two entry points. The guide started from a situation. The reference started from a symbol in the code.

Gherkin made behavior reviewable outside the Rust implementation
Message types describe the shape of an operation. They do not fully describe its behavior. A transfer message can contain a recipient and amount without saying what happens when the amount exceeds the sender's balance.
I used Gherkin scenarios for those behavioral rules:
Scenario: a withdrawal larger than the balance is refused
Given an account holding 100 tokens
When the owner withdraws 150 tokens
Then the transaction fails
And the balance is unchangedThe format uses ordinary sentences and a small fixed vocabulary. A product designer or protocol contributor who cannot review the Rust implementation can still challenge the expected outcome.
Engineers then bind the scenario to executable tests. That adds work compared with writing a Rust test alone, but it produces one behavior specification that both technical and nontechnical reviewers can read.

I kept Gherkin for externally meaningful behavior. Low-level implementation tests remained in Rust. This prevented the specification from becoming a verbose restatement of every internal function.
The generator reads the contract interface from the AST
The reference generator parses the same Rust source the compiler sees. Message enums identify entry points. Struct fields provide names and types. Doc comments provide descriptions. Handler functions show which code processes each message.
I designed the parser as shared infrastructure:
┌──────────────────┐
Rust source → AST → │ documentation │
│ semantic checks │
│ linter │
│ code search │
└──────────────────┘The documentation generator did not need a private interpretation of the code. The linter and semantic checker could use the same nodes and relationships. A message variant declared without a corresponding handler was both a documentation gap and a program-structure warning.

CosmWasm's execution model made handlers easier to describe. A contract handles one message, updates its own state, returns messages for the chain to process, and exits. Control does not leave in the middle of the function and later resume on the same stack.
That allowed me to represent a handler as an ordered list of logical steps:
pub fn execute_transfer(
deps: DepsMut,
info: MessageInfo,
recipient: String,
amount: Uint128,
) -> Result<Response, ContractError> {
// 1. Validate the recipient address.
let recipient = deps.api.addr_validate(&recipient)?;
// 2. Debit the sender, rejecting an overdraft.
BALANCES.update(deps.storage, &info.sender, /* ... */)?;
// 3. Credit the recipient.
BALANCES.update(deps.storage, &recipient, /* ... */)?;
Ok(Response::new().add_attribute("action", "transfer"))
}The numbered comments mark documentation boundaries. The generator associates each step with the following code and emits them in execution order. The linter can require numbering to remain sequential and warn when a large block has no documented step.

These comments become part of the contract interface for tooling, so I kept the syntax deliberately narrow. They describe externally relevant operations, not every line of implementation.
Annotations carry warnings and constraints beside the field
Ordinary doc comments explain what a message or field means. I added structured annotations for facts other tools could process:
pub enum ExecuteMsg {
/// Increases the allowance for `address` by `amount`.
/// @warning Allows another account to spend the owner's funds.
IncreaseAllowance {
/// Amount added to the existing allowance.
/// @constraint Must be greater than zero.
amount: Uint128,
/// Account receiving the allowance.
address: Addr,
},
}@warning identifies a consequence the caller should see before submitting the message. @constraint states a condition on a value. The reference can render both consistently, while tests and linters can inspect the same metadata.
I kept general explanation in normal prose. Adding a marker only helped when a downstream tool needed to distinguish that fact from the surrounding description.
The annotation remains hand-written and can still become stale. Generation removes the additional copies. A warning written beside the Rust field can appear in the reference, guide excerpts, and generated SDK documentation without being rewritten in each output.

The code and guide now do different jobs
The final system uses one source for contract facts and another for explanation. Rust types, signatures, handler steps, warnings, and constraints produce the exhaustive reference. The conceptual guide organizes those facts around the work a developer is trying to complete. Gherkin scenarios state behavior that needs review from people who do not read Rust.
This division made maintenance explicit. Changing a message field updates every generated reference page. Changing the way I explain contract execution still requires an editor because no parser can decide which explanation will make sense to a beginner.
That was the documentation problem I needed to solve. I did not want to generate prose that pretended to teach, and I did not want people manually copying hundreds of facts the code already knew. Terran One generated the facts and spent human attention on the explanation.