Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
21c0c3b
Create docs-sync-to-example.yml
evanorti Mar 19, 2026
edc3bf3
Update CLAUDE.md
evanorti Mar 19, 2026
24def85
Update docs.json
evanorti Mar 19, 2026
72787a6
Update accounts.mdx
evanorti Mar 19, 2026
e92e0bf
Update app-go.mdx
evanorti Mar 19, 2026
c6ca1f0
Create 02-quickstart.mdx
evanorti Mar 19, 2026
092d9b3
Create 03-build-a-module.mdx
evanorti Mar 19, 2026
5d16919
Create 04-counter-walkthrough.mdx
evanorti Mar 19, 2026
93ea22e
Create 05-run-and-test.mdx
evanorti Mar 19, 2026
f91fa22
Create build-a-module.mdx
evanorti Mar 19, 2026
4013495
Create 01-prerequisites.mdx
evanorti Mar 19, 2026
0b58459
updates
evanorti Mar 19, 2026
43385df
Delete build-a-module.mdx
evanorti Mar 19, 2026
0a70b8c
Update sdk-app-architecture.mdx
evanorti Mar 19, 2026
e66fb42
Update 03-build-a-module.mdx
evanorti Mar 19, 2026
33f150d
Update 01-prerequisites.mdx
evanorti Mar 19, 2026
ef28ee7
Update accounts.mdx
evanorti Mar 19, 2026
8ee37bd
Update sdk-app-architecture.mdx
evanorti Mar 19, 2026
ac04482
Update encoding.mdx
evanorti Mar 19, 2026
d5319ed
Update sdk/next/learn/intro/sdk-app-architecture.mdx
evanorti Mar 19, 2026
f57502f
Update docs-sync-to-example.yml
evanorti Mar 19, 2026
ae1cd2f
Merge branch 'feat/example-tutorial-sync' of https://github.com/cosmo…
evanorti Mar 19, 2026
cd1d078
Update .gitignore
evanorti Mar 19, 2026
25a93be
Create transform.py
evanorti Mar 19, 2026
76e753b
Update docs-sync-to-example.yml
evanorti Mar 19, 2026
fda51ea
Update CLAUDE.md
evanorti Mar 19, 2026
56abe1c
Update docs-sync-to-example.yml
evanorti Mar 19, 2026
0706147
Update transform.py
evanorti Mar 19, 2026
c62b447
Update docs-sync-to-example.yml
evanorti Mar 19, 2026
48ecdca
Update 04-counter-walkthrough.mdx
evanorti Mar 19, 2026
f55022c
Revert "Update 04-counter-walkthrough.mdx"
evanorti Mar 19, 2026
05ffb0a
Update 00-overview.mdx
evanorti Mar 24, 2026
dce3990
Update 01-prerequisites.mdx
evanorti Mar 24, 2026
f91c1c0
Update 03-build-a-module.mdx
evanorti Mar 24, 2026
3b8105c
Update docs.json
evanorti Mar 24, 2026
6c642c2
Update learn.mdx
evanorti Mar 24, 2026
c664b47
Update sdk-structure.mdx
evanorti Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .github/workflows/docs-sync-to-example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: Docs Sync → cosmos/example

# Runs when example tutorial .mdx files change on main.
# Transforms .mdx → .md and opens a PR on the example repo.
# If a sync PR is already open, updates it instead of opening a new one.
# Skip if the commit was itself produced by the sync (loop guard).

on:
push:
branches:
- main
paths:
- "sdk/next/tutorials/example/**"

jobs:
sync:
name: Sync example tutorials to cosmos/example
runs-on: ubuntu-latest
# Loop guard: skip commits that the docs-sync bot created
if: "!contains(github.event.head_commit.message, '[docs-sync]')"

steps:
- name: Checkout cosmos/docs
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Checkout cosmos/example
uses: actions/checkout@v4
with:
repository: cosmos/example
# Fine-grained PAT with contents:write and pull-requests:write on cosmos/example
token: ${{ secrets.EXAMPLE_REPO_TOKEN }}
path: cosmos-example

- name: Transform Mintlify → example repo format
run: |
python3 scripts/docs-sync/transform.py \
--direction to-example \
--input sdk/next/tutorials/example/ \
--output-dir cosmos-example/docs/

- name: Check for changes
id: diff
run: |
cd cosmos-example
[ -n "$(git status --porcelain docs/)" ] \
&& echo "changed=true" >> "$GITHUB_OUTPUT" \
|| echo "changed=false" >> "$GITHUB_OUTPUT"

- name: Open or update PR on cosmos/example
if: steps.diff.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.EXAMPLE_REPO_TOKEN }}
run: |
cd cosmos-example
Comment thread
evanorti marked this conversation as resolved.

git config user.name "docs-sync[bot]"
git config user.email "docs-sync[bot]@users.noreply.github.com"

# Check for an existing open sync PR
EXISTING=$(gh pr list \
--repo cosmos/example \
--label "docs-sync" \
--state open \
--json number,headRefName \
--jq '.[0]')

if [ -n "$EXISTING" ]; then
PR_NUMBER=$(echo "$EXISTING" | jq -r '.number')
BRANCH=$(echo "$EXISTING" | jq -r '.headRefName')

# Stash the transform output before switching branches,
# then restore it on top of the existing sync branch.
git stash
git fetch origin "$BRANCH"
git checkout "$BRANCH"
git stash pop
git add docs/
git commit -m "docs: sync example tutorials from cosmos/docs [docs-sync]"
git push origin "$BRANCH"

gh pr comment "$PR_NUMBER" \
--repo cosmos/example \
Comment on lines +84 to +87
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 git stash silently skips untracked files — stash pop will fail

git stash only stashes changes to already-tracked files. When the transform writes .md files into cosmos-example/docs/ and that directory does not yet exist on cosmos/example's default branch (e.g. on the very first sync run, or whenever a new tutorial page is added), those output files are untracked. git stash prints "No local changes to stash" and exits 0 — it saves nothing. The subsequent git stash pop then fails with error: No stash entries found., aborting the entire "update existing PR" code path.

The fix is to include untracked files in the stash:

Suggested change
git push origin "$BRANCH"
gh pr comment "$PR_NUMBER" \
--repo cosmos/example \
git stash --include-untracked
git fetch origin "$BRANCH"
git checkout "$BRANCH"
git stash pop

Using --include-untracked (or the short form -u) ensures newly-created files are stashed alongside modified tracked files and correctly restored on top of the sync branch.

--body "Sync updated: cosmos/docs was updated before this PR merged. Branch has been refreshed — please re-review."
echo "Updated existing PR #$PR_NUMBER"

else
BRANCH="docs-sync/from-docs-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
git add docs/
git commit -m "docs: sync example tutorials from cosmos/docs [docs-sync]"
git push origin "$BRANCH"
Comment thread
evanorti marked this conversation as resolved.

gh pr create \
--repo cosmos/example \
--head "$BRANCH" \
--base main \
--title "docs: sync example tutorials from cosmos/docs" \
--label "docs-sync" \
--body "Auto-synced from cosmos/docs. Transforms sdk/next/tutorials/example/*.mdx to docs/*.md. Do not edit docs/ files directly in cosmos/example — edit the source and let the sync bot update them."
fi
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ scripts/*
!scripts/versioning/**
!scripts/migration/
!scripts/migration/**
!scripts/docs-sync/
!scripts/docs-sync/**
# Re-ignore node_modules after un-ignoring parent directories
scripts/versioning/node_modules/
scripts/migration/node_modules/
Expand Down
24 changes: 24 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ When updating documentation:
- **Precompile Addresses**: Fixed addresses documented in tests/README.md
- **Network Endpoints**: Configure in tests/config.js for testing

## Example Tutorial Sync (cosmos/example ↔ this repo)

The Cosmos SDK example chain tutorials live in `sdk/next/tutorials/example/` (files `00-overview.mdx` through `05-run-and-test.mdx`) and are kept in sync with the `cosmos/example` repo via a bidirectional GitHub Actions workflow. When either side merges a change to these files, a PR is automatically opened on the other repo with the content transformed between formats (H1 ↔ frontmatter, absolute ↔ relative links).

The transform script exists in two places and must be kept in sync:
- `scripts/docs-sync/transform.py` in **this repo** — used by `.github/workflows/docs-sync-to-example.yml` to transform `.mdx` → `.md` when syncing to `cosmos/example`
- `scripts/docs-sync/transform.py` in **`cosmos/example`** — used for manual local syncs in both directions

`scripts/docs-sync/` is explicitly unignored in `.gitignore` (the default `scripts/*` rule would otherwise hide it).

When editing these tutorial pages, `title:` is always owned by the sync (sourced from the H1 in the example repo) — but any other frontmatter you add here (e.g. `description:`) will be preserved across syncs.

## Internal Links

Always use absolute Mintlify paths for internal links — never relative file paths or `.mdx` extensions:

```md
✅ [Build a Module](/sdk/next/tutorials/example/03-build-a-module)
❌ [Build a Module](./03-build-a-module.mdx)
❌ [Build a Module](03-build-a-module)
```

The path is the file's location relative to the `docs/` root, without the `.mdx` extension.

## Important Notes

- All documentation files use MDX format with Mintlify-specific components
Expand Down
122 changes: 73 additions & 49 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -638,40 +638,69 @@
"tab": "Cosmos SDK",
"groups": [
{
"group": "Learn",
"group": "Overview",
"pages": [
"sdk/next/learn",
"sdk/next/learn/intro/cosmos-stack",
"sdk/next/learn/intro/overview",
"sdk/next/learn/intro/why-app-specific",
"sdk/next/learn/intro/blockchain-basics",
"sdk/next/learn/intro/sdk-app-architecture",
"sdk/next/learn/intro/sdk-design"
]
},
{
"group": "Concepts",
"pages": [
{
"group": "Overview",
"group": "Fundamentals",
"expanded": true,
"pages": [
"sdk/next/learn/intro/cosmos-stack",
"sdk/next/learn/intro/overview",
"sdk/next/learn/intro/why-app-specific",
"sdk/next/learn/intro/blockchain-basics",
"sdk/next/learn/intro/sdk-app-architecture",
"sdk/next/learn/intro/sdk-design"
"sdk/next/learn/concepts/accounts",
"sdk/next/learn/concepts/transactions",
"sdk/next/learn/concepts/lifecycle"
]
},
{
"group": "Concepts",
"group": "Modules",
"expanded": true,
"pages": [
"sdk/next/learn/concepts/accounts",
"sdk/next/learn/concepts/transactions",
"sdk/next/learn/concepts/lifecycle",
"sdk/next/learn/concepts/modules",
"sdk/next/learn/concepts/store",
"sdk/next/learn/concepts/encoding",
"sdk/next/learn/concepts/context-gas-events",
"sdk/next/learn/concepts/context-gas-events"
]
},
{
"group": "Blockchains",
"expanded": true,
"pages": [
"sdk/next/learn/concepts/sdk-structure",
"sdk/next/learn/concepts/baseapp",
"sdk/next/learn/concepts/app-go",
"sdk/next/learn/concepts/cli-grpc-rest",
"sdk/next/learn/concepts/testing"
]
},
}
]
},
{
"group": "Tutorials",
"pages": [
"sdk/next/tutorials/example/00-overview",
"sdk/next/tutorials/example/01-prerequisites",
"sdk/next/tutorials/example/02-quickstart",
"sdk/next/tutorials/example/03-build-a-module",
"sdk/next/tutorials/example/04-counter-walkthrough",
"sdk/next/tutorials/example/05-run-and-test"
]
},
{
"group": "SDK Internals",
"pages": [
{
"group": "Fundamentals",
"expanded": false,
"pages": [
"sdk/next/learn/beginner/app-anatomy",
"sdk/next/learn/beginner/tx-lifecycle",
Expand All @@ -681,45 +710,40 @@
]
},
{
"group": "In-depth Concepts",
"group": "Core Components",
"expanded": false,
"pages": [
{
"group": "Core Components",
"expanded": true,
"pages": [
"sdk/next/learn/advanced/baseapp",
"sdk/next/learn/advanced/transactions",
"sdk/next/learn/advanced/context",
"sdk/next/learn/advanced/encoding",
"sdk/next/learn/advanced/store",
"sdk/next/build/spec/addresses/bech32"
]
},
{
"group": "Security & Execution",
"expanded": true,
"pages": [
"sdk/next/learn/advanced/ocap",
"sdk/next/learn/advanced/runtx_middleware"
]
},
"sdk/next/learn/advanced/events",
"sdk/next/learn/advanced/node",
{
"group": "Chain CLI & Endpoints",
"expanded": true,
"pages": [
"sdk/next/learn/advanced/grpc_rest",
"sdk/next/learn/advanced/cli",
"sdk/next/learn/advanced/autocli"
]
}
"sdk/next/learn/advanced/baseapp",
"sdk/next/learn/advanced/transactions",
"sdk/next/learn/advanced/context",
"sdk/next/learn/advanced/encoding",
"sdk/next/learn/advanced/store",
"sdk/next/build/spec/addresses/bech32"
]
},
{
"group": "Security & Execution",
"expanded": false,
"pages": [
"sdk/next/learn/advanced/ocap",
"sdk/next/learn/advanced/runtx_middleware"
]
},
"sdk/next/learn/advanced/events",
"sdk/next/learn/advanced/node",
{
"group": "Chain CLI & Endpoints",
"expanded": false,
"pages": [
"sdk/next/learn/advanced/grpc_rest",
"sdk/next/learn/advanced/cli",
"sdk/next/learn/advanced/autocli"
]
}
]
},
{
"group": "Building a Chain",
"group": "Chain Development",
"pages": [
"sdk/next/build",
{
Expand Down Expand Up @@ -757,7 +781,7 @@
]
},
{
"group": "Building a Module",
"group": "Modules",
"pages": [
{
"group": "Module Development",
Expand Down Expand Up @@ -875,7 +899,7 @@
]
},
{
"group": "How-to Guides",
"group": "Advanced Guides",
"pages": [
"sdk/next/user",
{
Expand Down
Loading