agentleFS
WikiEducationFoundationWikiEducationFoundation/WikiEduDashboard/.claude/CLAUDE.md

WikiEduDashboard

CLAUDE.md431 starsChanged 8 months agoMITView on GitHub

This is the single canonical source of repository guidance for every AI coding agent. AGENTS.md points non-Claude agents here; keep substantive instructions and workflows in this file rather than duplicating them in agent-specific instruction files. The canonical workflow skills are stored under .claude/skills/, with legacy session commands under .claude/commands/. Before doing a task that matches one of these workflows, read the corresponding file in full and follow it, even if the current client does not automatically discover that directory: When…

  • Commits and pushes

The file

Show its rules and text

We split this CLAUDE.md into the rules it gives an agent

17 rules. About 0 are common, 2 are distinctive, and 15 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 15

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Write browser-based feature specs: .claude/skills/feature-spec/SKILL.md

    line 18
  2. Very specific:

    When asked to run the full test suite and save coverage, use bin/full-suite.

    line 34
  3. Very specific:

    Use require_dependency "#{Rails.root}/lib/..." for lib/ files that may not be autoloaded

    line 59
  4. Very specific:

    When user-facing text is needed but the operator hasn't supplied it yet, leave a [PLACEHOLDER - <description of the copy needed>] marker in …

    line 95
  5. Very specific:

    Add strings to config/locales/en.yml only (other locales come from translatewiki.net).

    line 102
  6. Very specific:

    Use WikiApi.new(wiki) for MediaWiki API calls.

    line 109
  7. Very specific:

    Run yarn build yourself (don't ask the user to do it) before running feature specs that depend on CSS changes.

    line 127
  8. Very specific:

    Run feature specs with bin/feature-spec.

    line 140
  9. Distinctive:

    Never commit without being asked, even after a spec run succeeds.

    line 144
  10. Distinctive:

    Use VCR for specs that hit external APIs:

    line 149
  11. Very specific:

    Do not define constants at the top level of a spec file — use local variables inside the describe block instead, to avoid re-initialization …

    line 156
  12. Very specific:

    Prefer one focused it block per behavior.

    line 158
  13. Very specific:

    Do not document infrastructure here.

    line 167
  14. Very specific:

    Use the current agent's actual product name in every attribution marker (for example, Claude Code or Codex).

    line 178
  15. Very specific:

    Always use the review-pr skill in .claude/skills/review-pr/SKILL.md when reviewing or revisiting a pull request.

    line 197
  16. Very specific:

    Always use the commit skill in .claude/skills/commit/SKILL.md when creating commits.

    line 203
  17. Very specific:

    Never push to a permanent branch (master, production, wmflabs, staging).

    line 216

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

WikiEduDashboard — AI Coding Agent Instructions

This is the single canonical source of repository guidance for every AI coding agent. AGENTS.md points non-Claude agents here; keep substantive instructions and workflows in this file rather than duplicating them in agent-specific instruction files.

Shared workflows

The canonical workflow skills are stored under .claude/skills/, with legacy session commands under .claude/commands/. Before doing a task that matches one of these workflows, read the corresponding file in full and follow it, even if the current client does not automatically discover that directory:

  • Commit changes: .claude/skills/commit/SKILL.md
  • Review or revisit a pull request: .claude/skills/review-pr/SKILL.md
  • Prepare a pull request: .claude/skills/prepare-pr/SKILL.md
  • Write browser-based feature specs: .claude/skills/feature-spec/SKILL.md
  • Investigate a slow or stuck course update: .claude/skills/course-update-recon/SKILL.md
  • Implement change requests from a downloaded Google Doc (.docx with comments and suggestions): .claude/skills/google-doc-change-requests/SKILL.md
  • Enter TDD mode for a session: .claude/commands/tdd.md

Running tests and linting

bundle exec rspec spec/path/to/spec.rb   # single spec file
bundle exec rspec                         # full Ruby suite
bin/full-suite                            # full suite + archive coverage
bundle exec rubocop                       # lint Ruby
yarn test                                 # JavaScript suite
yarn lint-non-build                       # ESLint on test/ and root JS files

When asked to run the full test suite and save coverage, use bin/full-suite. It runs bundle exec rspec, then renames coverage/ to coverage.all.YYYY-MM-DD/ (with a numeric suffix if that name already exists).

RuboCop and ESLint are enforced. Fix offenses before considering a task done. Key project limits (differ from RuboCop defaults):

  • Line length: 100 characters
  • Method length: 16 lines
  • ABC size: 23
  • Class length: 130 lines

Project structure

  • app/services/ — plain Ruby service objects, one public responsibility each
  • lib/ — utilities, API wrappers, and domain logic
  • lib/utils/ — small utility classes (e.g. WikiUrlParser)
  • spec/services/ — service specs; spec/lib/ — lib specs
  • fixtures/vcr_cassettes/ — recorded HTTP interactions for specs (not committed)

Service class conventions

  • Naming: verb + noun, CamelCase, no "Service" suffix — e.g. GetRevisionPlaintext, ExtractClaimsAndSources
  • File: app/services/snake_case_name.rb
  • Initialize with all required inputs; call the main method at the end of initialize
  • Expose results via attr_reader; keep everything else private
  • Use require_dependency "#{Rails.root}/lib/..." for lib/ files that may not be autoloaded

Example skeleton:

# frozen_string_literal: true

class DoSomethingUseful
  attr_reader :result

  def initialize(input)
    @input = input
    @result = []
    perform
  end

  private

  def perform
    # ...
  end
end

User-facing text

By default, we never want AI-created or re-written text that users will see. Anything more substantive than a one-or-two-word button label should come from the operator, not generated by the AI. Ask for appropriate messaging any time user-facing text is needed; the AI should only write it if explicitly directed to do so at the individual message level.

Exception: errors a normal user should never see. The AI may write these without asking. This covers refusals for actions the interface does not offer that user, and failures that only a malformed or hand-crafted request can reach — the message exists so the response is not blank, and seeing it means something is wrong. Keep it to one short factual sentence and match the style of its neighbours. If a user could plausibly hit the message during ordinary use, this exception does not apply and the default rule above does, even when the string lives among error messages.

When user-facing text is needed but the operator hasn't supplied it yet, leave a [PLACEHOLDER - <description of the copy needed>] marker in its place instead of inventing copy — invented text must never ship. Use this exact marker everywhere (greppable as [PLACEHOLDER) so pending copy is trivial to find and fill in.

Translations

Add strings to config/locales/en.yml only (other locales come from translatewiki.net). JS reads them from an export that yarn start doesn't refresh; after editing en.yml, run bundle exec i18n export -c config/i18n-js.yml. Details: docs/i18n.md.

WikiApi usage

Use WikiApi.new(wiki) for MediaWiki API calls. The standard public methods (query, get_page_content, etc.) are preferred. For actions not covered by public methods, follow the pattern used in GetRevisionPlaintext:

@wiki_api.send(:api_client).send('action', 'parse', params)

Stylesheets

Stylesheets are in app/assets/stylesheets/ and use Stylus. Changes have no effect until the assets are recompiled:

yarn build   # one-off compile (exits when done; use before running tests)
yarn start   # continuous watcher (recompiles on save; normally running in dev)

Run yarn build yourself (don't ask the user to do it) before running feature specs that depend on CSS changes. New module files in app/assets/stylesheets/modules/ are auto-imported via the @import "modules/*" glob in main.styl — no manual import needed.

There are separate CSS bundles for some layouts (training.styl for the training layout, surveys.styl for surveys) that cherry-pick imports instead of globbing modules/*. If a new module needs to apply to those layouts too — anything that touches the nav or other shared chrome — add an explicit @import in the bundle that needs it.

Feature specs

Run feature specs with bin/feature-spec. Once the user has asked to "show me" in a session, run all subsequent feature specs headed (HEADED=1) for the rest of that session. Only add SLOW= when the user explicitly requests slow mode.

Never commit without being asked, even after a spec run succeeds.

Specs

  • Always require 'rails_helper'
  • Use VCR for specs that hit external APIs:
    VCR.use_cassette 'subdirectory/cassette_name' do
      # ...
    end
    Cassette files live in fixtures/vcr_cassettes/ and are not committed to git
  • Do not define constants at the top level of a spec file — use local variables inside the describe block instead, to avoid re-initialization errors
  • Prefer one focused it block per behavior; avoid bundling unrelated assertions

Production infrastructure

Two independent production deployments share this codebase: the Wiki Ed Dashboard (cap stage production, branch production, dashboard.wikiedu.org) and the Programs & Events Dashboard (cap stage peony, branch wmflabs, peony-web on WMCloud).

Do not document infrastructure here. Server and database configuration, firewall and backups are in server_config/SERVER_CONFIG.md; the P&E server breakdown, Toolforge integrations and third-party APIs are in docs/admin_guide.md.

AI attribution on external communication

Anything an AI coding agent publishes that another person reads as if a human wrote it must be explicitly marked as AI-generated. It must never be ambiguous or unstated when AI does things in this repo.

Use the current agent's actual product name in every attribution marker (for example, Claude Code or Codex). Never attribute one agent's output to a different agent.

  • PR / issue / review comments posted via gh pr comment, gh issue comment, gh pr review, etc.: end the body with a blank line and (Comment written by <agent name>.).
  • PR descriptions created via gh pr create: end the body with (PR description written by <agent name>.) (the prepare-pr skill handles this — keep using it).
  • Commit messages: the commit skill adds (Commit message written by <agent name>.) and the Co-Authored-By: trailer. Keep using it.
  • Anything else published to humans (Slack drafts, email drafts, public docs, etc.): add an equivalent trailer. When in doubt, add the marker.

PR review

Always use the review-pr skill in .claude/skills/review-pr/SKILL.md when reviewing or revisiting a pull request. Load it immediately — do not gather PR data manually first.

Commit messages

Always use the commit skill in .claude/skills/commit/SKILL.md when creating commits. It handles staging, message format, and session accounting.

While working, note anything that would otherwise be lost by commit time: pre-existing code the user brought in, abandoned approaches, or any context about the session character that isn't visible in the tool call history.

Git pushes

Push only as part of opening or updating a PR: a plain push of the PR's feature branch, and bin/open-pr's force-push of its pr-screenshots/<branch> orphan branch. Say what was pushed.

Never push to a permanent branch (master, production, wmflabs, staging); merging a PR or fast-forwarding a deploy branch counts. Force-push a feature branch or delete a remote branch only when the current message asks.

Keeping the checkout clean

git status should show only work in progress. Before finishing a task, account for every file you created: commit it, delete it, or move it out of the repo. Don't leave untracked files for a later session to puzzle over.

  • Analytics and research scripts go in docs/analytics_scripts/<project>/, with a README saying what each script does, when it was run and why. Commit them, either with the PR for the work they support or in a PR of their own once they've been run. One-time production fixes go in docs/cleanup_scripts/.
  • Data never goes in the tracked tree (lib/, app/, config/, spec/). Exports, spreadsheets, caches and intermediate results go in the project's data/ directory, which .gitignore covers, or outside the repo. Raw production dumps, and anything else holding users' emails, real names, or student writing that isn't public on a wiki, go outside the repo (for example ~/<project>/). Console scripts write to ~ by default.
  • Ignore rules that protect data go in the committed .gitignore, or in .git/info/exclude if they only matter on this machine. Never leave one as an uncommitted edit: workflows that switch branches stash uncommitted changes, and a rule left in a stash protects nothing.
  • Untracked screenshot specs (spec/features/*_screenshots_spec.rb, from prepare-pr's Strategy A) are deleted once their PR merges. Delete any you find whose PR has merged.
  • Stashes: pop what you stash before finishing, and report any you leave.
  • Local branches: review/<number> and pr-screenshots/<branch> branches are disposable once their PR is merged or closed.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.