Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .claude/agents/translator.md
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 6 additions & 0 deletions .claude/agents/writer.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion .github/workflows/conventions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<!-- conventions · v1.4.0 -->
<!-- conventions · v1.5.0 -->
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.

- `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
Expand Down
2 changes: 1 addition & 1 deletion conventions.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "repo": "robertblust/conventions", "tag": "v1.4.0" }
{ "repo": "robertblust/conventions", "tag": "v1.5.0" }
21 changes: 12 additions & 9 deletions conventions/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<!-- conventions · v1.4.0 -->
<!-- conventions · v1.5.0 -->
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.

- `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
Expand All @@ -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
Expand Down
31 changes: 31 additions & 0 deletions conventions/GLOSSARY.md
Original file line number Diff line number Diff line change
@@ -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.
46 changes: 46 additions & 0 deletions conventions/TRANSLATOR.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 5 additions & 3 deletions conventions/WORKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
36 changes: 36 additions & 0 deletions conventions/WRITER.md
Original file line number Diff line number Diff line change
@@ -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.
41 changes: 35 additions & 6 deletions conventions/WRITING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion conventions/conventions-sync
Original file line number Diff line number Diff line change
Expand Up @@ -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='^<!-- conventions · v[^ ]* -->$'
CLOSE='<!-- end conventions -->'

Expand Down
13 changes: 8 additions & 5 deletions conventions/manifest.json
Original file line number Diff line number Diff line change
@@ -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"
}
}