Working conventions for any AI coding agent operating in this repository — Claude Code, GitHub Copilot, OpenAI Codex / ChatGPT, or anything else. This file is canonical: when a client-specific file disagrees with it, this file wins.
This project adopts the Flux76 baseline in
Flux76HQ/App-Guidance, shared/guidelines/project-baseline.md,
as far as it applies to a repository that is not an app (see below). This file
describes how to work here.
| Client | Entry file it reads automatically | Client-specific extras |
|---|---|---|
| OpenAI Codex / ChatGPT | AGENTS.md (this file) |
none |
| Claude Code | CLAUDE.md |
none |
| GitHub Copilot | .github/copilot-instructions.md |
none |
CLAUDE.md and .github/copilot-instructions.md are deliberately thin: they
point here and add nothing. A rule stated twice is a rule that will drift.
data.mealieshopper.nl is a public store of JSON data for
MealieShopper, not an app. People
send data as a pull request — a .json file or a .zip of .json files under
data/<collection>/ — a check shows the reviewer what would change on the site,
the owner approves and merges, and a workflow publishes it: unpacked and
formatted on the branch publicatie, and on GitHub Pages at
https://data.mealieshopper.nl. Most changes are data; changes to the code are
rare and go in their own pull request. How it works for people is in
README.md (Dutch) and README.en.md.
| Path | What it is |
|---|---|
data/ |
the approved sources: .json, or .zip files that unpack in place. The first folder is the collection. |
schemas/<collection>.schema.json |
optional JSON Schema per collection; its title and description name the collection on the site |
scripts/datastore.py |
check, build and unpack; the only code |
site/ |
the landing page template and its images, copied into every build |
.github/workflows/inzending.yml |
Inzending controleren: checks a pull request’s data with main’s code (pull_request_target) |
.github/workflows/controleren.yml |
Tests: the unit tests and the full check, with the pull request’s own code |
.github/workflows/publiceren.yml |
on push to main: build, commit to publicatie, deploy to Pages |
README.md, Hoe een inzending gepubliceerd wordt, for the flow, and
the docstring of scripts/datastore.py for the rules.publicatie by hand. It is rebuilt from main on every publish;
a hand edit is overwritten and never reviewed.main from a workflow. GITHUB_TOKEN cannot pass main’s branch
protection and cannot be a bypass actor; that is why the unpacked result goes to publicatie
instead. If unpacked files are wanted in main, run python scripts/datastore.py unpack <zip>
and open a pull request.token, api_key, password, …); do not weaken that list to get data in.Inzending controleren fails one that changes
data/ or schemas/ together with scripts/, tests/, site/, .github/ or
requirements.txt, so a submission cannot change the rules it is checked by.This repository has no VERSION file and no releases: it is a data store, not an app, and
nothing is installed from it. A publication is identified by the commit of the last change to
data/ or schemas/, which index.json carries as commit and generated_at, and every document
in index.json carries its sha256. Consumers pin on those.
| Job name | Workflow | What it checks |
|---|---|---|
Inzending controleren |
inzending.yml |
the merged data of a pull request, with main’s code: valid JSON, paths, zip safety, limits, schemas, secrets, one source per published path, and data and code not mixed. Writes what changes on the site to the job summary. |
Tests |
controleren.yml |
python -m unittest discover -s tests and datastore.py check with the pull request’s own code |
Site bouwen, Naar data.mealieshopper.nl |
publiceren.yml |
on main only: builds, commits to publicatie, deploys Pages |
The owner makes Inzending controleren and Tests required in the branch protection of main.
Neither workflow has a paths filter, on purpose: a required check that does not run blocks the
pull request forever.
inzending.yml runs on pull_request_target, so it must never execute anything from the pull
request: the pull request’s merge commit is checked out into inzending/ without credentials and
only read; the script, its dependencies and Python run from basis/, which is main. Keep it that way
— no pip install from inzending/, no script from it, no npm, no make.
GITHUB_TOKEN only. Do not add a personal access
token or deploy key to make a workflow push to main..env, no runtime configuration, no persistent data outside git.main. This repository is not an app, so it has no beta
channel (baseline §20, Where this does not apply). Pull requests go to main; main is
GitHub’s Default branch.publicatie is written by publiceren.yml only. Do not protect it in a way that blocks
github-actions[bot]..github/dependabot.yml) keeps jsonschema and the actions current; with a single
integration branch it has no target-branch.main; never commit directly to main..github/PULL_REQUEST_TEMPLATE.md): the submission part for
data, the code part for code. A change to a limit states the new value as a number.scripts/datastore.py): 10 MB per document, 25 MB per zip (GitHub’s limit for a file
added in the browser), 100 MB unpacked per zip, 2000 files per zip. A change states the new value
in the pull request and in both READMEs.-; a file name letters, digits,
., - and _. Anything else would need escaping in every consumer.NaN/Infinity,
an object or array at the top.ensure_ascii=False, indent=2 plus a newline, keys in the submitter’s order, so its sha256 in
index.json is stable. Changing serialize() changes every hash; treat it as a breaking change
for consumers.README.md and README.en.md have the same headings in the same order.Before committing, confirm:
python -m unittest discover -s tests passes and python scripts/datastore.py check reports no problems..env files are staged.README.md and README.en.md still match, and describe any changed limit.CLAUDE.md and .github/copilot-instructions.md still only point here.