Skip to content

PROJECT: action-code-style — deterministic black formatting for Python in MyST/markdown #320

Description

@mmcky

Summary

Build a standalone GitHub Action that runs black over Python code embedded in MyST {code-cell} directives and standard markdown fenced code blocks, keeping lecture code PEP8-compliant and consistently formatted. The tool is deterministic (no AI), cheap, and safe to run automatically.

This issue captures the essence of the closed Copilot PR #240 and the original request in #221, plus the architecture decision reached in discussion (a separate repo, not folded into action-style-guide), so the feature can be cleanly re-implemented once it has a home.

Background

  • #221 requested automatic black style checks on Python contained in MyST code-cell directives and standard fenced markdown code blocks.
  • #240 (Copilot) implemented a code-style-checker action inside meta (.github/actions/code-style-checker/), comment-triggered via @quantecon-code-style. It was never reviewed/merged and is structured the old (in-meta) way, contrary to the migration of actions into individual repos (#244). It has been closed in favour of this documented project.
  • This is a real, still-unmet need: no current QuantEcon repo provides deterministic black formatting of code embedded in markdown. action-style-guide is adjacent but fundamentally different (see below).

Architecture decision: separate action-code-style, not part of action-style-guide

The two share the phrase "code style" but differ on every axis that matters for packaging:

Axis black formatting (this project) action-style-guide
Mechanism Deterministic, fixed rules AI (Claude), non-deterministic, confidence-scored
Dependencies black only — no API key, free LLM API key, cost per run
Auto-run Safe on every PR / push Comment-triggered only (cost + noise)
Cadence Tiny, stable utility Large, evolving (prompt versioning, rules DB)
Audience Any MyST/Jupyter Book project QuantEcon-opinionated

Decisive points:

  1. Invocation policy differsblack wants to be cheap and always-on (a normal CI check); the AI style guide must stay comment-triggered to avoid being intrusive/expensive. One repo cannot cleanly serve both runtime profiles.
  2. Coupling a stable formatter to a fast-moving AI tool creates release friction — every prompt/rule change would churn a repo that also houses a formatter that rarely changes.
  3. Small, single-purpose repos match the #244 grain (action-link-checker, action-check-warnings, …).

The one genuine overlap is the MyST/markdown code-extraction parser (both need to pull Python out of {code-cell} and fenced blocks). If duplication becomes annoying, factor that into a small shared helper rather than merging two tools with opposite runtime profiles.

➡️ Home: a new standalone QuantEcon/action-code-style repo. (The standalone-vs-centralised question is being worked through more broadly in #266 — the final home should be consistent with whatever that lands on.)

Relationship to myst-lint (#268)

#268 proposes myst-lint, a deterministic MyST quality tool (wraps markdownlint + MyST rules: directive/role validation, math-delimiter matching, code-block delimiters, code-cell validation). It shares this project's exact design philosophy (deterministic, no API cost, fast, CI/pre-commit) but a different concern:

Open question to resolve before building: one tool or two? They could ship as separate siblings, or black-formatting could be a module/rule-set within myst-lint (one deterministic "MyST quality" tool with both a structure-lint pass and a code-format pass). Decide this jointly with #268 rather than in isolation.

Scope / requirements

(capturing the essence of #221 + #240)

  • Parse md files and extract Python from both MyST {code-cell} directives and standard fenced ```python blocks
  • Only format blocks tagged python, python3, ipython, ipython3; skip others (e.g. julia) with an informative log line
  • Run black over each extracted block and write the formatted code back into the file, preserving the surrounding markdown/directive structure exactly
  • Configurable inputs:
    • files — explicit list and/or glob patterns (e.g. lecture/**/*.md)
    • toggle MyST code-cell scanning (default on)
    • toggle standard markdown block scanning (default on)
    • python-languages (default python,python3,ipython,ipython3)
    • black-args (e.g. --line-length=88)
  • Design intent: deterministic and cheap → support always-on / push-triggered CI usage, in addition to an optional comment trigger (@quantecon-code-style)
  • Check mode (non-mutating): report diffs / fail CI without committing, so it can run as a status check
  • Fix mode: commit formatted results, per-file, with a message like [{filename}] applying black changes to code (per #221)
  • Tests: unformatted MyST+markdown, already-formatted (no-op), non-python (skip), glob expansion

Reference implementation

#240 (closed) is a usable starting point — it already had a working line-by-line MyST/markdown parser, language detection, glob handling, and a test suite. Re-implement cleanly in the new repo rather than porting the Copilot bulk wholesale.

Related

  • #221 — original feature request (closed, superseded by this project)
  • #240 — closed Copilot PR; reference implementation
  • #244 — migration of actions into individual repos (the grain this follows)
  • #268myst-lint, sibling deterministic MyST quality tool; resolve "one tool or two?" jointly
  • #266 — mono-repo vs centralised actions vs hybrid (informs the home decision)
  • QuantEcon/action-style-guide — adjacent AI style tool; intentionally kept separate
  • QuantEcon/actions — build/preview/publish actions monorepo

Suggested next steps

  1. Create QuantEcon/action-code-style (+ a test-action-code-style fixture repo, matching the action-style-guide pattern)
  2. Port/clean the parser + black runner from #240
  3. Implement both check mode (always-on CI) and fix mode (comment trigger / commit)
  4. Pilot on one lecture repo, then roll out

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions