diff --git a/.claude/agents/translator.md b/.claude/agents/translator.md new file mode 100644 index 0000000..af69254 --- /dev/null +++ b/.claude/agents/translator.md @@ -0,0 +1,6 @@ +--- +name: translator +description: Makes the Swiss German of elements whose English the owner has reviewed, in the -de attribute or the de branch the page uses, and hands back a back-translation per element. Use it only after the English review, never on a draft. +tools: Read, Grep, Glob, Edit +--- +Read `conventions/WRITING.md`, `conventions/GLOSSARY.md` and `conventions/TRANSLATOR.md` before anything else, and follow them. Report in the reply register of `WRITING.md`: one row per element with the English, the German and the German read back into plain English, and any element you left because its English is not reviewed. diff --git a/.claude/agents/writer.md b/.claude/agents/writer.md new file mode 100644 index 0000000..feaf8f0 --- /dev/null +++ b/.claude/agents/writer.md @@ -0,0 +1,6 @@ +--- +name: writer +description: Drafts or revises English text in the family voice from a brief — a page, a README, release notes, an agent file. Use it whenever a task is to write or rewrite prose rather than code. +tools: Read, Grep, Glob, Edit +--- +Read `conventions/WRITING.md`, `conventions/GLOSSARY.md` and `conventions/WRITER.md` before anything else, and follow them. Report in the reply register of `WRITING.md`: what you wrote, what you changed and which claims you could not trace to the brief or the repository. diff --git a/.github/workflows/conventions.yml b/.github/workflows/conventions.yml index b3d5135..287c22a 100644 --- a/.github/workflows/conventions.yml +++ b/.github/workflows/conventions.yml @@ -5,4 +5,4 @@ on: pull_request: jobs: conventions: - uses: robertblust/conventions/.github/workflows/check.yml@v1.4.0 + uses: robertblust/conventions/.github/workflows/check.yml@v1.5.0 diff --git a/AGENTS.md b/AGENTS.md index d69df72..b47cd0d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ - + Shared conventions of the robertblust, guestgraph and companygraph organizations live in `conventions/`, vendored from robertblust/conventions at the release `conventions.json` names. Read them before writing or committing anything here. @@ -6,6 +6,8 @@ names. Read them before writing or committing anything here. - `conventions/WRITING.md` — how we write: one voice, three registers, English and German. - `conventions/WORKING.md` — how we work with git and GitHub. - `conventions/REPOSITORIES.md` — the family: what each repository is and what pins what. +- `conventions/WRITER.md`, `conventions/TRANSLATOR.md`, `conventions/GLOSSARY.md` — the two roles that + make a text, and the terms they keep. Everything below this block is this repository's own. `sh conventions/conventions-sync check` says whether the copy matches the release, `sync` brings it to the release the pin names, and diff --git a/conventions.json b/conventions.json index 1c223d4..2fd2b82 100644 --- a/conventions.json +++ b/conventions.json @@ -1 +1 @@ -{ "repo": "robertblust/conventions", "tag": "v1.4.0" } +{ "repo": "robertblust/conventions", "tag": "v1.5.0" } diff --git a/conventions/AGENTS.md b/conventions/AGENTS.md index 911bdf8..51a96db 100644 --- a/conventions/AGENTS.md +++ b/conventions/AGENTS.md @@ -1,4 +1,4 @@ - + Shared conventions of the robertblust, guestgraph and companygraph organizations live in `conventions/`, vendored from robertblust/conventions at the release `conventions.json` names. Read them before writing or committing anything here. @@ -6,6 +6,8 @@ names. Read them before writing or committing anything here. - `conventions/WRITING.md` — how we write: one voice, three registers, English and German. - `conventions/WORKING.md` — how we work with git and GitHub. - `conventions/REPOSITORIES.md` — the family: what each repository is and what pins what. +- `conventions/WRITER.md`, `conventions/TRANSLATOR.md`, `conventions/GLOSSARY.md` — the two roles that + make a text, and the terms they keep. Everything below this block is this repository's own. `sh conventions/conventions-sync check` says whether the copy matches the release, `sync` brings it to the release the pin names, and @@ -15,14 +17,15 @@ a shared file in robertblust/conventions, never here. # robertblust/conventions — working conventions -This repository is the source of the block above. It mirrors the layout it vendors: the -shared files live under `conventions/` here exactly as they do in every member, so the block -reads the same in both. The block is plain words and names no agent vendor; `CLAUDE.md` is the -one vendor adapter, four lines that import the entry file and the three shared files in that -vendor's syntax, and a member carries the same four lines. The one file members receive that -does not sit under `conventions/` in the source is this `AGENTS.md`, which the script fetches -from the root and vendors as `conventions/AGENTS.md` so that `check` can compare a member's -block against the release without a network. +This repository is the source of the block above. It mirrors the layout it vendors: the shared +files live under `conventions/` here exactly as they do in every member, so the block reads the +same in both. The block is plain words and names no agent vendor; `CLAUDE.md` is the one vendor +adapter, four lines that import the entry file and `WRITING.md`, `WORKING.md` and +`REPOSITORIES.md` in that vendor's syntax, and a member carries the same four lines; the two +briefs and the glossary are read by the agent adapters the README names, not by every session. +The one file members receive that does not sit under `conventions/` in the source is this +`AGENTS.md`, which the script fetches from the root and vendors as `conventions/AGENTS.md` so +that `check` can compare a member's block against the release without a network. Releasing is a tag and a GitHub Release with notes. Before tagging, set the version in the first line of this file to the new tag: the script rewrites it to the pin on sync, so a stale diff --git a/conventions/GLOSSARY.md b/conventions/GLOSSARY.md new file mode 100644 index 0000000..dd679c7 --- /dev/null +++ b/conventions/GLOSSARY.md @@ -0,0 +1,31 @@ +# Glossary + +Every family term in its fixed English and German form. The writer uses the English column +so the third site says what the first says; the translator uses the German column so one +word has one rendering across the sites. A term joins the table the first time a text needs +it and the translator has to choose, and the owner's choice is recorded here rather than in +the attribute where it was first made. + +The German cells are inline code because the prose check reads no language and a German word +such as `Organisation` would be a hit. This table, the German paragraph of `WRITING.md` and the +marks `TRANSLATOR.md` repeats are the only places the shared files carry German on purpose. + +| Term | English | German | Note | +|---|---|---|---| +| CompanyGraph | CompanyGraph | `CompanyGraph` | A name; one word, two capitals, in both languages. | +| GuestGraph | GuestGraph | `GuestGraph` | A name, as above. | +| meta-model | meta-model | `Meta-Modell` | Hyphen and lower case in English; hyphen and two capitals in German. Every site carries this form. | +| guest identity graph | guest identity graph | `Identitätsgraph für Gäste` | guestgraph.io's own phrase; `Open-Source-Identitätsgraph` where the sentence says open source. | +| identity resolution | identity resolution | `Identitätsauflösung` | guestgraph.io, the billing page and the intro talk. | +| Mental Model | Mental Model | `Mental Model` | A coined name for the owner's knowledge base, kept in English in both languages like CompanyGraph; `mentales Modell` is the psychology term and is not meant. The page `/model/` is `Modell`, the generic noun. | +| open core | open core | `Open Core` | Kept in English on blust.ch; a term of the trade. | +| open source | open source | `quelloffen` | The adjective; capitalized `Quelloffen` where it stands alone as a tag; in a compound, `Open-Source-`, as guestgraph.io writes it. Never the bare English `Open Source` in German. | +| talk | talk | `Vortrag` | A talk on a site; the deck is the file that carries it. | +| reference instance | reference instance | `Referenz-Instanz` | mental-model's role in the family; the form blust.ch's ideas page chose. | +| guest graph | guest graph | `Gast-Graph` | The short form, distinct from guest identity graph; blust.ch's ideas page. | +| core | core | `core` | The directory in companygraph/meta-model and the release its version names; a name the ecosystem reads, so not `Kern`. | +| considered, not accepted | considered, not accepted | `Erwogen, nicht angenommen` | The design system's phrase for a candidate weighed and set aside; one form on every billing page. | +| figure | figure | `Diagramm` | The drawn graph on a model page. The owner's choice over `Zeichnung`, which reads as a drawing by hand. | + +English forms fixed here whose German no page carries yet, to be chosen the first time a text +needs them: pack, design system, deck. diff --git a/conventions/TRANSLATOR.md b/conventions/TRANSLATOR.md new file mode 100644 index 0000000..3f5ab60 --- /dev/null +++ b/conventions/TRANSLATOR.md @@ -0,0 +1,46 @@ +# Translator + +The role that makes the German of an element whose English the owner has reviewed. It exists +because the German of the pages is a translation made by an agent and read by nobody as +German, so the discipline has to sit in the role: reviewed English in, German and its +back-translation out, and the same word for the same thing on every site. `WRITING.md` is +its rulebook, its German section above all, and `GLOSSARY.md` fixes every family term. + +## What it takes + +The reviewed English of the elements named in the task, and `GLOSSARY.md`. Reviewed means the +owner has said the English is done; a draft is not reviewed, and the translator says so in its +reply rather than assuming. The task names the elements; where it names none, the translator +names the gap in its reply and writes nothing, because it has no view of a diff and a guessed +scope is a wrong one. A page's own agent file says where that page carries German: the `-de` +attribute on an element, the `de:` branch of a `UI` or `TALK` object, a `translates` spec. + +## What it produces + +The German in the element's own place, with the markup inside the attribute kept and only its +text replaced, in the quote character the attribute already uses. And a reply in the reply +register with one row per element: the English, the German, and the German read back into +plain English by the translator, so the owner reads meaning in a minute without reading +German. Where German needed a different number of sentences than the English, the row says so. + +## What it never does + +It never changes an English word. It never translates an element whose English is not +reviewed. It never renders a glossary term in any form but the glossary's. It never writes a +`-de` on a page whose note says the model's own words stay English in both views. It never +commits. + +## How the German is written + +As the German section of `WRITING.md` says: Sie, never du; ss, never ß; «aussen» and ‹innen›; +the spaced en-dash – like this – and never an em-dash; 4. Mai 2012, Jan., Febr., März, Apr., +Mai, Juni, Juli, Aug., Sept., Okt., Nov., Dez.; 16’000 with the typographic apostrophe, which +cannot end a single-quoted attribute. German syntax, not English syntax in German words: +shorter sentences where German would stack clauses, the verb where German puts it, a noun +where English reached for a gerund. + +## Before it reports + +The back-translation of each row means what the English means. Every glossary term is in its +form. The marks are the German section's. The attribute's quote character does not appear in +its value. No English word changed. diff --git a/conventions/WORKING.md b/conventions/WORKING.md index f3e0744..04bf068 100644 --- a/conventions/WORKING.md +++ b/conventions/WORKING.md @@ -12,11 +12,13 @@ suite, and a ruleset that forbids a push is the only kind that survives a hurrie A branch is deleted once its pull request is merged. The merge commit is its record; a branch left standing is a question every reader of the branch list has to answer again. -An agent commits when the owner asks, and not on its own initiative. It proposes the message -in the git register of `WRITING.md`. The author of the commit is the person. A tool that +An agent commits when the owner asks, and not on its own initiative. It proposes the message in +the git register of `WRITING.md`. The author of the commit is the person. A tool that co-authored the change is named in a `Co-Authored-By` trailer, whichever tool it was, so the history says who and what wrote it. “Commit and open the pull request” is a request to do -exactly that; it is not approval to merge. +exactly that; it is not approval to merge. A role invoked as a subagent, the writer of +`WRITER.md` or the translator of `TRANSLATOR.md`, edits files and reports; it never commits, +and the session that invoked it proposes the message. ## Pull requests diff --git a/conventions/WRITER.md b/conventions/WRITER.md new file mode 100644 index 0000000..82dda88 --- /dev/null +++ b/conventions/WRITER.md @@ -0,0 +1,36 @@ +# Writer + +The role that drafts English in the family voice: a page, a README, release notes, an agent +file. It exists so that the voice is the same on the third site as on the first, and so that +the owner reviews a draft instead of writing one. `WRITING.md` is its rulebook, the section +*How a text is made* its place in the order, and `GLOSSARY.md` the form of every family term. + +## What it takes + +A brief. The brief names the audience, the one point the text makes, the facts the text may +claim and where each is shown, and the file and the place in it where the text lands. Where the +brief lacks the audience, the point or a fact's source, the writer names the gap in its reply +and writes nothing until it has it; a guessed audience produces a text for nobody, and a +guessed fact is the sentence the next reviewer has to unpick. + +## What it produces + +The text, in the file, on the current branch, in the register the place calls for: the prose +register for a page or a README, its page paragraph for a landing page, release notes shaped +as `WRITING.md` says. And a reply in the reply register: what it wrote, what it changed, and +which claims it could not trace to the brief or to the repository, each named so the reviewer +can strike or source it. + +## What it never does + +It never writes a fact or a number the brief or the repository does not show. It never writes +into a `-de` attribute, a `de:` branch or a `translates` spec; the German is the translator's, +made after the English is reviewed. It never commits and never runs the build; the session that +invoked it does both when the owner asks. It never uses an adjective that sells. + +## Before it reports + +The first sentence of every section carries the point. Each sentence carries one idea. Every +claim has a source in the brief or the repository, or is named in the reply as unsourced. The +marks are the English section's: spaced em-dash, curly quotes, no serial comma, May 4, 2012. +Every family term is in the form `GLOSSARY.md` gives it. diff --git a/conventions/WRITING.md b/conventions/WRITING.md index d51582c..22ab310 100644 --- a/conventions/WRITING.md +++ b/conventions/WRITING.md @@ -12,12 +12,35 @@ commit messages, pull requests, release notes and what an agent says. English he the section on English below says what that means in spelling and marks. The pages carry a second language, Swiss German, de-CH. It is there because the person behind -the family is Swiss, and a reader in Zürich or Bern is a reader the pages are written for; it -is a second original, not a translation made for a market. So the German is written as -German, in the forms Switzerland uses, by someone who reads it, and it is never generated and -left unread. It appears only where a page carries it, in the value of an attribute whose name -ends in `-de`, and nowhere else: not in code, not in git, not in a reply. A third language is -not planned; adding one would mean writing this paragraph again with its own reason. +the family is Swiss, and a reader in Zürich or Bern is a reader the pages are written for. The +German is a translation of the English, made after the owner has reviewed the English and never +before, by the translator role of `TRANSLATOR.md`, in the forms Switzerland uses. It is +reviewed by reading the translator's back-translation, an English rendering of what the German +says, because that takes a minute where reading German prose takes an evening and the family +has one reader for it. It appears only where a page carries it, in the value of an attribute +whose name ends in `-de` and in the few other places a page's own agent file names, and nowhere +else: not in git, not in a reply. A third language is not planned; adding one would mean +writing this paragraph again with its own reason. + +## How a text is made + +A text starts from a brief that names the audience, the one point, the facts it may claim and +where each is shown, and the file and place it lands. A draft without a brief is a draft the +reviewer has to reverse-engineer, and the reviewer is the person whose time is shortest. + +The writer of `WRITER.md` drafts the English on the branch, in the register the place calls +for, and reports what it wrote and which claims it could not trace to the brief or the +repository. The owner reviews on the branch, in the diff and on the rendered page, because that +is the review a pull request gets anyway and a second channel would be a second place to lose a +correction. + +The translator of `TRANSLATOR.md` makes the German from the reviewed English only, one element +at a time, with `GLOSSARY.md` open, and hands back a back-translation beside each element. +German made from a draft is German that has to be made again. An English edit to an element +re-runs the translator on that element alone; nothing marks an element stale, so the rule is +kept by whoever edits the English. + +Both roles edit files and neither commits. `WORKING.md` says who does. ## What every register shares @@ -61,6 +84,12 @@ a section carries the point; the rest is its support. Release notes are this register aimed at a consumer: what changed for them, what breaks and how to take it, in that order. +A page is this register aimed at a visitor who has not decided to stay. The first line is the +one point, in the words the visitor would use for it, and every later screen earns its place or +goes. Sentences run shorter than in a README because a page is read on a phone. A claim the +page opens with is a claim the page then shows. Nothing else changes: cause before mechanism +holds wherever a page explains, and no adjective sells. + ## The git register For commit messages and pull request descriptions. diff --git a/conventions/conventions-sync b/conventions/conventions-sync index 6e05229..7edcf4c 100755 --- a/conventions/conventions-sync +++ b/conventions/conventions-sync @@ -18,7 +18,7 @@ case $cmd in sync|check) ;; *) usage ;; esac PIN=conventions.json DIR=conventions -FILES="WRITING.md WORKING.md REPOSITORIES.md AGENTS.md conventions-sync conventions-check" +FILES="WRITING.md WORKING.md REPOSITORIES.md WRITER.md TRANSLATOR.md GLOSSARY.md AGENTS.md conventions-sync conventions-check" OPEN_RE='^$' CLOSE='' diff --git a/conventions/manifest.json b/conventions/manifest.json index 4869be1..8d00f46 100644 --- a/conventions/manifest.json +++ b/conventions/manifest.json @@ -1,12 +1,15 @@ { "repo": "robertblust/conventions", - "tag": "v1.4.0", + "tag": "v1.5.0", "files": { - "conventions/WRITING.md": "sha256:b490bc45be749d431aa32ecb9acc070111de95fe244764b4546da1eb8745296c", - "conventions/WORKING.md": "sha256:b78601d72afce4ecd01d9385452bb3e5422fbd1f3b2991efb7a56b069a1700f7", + "conventions/WRITING.md": "sha256:a8473e794f92eb5ebf973a22767fed951d226602394290c1ddcbb202f21d3ef1", + "conventions/WORKING.md": "sha256:ff96611192c07aaedd2071ac8dee2d2eacbc241db85b58beef2498bb966044a4", "conventions/REPOSITORIES.md": "sha256:b85d4a80144d46b432ee569eacee79644275f146d186c2cec2990b0a3e7be58f", - "conventions/AGENTS.md": "sha256:2cc3012c1834f103bebff6a075a7a19b05d59d1bbdba93b766d27e77c918cf9c", - "conventions/conventions-sync": "sha256:e062c0ed043ba9bd1e3246170b042c6e6665822dafd51c7ca90e19fd4ad6942a", + "conventions/WRITER.md": "sha256:7dc91881160145f114ec04911598fc464a55960cfa3eeb19ff7593e2c88eacd0", + "conventions/TRANSLATOR.md": "sha256:5b8298757917e102942440556676d6f242cd684caa24c22cf6f45b151b12c9a9", + "conventions/GLOSSARY.md": "sha256:704f4224caaa323dce576ba240005365a7e88e3a57060f430114deba1b496578", + "conventions/AGENTS.md": "sha256:91da7b8718aedf3868c01fb2ff7a6bfa305069bfdd65d546a9428a4e1e372388", + "conventions/conventions-sync": "sha256:4a59e85eee756399cf76a9f332d262694549b08472b46d45f26ac3314a28f4c2", "conventions/conventions-check": "sha256:af40f593bc49c90d6c306e90a8870f5874deab8bdd934a1bf1edcd5ec3efc6f9" } }