demolab-cli 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. demolab_cli-1.0.0/.github/workflows/landing-preview.yml +62 -0
  2. demolab_cli-1.0.0/.github/workflows/landing.yml +76 -0
  3. demolab_cli-1.0.0/.github/workflows/publish.yml +33 -0
  4. demolab_cli-1.0.0/.github/workflows/tests.yml +69 -0
  5. demolab_cli-1.0.0/.gitignore +35 -0
  6. demolab_cli-1.0.0/AGENTS.md +59 -0
  7. demolab_cli-1.0.0/CLAUDE.md +19 -0
  8. demolab_cli-1.0.0/DEVELOPING.md +76 -0
  9. demolab_cli-1.0.0/LICENSE +21 -0
  10. demolab_cli-1.0.0/PKG-INFO +101 -0
  11. demolab_cli-1.0.0/README.md +70 -0
  12. demolab_cli-1.0.0/demolab_cli/CHANGELOG.md +445 -0
  13. demolab_cli-1.0.0/demolab_cli/VERSION +1 -0
  14. demolab_cli-1.0.0/demolab_cli/__init__.py +10 -0
  15. demolab_cli-1.0.0/demolab_cli/_paths.py +63 -0
  16. demolab_cli-1.0.0/demolab_cli/build.py +284 -0
  17. demolab_cli-1.0.0/demolab_cli/cli.py +414 -0
  18. demolab_cli-1.0.0/demolab_cli/deploy/deploy.yml +61 -0
  19. demolab_cli-1.0.0/demolab_cli/deploy/preview.yml +56 -0
  20. demolab_cli-1.0.0/demolab_cli/devserver.py +380 -0
  21. demolab_cli-1.0.0/demolab_cli/guides/AUTORESEARCH-RULES.md +149 -0
  22. demolab_cli-1.0.0/demolab_cli/guides/GLOSSARY.md +55 -0
  23. demolab_cli-1.0.0/demolab_cli/guides/HOUSESTYLE.md +108 -0
  24. demolab_cli-1.0.0/demolab_cli/guides/RULES.md +142 -0
  25. demolab_cli-1.0.0/demolab_cli/guides/SLIDES.md +145 -0
  26. demolab_cli-1.0.0/demolab_cli/guides/STRUCTURE.md +78 -0
  27. demolab_cli-1.0.0/demolab_cli/guides/SUPPORT.md +36 -0
  28. demolab_cli-1.0.0/demolab_cli/overlay.py +47 -0
  29. demolab_cli-1.0.0/demolab_cli/runbooks/AUTORESEARCH.md +67 -0
  30. demolab_cli-1.0.0/demolab_cli/runbooks/DOCTOR.md +116 -0
  31. demolab_cli-1.0.0/demolab_cli/runbooks/EMBED-DOCS.md +39 -0
  32. demolab_cli-1.0.0/demolab_cli/runbooks/FROM-JUPYTER.md +84 -0
  33. demolab_cli-1.0.0/demolab_cli/runbooks/FROM-PAPER.md +48 -0
  34. demolab_cli-1.0.0/demolab_cli/runbooks/GETTING-STARTED.md +281 -0
  35. demolab_cli-1.0.0/demolab_cli/runbooks/GROUND-CLAIMS.md +166 -0
  36. demolab_cli-1.0.0/demolab_cli/runbooks/LINT.md +176 -0
  37. demolab_cli-1.0.0/demolab_cli/runbooks/MIGRATE-CODE.md +49 -0
  38. demolab_cli-1.0.0/demolab_cli/runbooks/MIGRATE-STACK.md +50 -0
  39. demolab_cli-1.0.0/demolab_cli/runbooks/NEXT.md +52 -0
  40. demolab_cli-1.0.0/demolab_cli/runbooks/NIGHT-SHIFT.md +68 -0
  41. demolab_cli-1.0.0/demolab_cli/runbooks/PLAN.md +64 -0
  42. demolab_cli-1.0.0/demolab_cli/runbooks/RED-TEAM.md +72 -0
  43. demolab_cli-1.0.0/demolab_cli/runbooks/STEELMAN.md +44 -0
  44. demolab_cli-1.0.0/demolab_cli/runbooks/TOUR.md +42 -0
  45. demolab_cli-1.0.0/demolab_cli/runbooks/UPDATE.md +84 -0
  46. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/ar018/swe-bench.svg +1 -0
  47. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp000/lif.svg +1103 -0
  48. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp000/net.png +0 -0
  49. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp000/numbers.json +38 -0
  50. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp000/run.sh +3 -0
  51. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp001/eif.svg +1122 -0
  52. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp001/enet.png +0 -0
  53. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp001/numbers.json +40 -0
  54. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp001/run.sh +3 -0
  55. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp002/cartpole.mp4 +0 -0
  56. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp002/numbers.json +18 -0
  57. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp002/run.sh +3 -0
  58. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp003/double_pendulum.mp4 +0 -0
  59. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp003/numbers.json +21 -0
  60. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/data/exp003/run.sh +3 -0
  61. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar000.pdf +546 -0
  62. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar003.pdf +773 -1
  63. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar004.pdf +2846 -2
  64. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar005.pdf +4216 -5
  65. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar006.pdf +1200 -0
  66. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar010.pdf +718 -0
  67. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar011.pdf +530 -0
  68. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar012.pdf +634 -1
  69. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar013.pdf +575 -1
  70. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar014.pdf +0 -0
  71. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar015.pdf +0 -0
  72. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar016.pdf +520 -0
  73. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar017.pdf +875 -1
  74. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/ar018.pdf +871 -1
  75. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/book.pdf +10343 -6
  76. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/exp000.pdf +2036 -4
  77. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/exp001.pdf +2226 -2
  78. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/exp002.pdf +683 -0
  79. demolab_cli-1.0.0/demolab_cli/scaffold/demo/artifacts/pdfs/exp003.pdf +767 -0
  80. demolab_cli-1.0.0/demolab_cli/scaffold/demo/demolab.yaml +26 -0
  81. demolab_cli-1.0.0/demolab_cli/scaffold/demo/experiments/exp000.py +106 -0
  82. demolab_cli-1.0.0/demolab_cli/scaffold/demo/experiments/exp001.py +106 -0
  83. demolab_cli-1.0.0/demolab_cli/scaffold/demo/experiments/exp002.py +74 -0
  84. demolab_cli-1.0.0/demolab_cli/scaffold/demo/experiments/exp003.py +73 -0
  85. demolab_cli-1.0.0/demolab_cli/scaffold/demo/experiments/playground.py +157 -0
  86. demolab_cli-1.0.0/demolab_cli/scaffold/demo/site/CNAME +1 -0
  87. demolab_cli-1.0.0/demolab_cli/scaffold/demo/site/landing.typ +38 -0
  88. demolab_cli-1.0.0/demolab_cli/scaffold/demo/tools/mujoco/test_mujoco.py +42 -0
  89. demolab_cli-1.0.0/demolab_cli/scaffold/demo/tools/mujoco/tool.py +393 -0
  90. demolab_cli-1.0.0/demolab_cli/scaffold/demo/tools/neuron/test_neuron.py +106 -0
  91. demolab_cli-1.0.0/demolab_cli/scaffold/demo/tools/neuron/tool.py +526 -0
  92. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar000.typ +86 -0
  93. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar003.typ +82 -0
  94. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar004.slide.typ +418 -0
  95. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar005.slide.typ +294 -0
  96. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar006.typ +148 -0
  97. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar010.typ +54 -0
  98. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar011.typ +32 -0
  99. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar012.typ +52 -0
  100. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar013.typ +47 -0
  101. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar014.typ +56 -0
  102. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar015.typ +33 -0
  103. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar016.typ +29 -0
  104. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar017.typ +98 -0
  105. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/ar018.typ +128 -0
  106. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/exp000.typ +77 -0
  107. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/exp001.typ +81 -0
  108. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/exp002.typ +47 -0
  109. demolab_cli-1.0.0/demolab_cli/scaffold/demo/writings/exp003.typ +61 -0
  110. demolab_cli-1.0.0/demolab_cli/scaffold/demo-manifest.json +54 -0
  111. demolab_cli-1.0.0/demolab_cli/scaffold/root/AGENTS.md +54 -0
  112. demolab_cli-1.0.0/demolab_cli/scaffold/root/CLAUDE.md +18 -0
  113. demolab_cli-1.0.0/demolab_cli/scaffold/root/README.md +28 -0
  114. demolab_cli-1.0.0/demolab_cli/scaffold/root/github/workflows/tests.yml +21 -0
  115. demolab_cli-1.0.0/demolab_cli/scaffold/root/gitignore +30 -0
  116. demolab_cli-1.0.0/demolab_cli/scaffold/root/pyproject.toml +32 -0
  117. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/HOUSESTYLE.local.md +25 -0
  118. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/artifacts/data/.gitkeep +0 -0
  119. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/artifacts/pdfs/.gitkeep +0 -0
  120. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/demolab.yaml +40 -0
  121. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/experiments/helpers/__init__.py +1 -0
  122. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/experiments/helpers/provenance.py +78 -0
  123. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/experiments/helpers/style.py +39 -0
  124. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/experiments/helpers/test_provenance.py +37 -0
  125. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/tools/.gitkeep +0 -0
  126. demolab_cli-1.0.0/demolab_cli/scaffold/skeleton/writings/.gitkeep +0 -0
  127. demolab_cli-1.0.0/demolab_cli/scaffold/starters/monte-carlo-pi/README.md +41 -0
  128. demolab_cli-1.0.0/demolab_cli/scaffold/starters/monte-carlo-pi/exp000.py +110 -0
  129. demolab_cli-1.0.0/demolab_cli/scaffold/starters/monte-carlo-pi/exp000.typ +63 -0
  130. demolab_cli-1.0.0/demolab_cli/slides.py +42 -0
  131. demolab_cli-1.0.0/demolab_cli/test_build_resilience.py +29 -0
  132. demolab_cli-1.0.0/demolab_cli/test_cli.py +48 -0
  133. demolab_cli-1.0.0/demolab_cli/test_command_catalog.py +37 -0
  134. demolab_cli-1.0.0/demolab_cli/test_devserver.py +84 -0
  135. demolab_cli-1.0.0/demolab_cli/test_engine_build.py +150 -0
  136. demolab_cli-1.0.0/demolab_cli/test_init_and_staging.py +133 -0
  137. demolab_cli-1.0.0/demolab_cli/test_overlay.py +43 -0
  138. demolab_cli-1.0.0/demolab_cli/test_slide_catalog.py +40 -0
  139. demolab_cli-1.0.0/demolab_cli/test_slides.py +18 -0
  140. demolab_cli-1.0.0/demolab_cli/typ/cite-popover.js +38 -0
  141. demolab_cli-1.0.0/demolab_cli/typ/favicon.svg +8 -0
  142. demolab_cli-1.0.0/demolab_cli/typ/lib.typ +518 -0
  143. demolab_cli-1.0.0/demolab_cli/typ/main.typ +92 -0
  144. demolab_cli-1.0.0/demolab_cli/typ/style.css +263 -0
  145. demolab_cli-1.0.0/pyproject.toml +69 -0
  146. demolab_cli-1.0.0/uv.lock +2256 -0
@@ -0,0 +1,62 @@
1
+ name: PR preview (demo site)
2
+
3
+ # Builds the shipped demo for every pull request and publishes it under pr-preview/pr-<N>/ on the
4
+ # gh-pages branch, posts a sticky comment on the PR with the URL, and tears the preview down when
5
+ # the PR closes or merges. This is what makes a PR's rendered doc set readable in place instead of
6
+ # a raw diff. Pairs with landing.yml (the same gh-pages branch); needs the Pages source set to
7
+ # "Deploy from a branch → gh-pages / (root)".
8
+ #
9
+ # Fork PRs get a read-only token and cannot write gh-pages, so previews are skipped for external
10
+ # contributors. Do NOT switch this to pull_request_target to "fix" that — it runs untrusted PR
11
+ # code with a write token (privilege-escalation footgun).
12
+ on:
13
+ pull_request:
14
+ types: [opened, synchronize, reopened, closed]
15
+
16
+ permissions:
17
+ contents: write
18
+ pull-requests: write
19
+
20
+ # One in-flight run per PR: rapid pushes supersede rather than race commits to gh-pages.
21
+ concurrency:
22
+ group: preview-pr-${{ github.event.pull_request.number }}
23
+ cancel-in-progress: true
24
+
25
+ env:
26
+ TYPST_VERSION: "0.15.0"
27
+
28
+ jobs:
29
+ preview:
30
+ # Upstream only, same as the production deploy — a fork must not publish into demolab's Pages.
31
+ if: github.repository == 'eoinmurray/demolab'
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ # On 'closed' we only tear the preview down (no build needed), so guard the build steps.
37
+ - name: Install Typst ${{ env.TYPST_VERSION }}
38
+ if: github.event.action != 'closed'
39
+ run: |
40
+ url="https://github.com/typst/typst/releases/download/v${TYPST_VERSION}/typst-x86_64-unknown-linux-musl.tar.xz"
41
+ curl -fsSL "$url" | tar -xJ
42
+ echo "$PWD/typst-x86_64-unknown-linux-musl" >> "$GITHUB_PATH"
43
+
44
+ - uses: astral-sh/setup-uv@v5
45
+ if: github.event.action != 'closed'
46
+
47
+ - name: Build the demo with the core engine
48
+ if: github.event.action != 'closed'
49
+ run: |
50
+ rsync -a --exclude 'site/' demolab_cli/scaffold/skeleton/ ./
51
+ rsync -a --exclude 'site/' demolab_cli/scaffold/demo/ ./
52
+ # Same landing-only homepage as production (landing.yml), so the preview matches.
53
+ cp demolab_cli/scaffold/demo/site/landing.typ ./landing.typ
54
+ uv run --no-dev demolab build
55
+
56
+ # Deploy artifacts/site (the raw built demo — no CNAME/installers; those only belong at the
57
+ # production root) to pr-preview/pr-<N>/, maintain the sticky comment, and remove the subdir
58
+ # on 'closed'. The action auto-detects deploy vs remove from the event type.
59
+ - name: Deploy / update / tear down the preview
60
+ uses: rossjrw/pr-preview-action@v1
61
+ with:
62
+ source-dir: artifacts/site
@@ -0,0 +1,76 @@
1
+ name: Deploy the site (demo at root)
2
+
3
+ # Publishes to GitHub Pages at demolab.eoinmurray.info via the BRANCH-based flow:
4
+ # build the shipped demo → assemble _site (demo at /, CNAME) → commit to the
5
+ # `gh-pages` branch. Branch-based (not the GitHub-Actions Pages flow) so per-PR previews
6
+ # (landing-preview.yml) can live in the same branch under pr-preview/. Requires the Pages source
7
+ # set to "Deploy from a branch → gh-pages / (root)". A user's own lab deploy is separate and
8
+ # opt-in (demolab_cli/deploy/deploy.yml, added by `demolab deploy-setup`).
9
+ on:
10
+ push:
11
+ branches: [main]
12
+ paths:
13
+ - "demolab_cli/**"
14
+ - "pyproject.toml"
15
+ - ".github/workflows/landing.yml"
16
+ workflow_dispatch:
17
+
18
+ # The deploy commits the assembled site to the gh-pages branch, so the token needs write.
19
+ permissions:
20
+ contents: write
21
+
22
+ # Serialise production deploys against each other and against preview teardowns so two writers
23
+ # never race a commit to gh-pages. Previews use their own per-PR group.
24
+ concurrency:
25
+ group: pages-deploy
26
+ cancel-in-progress: false
27
+
28
+ env:
29
+ TYPST_VERSION: "0.15.0" # match the engine's local toolchain
30
+
31
+ jobs:
32
+ deploy:
33
+ # Upstream only. Forks/templates inherit this file, but must never publish demolab's site to
34
+ # their own Pages — so the job is skipped everywhere but the source repo.
35
+ if: github.repository == 'eoinmurray/demolab'
36
+ runs-on: ubuntu-latest
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Install Typst ${{ env.TYPST_VERSION }}
41
+ run: |
42
+ # Download the pinned release directly (deterministic, no third-party action to track).
43
+ url="https://github.com/typst/typst/releases/download/v${TYPST_VERSION}/typst-x86_64-unknown-linux-musl.tar.xz"
44
+ curl -fsSL "$url" | tar -xJ
45
+ echo "$PWD/typst-x86_64-unknown-linux-musl" >> "$GITHUB_PATH"
46
+
47
+ - uses: astral-sh/setup-uv@v5
48
+
49
+ - name: Build the demo with the core engine
50
+ run: |
51
+ # Materialise the shipped demo at the repo root (skeleton + demo overlay), exactly as
52
+ # `demolab add-demo-content` does, then compile it with the engine. The engine has zero
53
+ # runtime deps and the demo ships its rendered figures/videos, so --no-dev skips the
54
+ # heavy science deps (they're only for *running* experiments and the test suite).
55
+ rsync -a --exclude 'site/' demolab_cli/scaffold/skeleton/ ./
56
+ rsync -a --exclude 'site/' demolab_cli/scaffold/demo/ ./
57
+ # The landing-only homepage (the marketing hero, a custom landing.typ) — kept under
58
+ # site/ so the add-demo-content overlay never puts it in a user's lab.
59
+ cp demolab_cli/scaffold/demo/site/landing.typ ./landing.typ
60
+ uv run --no-dev demolab build
61
+
62
+ - name: Assemble the Pages tree (demo at /, CNAME at root)
63
+ run: |
64
+ rm -rf _site && cp -R artifacts/site/. _site/
65
+ cp demolab_cli/scaffold/demo/site/CNAME _site/
66
+
67
+ # Publish _site to the root of gh-pages. clean-exclude preserves the live PR previews
68
+ # (pr-preview/, owned by landing-preview.yml) — CNAME is re-emitted from _site every run.
69
+ - name: Deploy to gh-pages
70
+ uses: JamesIves/github-pages-deploy-action@v4
71
+ with:
72
+ folder: _site
73
+ branch: gh-pages
74
+ clean: true
75
+ clean-exclude: pr-preview/
76
+ single-commit: true
@@ -0,0 +1,33 @@
1
+ name: Publish demolab-cli to PyPI
2
+
3
+ # Tag-triggered release: `git tag v<VERSION> && git push --tags` builds the wheel from a
4
+ # clean checkout and publishes it via PyPI Trusted Publishing (OIDC — no API token stored).
5
+ # One-time setup on pypi.org: Account → Publishing → add a pending publisher for project
6
+ # `demolab-cli`, owner `eoinmurray`, repo `demolab`, workflow `publish.yml`, environment
7
+ # `pypi` — and create the matching `pypi` environment in this repo's GitHub settings.
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ publish:
17
+ # Upstream only — a fork's tags must never try to publish the package.
18
+ if: github.repository == 'eoinmurray/demolab'
19
+ runs-on: ubuntu-latest
20
+ environment: pypi
21
+ permissions:
22
+ id-token: write # OIDC for Trusted Publishing
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - name: Tag must match the engine VERSION
27
+ run: test "v$(cat demolab_cli/VERSION)" = "$GITHUB_REF_NAME"
28
+
29
+ - uses: astral-sh/setup-uv@v5
30
+
31
+ - run: uv build
32
+
33
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,69 @@
1
+ name: Tests
2
+
3
+ # Runs the Python test suite on Linux AND Windows. The Windows leg guards the portability
4
+ # fixes a real Windows user's field report drove: the dev server's dual-stack bind (Windows
5
+ # resolves `localhost` to ::1, so an IPv4-only bind makes the printed URL dead there), the
6
+ # overlay.py copy behind demolab scaffold / add-demo-content (rsync doesn't exist on
7
+ # Windows), and slides.py's deck detection (grep/basename didn't either). macOS/Linux pass
8
+ # these trivially — only a real Windows runner is an honest check.
9
+ #
10
+ # Installing typst on the Linux leg unskips the engine build smoke test there; Windows
11
+ # stays typst-less and fast. The packaging job builds the wheel from this clean checkout
12
+ # and inits a lab from it — the same path `uvx demolab-cli init` takes in the wild.
13
+ on:
14
+ push:
15
+ branches: [main]
16
+ paths:
17
+ - "demolab_cli/**"
18
+ - "pyproject.toml"
19
+ - ".github/workflows/tests.yml"
20
+ pull_request:
21
+ paths:
22
+ - "demolab_cli/**"
23
+ - "pyproject.toml"
24
+ - ".github/workflows/tests.yml"
25
+ workflow_dispatch:
26
+
27
+ permissions:
28
+ contents: read
29
+
30
+ jobs:
31
+ pytest:
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ os: [ubuntu-latest, windows-latest]
36
+ runs-on: ${{ matrix.os }}
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - uses: astral-sh/setup-uv@v5
41
+
42
+ - name: Install typst (Linux — unskips the engine build tests)
43
+ if: runner.os == 'Linux'
44
+ env:
45
+ TYPST_VERSION: "0.15.0" # match the engine's toolchain (see landing.yml)
46
+ run: |
47
+ curl -sL "https://github.com/typst/typst/releases/download/v${TYPST_VERSION}/typst-x86_64-unknown-linux-musl.tar.xz" \
48
+ | tar -xJf - -C /usr/local/bin --strip-components=1 "typst-x86_64-unknown-linux-musl/typst"
49
+
50
+ - name: Run the test suite
51
+ run: uv run pytest
52
+
53
+ packaging:
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - uses: astral-sh/setup-uv@v5
59
+
60
+ - name: Build the wheel and init a lab from it
61
+ run: |
62
+ uv build
63
+ # Noise that must never ship (untracked locally, but belt-and-braces).
64
+ if unzip -l dist/demolab_cli-*.whl | grep -E 'demo/temp/|demo/artifacts/site/|__pycache__|\.demolab/'; then
65
+ echo "wheel carries build noise" && exit 1
66
+ fi
67
+ mkdir /tmp/lab && cd /tmp/lab
68
+ uvx --from "$(ls "$GITHUB_WORKSPACE"/dist/demolab_cli-*.whl)" demolab-cli init
69
+ test -f demolab.yaml && test -f .demolab/lib.typ && test -f AGENTS.md
@@ -0,0 +1,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ .uv/
7
+
8
+ # Tool caches
9
+ .pytest_cache/
10
+
11
+ # macOS
12
+ .DS_Store
13
+
14
+ # Agent / editor local tooling (not part of the repo)
15
+ .claude/
16
+
17
+ # Short-lived run scratch (regenerated by every tool run).
18
+ # Note: artifacts/data/ (figures + numbers.json) and artifacts/pdfs/ (compiled
19
+ # deliverables you host/link) are committed; artifacts/site/ is a regenerable build.
20
+ temp/
21
+ dist/
22
+ artifacts/site/
23
+ demolab_cli/scaffold/demo/temp/
24
+ demolab_cli/scaffold/demo/artifacts/site/
25
+ # Transient preview copy written by `demolab dev --demo --landing` (source of truth is
26
+ # demo/site/landing.typ) — never committed, never part of the user-facing demo overlay.
27
+ demolab_cli/scaffold/demo/landing.typ
28
+
29
+ # Engine staging dir the demolab CLI materialises at the lab root (lib.typ + web assets
30
+ # + version stamp) — regenerated whenever the installed demolab-cli version changes.
31
+ .demolab/
32
+
33
+ # Secrets — never commit
34
+ .env
35
+ .env.local
@@ -0,0 +1,59 @@
1
+ # AGENTS.md
2
+
3
+ Demolab — an agent-operated lab notebook for computational science. This file is the thin
4
+ entry point; the substance (runbooks + guides) ships inside the `demolab-cli` package and
5
+ is reached through the CLI, so it's always in step with the installed engine. **Read the
6
+ rules before working here.**
7
+
8
+ > **This checkout is also the demolab-cli source repo** — the engine lives in
9
+ > `demolab_cli/` (build code, Typst templates, runbooks, guides, scaffold). Editing the
10
+ > engine itself? Read [DEVELOPING.md](DEVELOPING.md) first. Everything below applies to
11
+ > operating a lab, here or anywhere.
12
+
13
+ **Finding the docs:** run `demolab docs` for the menu of runbooks (step-by-step procedures)
14
+ and guides (reference). `demolab docs <NAME>` prints the file's absolute path — read that
15
+ file. Start with `demolab docs RULES` — the single conventions doc: toolchain, what you may
16
+ edit, commits, the tool ↔ experiment contract + schemas, and how to add a tool /
17
+ experiment / writing. Unfamiliar with a term? `demolab docs GLOSSARY`. Authoring a writing?
18
+ `demolab docs HOUSESTYLE` (a root `HOUSESTYLE.local.md`, if present, extends or replaces it
19
+ — read it too). A slide deck? `demolab docs SLIDES`. Lost in the layout? `demolab docs
20
+ STRUCTURE`. Need a human? `demolab docs SUPPORT`.
21
+
22
+ Three rules important enough to state here too:
23
+
24
+ - **Toolchain:** use `uv` (Python) and `typst` (publishing) via the `demolab` CLI. Never
25
+ call `pip` / `python` / `python3` directly.
26
+ - **Commits:** author every commit as the human only — never a `Co-Authored-By:` / agent
27
+ trailer, never an agent in the author/committer fields.
28
+ - **Don't hand-edit machine-managed dirs:** the gitignored `.demolab/` staging dir at a
29
+ lab root belongs to the CLI. In a user's lab the engine isn't even on disk to edit — it
30
+ lives in the installed package; updating it is a dependency bump (`demolab docs UPDATE`).
31
+
32
+ ## Commands — type a NAME
33
+
34
+ demolab is driven by typing a **name in CAPS** (SCREAMING-KEBAB). Three commands:
35
+
36
+ - **`HELP`** — run `demolab docs` and present its menu, one line each.
37
+ - **`<RUNBOOK>`** — a runbook name (e.g. `GETTING-STARTED`, `LINT`, `DOCTOR`) → run
38
+ `demolab docs <NAME>`, read the file, then **start it** and drive it step by step: run a
39
+ step, show the result, confirm before the next. Never dump the whole runbook at once.
40
+ - **`<GUIDE>`** — a guide name (e.g. `RULES`, `SLIDES`) → read it the same way, then **walk
41
+ the user through it**: summarise, go section by section, answer questions — don't just
42
+ paste the file.
43
+
44
+ **The NAME is the command.** If the user's message is (or starts with) one of these names,
45
+ that *is* the request: act on it, don't ask what they mean. Natural phrasings route too
46
+ ("lint the writings" → `LINT`, "set up my lab" → `GETTING-STARTED`) — the `demolab docs`
47
+ menu's one-liners tell you which doc covers what.
48
+
49
+ **Docs are the source of truth.** When the user is confused, stuck, or asks "how do I…"
50
+ about operating demolab, check the menu *before* improvising an answer. If a runbook or
51
+ guide covers it, ground your answer in it — cite it, or offer to start it — rather than
52
+ explaining from memory.
53
+
54
+ > **`GETTING-STARTED`** ("set up my lab", "how do I get started") means **following the
55
+ > runbook as a conversation** — orient the user, then ask the gated questions *in order*
56
+ > and wait for answers. **Do not autonomously scaffold, install, build an experiment, and
57
+ > report back** — that races past every choice the user is supposed to make (what to
58
+ > compute, branding, publishing). Read the runbook first; run nothing before its step-0
59
+ > orient + ready-check.
@@ -0,0 +1,19 @@
1
+ # CLAUDE.md
2
+
3
+ Read **[AGENTS.md](AGENTS.md)** before working here — it's the entry point. (This checkout
4
+ is also the demolab-cli source repo; engine work goes through [DEVELOPING.md](DEVELOPING.md).)
5
+
6
+ ## Commands — type a NAME
7
+
8
+ demolab is driven by names in CAPS. **If the user's message is just one of these names,
9
+ that IS the command — do it, don't ask what they mean:**
10
+
11
+ - **`HELP`** — run `demolab docs` and present the menu of runbooks and guides.
12
+ - **A runbook name** (e.g. `GETTING-STARTED`, `TOUR`, `LINT`, `DOCTOR`, `RED-TEAM`,
13
+ `STEELMAN`, `NEXT`, `UPDATE`) — run `demolab docs <NAME>`, read the file it points at,
14
+ then **start that runbook** and drive it step by step.
15
+ - **A guide name** (e.g. `RULES`, `HOUSESTYLE`, `SLIDES`, `STRUCTURE`, `GLOSSARY`,
16
+ `SUPPORT`) — read it the same way, then **walk the user through it** interactively.
17
+
18
+ The full, current menu (names + one-liners) comes from `demolab docs` — run it rather than
19
+ relying on a memorised list. Details of the interaction rules are in [AGENTS.md](AGENTS.md).
@@ -0,0 +1,76 @@
1
+ # Developing demolab
2
+
3
+ This repo is the source of the **`demolab-cli`** package — the engine (`demolab_cli/`:
4
+ build code, Typst templates, runbooks, guides, scaffold + demo) plus the packaging to ship
5
+ it to PyPI. `uv sync` installs the package **editable**, so the `demolab` command here runs
6
+ the working tree's code directly, and the engine-data lookup resolves to these very files —
7
+ edit, run, no reinstall.
8
+
9
+ ## Serve the shipped demo — the usual case
10
+
11
+ ```sh
12
+ demolab dev --demo # materialises the demo into temp/demo-preview and serves it
13
+ demolab dev --demo --landing # …and previews the marketing landing page (site/landing.typ)
14
+ ```
15
+
16
+ This copies the demo into `temp/demo-preview/` (a disposable lab; rebuilt fresh on every
17
+ invocation) and serves it. **Engine edits hot-reload** — the dev server watches the package's
18
+ `typ/` assets and `.py` files, which here *are* the working tree. **Demo-content edits don't**
19
+ (the served copy is a snapshot): edit under `demolab_cli/scaffold/demo/`, then rerun the
20
+ command — or serve the demo source directly when iterating on demo content itself:
21
+
22
+ ```sh
23
+ DEMOLAB_ROOT=demolab_cli/scaffold/demo uv run python -m demolab_cli.devserver
24
+ ```
25
+
26
+ (That writes build scratch into `scaffold/demo/temp/` + `scaffold/demo/artifacts/site/` —
27
+ both gitignored, both excluded from the wheel.)
28
+
29
+ ## Full sandbox — when you need to *run* the experiments
30
+
31
+ To **run** the demo's experiments (regenerate figures, tweak a runner), materialise the demo
32
+ at the repo root — this repo's own `demolab.yaml` makes it a valid lab:
33
+
34
+ ```sh
35
+ demolab add-demo-content # copy the worked demo (skeleton + demo) to the repo root
36
+ demolab dev # serve whatever content is at the root
37
+ demolab run exp000 # re-run a runner, etc.
38
+ ```
39
+
40
+ This *copies* the demo to the root, so keep it out of git with a **local** exclude — never
41
+ the shipped `.gitignore`. `.git/info/exclude` is per-clone and never committed:
42
+
43
+ ```sh
44
+ cat >> .git/info/exclude <<'EOF'
45
+ # local dev sandbox — never committed
46
+ /writings/
47
+ /experiments/
48
+ /tools/
49
+ /artifacts/
50
+ EOF
51
+ ```
52
+
53
+ Tear it down with `demolab clear-demo-content` (or `rm -rf writings experiments tools artifacts`).
54
+
55
+ ## Packaging & release
56
+
57
+ - **Build + inspect the wheel:** `uv build`, then `unzip -l dist/demolab_cli-*.whl` — the
58
+ wheel must carry `typ/`, `runbooks/`, `guides/`, `scaffold/` (demo *without* its
59
+ `temp/`/`artifacts/site/` noise) and no `demolab_cli/test_*.py`. CI builds from a clean
60
+ checkout, so local noise can't ship even if the excludes drift.
61
+ - **Version:** `demolab_cli/VERSION` is the single source of truth (hatchling reads it via
62
+ the regex version source; `demolab version` prints it; lib.typ stamps it into the site's
63
+ generator meta). SemVer per `demolab_cli/CHANGELOG.md`.
64
+ - **Test from the wheel:** `uvx --from dist/demolab_cli-*.whl demolab-cli init` in an empty
65
+ dir, then point the fresh lab's `[tool.uv.sources]` at the wheel to `uv sync` against it.
66
+ - **Release:** update `CHANGELOG.md`, bump `VERSION`, commit, then
67
+ `git tag v<VERSION> && git push --tags` — `.github/workflows/publish.yml` builds and
68
+ publishes to PyPI via trusted publishing (the tag must match `VERSION`).
69
+
70
+ ## Why the lab needs `.demolab/` staging at all
71
+
72
+ Writings use root-relative paths (`/.demolab/lib.typ`, `/artifacts/…`) and Typst confines
73
+ every read to `--root` (the lab). The engine lives in site-packages — outside every lab —
74
+ so the CLI materialises the few files Typst must read (`lib.typ` + web assets) into the
75
+ gitignored `.demolab/` and stages `main.typ` into `temp/bundle/` per build. Everything else
76
+ the engine does happens in Python, where site-packages is a perfectly good home.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eoin Murray
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: demolab-cli
3
+ Version: 1.0.0
4
+ Summary: Lab notebook for computational science: Python tools produce per-run artifacts; Typst publishes them as a web bundle, per-entry PDFs, and a book.
5
+ Project-URL: Homepage, https://github.com/eoinmurray/demolab
6
+ Project-URL: Changelog, https://github.com/eoinmurray/demolab/blob/main/demolab_cli/CHANGELOG.md
7
+ License: MIT License
8
+
9
+ Copyright (c) 2026 Eoin Murray
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ License-File: LICENSE
29
+ Requires-Python: >=3.10
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Demolab
33
+
34
+ **A lab notebook for computational science — reproducible results, published and citable, run by a coding agent instead of a build system.**
35
+
36
+ > **Coding agent setting someone up?** Run `uvx demolab-cli docs GETTING-STARTED`, read the file it prints, and follow it strictly, step by step. *(Human, setting up by hand? See [Quickstart](#quickstart).)*
37
+
38
+ You write a model or experiment once as a small program. Demolab runs it, captures everything it produced, stamps it with the exact code version, and publishes a clean page — figures, numbers, and real typeset maths — to both the web and PDF. The numbers on the page are read from the run, so they can't drift. You drive it all by talking to a coding agent; there's no web development or build config to touch.
39
+
40
+ ## Quickstart
41
+
42
+ Open your coding agent in an empty folder and paste:
43
+
44
+ > Run `uvx demolab-cli init` here, then follow its GETTING-STARTED runbook strictly.
45
+
46
+ It lays your lab down, walks you through the toolchain (`uv`, `typst`) and your first experiment, one step at a time.
47
+
48
+ <details>
49
+ <summary><b>Set it up by hand instead?</b></summary>
50
+
51
+ Install [`uv`](https://docs.astral.sh/uv/) and [`typst`](https://typst.app) (`brew install uv typst`), then:
52
+
53
+ ```sh
54
+ mkdir my-lab && cd my-lab
55
+ uvx demolab-cli init # lab structure + git init — yours from the first commit
56
+ uv sync # installs the deps and the `demolab` command
57
+ ```
58
+
59
+ Then `demolab add-demo-content && demolab run exp000 && demolab dev` to see the loop. `demolab clear-demo-content` wipes the demo again. The engine lives in the `demolab-cli` package — updating it is `uv lock --upgrade-package demolab-cli && uv sync`.
60
+
61
+ </details>
62
+
63
+ ## What to ask your agent
64
+
65
+ Open your lab in your agent and say a runbook's name — it follows that runbook one step at a time. `demolab docs` lists them all (each is a plain file shipped in the package; `demolab docs <NAME>` prints its path). In this repo they live under [`demolab_cli/runbooks/`](demolab_cli/runbooks/).
66
+
67
+ | Say… | …and it will |
68
+ |------|--------------|
69
+ | **GETTING-STARTED** | set you up end to end: scaffold, your first experiment live on a page, brand, publish |
70
+ | **TOUR** | guided walkthrough of the lab — what's here, what it found, where to start |
71
+ | **MIGRATE-CODE** | bring an existing codebase in, one experiment at a time |
72
+ | **FROM-JUPYTER** | launder a Jupyter notebook into a reproducible, seeded experiment |
73
+ | **FROM-PAPER** | scaffold experiments to reproduce a paper's key result in your stack |
74
+ | **MIGRATE-STACK** | write your tools in MATLAB / Julia / R / Octave instead of Python |
75
+ | **EMBED-DOCS** | drop demolab into another project as a `docs/` site |
76
+ | **NEXT** | read your whole arc and propose the next experiments worth running |
77
+ | **GROUND-CLAIMS** | find the source sentences behind each citation |
78
+ | **LINT** | check your writeups against the house style |
79
+ | **DOCTOR** | audit the repo against the conventions |
80
+ | **RED-TEAM** | adversarially check a result holds up before you publish it |
81
+ | **STEELMAN** | build the strongest honest case for a result, so you don't under-sell it |
82
+ | **UPDATE** | update the engine package, leaving your content untouched |
83
+
84
+ ## How it works
85
+
86
+ One decoupled loop: **a tool computes → drops data → an experiment writes it up → the site publishes it.** Every run records its exact parameters and the git commit it came from (stamped on the page), and tables read their numbers straight from the run — so prose and results can't disagree. A single Typst pass emits a website, a PDF per entry, and a book, all sharing the same live numbers.
87
+
88
+ The detail lives in the guides (in a lab: `demolab docs <NAME>`; in this repo, the files under `demolab_cli/guides/`):
89
+
90
+ - **[RULES.md](demolab_cli/guides/RULES.md)** — the tool ↔ experiment contract, schemas, provenance, and how to add things.
91
+ - **[STRUCTURE.md](demolab_cli/guides/STRUCTURE.md)** — the annotated file tree.
92
+ - **[HOUSESTYLE.md](demolab_cli/guides/HOUSESTYLE.md)** — prose, maths, and figure style.
93
+ - **[AGENTS.md](AGENTS.md)** — the agent entry point.
94
+
95
+ ## Commands
96
+
97
+ `demolab` shows them all. The everyday ones: `init`, `docs`, `install`, `scaffold` · `add-demo-content` · `clear-demo-content`, `run expNNN`, `dev`, `build`, `test`.
98
+
99
+ ## License
100
+
101
+ [MIT](LICENSE) — free to use, fork, and adapt for your own lab.
@@ -0,0 +1,70 @@
1
+ # Demolab
2
+
3
+ **A lab notebook for computational science — reproducible results, published and citable, run by a coding agent instead of a build system.**
4
+
5
+ > **Coding agent setting someone up?** Run `uvx demolab-cli docs GETTING-STARTED`, read the file it prints, and follow it strictly, step by step. *(Human, setting up by hand? See [Quickstart](#quickstart).)*
6
+
7
+ You write a model or experiment once as a small program. Demolab runs it, captures everything it produced, stamps it with the exact code version, and publishes a clean page — figures, numbers, and real typeset maths — to both the web and PDF. The numbers on the page are read from the run, so they can't drift. You drive it all by talking to a coding agent; there's no web development or build config to touch.
8
+
9
+ ## Quickstart
10
+
11
+ Open your coding agent in an empty folder and paste:
12
+
13
+ > Run `uvx demolab-cli init` here, then follow its GETTING-STARTED runbook strictly.
14
+
15
+ It lays your lab down, walks you through the toolchain (`uv`, `typst`) and your first experiment, one step at a time.
16
+
17
+ <details>
18
+ <summary><b>Set it up by hand instead?</b></summary>
19
+
20
+ Install [`uv`](https://docs.astral.sh/uv/) and [`typst`](https://typst.app) (`brew install uv typst`), then:
21
+
22
+ ```sh
23
+ mkdir my-lab && cd my-lab
24
+ uvx demolab-cli init # lab structure + git init — yours from the first commit
25
+ uv sync # installs the deps and the `demolab` command
26
+ ```
27
+
28
+ Then `demolab add-demo-content && demolab run exp000 && demolab dev` to see the loop. `demolab clear-demo-content` wipes the demo again. The engine lives in the `demolab-cli` package — updating it is `uv lock --upgrade-package demolab-cli && uv sync`.
29
+
30
+ </details>
31
+
32
+ ## What to ask your agent
33
+
34
+ Open your lab in your agent and say a runbook's name — it follows that runbook one step at a time. `demolab docs` lists them all (each is a plain file shipped in the package; `demolab docs <NAME>` prints its path). In this repo they live under [`demolab_cli/runbooks/`](demolab_cli/runbooks/).
35
+
36
+ | Say… | …and it will |
37
+ |------|--------------|
38
+ | **GETTING-STARTED** | set you up end to end: scaffold, your first experiment live on a page, brand, publish |
39
+ | **TOUR** | guided walkthrough of the lab — what's here, what it found, where to start |
40
+ | **MIGRATE-CODE** | bring an existing codebase in, one experiment at a time |
41
+ | **FROM-JUPYTER** | launder a Jupyter notebook into a reproducible, seeded experiment |
42
+ | **FROM-PAPER** | scaffold experiments to reproduce a paper's key result in your stack |
43
+ | **MIGRATE-STACK** | write your tools in MATLAB / Julia / R / Octave instead of Python |
44
+ | **EMBED-DOCS** | drop demolab into another project as a `docs/` site |
45
+ | **NEXT** | read your whole arc and propose the next experiments worth running |
46
+ | **GROUND-CLAIMS** | find the source sentences behind each citation |
47
+ | **LINT** | check your writeups against the house style |
48
+ | **DOCTOR** | audit the repo against the conventions |
49
+ | **RED-TEAM** | adversarially check a result holds up before you publish it |
50
+ | **STEELMAN** | build the strongest honest case for a result, so you don't under-sell it |
51
+ | **UPDATE** | update the engine package, leaving your content untouched |
52
+
53
+ ## How it works
54
+
55
+ One decoupled loop: **a tool computes → drops data → an experiment writes it up → the site publishes it.** Every run records its exact parameters and the git commit it came from (stamped on the page), and tables read their numbers straight from the run — so prose and results can't disagree. A single Typst pass emits a website, a PDF per entry, and a book, all sharing the same live numbers.
56
+
57
+ The detail lives in the guides (in a lab: `demolab docs <NAME>`; in this repo, the files under `demolab_cli/guides/`):
58
+
59
+ - **[RULES.md](demolab_cli/guides/RULES.md)** — the tool ↔ experiment contract, schemas, provenance, and how to add things.
60
+ - **[STRUCTURE.md](demolab_cli/guides/STRUCTURE.md)** — the annotated file tree.
61
+ - **[HOUSESTYLE.md](demolab_cli/guides/HOUSESTYLE.md)** — prose, maths, and figure style.
62
+ - **[AGENTS.md](AGENTS.md)** — the agent entry point.
63
+
64
+ ## Commands
65
+
66
+ `demolab` shows them all. The everyday ones: `init`, `docs`, `install`, `scaffold` · `add-demo-content` · `clear-demo-content`, `run expNNN`, `dev`, `build`, `test`.
67
+
68
+ ## License
69
+
70
+ [MIT](LICENSE) — free to use, fork, and adapt for your own lab.