From 8b52b25a3841c64ef629d25072a9b24bebc9d3f3 Mon Sep 17 00:00:00 2001 From: Matteo Lissandrini Date: Fri, 2 Oct 2026 14:00:33 +0200 Subject: [PATCH 1/4] chore(git): add .gitignore for local config and build output [BOT] Keeps the per-clone identity, the local agent configuration, scratch space, Finder metadata and the Pages staging directory out of the repository. --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77508b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Per-person commit identity; see .gitidentity.example +.gitidentity + +# Local agent configuration and scratch space +CLAUDE.md +.claude/ +.temp/ + +# macOS Finder metadata, written into any directory the Finder opens +.DS_Store + +# Build output +dist/ +.cache/ + +# Node, when a build step exists +node_modules/ + +# Build output, and the site as staged for GitHub Pages +_site/ From b755e7ef1a10b07812c14f90a640ed6ac8dc27eb Mon Sep 17 00:00:00 2001 From: Matteo Lissandrini Date: Fri, 2 Oct 2026 14:00:49 +0200 Subject: [PATCH 2/4] chore(agents): add AGENTS.md, commit hooks and identity template [BOT] AGENTS.md carries the core rules for any coding agent and tells it to read whichever other agents' instruction files are present. The hooks check the commit message format and reject added lines that name a local path. .gitidentity.example is the template for the per-clone commit identity. --- .githooks/commit-msg | 99 ++++++++++++++++++++++++++++++++++++++++++++ .githooks/pre-commit | 38 +++++++++++++++++ .gitidentity.example | 28 +++++++++++++ AGENTS.md | 39 +++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100755 .githooks/commit-msg create mode 100755 .githooks/pre-commit create mode 100644 .gitidentity.example create mode 100644 AGENTS.md diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 0000000..83a7d65 --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,99 @@ +#!/bin/sh +# +# Enforce the commit message format: +# +# (): [ [BOT]] +# +# type feat fix docs refactor perf test build ci chore style content +# scope optional, lowercase letters, digits and . _ / - +# subject imperative, lowercase first letter, no trailing full stop +# +# The subject line must be 72 characters or fewer. A trailing " [BOT]" marks a +# commit written by an agent rather than by hand. It is optional, because this +# hook checks hand-written commits too, but when it is present it must be +# exactly that, at the end, and the commit must carry no attribution trailer. +# +# Enable once per clone: +# git config core.hooksPath .githooks + +# Byte-wise matching, so [a-z] means ASCII a to z in every locale. +LC_ALL=C +export LC_ALL + +# Git runs this hook before it cleans the message up, so with "git commit -v" +# the file still holds the diff below the scissors line. Check the message +# only, without comments or the leading blank lines git would also drop. +msg=$(sed -e '/^# -* >8 -*$/,$d' -e '/^#/d' "$1" | sed '/./,$!d') +subject=$(printf '%s\n' "$msg" | head -n 1) + +# The way out is for people only: an agent's commit is the one this hook +# exists to hold to the format, and the git guard denies it --no-verify anyway. +fail() { + echo "commit-msg: $1" >&2 + echo " $subject" >&2 + [ -n "$2" ] && printf '%s\n' "$2" >&2 + echo "A hand-written commit can keep its message with git commit --no-verify," >&2 + echo "which skips this check and pre-commit, for that one commit only." >&2 + echo "An agent fixes the message instead." >&2 + exit 1 +} + +# Merges, reverts and fixups are generated by git itself; leave them alone. +case "$subject" in + Merge\ *|Revert\ *|fixup!\ *|squash!\ *|amend!\ *) exit 0 ;; +esac + +# dash (the /bin/sh on Debian and Ubuntu) counts bytes, so an accented letter +# would cost two. Dropping UTF-8 continuation bytes leaves one byte per character. +length=$(printf '%s' "$subject" | tr -d '\200-\277' | wc -c | tr -d ' ') +[ "$length" -gt 72 ] && fail "subject line is $length characters, the limit is 72" + +case "$subject" in + *[[:space:]]) fail "subject line ends in whitespace" ;; +esac + +# The marker, if present, is exactly " [BOT]" and the last token. Anything +# resembling it elsewhere is a mistake, not a variant. +bot= +case "$subject" in + *' [BOT]') bot=1; body=${subject% \[BOT\]} ;; + *) body=$subject ;; +esac +# Two spaces before the marker leave one behind, which the pattern below accepts. +case "$body" in + *[[:space:]]) fail "subject line ends in whitespace" ;; +esac +if printf '%s' "$body" | grep -iq '\[ *bot *\]'; then + fail "the [BOT] marker must be the literal ' [BOT]' at the end of the subject" +fi + +pattern='^(feat|fix|docs|refactor|perf|test|build|ci|chore|style|content)(\([a-z0-9._/-]+\))?: [a-z].*[^.]$' +if ! printf '%s' "$body" | grep -Eq "$pattern"; then + fail "subject line does not match (): " \ +" type feat fix docs refactor perf test build ci chore style content + subject imperative, lowercase first letter, no trailing full stop" +fi + +description=${body#*: } +first=${description%% *} +case "$first" in + added|adds|fixed|fixes|updated|updates|removed|removes|changed|changes|\ + renamed|renames|moved|moves|improved|improves|refactored|refactors|\ + created|creates|deleted|deletes|documented|documents) + fail "'$first' is not imperative; write 'add', not 'added'" ;; +esac +case "$description" in + update|updates|wip|fix|fixes|changes|misc|stuff|tmp|temp|minor) + fail "'$description' is a placeholder; say what changed" ;; +esac + +# A body, if any, is separated from the subject by one blank line. +second=$(printf '%s\n' "$msg" | sed -n '2p') +[ -n "$second" ] && fail "leave the second line blank" + +if [ -n "$bot" ] && printf '%s\n' "$msg" | + grep -Eiq '^co-authored-by:|generated with \[?claude'; then + fail "agent commits carry [BOT] and no attribution trailer" +fi + +exit 0 diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..b926b1e --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,38 @@ +#!/bin/sh +# +# Refuse a commit that adds a machine-local absolute path: where this clone +# lives, or the committer's home directory. The path exists on one machine +# only, so to everyone else it is a dangling reference, and it publishes the +# account name it contains besides. Write paths relative to the repository +# root instead. +# +# Only added lines are checked, so a file that already carries such a path can +# still be edited. Where content genuinely has to hold one, commit it by hand +# with --no-verify. +# +# Enable once per clone: +# git config core.hooksPath .githooks + +root=$(git rev-parse --show-toplevel) || exit 1 + +# A home of / (some containers) would match every line, so it is skipped. +home=${HOME:-} +[ "$home" = / ] && home= + +found=$(git diff --cached --no-color --no-ext-diff -U0 --diff-filter=ACMR | + awk -v root="$root" -v home="$home" ' + /^\+\+\+ / { file = substr($0, 7); next } + /^\+/ { + line = substr($0, 2) + if (index(line, root) || (home != "" && index(line, home))) + printf " %s: %s\n", file, substr(line, 1, 100) + }') + +if [ -n "$found" ]; then + echo "pre-commit: staged lines add a machine-local absolute path" >&2 + printf '%s\n' "$found" >&2 + echo "Write it relative to the repository root instead." >&2 + exit 1 +fi + +exit 0 diff --git a/.gitidentity.example b/.gitidentity.example new file mode 100644 index 0000000..d1e73a6 --- /dev/null +++ b/.gitidentity.example @@ -0,0 +1,28 @@ +# Commit identity for this repository. +# +# Copy this file to .gitidentity, fill in your own details, and wire it up once +# per clone: +# +# cp .gitidentity.example .gitidentity +# git config --local include.path ../.gitidentity +# +# This is a git config file, so git reads it natively; there is no script in +# between. The include path is relative to .git/, which is why it starts with +# ../ and why the include line itself lives in .git/config rather than here. +# +# .gitidentity is gitignored: it is a per-person setting, and cloning the +# repository must not hand you somebody else's address or signing key. +# +# Find your key id with: gpg --list-secret-keys --keyid-format=long +# Inspect the last entry: git log -1 --show-signature + +[user] + name = Your Name + email = you@univr.it + signingkey = 0123456789ABCDEF + +[commit] + gpgsign = true + +[tag] + gpgsign = true diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f0ca220 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,39 @@ +# AGENTS.md — ARMADA site + +Static GitHub Pages website for the ARMADA doctoral network on reliable conversational data exploration, served at armada-dn.eu. + +## Core rules + +These are binding. They override any general default behaviour. + +1. **Never touch anything outside this repository.** Not sibling repositories, + not `$HOME` dotfiles, not system paths, not global installs. Reading outside + it is not allowed either without asking first. +2. **Never `git commit` without explicit permission**, every time. "The change + is finished" is not permission. +3. **Check the branch before starting; never switch without a yes.** If the + work belongs on another branch or a new one, propose the switch and wait. +4. **Never stage in bulk.** No `git add -A`, `git add .`, `git add -u`, + `git commit -a`. Enumerate paths. +5. **One commit per topic**, and every commit an agent authors ends its subject + line with `[BOT]`. Never a commit called "update". +6. **`.temp/` is gitignored scratch space.** Read it, ask before writing, never + overwrite without a named yes, never commit it, and never name its paths in a + committed file. +7. **Size-check before reading any file.** A large generated file saturates the + context window and blocks the user's work. +8. **Never start a long-running or destructive operation on your own + initiative.** Describe the command and let the user run it. +9. **Ask instead of investigating, when asking is cheaper**, and be brief. + +## Other instruction files + +Coding agents keep their instructions in files of their own. Look for each of +these in the repository root and read every one you find: +`CLAUDE.md`, `.claude/rules/`, `GEMINI.md`, `.cursor/rules/`, `.cursorrules`, `.github/copilot-instructions.md`, `.windsurfrules`, `.agent-defs/`. The rules above are the floor. Where two rules +differ only in how strict they are, follow the stricter one. Where they cannot +both be followed, stop and ask which one applies. + +## Project guides + +The guides in `docs/` say how the site is built and written: `voice.md` before writing or editing copy, `design.md` before changing markup or styles, `adding-content.md` before adding content. From 7019e68b411b1450844d0436a7e3733e1de42ffa Mon Sep 17 00:00:00 2001 From: Matteo Lissandrini Date: Fri, 2 Oct 2026 14:00:49 +0200 Subject: [PATCH 3/4] docs(site): add voice, design and content guides [BOT] Generated from the site as it stands. Lines marked (unverified) and sections marked to fill in still need confirming by hand. --- docs/adding-content.md | 44 ++++++++++++++++++++++++++ docs/design.md | 71 ++++++++++++++++++++++++++++++++++++++++++ docs/voice.md | 30 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 docs/adding-content.md create mode 100644 docs/design.md create mode 100644 docs/voice.md diff --git a/docs/adding-content.md b/docs/adding-content.md new file mode 100644 index 0000000..750cb0b --- /dev/null +++ b/docs/adding-content.md @@ -0,0 +1,44 @@ +# Adding content + +How to add to the site without changing its design. Read this before adding a +page or an entry. What each component is, is in [design.md](design.md); how the +copy should read, in [voice.md](voice.md). + +Sections marked (unverified) were found in the site as it stood when this file +was generated: confirm or correct them, then drop the mark. + +## Adding a page + +The pages today: `2026-univr-winterschool.html`, `call.html`, `index.html`. + +_To fill in: which page to copy as the starting point, what to change in its +`` (title, description, metadata), and where to link the new page from._ + +## Adding a `.task` (unverified) + +Repeated 15 times in `call.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.task-name` (unverified) + +Repeated 15 times in `call.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.task-leader` (unverified) + +Repeated 15 times in `call.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.wp-container` (unverified) + +Repeated 5 times in `call.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.row` (unverified) + +Repeated 5 times in `index.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.wide` (unverified) + +Repeated 4 times in `index.html`. _To fill in: which elements it needs, in what order, and which are optional._ + +## Adding a `.intro` (unverified) + +Repeated 3 times in `index.html`. _To fill in: which elements it needs, in what order, and which are optional._ + diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..f53c83b --- /dev/null +++ b/docs/design.md @@ -0,0 +1,71 @@ +# Design + +The site's visual system first, then the components built on it. Read this +before changing markup or styles. + +Lines marked (unverified) were filled in from the site as it stood when this +file was generated: confirm or correct them, then drop the mark. + +## Style guide + +### Stylesheets + +- `styles.css`: the site's own +- `flexboxgrid.min.css`: vendored, replace it and never edit it (unverified) +- `pico.min.css`: vendored, replace it and never edit it (unverified) + +A vendored stylesheet is replaced with a newer release, never edited. Changes go +in the site's own. + +### Custom properties + +- `--space-indigo: #272649ff` in `styles.css` +- `--vintage-grape: #52506dff` in `styles.css` +- `--dusty-grape: #6f58a1ff` in `styles.css` +- `--pacific-blue: #6ab0b7ff` in `styles.css` +- `--spicy-orange: #d74e09ff` in `styles.css` +- `--bright-lemon: #ffeb3bff` in `styles.css` +- `--azure-mist: #e1eff1ff` in `styles.css` +- `--platinum: #f7f9fcff` in `styles.css` +- `--primary-color: var(--space-indigo)` in `styles.css` +- `--primary-color-light: var(--pacific-blue)` in `styles.css` +- `--secondary-color: var(--azure-mist)` in `styles.css` +- `--accent-color: var(--spicy-orange)` in `styles.css` +- `--accent-color2: var(--bright-lemon)` in `styles.css` +- `--accent-color3: var(--platinum)` in `styles.css` +- `--white-color: var(--platinum)` in `styles.css` +- `--text-color: var(--space-indigo)` in `styles.css` +- `--text-color2: var(--dusty-grape)` in `styles.css` +- `--dark-color: var(--space-indigo)` in `styles.css` +- `--dark-color2: var(--vintage-grape)` in `styles.css` + +_To fill in: the colours, type scale and spacing, by the custom property that +holds each one._ + +### Typography + +- `"Montserrat", "Space Grotesk", sans-serif` +- `"Montserrat", "Archivo Black", sans-serif` + +## Components + +Each component: where its markup is used, where it is styled, and what it +exposes as custom properties so a new use can retune it without copying it. + +- `.bottom`: on 3 pages, no styles found (unverified) +- `.col-md-2`: on 3 pages, no styles found (unverified) +- `.col-md-4`: on 3 pages, no styles found (unverified) +- `.col-md-8`: on 3 pages, no styles found (unverified) +- `.col-md-offset-2`: on 3 pages, no styles found (unverified) +- `.col-xs-12`: on 3 pages, no styles found (unverified) +- `.container`: on 3 pages, no styles found (unverified) +- `.eu-logo`: on 3 pages, styled in `styles.css` (unverified) +- `.fas`: on 3 pages, no styles found (unverified) +- `.hero`: on 3 pages, styled in `styles.css` (unverified) +- `.hero-content`: on 3 pages, styled in `styles.css` (unverified) +- `.intro`: on 3 pages, styled in `styles.css` (unverified) +- `.logo`: on 3 pages, styled in `styles.css` (unverified) +- `.row`: on 3 pages, no styles found (unverified) +- `.side`: on 3 pages, styled in `styles.css` (unverified) + +_To fill in: for each component, what it is for and what may be changed._ diff --git a/docs/voice.md b/docs/voice.md new file mode 100644 index 0000000..d15aec0 --- /dev/null +++ b/docs/voice.md @@ -0,0 +1,30 @@ +# Voice + +Who the site is for, and how it speaks to them. Read this before writing or +editing any copy. It covers the words the site shows its readers, not how the +repository's own documentation is written. + +Lines marked (unverified) were filled in from the site as it stood when this +file was generated: confirm or correct them, then drop the mark. + +## Audience + +_To fill in: who reads the site, what they come to do, and what they already +know. The main audience first, then any other._ + +## Tone + +_To fill in: how formal and how technical the copy is, whether the site speaks +as "we", and how it addresses the reader._ + +## Language + +- `en`: 3 page(s) (unverified) + +_To fill in: which language is primary, which pages are translated, and which +spelling the site follows._ + +## Terminology + +_To fill in: the names the site always uses for its own projects, people and +groups, and the terms it avoids._ From 1dfee8a657141e83a2268650d9c7f489a42472cf Mon Sep 17 00:00:00 2001 From: Matteo Lissandrini Date: Fri, 2 Oct 2026 14:00:50 +0200 Subject: [PATCH 4/4] ci(pages): deploy with GitHub Actions, leaving out doc assets [BOT] Deploying from the branch publishes every file in it, including AGENTS.md and docs/. The workflow stages the site without what .pagesignore lists and fails if a doc asset from the README's table would be published anyway. The README records that the Pages source still has to be switched to GitHub Actions, and how. --- .github/pages-stage.sh | 22 ++++++++++++ .github/workflows/pages.yml | 37 ++++++++++++++++++++ .pagesignore | 17 +++++++++ README.md | 70 ++++++++++++++++++++++++++++++++++++- 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100755 .github/pages-stage.sh create mode 100644 .github/workflows/pages.yml create mode 100644 .pagesignore diff --git a/.github/pages-stage.sh b/.github/pages-stage.sh new file mode 100755 index 0000000..25dd631 --- /dev/null +++ b/.github/pages-stage.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Stage the site for GitHub Pages: copy the repository into _site/, leaving out +# what .pagesignore lists, then fail if a doc asset from the README's asset +# table would be published anyway. +set -eu + +[ -f .pagesignore ] || { echo "pages-stage: no .pagesignore" >&2; exit 1; } +[ -f README.md ] || { echo "pages-stage: no README.md, so no asset table to check" >&2; exit 1; } + +rm -rf _site +mkdir _site +rsync -a --exclude-from=.pagesignore ./ _site/ + +status=0 +for path in $(awk -F'|' '$3 ~ /^ *doc *$/ { gsub(/[ `]/, "", $2); print $2 }' README.md); do + if [ -e "_site/$path" ]; then + echo "pages-stage: $path is a doc asset in README.md but would be published;" \ + "add it to .pagesignore" >&2 + status=1 + fi +done +exit "$status" diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..0822b6f --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,37 @@ +# Publishes the site to GitHub Pages on every push to main. The Pages +# source must be set to "GitHub Actions" in the repository settings. +# .github/pages-stage.sh decides what is published: everything .pagesignore +# does not list, hidden files included (.git and .github never are). +name: Pages + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@v7 + - uses: actions/configure-pages@v6 + - name: Stage the site + run: sh .github/pages-stage.sh + - uses: actions/upload-pages-artifact@v5 + with: + path: _site + include-hidden-files: true + - id: deployment + uses: actions/deploy-pages@v5 diff --git a/.pagesignore b/.pagesignore new file mode 100644 index 0000000..01020c2 --- /dev/null +++ b/.pagesignore @@ -0,0 +1,17 @@ +# Left out of the published site by .github/pages-stage.sh, one rsync pattern +# per line. A leading / anchors a pattern at the repository root. +# +# Every row of kind "doc" in the README's asset table must be matched here: the +# stage script fails the deploy when one would be published anyway. +/.git/ +/.github/ +/.githooks/ +/.agent-defs/ +/.temp/ +/_site/ +/docs/ +/README.md +/AGENTS.md +/.gitignore +/.gitidentity.example +/.pagesignore diff --git a/README.md b/README.md index d4fc292..a456c65 100644 --- a/README.md +++ b/README.md @@ -1 +1,69 @@ -# ARMADA-DN.github.io \ No newline at end of file +# ARMADA-DN.github.io + +Website of the ARMADA doctoral network, Reliable Conversational Data +Exploration, served at [armada-dn.eu](https://armada-dn.eu). + +Hand-written HTML and CSS with no build step. + +## Preview locally + +Pages link their assets with root-relative paths (`/styles.css`), so serve the +repository root rather than opening the files directly: + +```sh +python3 -m http.server 8000 +``` + +Then open . + +## Deployment + +**Status (2026-10-01): moving from "Deploy from a branch" to "GitHub Actions".** +Until the switch below is done, `main` is still published as-is, including the +files listed as `doc` in the table below. + +Once switched, every push to `main` runs `.github/workflows/pages.yml`, which +stages the site with `.github/pages-stage.sh`: everything is copied into +`_site/` except what `.pagesignore` lists, and the deploy fails if a `doc` asset +below would be published anyway. A push to `main` is a deployment. + +### Switching the Pages source + +1. Merge the branch that adds `.github/workflows/pages.yml` into `main` only + when ready to do steps 2 and 3 straight after. +2. In the repository on GitHub: **Settings → Pages → Build and deployment → + Source**, choose **GitHub Actions**. +3. On the same page, check that **Custom domain** still reads `armada-dn.eu` + and that **Enforce HTTPS** is on. With Actions the domain comes from this + setting; the `CNAME` file is kept but no longer decides it. +4. **Actions → Pages → Run workflow** on `main`, or push to `main`, and wait + for the deploy to go green. +5. Check that loads with its styles, and that + and + now return 404. +6. Update the status line above. + +To go back, set the source to **Deploy from a branch**, `main`, `/ (root)`. + +## Assets + +Every path in the repository root is either published as part of the site or +is a `doc` asset that describes it. Each `doc` row must be matched in +`.pagesignore`. + +| Path | Kind | What | +| - | - | - | +| `index.html`, `call.html`, `2026-univr-winterschool.html` | site | Pages | +| `styles.css` | site | The site's own styles | +| `pico.min.css`, `flexboxgrid.min.css` | site | Vendored, replaced, never edited | +| `logos/`, `images/`, `armada-logo.png`, `euflag.png` | site | Images | +| `redirects/` | site | Short paths to external URLs | +| `CNAME`, `LICENSE` | site | Domain record, licence | +| `README.md` | doc | This file | +| `AGENTS.md` | doc | Rules for coding agents | +| `docs/` | doc | Voice, design and content guides | +| `.github/` | doc | Pages workflow and stage script | +| `.githooks/` | doc | Commit hooks | +| `.gitignore` | doc | Git ignore list | +| `.gitidentity.example` | doc | Commit identity template | +| `.pagesignore` | doc | What the deploy leaves out |