Here we intend to document the script and steps within to build a new Info action and submit it in a transaction.
Using the Google Docs template:
Export your metadata from Google Docs as markdown file (.md).
Set secrets, you can use the .env file for this.
source ./scripts/.envOptionally you can some variables to be reused.
export DEPOSIT_RETURN_ADDR="my-address"Make sure that CARDANO_NODE_NETWORK_ID and CARDANO_NODE_SOCKET_PATH are set.
These are needed to build the governance action file.
Convert the .md to intersect's metadata standard (this is a modified CIP-108 document).
With the metadata-create script taking the data from the doc and creating a .jsonld.
The input file must be a .md file structured with H2 headers (## Title, ## Abstract, ## Motivation, ## Rationale, ## References, ## Authors). Pass --language <BCP-47-tag> to override the default en in the generated @context.@language.
./scripts/metadata-create.sh my-metadata.md --governance-action-type info --deposit-return-addr $DEPOSIT_RETURN_ADDRGenerate a(nother) markdown representation from the created .jsonld
and manually compare against the .docx.
./scripts/cip-108-markdown.sh my-metadata.jsonldWe can then run our validation script to check
- compliance with CIP schema(s)
- compliance with Intersect schemas
- spell check (aspell personal dictionary fetched from the
mainbranch of this repo at runtime; skip with--no-spell-check) - URI reachability for every
uri/urlfield plus markdown links and bare URLs inside prose fields;ipfs://<cid>is resolved via$IPFS_GATEWAY_URI(fallbackhttps://ipfs.io). Skip with--no-check-links. body.titlelength ≤ 80 andbody.abstractlength ≤ 2500 characters (when those fields are present)
Because the metadata at this point in the procedure has not yet been signed, run with --draft:
./scripts/metadata-validate.sh my-metadata.jsonld --cip108 --cip169 --draftAt least one schema flag (--cipNNN, --intersect-schema, or --schema <URL>) is required.
The --draft flag is what suppresses the "missing author" failure at this stage; it must be omitted in step 9 below so the strict post-signing pass actually catches an empty-authors regression.
If metadata passes all the above validations. We can sign it with author key(s).
You can either pass the my-metadata.jsonld to authors to sign, using something like ./scripts/author-create.sh.
Or you can run ./scripts/metadata-canonize.sh and share the canonized body hash to sign via standard cardano wallets. In that case, HWW are supported too, but you need to change the witnessAlgorithm from ed25519 to CIP-0008 for those authors that do.
If you are not sure how your author key signs, CIP-8 signing produces a significantly longer (214 byte) signature string than ed25519 signing (62 bytes).
Just to double check that all is good now, with author.
./scripts/author-validate.sh my-metadata.jsonldPass --no-intersect to skip the comparison against Intersect's well-known author public key.
Just to double check that all is good now.
- compliance with CIP schema(s)
- compliance with Intersect schemas
- spell check (skip with
--no-spell-check) - URI reachability (skip with
--no-check-links) - title/abstract length limits
- structural integrity (non-empty
authors)
Run without --draft so the empty-authors check is strict — this is what guarantees the document was actually signed in step 7:
./scripts/metadata-validate.sh my-metadata.jsonld --cip108 --cip169Pin the metadata to different IPFS pinning services.
./scripts/ipfs-pin.sh my-metadata.jsonldTo skip a specific pinning service use --no-local, --no-pinata, --no-blockfrost, or --no-nmkr.
This will now additionally check that the file is accessible via IPFS.
./scripts/ipfs-check.sh my-metadata.jsonldNow we can create an Info governance action file from our metadata. The stake key must be registered via a registration certificate (auto done by e.g. pool delegations) and the deposit will eventually appear as staking reward.
./scripts/action-create-info.sh my-metadata.jsonld --deposit-return-addr $DEPOSIT_RETURN_ADDRWe can now include this .action file in a transaction.
Note that the GA deposit is balanced out across all inputs, as if we were to create a new UTXO, and we can spend multiple inputs to get to the deposit. Thus, the below example with only one --tx-in consumes a UTXO that must contain 100k ada + fees.
cardano-cli latest transaction build \
--tx-in "$(cardano-cli query utxo --address "$(< payment.addr)" --output-json | jq -r 'keys[0]')" \
--change-address $(< payment.addr) \
--proposal-file info.action \
--out-file tx.rawWe copy the contents of tx.raw to wherever the key is that contains the input we spend. No other signatures are required.
Depending on the setup, e.g. for testnets, copying the raw CBOR could be used to import the tx in certain GUI wallets and sign via those. However, at the moment (Q4 2025), only the Keystone HWW supports signing Governance Actions.
cardano-cli latest transaction sign \
--tx-body-file tx.raw \
--signing-key-file payment.skey \
--out-file tx.signedE.g.: through CLI
cardano-cli latest transaction submit \
--tx-file tx.signed