Skip to content

Sync with liulab-repo-template: gaps, justified divergences, and what to send upstream #499

Description

@lhqing

Template sync audit. Compares this repo against
liulab-repo-template at 815f179
(2026-08-31), auditing this repo at 744ba10. Produced by running the template's
scripts/conformance.py --root against a clean clone, then a file-by-file comparison.

This is a tracking issue, not a work order. Findings are split into Gaps (adopt),
Justified divergences (this repo is right, leave it) and Upstream candidates (this
repo is ahead of the template). Several gaps need a maintainer decision before anyone
starts — those are called out in Notes for the maintainer at the end. Split it into
per-area issues if that suits better.

Coordinator note: G1 verified independently — .gitignore:83 is /.claude/, and
git ls-files shows the eight .agents/skills/* symlinks tracked with no
.claude/skills/* counterpart.


seqforge — template sync gap report

Shape: published — src/seqforge/ + tests/ + CHANGELOG.md + .github/workflows/release.yml
publishing to PyPI by Trusted Publishing; README.md documents pip install seqforge.

Summary: seqforge is the most template-like repo in the lab and in several places it is ahead of
the template — its scripts/check.sh is a strict superset, and it has tests holding that runner to
its own invariants. The drift is concentrated in the writing and conformance half of the
standard: .vale.ini, styles/, scripts/conformance.py and the [tool.liulab] declarations are
all absent, markdownlint is not a step of check, and the tracked .claude/skills/ symlinks are
missing because .gitignore carries the blanket /.claude/ the template forbids. The single most
important fix is that last one: a fresh clone of seqforge gives Claude Code zero of the eight skills
this repo ships.

Gaps

G1. Stop ignoring /.claude/ and track the eight .claude/skills/ symlinks

  • Priority: high
  • Area: skills
  • Now: .gitignore (last line) has a blanket /.claude/, added for agent worktrees. .claude/
    does not exist in the clone at all; git ls-files shows the eight .agents/skills/* symlinks and
    no .claude/skills/*.
  • Template: .gitignore names .claude/settings.local.json and .claude/worktrees/ and
    nothing else, with the comment: "Never a blanket /.claude/: the skill symlinks under
    .claude/skills/ and .agents/skills/ are TRACKED, because init-repo has to be discoverable
    the instant you clone — before anyone could run the thing that runs installers."
    Its
    .claude/skills/init-repo and .claude/skills/template-dev are mode-120000 tracked entries.
  • Change: in .gitignore, replace /.claude/ with .claude/settings.local.json and
    .claude/worktrees/. Then python skills/install.py --target claude and commit the eight
    resulting relative symlinks.
  • Why it matters: every clone and every CI checkout of seqforge discovers no skills for Claude
    Code until somebody remembers to run the installer. The .agents/skills/ links are correct
    (relative, non-dangling, verified) — only the Claude path is lost, and it is lost by one line.

G2. Add scripts/conformance.py and the [tool.liulab] declarations

  • Priority: high
  • Area: gates
  • Now: no scripts/conformance.py, no conformance pixi task, and no [tool.liulab.agent-docs]
    or [tool.liulab.waived] table in pyproject.toml. Running the template's checker against the
    clone reports rules 2 and 4 as "not checked" purely because the declarations are absent.
  • Template: scripts/conformance.py (8 rules + 2 warnings), invoked by the conformance task
    and named in check-static; declarations at pyproject.toml:166-179.
  • Change: copy scripts/conformance.py verbatim (it is written to be shared), add
    conformance = "python scripts/conformance.py" to [tool.pixi.tasks], add pyyaml to the
    default environment's dependencies (it is already a runtime dep, so this is free), and declare
    [tool.liulab.agent-docs] with seqforge's real paths — AGENTS.md, CONTEXT.md,
    docs/adr/, skills/, docs/research/ = false.
  • Why it matters: none of the shared rules are mechanised here. G1 is exactly the class of
    failure rule 7 exists to catch, and it has been live on main undetected.

G3. Adopt .vale.ini and styles/Lab/

  • Priority: high
  • Area: writing
  • Now: neither file exists; there is no vale task and no CI job runs one. The lab's writing
    rules are entirely unenforced in this repo.
  • Template: .vale.ini (four sections, every rule named in every section) and four tracked
    rules under styles/Lab/: Jargon.yml, LengthDoc.yml (1000 words), LengthAdr.yml (400),
    Readability.yml.
  • Change: copy .vale.ini and styles/Lab/, add vale = "3.19.0.*" to the default
    environment and vale = "vale --glob='!{.pixi,site,dist,build}/**' ." to [tool.pixi.tasks].
    Confirm styles/ is not gitignored (it currently is not).
  • Why it matters: measured against today's tree, the cost of adopting it is bounded and small.
    Six agent-facing files exceed the 1000-word LengthDoc cap — skills/seqforge-kb-author/SKILL.md
    (1708), AGENTS.md (1705), src/seqforge/compose/CONTEXT.md (1612),
    skills/seqforge-orchestrate/SKILL.md (1392), skills/seqforge-manifest/SKILL.md (1324),
    src/seqforge/resolve/CONTEXT.md (1033) — and three records exceed the 400-word LengthAdr cap
    (0053-a-mate-that-did-not-align... 757, 0049-stars-command-line... 746,
    0051-a-composed-pipeline-runs-on-one-machine 555). CONTEXT-MAP.md at 957 already passes.

G4. Port --check into skills/install.py

  • Priority: high
  • Area: skills
  • Now: skills/install.py is byte-for-byte the template's file minus the check half. discover,
    TARGETS and install_one are identical, including comments. Missing: the CHECKED_TARGETS
    constant, _problem(), check(), report_check(), the --check argparse flag and the early
    if args.check: return. --check therefore exits 2 with
    install.py: error: unrecognized arguments: --check.
  • Template: skills/install.py lines 43-46 (CHECKED_TARGETS), 88-205 (_problem, check,
    report_check), 226-230 (the flag) and 234-239 (the early return); the parser also uses
    description=__doc__ with RawDescriptionHelpFormatter rather than
    description=__doc__.splitlines()[0].
  • Change: copy those five blocks in, switch the parser to __doc__ +
    RawDescriptionHelpFormatter, and add the --check paragraph to the module docstring. Keep
    seqforge's trailing seqforge hook install line in main(). Nothing else in the file changes.
  • Why it matters: --check is what conformance rule 7 calls, and it is the check that would
    have caught G1 — it holds .claude/skills and .agents/skills to three invariants (a link in
    both, nothing dangling, every link relative) and prints the repairing command on each problem.

G5. Make markdownlint a step of the gate, and delete the second exclusion list

  • Priority: medium
  • Area: gates
  • Now: markdownlint is in no pixi task. It runs in two other places: as a pre-commit hook
    (.pre-commit-config.yaml, markdownlint-cli2 rev v0.23.1) and as its own CI job
    (.github/workflows/ci.yml, npx --yes markdownlint-cli2@0.23.1 on a Node runner).
    .markdownlint-cli2.yaml has narrow globs: (docs/**/*.md, the KB specs, README.md) plus an
    eleven-entry ignores: list and no gitignore: true.
  • Template: markdownlint = "markdownlint-cli2" is a task and a check-static step, with
    markdownlint-cli2 installed from conda-forge. .markdownlint-cli2.yaml is gitignore: true +
    globs: ["**/*.md"] + config: {default: true, MD013: false}, with "deliberately no ignores:
    list. It used to exist only to mirror a second list of excluded paths kept elsewhere, and two
    lists that must agree are a drift waiting to happen."
  • Change: add markdownlint-cli2 to the default environment and a markdownlint task; add it
    to the check line in [tool.pixi.tasks]. Then set gitignore: true, widen globs to
    ["**/*.md"], and drop ignores: — replacing the mkdocs.yml exclude_docs: mirror with
    per-file <!-- markdownlint-disable --> where a KB wrapper genuinely has nothing to lint.
  • Why it matters: seqforge's own config comment concedes the template's argument — "The
    ignores: list below and mkdocs.yml's exclude_docs: are the SAME list… they drifted once
    already, turning CI red on every open PR."
    Two pins of the same tool (npx 0.23.1, pre-commit
    0.23.1) plus a third toolchain (Node) to lint markdown is the cost of not having it in pixi.

G6. Move the version to hatch-vcs

  • Priority: medium
  • Area: toolchain
  • Now: pyproject.toml:24 has version = "2026.7.1" hand-written, [build-system] requires
    is ["hatchling"] only, and there is no [tool.hatch.version]. release.yml carries a whole
    extra step ("Check tag matches pyproject version") that reads the version back out with tomllib
    and compares it to GITHUB_REF_NAME. CHANGELOG.md says the version "tracks [project].version
    in pyproject.toml".
  • Template: dynamic = ["version"], requires = ["hatchling", "hatch-vcs"],
    [tool.hatch.version] source = "vcs", with "No fallback-version: that is a hand-written
    version string."
  • Change: add hatch-vcs to requires, replace the version key with dynamic = ["version"],
    add [tool.hatch.version] source = "vcs", delete the tag-check step from release.yml, and make
    sure the build job keeps fetch-depth: 0.
  • Why it matters: the tag-vs-file check exists only because there are two copies of the version.
    The template deletes the second copy instead of guarding it, and the tag stays the single source.

G7. Build the released wheel with pixi, not a separate pip toolchain

  • Priority: medium
  • Area: ci
  • Now: release.yml's build job uses actions/setup-python@v5 with python-version: "3.12"
    and python -m pip install --upgrade build twine, then python -m build. ci.yml's build job
    uses pixi run -e default build. The wheel that ships is therefore built by a toolchain no pull
    request ever exercises. Neither release job uses fetch-depth: 0.
  • Template: release.yml's build job is setup-pixi with locked: true and pixi run build —
    "The same task the build job in ci.yml runs, so what is published was built the way every
    pull request already proved."
  • Change: swap setup-python + pip for prefix-dev/setup-pixi with locked: true and
    pixi run build; add fetch-depth: 0 to the checkout (required once G6 lands). Keep the
    twine check step — see Upstream candidates.
  • Why it matters: two build paths that diverge silently, and the divergent one is the only one
    whose output reaches users.

G8. Add docs/agents/, starting with writing.md

  • Priority: medium
  • Area: agent-docs
  • Now: no docs/agents/ directory. .github/ISSUE-CONVENTIONS.md covers what the template
    splits across issue-tracker.md and triage-labels.md (and covers it better — see Upstream
    candidates). Nothing covers writing.md or domain.md.
  • Template: docs/agents/domain.md, issue-tracker.md, triage-labels.md, writing.md, each
    with search: exclude: true front matter and none of them in nav:.
  • Change: add docs/agents/writing.md (the three rules and the cap table) at minimum; either
    move .github/ISSUE-CONVENTIONS.md to docs/agents/issue-tracker.md + triage-labels.md or
    declare .github/ISSUE-CONVENTIONS.md under [tool.liulab.agent-docs] and leave it where it is.
  • Why it matters: writing.md is where the word caps and the reason for them are written. G3
    installs the enforcement; without this document a contributor meets a red vale run with no
    explanation of what 1000 means or where the dial lives.

G9. Declare the Python version in two places, not five

  • Priority: medium
  • Area: toolchain
  • Now: five declarations, and they disagree — requires-python = ">=3.12" (line 9),
    classifiers listing both 3.12 and 3.13 (lines 18-19), [tool.pixi.feature.py313.dependencies] python = "3.13.*" (line 172), [tool.ruff] target-version = "py312" (line 299),
    [tool.mypy] python_version = "3.12" (line 315), plus python-version: "3.12" in release.yml.
  • Template: exactly two — requires-python and [tool.pixi.dependencies] python, with "No
    target-version: ruff infers it from requires-python"
    and "No pythonVersion: taken from the
    interpreter in the environment above."
  • Change: delete [tool.ruff] target-version (ruff infers it). Keep [tool.mypy] python_version — mypy defaults to the running interpreter (3.13) and this repo genuinely
    supports 3.12, so this one is load-bearing; add a one-line comment saying so. release.yml's pin
    disappears with G7.
  • Why it matters: the environment runs 3.13 while the checkers are told 3.12. That is the
    correct conservative choice for a package declaring >=3.12, but it is three numbers that must
    move together and only one of them has to.

G10. Widen the ruff rule set

  • Priority: medium
  • Area: config
  • Now: [tool.ruff.lint] select = ["E", "W", "F", "I", "UP", "B"],
    ignore = ["E501", "UP046", "UP047"]. No [tool.ruff.lint.pydocstyle], no per-file-ignores.
    [tool.ruff] src = ["src", "tests"] — scripts is absent though scripts/ holds three files.
  • Template: select = ["E","W","F","I","UP","B","C4","SIM","PT","PTH","N","D","RUF"],
    ignore = ["E501","D203","D213"], convention = "numpy", "tests/**" = ["D"],
    src = ["src", "tests", "scripts"].
  • Change: add C4, SIM, PT, PTH, N, RUF first (cheap, mostly autofixable); add D
    with the numpy convention and the tests/** exemption as a follow-up, since it will flag a lot on
    a package this size. Add "scripts" to src. Keep UP046/UP047 ignored — the pydantic-v2
    reason given at line 306 is sound.
  • Why it matters: D is the one that costs something today: seqforge ships to PyPI and has no
    docstring gate at all, while mkdocstrings-style API rendering (G16) depends on docstrings existing.

G11. Replace the two pre-commit tool copies with the pixi ones

  • Priority: medium
  • Area: toolchain
  • Now: .pre-commit-config.yaml installs ruff-pre-commit v0.15.16 and
    markdownlint-cli2 v0.23.1 into pre-commit's own environments. pixi separately declares
    ruff = "*" in the dev feature. mypy is already routed through pixi
    (entry: pixi run --no-progress typecheck), and pytest is deliberately excluded.
  • Template: ships no .pre-commit-config.yaml: "the gate is pixi run check… pre-commit is a
    second toolchain installing its own pinned copies of ruff outside pixi."
  • Change: either drop the file, or keep it and route ruff-check/ruff-format/markdownlint
    through pixi the way the mypy hook already is (entry: pixi run --no-progress lint, etc.). Keep
    the generic pre-commit-hooks and shellcheck entries either way — those install nothing pixi
    also owns.
  • Why it matters: pinned ruff v0.15.16 in pre-commit and floating ruff = "*" in pixi will
    eventually disagree, and the disagreement surfaces as a commit that pre-commit formatted one way
    and CI fails the other. The mypy hook already shows the fix.

G12. Keep the gate's step list in one place, and let CI use it

  • Priority: medium
  • Area: gates
  • Now: check = "bash scripts/check.sh lint fmt-check typecheck test test-corpus test-external"
    — one task, no check-static. ci.yml never calls check.sh; its lint job spells lint,
    fmt-check, typecheck and docs-build as four separate steps, and markdownlint lives in a
    fifth job with its own toolchain.
  • Template: check-static = "bash scripts/check.sh lint fmt-check typecheck vale markdownlint conformance" and check = { depends-on = ["check-static", "test"] }; ci.yml's check job is a
    single pixi run check-static, "so this file and a laptop cannot drift: adding a step is one more
    word there and nothing here."
  • Change: split check into check-static (lint, fmt-check, typecheck, vale, markdownlint,
    conformance) and check = { depends-on = ["check-static", "test", "test-corpus"] }; make
    ci.yml's lint job pixi run check-static.
  • Why it matters: seqforge's own check.sh header documents this drift happening — "the prose
    here used to claim the gate ran CI's selections outright, which drifted the moment those jobs were
    added and then read as a bug."
    The template's fix is structural rather than a comment.

G13. Add search: exclude: true front matter to docs/adr/ and docs/research/

  • Priority: low
  • Area: docs
  • Now: no page under docs/adr/ or docs/research/ carries front matter (checked
    docs/adr/0002-*.md, docs/adr/README.md, docs/research/star-on-a-chimera.md). Exclusion
    relies entirely on mkdocs.yml's exclude_docs: block plus the explicit nav:.
  • Template: every page under docs/agents/, docs/adr/ and docs/research/ opens with
    ---\nsearch:\n exclude: true\n---, and "exclude_docs: is silently ignored [by zensical], so
    both are needed."
  • Change: prepend the three-line front matter block to every file under docs/adr/,
    docs/research/ and src/seqforge/*/docs/adr/.
  • Why it matters: correct today — real mkdocs honours exclude_docs:, so this is not a live
    leak. It is cheap insurance against a future zensical move, and it is what conformance rule 2
    checks once G2 lands.

G14. Reconcile CONTEXT-MAP.md with the template's CONTEXT.md

  • Priority: low
  • Area: agent-docs
  • Now: CONTEXT-MAP.md at the root (957 words) is a router to five per-context glossaries under
    src/seqforge/*/CONTEXT.md. AGENTS.md links it by that name.
  • Template: CONTEXT.md at the root, declared under [tool.liulab.agent-docs] and capped both
    by Lab.LengthDoc and by conformance rule 4's per-entry 200-word limit. The spec calls
    CONTEXT-MAP.md "an older name for this [that] should be reconciled".
  • Change: the cheapest reconciliation is to rename CONTEXT-MAP.md to CONTEXT.md (updating
    the two links in AGENTS.md) and declare "CONTEXT.md" = "LengthDoc" plus
    "src/seqforge/" = "LengthDoc" — or leave the name and declare "CONTEXT-MAP.md". Do not
    reshape the multi-context layout itself; see Upstream candidates.
  • Why it matters: naming only, but the conformance and vale rules key on the path, so one of the
    two files has to move or the declaration has to name the local spelling.

G15. Refresh the GitHub Action pins

  • Priority: low
  • Area: ci
  • Now: across ci.yml, docs.yml, release.yml, benchmark.yml: actions/checkout@v5,
    prefix-dev/setup-pixi@v0.10.0, actions/upload-artifact@v4, actions/download-artifact@v4.
    locked: true is set on every setup-pixi — that part is already right.
  • Template: actions/checkout@v7, prefix-dev/setup-pixi@v0.10.2, actions/upload-artifact@v7,
    actions/download-artifact@v8, peaceiris/actions-gh-pages@v4,
    pypa/gh-action-pypi-publish@release/v1.
  • Change: bump the four in one commit.
  • Why it matters: cosmetic today; keeping the pins aligned across lab repos is what makes a
    future bump one sweep rather than five investigations.

G16. Decide on an API reference page

  • Priority: low
  • Area: docs
  • Now: mkdocs.yml has plugins: [search] only — no mkdocstrings, no docs/api.md, and no
    mkdocstrings-python dependency. The site documents the CLI and the concepts.
  • Template: package shapes get mkdocstrings with the python handler, paths: [src], numpy
    docstring style, and docs/api.md in nav:.
  • Change: either add mkdocstrings + docs/api.md (pairs naturally with the D rules in G10),
    or record the decision — a compiler whose interface is the CLI (ADR-0013) may legitimately not
    want a rendered Python API.
  • Why it matters: low. This is a genuine judgement call, not obviously a defect; flagging it so
    the answer is written down rather than implied.

Justified divergences

  • benchmark.yml — the template ships no benchmark workflow and asks a repo that has one to say
    why. seqforge says why at length in the file header, and the reasoning holds: it is release +
    workflow_dispatch only (never push/PR/schedule), runs --no-llm so no API key or provider secret
    is ever exposed to it, keeps permissions: contents: read, and an unreachable package skips rather
    than fails. This is the networked tier of a validation corpus, which is a claim per-commit CI
    cannot make. No change wanted, and the template need not learn from it — most repos have no corpus.
  • mypy --strict instead of pyright standard — the template's stated goal is one verdict from
    editor and CI, and seqforge achieves it the other way round: [tool.pyright] typeCheckingMode = "off" in pyproject.toml (so any pyright-based server honours it, not just VS Code) plus
    ms-python.mypy-type-checker pointed at the pixi interpreter. [tool.mypy] files owns the scope
    so the typecheck task is bare. Strictly stronger than the template's setting; leave it.
  • Three test lanes and the test-star environment — the unit / hermetic-corpus / external
    partition, no-default-feature + a separate solve group for the aligner, and the divided
    --maxprocesses caps are all measured decisions documented in pyproject.toml and ci.yml. The
    template's single test task is right for a repo with no external binaries; this is right here.
  • mkdocs-material rather than zensical; exclude_docs: in mkdocs.yml — the site predates
    ADR-0001 and leans on material-specific features (pymdownx.snippets with check_paths, mermaid
    fences, the palette, the shared GA4 property). exclude_docs: is only silently ignored by
    zensical; real mkdocs honours it, so the exclusion works today. Revisit if the site ever moves.
  • channels = ["conda-forge", "bioconda"], platforms including osx-64 — bioconda is where
    STAR/samtools/htslib live; osx-64 widens the lab-machine coverage. Both are additive.
  • Git pypi-dependencies for liulab-genome / liulab-data — kept out of
    [project] dependencies because PyPI rejects git+https metadata, with the deliberate absence of
    [tool.hatch.metadata] allow-direct-references as a tripwire. Well argued; the template has no
    equivalent situation.

Upstream candidates

  • scripts/check.sh — the process-group cleanup. seqforge's runner sets set -muo pipefail, so
    each step is its own process group, and its cleanup() kills every leftover group before it
    removes the scratch directory, with trap 'exit 130' INT / trap 'exit 143' TERM turning the two
    signals that reach an abandoned gate into an ordinary exit. The template's version has none of
    this: Ctrl-C on a template gate kills the shell without running the EXIT trap, leaving live pytest
    runs writing into a directory that is about to disappear. It also runs steps as
    pixi run --no-progress and tails 3 lines of a green step instead of dumping it whole, and prints
    elapsed seconds in the summary. The template should adopt all of this.
  • The three gate-runner tests in tests/test_repo_invariants.py. The template's check.sh
    header records a real bash-3.2 bug — an associative array that failed on macOS, set -e absent so
    the script ran on, and "the gate reported green on every macOS host" — and then tests nothing.
    seqforge has test_the_gate_runner_stays_within_the_bash_macos_ships (a regex guard on declare -A / mapfile, which fires on a Linux runner too),
    test_the_gate_exits_non_zero_and_says_which_step_failed, and
    test_an_interrupted_gate_leaves_no_step_running (starts two lingering steps, sends SIGINT,
    asserts no grandchild survives and the scratch directory is gone). The template should adopt
    these; the bug they guard is one the template has already had.
  • scripts/require_binaries.sh and the "a skip is green" principle. A depends-on that proves
    each external binary answers (--version, not which) before pytest selects, so a lane cannot
    report green having run nothing. The template has no external-binary lane today, but the principle
    and the shape are generic enough to belong in docs/agents/ or a template ADR.
  • .vscode/settings.json + .vscode/extensions.json. The template ships neither, and seqforge's
    fixes a failure every pixi repo has: python-envs.workspaceSearchPaths pointed at
    .pixi/envs/default because the extension searches [".venv", "*/.venv"] and "the interpreter
    silently fell back to a system python 3.10 and every third-party import went unresolved while the
    pixi env sitting in the tree had them all."
    defaultInterpreterPath alone does not fix it. The
    template should ship the pixi-interpreter half (adjusting the checker keys to pyright).
  • .github/ISSUE-CONVENTIONS.md's wayfinding section. Beyond the template's
    issue-tracker.md + triage-labels.md, it documents GitHub's native issue dependencies with the
    exact gh api call and the trap that costs an hour — the blocker's numeric database id
    (gh api repos/<o>/<r>/issues/<n> --jq .id), not the #number or node_id — plus the frontier
    query and the fallback when dependencies are unavailable. The template's issue docs should absorb
    this.
  • Per-context CONTEXT.md and colocated docs/adr/ under src/<pkg>/<context>/. The template's
    docs/agents/domain.md opens "Single-context: one CONTEXT.md and one docs/adr/ at the repo
    root"
    and offers nothing else. seqforge runs the multi-context shape — five per-context
    glossaries routed from CONTEXT-MAP.md, records beside the code they govern, cited by number
    never by path so a record can move, and deliberately shipped in the wheel
    (pyproject.toml:70-76). The template should describe this as the second supported shape, with the
    conformance/vale declarations that go with it.
  • twine check dist/* in the release build. Validates the rendered metadata the way PyPI will,
    and here it doubles as the tripwire for a regressed git+https direct reference. Cheap; the
    template's release build has no equivalent.

Notes for the maintainer

  • G3 and G10 are the two that will produce work rather than a diff. G3's exact bill is measured
    above: six agent docs and three records over cap. G10's D rules are the unknown — I did not run
    ruff against the tree, so I cannot say how many docstrings are missing. Land the other select
    codes first and treat D as its own issue.
  • G8 vs. .github/ISSUE-CONVENTIONS.md is a real choice, not a defect to fix mechanically.
    seqforge's file is better than what it would replace, and it is where AGENTS.md points. Moving
    it to docs/agents/ buys alignment and costs a good location; declaring it in
    [tool.liulab.agent-docs] where it stands buys the caps without the move. My recommendation is
    the second, plus a new docs/agents/writing.md.
  • G14 touches AGENTS.md, which is at 1705 words and already over the cap G3 introduces. Doing
    the rename and the AGENTS.md trim in one commit is probably cheaper than two passes over the same
    file.
  • I could not determine whether the docs feature belongs in the default environment.
    ci.yml folds docs-build into the lint job and justifies it by measurement (1.7s versus ~28s for
    another setup-pixi), which is sound for mkdocs-material. The template's separate docs job
    exists because zensical's environment is heavy. If seqforge stays on material, leave it; revisit if
    the site ever moves to zensical. Not filed as a gap.
  • Nothing in this report was verified by running seqforge's own gate. The clone was read only —
    no pixi install, no check, no ruff or mypy run. Every claim above is from file contents,
    git ls-files, symlink inspection and wc -w.

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

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions