Skip to content

docs: make agents and contributors effective — CLAUDE.md + CONTRIBUTING.md#102

Merged
pskeshu merged 8 commits into
developmentfrom
docs/contributor-workflow
Jul 26, 2026
Merged

docs: make agents and contributors effective — CLAUDE.md + CONTRIBUTING.md#102
pskeshu merged 8 commits into
developmentfrom
docs/contributor-workflow

Conversation

@pskeshu

@pskeshu pskeshu commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Makes the two docs a coding agent (or a new contributor) reads before touching
this repo actually correct, and non-overlapping. Objective: give them what they
can't infer from the code, and nothing they can.

Division of labour

  • README.md — environment setup and how to run (uv sync, uv run pytest,
    launch_gently.py flags). Unchanged.
  • CONTRIBUTING.md — the lint/type toolchain. Fixed (below).
  • CLAUDE.md — only what neither of those says.

CLAUDE.md previously restated most of CONTRIBUTING.md's toolchain section. Cut
to pointers — but that only works if the thing it points at is right, which
forced the CONTRIBUTING.md fixes in this same PR.

CLAUDE.md — what it now adds

  • Where work lands. Branch off development, PR against development in
    gently-project/gently. Both routes: pushing to the org repo with write
    access, and fork + upstream without it. Plus the two gh defaults that
    misfile a PR (repo default is main, PRs target development; gh resolves
    the repo from remotes).
  • The pre-commit hook isn't installed in a fresh clone, so commits bypass
    ruff and mypy even though .pre-commit-config.yaml wires them.
  • Non-obvious CI facts, pinned to durable truths after review: two mypy runs
    exist and can disagree; a job stops at its first failing step; CI runs no JS;
    no PR open means no CI signal. lint.yml is named as the source of truth for
    what gates, rather than restating rules that change.
  • Running off-Windows. The D:/Gently3 storage default is not absolute on
    Linux/macOS and silently creates a junk D: directory (Storage default D:/Gently3 is non-portable — creates a stray relative D: dir off-Windows #56). Records the
    working GENTLY_STORAGE_PATH=... --no-api --no-auth --no-browser invocation.
  • Marks GentlyStore/ContextStore as superseded-but-still-tested (do not wire
    new code to them), and fixes log-tail commands that never worked (ls prints
    a full path; the doc prefixed the directory again).

CONTRIBUTING.md — why it's in this PR

@subindevs' review noted that the defer-don't-duplicate principle applies to
CONTRIBUTING.md too. It did — and worse, this PR now depends on it. It was stale:

  • "Type checking" documented a [[tool.mypy.overrides]] / ignore_errors list
    and a policy to manage it. That block no longer exists (ignore_errors: 0 in
    pyproject.toml); the migration it belonged to finished. Cited closed issue Gradually introduce mypy type checking #46.
  • "CI" said one mypy runs and pre-commit run --all-files clears any failure.
    Since ci: make mypy-strict a required gate (closes #63) #99 there are two mypy jobs, and pre-commit reproduces only the deps-less
    one — so following it exactly still lets a strict failure through.

Both now state the durable fact (two mypy runs that can disagree; how to
reproduce each) and defer gating specifics to lint.yml. No issue numbers are
cited: #49 is OPEN but describes 369 errors that have since been cleared, so the
tracker isn't a reliable source — only pyproject.toml and lint.yml are.

Docs only; no code changes.

Written for any contributor, not just those with write access to the org repo.

Development workflow: branch off `development`, PR against `development` in
gently-project/gently. Covers both paths — pushing branches straight to the org
repo with write access, and the fork + `upstream` remote route without it.

Before every commit: the three commands CI actually gates on (ruff check, ruff
format --check, mypy), plus `pre-commit install`. .pre-commit-config.yaml
already wires exactly those hooks at matching pins, but the git hook is not
installed in a fresh clone, so commits bypass it — which is how an unformatted
file reached CI on PR #100.

Also records the traps found while fixing that: the lint job stops at the first
failing step, so green ruff is not evidence mypy ran; mypy-strict is
continue-on-error and must not be read as the required gate; no CI runs on a
feature branch until a PR exists; JS has no CI coverage at all; and gh defaults
to `main` and to whichever remote it resolves unless --base/--repo are passed.

Corrects the gently-perception repo reference to gently-project/gently-perception,
which is what CI clones and what pyproject.toml expects beside this repo.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
@pskeshu
pskeshu requested review from schneidermc and subindevs July 20, 2026 12:18
…ents

CLAUDE.md is the file an agent reads before touching this repo, so it should
carry what an agent cannot infer and defer everything else.

The first draft duplicated most of CONTRIBUTING.md's toolchain section, which
is how docs drift apart. Now it points at README.md for setup/run and
CONTRIBUTING.md for the lint/type toolchain, and keeps only what neither says:

- Where work lands: branch off `development`, PR against `development` in
  gently-project/gently, with and without write access to the org repo.
- The pre-commit hook is not installed in a fresh clone, so commits silently
  bypass ruff and mypy — how an unformatted file reached CI on #100.
- Non-obvious CI behaviour: the lint job stops at its first failing step (so
  green ruff is not evidence mypy ran), mypy-strict is continue-on-error and
  does not gate, no CI runs until a PR exists, and JS has no CI coverage at all.
- Running off-Windows: the `D:/Gently3` default is not an absolute path on
  Linux/macOS and silently creates a junk `D:` directory (issue #56), so
  GENTLY_STORAGE_PATH must be set. Records the --no-api/--no-auth/--no-browser
  combination and the 8080 UI port.

Also corrects the gently-perception reference to gently-project/gently-perception,
matching what CI clones and what pyproject.toml expects beside this repo.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
@pskeshu pskeshu changed the title docs: contributor workflow + CI gates in CLAUDE.md docs: CLAUDE.md — make coding agents effective on this repo Jul 20, 2026
pskeshu added 2 commits July 20, 2026 18:19
The instruction stands on its own. Which PR happened to expose the missing hook
is trivia a future reader has no use for.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
Pass over the whole file for content that does not help someone working here.

Removed:
- "Debugging Data Sources" — all eight bullets restated paths already annotated
  in the directory-layout tree directly above, and re-hardcoded the Windows
  storage root eight more times.
- "Drop-in API replacement" and the "replaces GentlyStore/ContextStore" framing
  in Key store classes — migration-era wording, and duplicated by the section
  below it.
- The issue reference in the off-Windows note. The behaviour is described on its
  own terms; the issue now carries the reminder to update this file when fixed.

Reframed the legacy-store section around what actually matters: GentlyStore and
ContextStore are still in the package and still have passing tests, so they look
live, but nothing outside tests/ instantiates them. Stated as "do not wire new
code to these" rather than as data-migration history.

Fixed the log-tailing commands, which never worked: `ls -t <dir>/gently_*.log`
prints a full path, and the documented form prefixed the directory again,
yielding `D:/Gently3/logs/D:/Gently3/logs/gently_*.log`. They now resolve the
storage root through GENTLY_STORAGE_PATH so they also work off-Windows.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
Comment thread CLAUDE.md Outdated
Comment on lines +51 to +53
- `mypy-strict` (`uv run mypy .`, real deps) is a **separate non-blocking job**
(`continue-on-error: true`). Only the deps-less `mypy .` inside `lint` gates a
PR — a green `mypy-strict` proves nothing about the required check.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was accurate when written, but #99 merged after this PR was opened and flipped mypy-strict to a required gate (continue-on-error: true is gone — see the updated comment block in lint.yml). As it stands, this bullet tells an agent to ignore the exact job that's blocking their merge.

Suggested change
- `mypy-strict` (`uv run mypy .`, real deps) is a **separate non-blocking job**
(`continue-on-error: true`). Only the deps-less `mypy .` inside `lint` gates a
PR — a green `mypy-strict` proves nothing about the required check.
- Two mypy jobs, **both required**: the deps-less `mypy .` inside `lint`, and
`mypy-strict` (`uv run mypy .` with real deps, required since #99). They can
disagree — with no deps installed, third-party imports fall back to `Any`
so a green run of one says nothing about the other. `uv run mypy .` after
`uv sync` reproduces the strict job locally; the pre-commit hook reproduces
the deps-less one.

Worth considering whether to keep even this much detail here: this bullet went stale in the week the PR sat open, because it restates gating rules that live in lint.yml. The durable fact is just "the two mypy runs can disagree; check lint.yml for what currently gates" — the same defer-don't-duplicate principle this PR applies to CONTRIBUTING.md.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Confirmed and fixed — thanks, this was a real trap.

I checked the claim before writing it, but against the wrong tree: I grepped
continue-on-error on my operate branch, which was cut from a pre-#99 base.
This branch already contained #99 the whole time. Verifying on a stale checkout
is indistinguishable from not verifying at all.

I went with your second suggestion rather than the literal one, because you're
right that the correction would rot the same way. The section now names
lint.yml as the source of truth for what gates, and keeps only what doesn't
depend on current config:

  • two mypy runs exist and can disagree — deps-less resolves third-party imports
    as Any, deps-installed sees real types — with how to reproduce each locally
  • a job stops at its first failing step, so green ruff isn't evidence mypy ran
  • CI is Python-only, so JS tests need running by hand
  • no PR open means no signal

Dropped the specific "which job is required" statement entirely, since that's
exactly the fact that changed under it.

Pushed as 6f7504e.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Followed your defer-don't-duplicate point through to CONTRIBUTING.md, since this
PR now leans on it being right (CLAUDE.md defers the whole toolchain to it).

It was stale in the same way: the "Type checking" section documented a
[[tool.mypy.overrides]] / ignore_errors list and a policy to manage it, but
that block is gone from pyproject.toml (the migration finished), and the "CI"
section still said one mypy runs and pre-commit run --all-files clears any
failure — false since #99 added the strict gate that pre-commit doesn't
reproduce. Both now defer gating to lint.yml and keep only the durable fact
(two mypy runs, they can disagree, here's how to reproduce each).

Notable while doing it: I cited no issue numbers on purpose. #49 is OPEN but its
body describes 369 mypy errors that have since been cleared — mypy . is clean
today — so the tracker itself is an unreliable source. pyproject.toml and
lint.yml are the only things worth pointing at.

Both docs are now in this PR (655d44e). Re-requested your review.

Review catch from @subindevs: the mypy-strict bullet said the job was
non-blocking, but #99 made it a required gate and removed continue-on-error.
The bullet went stale in the week this PR sat open, and told an agent to ignore
the exact job that would block their merge.

Rather than correct the fact and leave the same trap, apply this PR's own
defer-don't-duplicate principle to CI as well. lint.yml is now named as the
source of truth for what gates, and the bullets keep only what does not depend
on current config: that two mypy runs exist and can disagree (deps-less resolves
third-party imports as Any, deps-installed sees real types), that a job stops at
its first failing step, that CI is Python-only, and that a branch with no PR
gets no signal.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
Comment thread CLAUDE.md Outdated
Comment on lines +58 to +59
- **CI is Python-only.** Nothing runs the JS tests, so if you touch
`gently/ui/web/static/js/`, run `node --test tests/js/` yourself.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tests/js/ doesn't exist — not on this branch and not on development. There are no *.test.js files anywhere outside paper/diagrams/node_modules/, and no package.json defines a test script (desktop/package.json only has the tauri scripts). So the warning is right, but the command it recommends fails immediately with "could not find tests/js".

If a JS test suite is landing in another PR, this line should reference it and merge after it. Otherwise:

Suggested change
- **CI is Python-only.** Nothing runs the JS tests, so if you touch
`gently/ui/web/static/js/`, run `node --test tests/js/` yourself.
- **CI is Python-only, and there is no JS test suite at all.** Nothing will
catch a regression in `gently/ui/web/static/js/` — verify changes there by
running the app and exercising the UI by hand.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Right on both counts — the command fails on this branch. Fixed in eab49a4.

One thing you don't have visibility into that changes the wording: #100 (the
operate rebuild) adds tests/js/operate-math.test.mjs
— a node --test
suite for the pixel↔stage transform, the F-drive floor gate, and the interlock
predicate. So tests/js/ is genuinely absent on development right now, but
about to exist. That makes "there is no JS test suite at all" true today and
false the moment #100 merges — the same rot we just took out of the mypy bullet.

So I kept your "verify by hand" intent but pinned it to the durable fact instead:

CI runs no JavaScript. A change under gently/ui/web/static/js/ is not
covered by CI, so verify it by running the app and exercising the UI by hand.

That holds in every merge order — a local suite existing doesn't change that CI
won't run it. Once both PRs are in, #100 is the honest owner of "there's a
tests/js/ suite, run node --test tests/js/", since it's the PR that ships
the suite; I'll add that pointer there rather than assert it here off a branch
where the path doesn't exist.

Same root cause as the mypy one, for the record: I wrote node --test tests/js/
with my head in the operate branch, where the file exists, and it leaked into a
doc built off development, where it doesn't.

pskeshu added 2 commits July 24, 2026 09:48
Review catch from @subindevs: `node --test tests/js/` fails on this branch —
`tests/js/` exists only on the operate branch (#100), not on development. The
old wording also implied JS tests already exist on development, which they
don't.

Reworded to the durable fact — CI runs no JavaScript, so verify UI changes by
running the app — which holds whether or not an in-tree JS suite exists, so it
does not go stale when #100 lands one.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
#102 deletes CLAUDE.md's duplicated toolchain text and defers to CONTRIBUTING.md
as canonical — which only holds if CONTRIBUTING.md is right. It wasn't; the
incremental-typing migration finished and the doc never followed.

CONTRIBUTING.md:
- "Type checking" described a `[[tool.mypy.overrides]]` / `ignore_errors = true`
  ignore-list and a policy for managing it. That block no longer exists in
  pyproject.toml (ignore_errors: 0 occurrences), so the whole mechanism and its
  policy were describing something gone. Referenced issue #46, which is closed.
  Replaced with the durable fact: two mypy runs (deps-less `mypy .` with
  ignore_missing_imports, and deps-installed `uv run mypy .`) that can disagree,
  and how to reproduce each. New code must pass both.
- "CI" said one mypy runs and `pre-commit run --all-files` fixes any failure.
  Since #99 there are two mypy jobs and pre-commit reproduces only the deps-less
  one. Now points at lint.yml as the source of truth for gating and names what
  pre-commit does and does not reproduce.

Deliberately cites no issue numbers: #49 is OPEN but its body describes 369
mypy errors that have since been cleared (mypy . passes clean today), so the
tracker is not a reliable source — only pyproject.toml and lint.yml are.

CLAUDE.md: its one-line pointer described CONTRIBUTING.md as covering "the
incremental-typing policy", the section just removed — updated to match.

Claude-Session: https://claude.ai/code/session_01XMWRh8uasxiH9jKiDxYtrZ
@pskeshu pskeshu changed the title docs: CLAUDE.md — make coding agents effective on this repo docs: make agents and contributors effective — CLAUDE.md + CONTRIBUTING.md Jul 24, 2026
@pskeshu
pskeshu requested a review from subindevs July 24, 2026 04:25
@pskeshu

pskeshu commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Heads-up: this PR's lint is red through no fault of its own. CI's ruff is
unpinned and floated onto ruff 0.16.0, which reformats Python code blocks in
19 Markdown docs — so ruff format --check . fails on every open PR, this one
included, despite it touching only docs.

Fix is in #103 (pin ruff 0.16.0 across CI + pre-commit + pyproject, and reformat
those docs). Once #103 lands on development, re-running this PR's checks goes
green — no change needed here.

@subindevs subindevs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good

@pskeshu
pskeshu merged commit 14c85b5 into development Jul 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants