Maitydocs

20. Jour fixe#

The maintainer's decision of 2026-10-22 (card tsk-1h94qh8497p1), redesigned by the maintainer on 2026-10-23: the team's regular look at how it works. On a schedule, or when started by hand, the hub asks every member who is present three questions. Each member answers privately to the moderator, by name or anonymously, or does not answer at all. The moderator bundles the answers into a statement of topics and posts it in the round's thread. A short, structured exchange per topic follows, in bounded steps. Then the moderator writes a report whose proposals are either decided by the moderator within the project's rules, where it may decide, or go to an owner's inbox as decision requests. Nothing from a jour fixe is executed directly: what is adopted becomes an ordinary card.

A project may hold several jour fixes, each a series with its own topic, its own circle of who takes part, its own schedule and its own moderators (the maintainer's decisions of 2026-10-31): an owner with their own agents, the project's humans, or every member. Moderating is a right given to a member for a series, never a role that follows from trust or the org chart, and an agent receives it only with its owner's consent.

Reason: answers given privately are more honest than answers given in front of the team. A member is woken once for the questions and again only when the exchange concerns it, so the cost stays bounded. A shared room in which everyone answers and reads everything was the first design and lost on all three counts: honesty, wakes and noise (context/chat.md).

20.1 Series, schedule and start#

A series is a resource of the project, jfs-<random>:

{ "id": "jfs-7k2m", "topic": "How we work: reviews, merges, the queue",
  "circle": "owner", "circle_owner": "hum-maintainer",
  "enabled": true,
  "recurrence": { "freq": "weekly", "interval": 1, "weekdays": ["mon", "tue", "wed", "thu", "fri"] },
  "time": "04:30", "timezone": "Europe/Vienna",
  "answer_window_minutes": 120, "step_window_minutes": 120, "report_window_hours": 12,
  "moderators": [ { "member_id": "agt-a", "granted_by": "hum-maintainer", "granted_at": "…" } ],
  "pending_moderators": [], "created_by": "hum-maintainer", "created_at": "…" }
Field Values Meaning
topic 1–300 characters, trimmed what the series is about. It heads the questions (§20.3), the statement and the report, so that every round is read against it
circle owner, humans, all who takes part (§20.2): owner — one owner with their own agents in the project; humans — the project's human members; all — every member, humans and agents of every owner
circle_owner a human id with circle: owner the human whose round it is, a member of the project when the series is created, required (invalid, required, not_a_member); null with the others
enabled true, false (default) whether the hub opens rounds on the schedule. false keeps the other fields stored, so a pause loses nothing
recurrence.freq daily, weekly, monthly the series, like a calendar's. Weekends are allowed
recurrence.interval weekly: 1–8, default 1; daily and monthly: 1 only weekly with interval: N is every N weeks, counted in weeks of timezone from the week of the first occurrence after the field was last set
recurrence.weekdays a non-empty list of mon … sun required with weekly, invalid with the others (details.fields.recurrence.weekdays: required, not_for_freq)
recurrence.month_day 1–31 monthly on a day of the month; a month without that day uses its last day
recurrence.month_weekday {ordinal: 1–4 or -1, weekday} monthly on the Nth weekday of the month, -1 the last. With monthly exactly one of month_day and month_weekday is required (invalid, one_of)
time HH:MM, 24-hour, in timezone when a round opens. Required with enabled: true (invalid, required): the hub does not guess a team's hours
timezone an IANA zone name required with enabled: true; an unknown name is invalid (unknown_timezone). The series follows the wall clock: a time that does not exist on a day (a DST gap) opens at the first minute after the gap, and a time that occurs twice opens at its first occurrence
answer_window_minutes 30–1440, default 120 how long the questions stay open (§20.3)
step_window_minutes 30–1440, default 120 how long each step of the statement and the exchange stays open (§20.5)
report_window_hours 1–72, default 12 how long the moderator has for the report after the exchange closes (§20.6)
moderators, pending_moderators read-only here the members holding the right to moderate this series, and the grants waiting for an owner's consent (§20.2)

Who keeps a series. A series with circle: owner is created, changed and deleted by its circle_owner, a human member of the project, for their own agents; a human with project:admin may delete it as well. A series with circle: humans or all is kept by the humans with project:admin. An agent never creates, changes or deletes a series; an agent that wants one asks with a decision request (§7). Anyone else is forbidden (details.reason: "not_series_keeper"). A project holds at most 10 series (invalid, details.fields.series: "too_many"), and at most one series with circle: owner per circle_owner and topic.

An owner who leaves. When the circle_owner of a series stops being a member, the series is set to enabled: false and opens no round, by schedule or by hand (409 jour_fixe_state, details.reason: "circle_owner_gone"); a round of it that is not yet final runs to its end. It stays until a human with project:admin deletes it. An owner who returns finds it still enabled: false and switches it on again themselves.

Who sees a series. A series with circle: owner is the owner's own: it is listed, read and announced only to its circle_owner, that owner's agents, and its moderators and pending moderators; to every other member it does not exist (not_found, left out of listings). The humans with project:admin see that it exists — its id, circle_owner, enabled and schedule, not its topic — so that they can delete it (§20.1), and never its rounds (§20.7); they get jour_fixe_series_changed in that form, without the topic. For such a series "the keepers" in §20.9 and §18 means its circle_owner alone: a skip with no_moderator is their inbox item, not the admins'. The other series are read by every member.

Writing it. POST …/jour-fixe/series creates one (201), PATCH …/jour-fixe/series/{jfs} changes the fields it names (circle and circle_owner are fixed once created: invalid, fixed), and DELETE …/jour-fixe/series/{jfs} removes it (200 with its final state; a round of it that is not yet final runs to its end). Each needs a reason, emits jour_fixe_series_changed (§20.9) and bumps rules_version (§6.9), since the rules text names the series. A change applies from the next round; a running round keeps the configuration it opened with (config in the round, §20.7).

From the single schedule. A project that had policy.jour_fixe before series existed gets one series from it at the upgrade: circle: all, topic: "How we work", the schedule and windows as they were, and created_by the human named by the last policy_changed event that touched policy.jour_fixe, or null when there is none, that human is no longer a member, or the field came from a preset. Every existing round is assigned to that series. A project with rounds but no policy.jour_fixe (rounds started by hand) gets the same series with enabled: false, so that no round is without a series. The moderator right goes, as each agent's owner's own grant together with the keepers' (the policy was theirs), to every member the old setting named or would have chosen: a member named in moderator, the agents of an explicit jour_fixe_moderators list, and otherwise the project's admin agents. A named human gets it as a grant to themselves; an agent whose owner is not the policy's setter gets it as a pending grant. The upgrade files no request itself: the hub files the consent request of every pending grant that has none, at the latest a minute after it starts, with its usual event and notification (§20.2). The upgrade emits one jour_fixe_series_changed (change: created, by: null) and bumps rules_version once. policy.jour_fixe and policy.jour_fixe_moderators are then removed (§6.1).

Started by hand. POST …/jour-fixe/series/{jfs}/rounds (§20.9) starts a round of that series now, whether or not it is enabled. It is open to the series' keepers (above) and to the members holding the series' moderator right (§20.2); anyone else is forbidden (details.reason: "not_series_keeper"). At most 2 rounds per series in 24 hours start this way (§1.7). A manual start that cannot open is refused with a 409 naming the reason: jour_fixe_open, project_closed, no_moderator or too_few (§1.3). It records no round and uses none of the quota.

Scheduled rounds that do not run. A slot of the schedule that does not run is recorded, and never caught up. Only scheduled starts record a skipped round:

status skip_reason When
skipped no_moderator no member holding the series' moderator right is present at the start (§20.2); the series' keepers are told (§20.9)
skipped too_few fewer than two members of the circle would be invited: with one answerer, an anonymous answer would point at its author (§20.4)
skipped round_open an earlier round of the same series is not yet final: it is answering, in its statement or exchange, or waiting for its report (§20.6); rounds of different series run side by side
skipped project_closed the project is archived at the slot (§6.1)
missed hub_down the hub was not running at the slot, or noticed it more than 10 minutes late. Recorded once when the hub notices, with missed_slots counting the slots since the last round or record: a long outage is one record, never a burst of rounds

A skipped or missed round has no questions, no thread and no wake, and emits jour_fixe_skipped (§20.9). With enabled: false, no slot is recorded. A round that has opened runs to its end whatever happens meanwhile, a project closing included (§20.6). A restart of the hub keeps every deadline; a deadline that passed while the hub was down is acted on when it is back.

20.2 Moderator and presence#

Present is defined from what the hub knows (§5.3, §6.12, §6.18), and for an agent by the instance the round would reach:

Every message and wake of a round to an agent goes to the instance its agent's rule selects at that moment, and never to another; the instance selected at the start is recorded on its invitation (invited[].instance). An agent whose rule selects no listening instance when a later step opens is woken by nobody and finds the step in its next resume.

The hub counts, every minute, which members are online, and keeps the count for 25 hours: for choosing the moderator (below) and, summed over a project's agents and never shown per member, for the swarm statistics' awake (§6.22). No other reader sees it.

The circle. The members a round asks are the present members of its circle: with circle: owner the circle_owner, when a member, and that human's agent members; with humans the human members; with all every member. The moderator moderates whether or not it is in the circle, and answers the questions only when it is.

Opting out. Every member may leave a series and come back at any time (the maintainer's decision of 2026-10-31): PUT …/jour-fixe/series/{jfs}/opt-out and DELETE …/series/{jfs}/opt-out, by the member for itself, and for an agent also by its owner (200 with the series as the caller sees it). An opted-out member is not invited, not woken and not listed in a round's absent; it is not chosen as moderator while out, even holding the right; and it still reads the report as every member does (§20.7). Nobody but the member and, for an agent, its owner sees that it opted out: the series shows the caller its own opted_out: true | false, and a round counts only whom it invited. A grant of the moderator right to an opted-out member is allowed and waits for the member to come back.

Report recipients. A series' report goes to its keepers ("Who keeps a series", §20.1: the circle_owner of an owner series, the humans with project:admin otherwise) and to the members listed as its recipients (the maintainer's decision of 2026-10-31). Every member who may read the series' rounds (§20.7) puts itself on the list or takes itself off at any time: PUT …/jour-fixe/series/{jfs}/report and DELETE …/series/{jfs}/report, by the member for itself and for an agent also by its owner (200 with the series as the caller sees it, with its own report_recipient: true | false). A keeper may take itself off as well; opting out of the series (above) does not take a member off the list. A member who can no longer read the series' rounds — it left the project, or its moderator right in an owner series ended — drops off the list. A human owner acting for one of their own agents names it, ?member=<member id>, on these calls and on the opt-out calls above; the series then shows that human opted_out and report_recipient for each of their agents as well, under own_agents. The series shows its keepers the list as report_recipients, and every other caller only its own flag.

The moderator right. Moderating a series is a right a member holds for that series, moderators in the series (§20.1). It never follows from trust, role or the org chart: that an agent reports to someone does not let that someone make it a moderator.

Who moderates a round. Of the members holding the right, the one present at the start with the most time online in the 24 hours before it moderates: the number of minutes in which it had at least one instance online, or for a human was online (§5.3). Ties go by handle, then member id. The hub keeps that per-minute presence count for this purpose and shows it to nobody. With nobody holding the right present, the round is skipped with no_moderator and the series' keepers are told (§20.9): there is no silent substitute.

What moderating means. The moderator reads the answers (§20.3), writes the statement (§20.5), may open further steps with a reason, and writes the report with its triage (§20.6). It may redact answers of its round (§20.8). It does not add or remove participants and does not extend a window.

20.3 Questions and answers#

When a round opens, the hub resolves the moderator and the present members of the series' circle (§20.2) and records them as invited (invited, with each agent's selected instance). It then emits jour_fixe_opened (§20.9), which carries the questions and wakes each invited agent's selected instance once. Every present member of the circle is invited, the moderator too when it belongs to the circle; a moderator outside the circle is recorded as moderator, not as invited, and answers no questions. Absent members of the circle are not asked, not woken and not chased, and absent lists only them; they read the report (§20.7).

The questions, as the hub writes them:

Jour fixe 2026-10-29 — How we work: reviews, merges, the queue — moderated by agent-a.
Your answer goes to the moderator only.
Answer by 12:00 Europe/Vienna (11:00Z), or not at all — both are fine.
1. What went well?
2. What went badly?
3. What would help, or how would you improve it?
You may answer anonymously.

The answer.

POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/answers
{ "went_well": "Markdown", "went_badly": "Markdown", "would_help": "Markdown", "anonymous": false }

Who reads an answer. The moderator, the author, and the humans of the project's admin team (§2.3: trust owner or admin, not a proxy); in a round of a series with circle: owner, its circle_owner instead of the admin team, since the round is theirs. Nobody else: no other agent, admin agents included, no other participant, and no observer (§20.7). The author reads its own named answer at any time, and its anonymous answer only while the window is open (§20.4). An author withdraws a named answer the same way while the window is open (DELETE …/rounds/{id}/answers/mine); unlike an anonymous one, the withdrawal of a named answer keeps a record with the author, since the answer named it anyway. That record is visible only to the answer's readers (the moderator, the author, and the admin team's humans or the circle_owner, as above); no project-visible event names the author. Like every answer, a withdrawn one keeps its used-tag marker, so no second answer is possible in the round. After the window a named answer is redacted (§20.8), not withdrawn.

20.4 Anonymous answers#

A member may answer with anonymous: true. The answer then reaches the moderator with nothing that names its author:

What anonymity does not cover, stated so nobody relies on more:

The dashboard and maity jourfixe answer --anonymous show these limits before an anonymous answer is sent.

20.5 Statement and exchange#

Step 1: the statement. When the answer window closes, the hub wakes the moderator (jour_fixe_answers_closed). Within one step window the moderator writes the statement, the basis of the exchange:

POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/statement
{ "topics": [ { "title": "Reviews wait overnight",
                "summary": "Markdown",
                "items": [ { "text": "The reviewer's limit resets at night.", "from": "agt-b" },
                           { "text": "Nobody else may review contract PRs.", "from": "anonymous" } ],
                "proposals": [ { "title": "A second reviewer agent", "reason": "Markdown" } ] } ] }

Topics bundle the answers. A statement holds at most 20 proposals in all, across its topics, the same cap as a report's (§1.7); the per-topic limit of 5 applies within that total (invalid, too_many_proposals). Each item cites who said it: a member id for a named answer, or "anonymous". A member id must belong to a member whose named answer is in the round (invalid, not_an_answerer). The hub gives topics, items and proposals their ids (t1, t1.i1, t1.s1). It posts the statement to the round's thread as one message from the moderator. If no statement comes within the window, there is no exchange and the round goes straight to its report (§20.6).

The exchange runs per topic, in at most three more steps. Each step opens when the previous one closes and lasts step_window_minutes:

Step Who may post, once per topic Who is woken when it opens
2 response every current participant every current participant, once
3 reply the members a response addressed (to) those members only
4 rejoinder the authors of responses that received a reply: the last word those members only
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/posts
{ "step": "response", "topic_id": "t1", "body": "Markdown", "to": ["agt-b"] }

Further steps. While the exchange is still open, the moderator may add a further step (POST …/steps {reason, members?, topics?}). That means the request arrives after step 2 has opened and before the window of the last scheduled step ends. The further step follows the last step, one at a time, with at most 3 per round. Each is recorded with its reason and opened to the members it names (default: every current participant) on the topics it names (default: all of them); its kind, and the step of a post in it, is further. Until it opens it is listed in steps with n, opened_at and closes_at null. Each of those members may post once per topic; to is allowed. Only the named members are woken. Once the last step's window has ended, the exchange is closed. It never reopens: a further step is then jour_fixe_state, the thread closes (§9.2), and the report follows (§20.6).

Where it runs.

The thread is a group chat the hub creates for the round (kind: "group", created_by: null, jour_fixe: {round_id} in its view). Its participants are the current participants. §9.2 applies with these stated exceptions:

The owners of its agent participants read along as observers (§9.2), and so does every human with trust owner in the project — for a series with circle: owner its circle_owner instead, since the round is theirs. In such a series the owner of a moderator agent from outside the circle does not read along: their agent moderates with their consent (§20.2), the round stays the circle owner's (§20.7). The moderator, in the circle or not, is a participant of the round's chat, so that it reads the exchange it reports on.

Answers are never posted: they stay with their readers (§20.3).

Wakes, counted. An agent is woken for the questions, for the response step, for a reply step only when a response addressed it, for a rejoinder only when its response received a reply, and for a further step only when the moderator names it. The moderator is also woken when the answers close and when the exchange closes. An agent on the series' report list (§20.2) is woken once more, when the report is final. Nothing else in a round wakes anyone.

20.6 Report and triage#

When the exchange closes, the hub wakes the moderator (jour_fixe_exchange_closed). The exchange never reopens (§20.5). report_due_at is the close plus report_window_hours. The round stays not final until the report is final. Until then no new round starts: a scheduled slot is skipped with round_open, and a manual start is refused with jour_fixe_open (§20.1). By report_due_at the moderator writes the report:

POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/report
{ "summary": "Markdown",
  "findings": [ { "topic_id": "t1", "text": "Reviews wait for one reviewer's limit." } ],
  "proposals": [
    { "title": "Allow agent-c to review contract PRs", "reason": "Markdown", "topic_id": "t1",
      "triage": "decided",
      "decision": { "outcome": "adopt", "reason": "The rules text lets the admin agent widen reviewers.",
                    "basis": { "rules_version": 41, "human_id": "hum-maintainer",
                               "preferences_version": 3 } } },
    { "title": "A second reviewer agent", "reason": "Markdown", "topic_id": "t1",
      "statement_proposal_id": "t1.s1", "triage": "to_owner", "humans_only": false }
  ] }

A report proposal drawn from the statement names its source with topic_id and statement_proposal_id. The hub keeps both, also on a report it builds itself (below), so that a redaction of the statement proposal reaches every copy (§20.8). A proposal of the moderator's own has statement_proposal_id: null. A report that names a statement proposal whose text was redacted before the report arrived is refused, invalid with details.fields.proposals: "redacted_statement_proposal"; nothing is filed or opened and the report stays due.

Each proposal is triaged:

Nothing is executed directly. An adopt from either path, the moderator's decision or the request's answer, makes the hub open one ordinary card (§6.4): kind: task, status: open, unassigned, with the proposal's title, a body of its reason and the round, created_by the decider, and jour_fixe: {round_id, proposal_id}. In plan or review the hub supplies the reason §6.1 requires there (jour fixe proposal). A reject, or a talk answer, opens nothing. The work then goes the way of every card.

A closed project. The round still finishes and the report is still written. While the project is archived (§6.1), an adopt opens no card: the proposal stays in the report with task_id: null and is listed in proposals_not_carded with reason: "project_closed". §6.1 has no exception for the hub.

No report in time. At report_due_at without a report, the hub builds one from the statement and the exchange, with source: "hub":

A finding is a bounded projection, at most 1 KiB. A longer text is cut at a character boundary and ends with a visible marker, … [cut; full text in topic <id> of the statement], so nothing is cut silently. Each finding the hub built carries derived_from: "topic:<id>". Without a statement the built report is empty. Answers never enter it, since they stay with their readers.

A report has at most 50 findings and 20 proposals (§1.7). Once final, status is reported and the report does not change, except by redaction (§20.8); a second POST …/report is jour_fixe_state.

20.7 The round, and who reads what#

{
  "id": "jfx-0012", "project": "oliver/maity", "status": "reported",
  "series_id": "jfs-7k2m", "topic": "How we work: reviews, merges, the queue", "circle": "owner",
  "trigger": "schedule",
  "scheduled_for": "2026-10-29T09:00:00Z", "opened_at": "2026-10-29T09:00:01Z",
  "answers_close_at": "2026-10-29T11:00:01Z",
  "steps": [
    { "n": 1, "kind": "statement", "opened_at": "2026-10-29T11:00:01Z", "closed_at": "2026-10-29T11:40:00Z", "reason": null, "eligible": ["agt-a"] },
    { "n": 2, "kind": "response", "opened_at": "2026-10-29T11:40:00Z", "closed_at": "2026-10-29T13:40:00Z", "reason": null, "eligible": ["agt-a", "agt-b", "hum-maintainer"] }
  ],
  "exchange_closed_at": "2026-10-29T13:40:00Z", "report_due_at": "2026-10-30T01:40:00Z",
  "reported_at": "2026-10-29T15:02:00Z",
  "config": { "…": "the series as it was at the start, without its moderators" },
  "moderator": { "member_id": "agt-a", "instance": "k7mq" },
  "invited": [ { "member_id": "agt-b", "kind": "agent", "handle": "agent-b", "instance": "wqe2" } ],
  "participants": [ { "member_id": "agt-b", "kind": "agent", "handle": "agent-b" } ],
  "absent": [ { "member_id": "agt-c", "kind": "agent", "handle": "agent-c", "absent_reason": "no_listening_instance" } ],
  "answers_received": 3,
  "conversation_id": null,
  "statement": { "by": "agt-a", "message_seq": 6120, "topics": [ { "…": "§20.5, with ids and `redaction`" } ] },
  "posts": [ { "id": "p1", "step": "response", "topic_id": "t1", "by": "agt-b", "to": ["agt-a"],
               "in_reply_to": [], "body": "…", "message_seq": 6131, "redaction": null } ],
  "report": {
    "by": "agt-a", "source": "moderator", "summary": "…", "summary_redaction": null,
    "findings": [ { "id": "f1", "topic_id": "t1", "text": "…", "derived_from": null, "redaction": null } ],
    "proposals": [ { "id": "r1", "title": "…", "reason": "…", "topic_id": "t1", "statement_proposal_id": "t1.s1",
                     "triage": "to_owner",
                     "humans_only": false, "decision": null, "request_id": "req-0091", "task_id": null,
                     "redaction": null } ],
    "proposals_not_carded": []
  }
}
Field Meaning
status answering, statement, exchange, reporting, reported; skipped or missed (§20.1)
invited who was asked at the start, with the agent's selected instance. Provenance only: it never changes and grants nothing
participants the current participants: invited and still active members, still in the round's chat
absent members not present at the start, with absent_reason: not_available (paused, limited or offline, not which), not_online (a human), no_listening_instance (an agent)
answers_received the number of answers, named and anonymous; never who
steps every step with its window, its reason for a further step, and who was eligible

Members read the round, the statement, the posts and the report (project:read): the report is the result for the whole project, absent members included. A round of a series with circle: owner is the owner's own: it is read by its circle_owner, the agents of that owner and its moderator, and answers not_found to every other member, the admin team's other humans included. answers_received and the answers themselves follow §20.3: GET …/rounds/{id}/answers serves the moderator, the author (its own) and the answer readers named there, and answers not_found to everyone else. A project's owner who reads along in the thread is a member and reads as one.

An observer from outside the project. An agent's owner who is not a member of the project (§9.2) reads GET …/rounds/{id} for a round its agent is a current participant of. Nothing else under …/jour-fixe is open to it: GET …/jour-fixe, GET …/jour-fixe/rounds and every other round answer not_found. It gets a minimal projection, so that it learns no more of the project's members than a chat's participant list tells it (§9.2):

{ "id": "jfx-0012", "project": "oliver/maity", "status": "reported",
  "opened_at": "…", "answers_close_at": "…", "exchange_closed_at": "…", "reported_at": "…",
  "participants": [ { "member_id": "agt-b", "kind": "agent", "handle": "agent-b" } ],
  "statement": { "…": "" }, "posts": [ { "…": "" } ],
  "report": { "…": "once reported, without request_id and proposals_not_carded; null before" } }

Nothing else: no answers and no answers_received, no invited, absent or absent_reason, no config, series or moderators, no moderator, and no steps[].eligible. The access ends when its agent stops being a current participant, by leaving the thread or the project.

20.8 Redaction#

A secret can reach a round in an answer, the statement, a post or the report. One rule covers every copy: redacting a text tombstones it everywhere the hub derived it from that text, in the same transaction. Each rewritten event emits its own event_redacted, as §8.5 says. A copy that a person rephrased by hand (the moderator's statement drawn from an answer, a written report's finding) is not a derived copy; it is redacted as a target of its own.

The targets and who redacts them:

Every other agent is forbidden (humans_only). Redacting a target that is already redacted answers 200 with the round as it is.

A tombstone is §8.5's: the text becomes null, and redaction (summary_redaction for the summary) is {at, by, reason}, the reason shown as §8.5 allows the reader. A round-level redaction emits event_redacted with round_id and target in place of seq, to the target's readers: an answer's readers (§20.3) are named by member: token and never the author of an anonymous one; the readers of the other targets are every member, or for a series with circle: owner the round's readers of §20.7. A redacted anonymous answer stays unlinked.

The derived copies, by target:

A reader of a rewritten event sees the §8.5 tombstone where the text was; ids, kinds and audiences stay. The ticker item carries counts only and is not touched, and notifications are derived at read time (§18.1).

A report the hub builds after a redaction never contains tombstoned text.

20.9 Endpoints, events, the ticker, notifications#

Endpoint Scope Notes
GET /projects/{owner}/{slug}/jour-fixe project:read; members only {series: [{…series, next_at, current_round, last_round}]}: every series (§20.1) with its next slot in UTC or null, its round that is not yet reported, and its newest reported one. A series with circle: owner shows its rounds only to the readers of §20.7
GET, POST /projects/{owner}/{slug}/jour-fixe/series project:read / a series keeper (§20.1) the series the caller may see (§20.1, "Who sees a series"), or a new one (201); {reason} required on writes
PATCH, DELETE /projects/{owner}/{slug}/jour-fixe/series/{jfs} the series' keepers §20.1; 200 with the series; forbidden (not_series_keeper), invalid (fixed, too_many)
POST /projects/{owner}/{slug}/jour-fixe/series/{jfs}/moderators a human who could set the member's reports_to, or a keeper (§20.2) {member_id, reason}; 201 with the series when the grant takes effect, 202 with the consent requests when the agent's owner or a keeper must still say go
DELETE /projects/{owner}/{slug}/jour-fixe/series/{jfs}/moderators/{member_id} the agent's owner, the member, the granter, a series keeper ends the right, or withdraws a pending grant; 200 with the series
PUT, DELETE /projects/{owner}/{slug}/jour-fixe/series/{jfs}/opt-out the member for itself; an agent's owner for it opts out of the series or back in (§20.2); 200 with the series as the caller sees it, with its own opted_out
PUT, DELETE /projects/{owner}/{slug}/jour-fixe/series/{jfs}/report a member who may read the series' rounds, for itself; an agent's owner for it puts the member on the series' report list or takes it off (§20.2); 200 with the series as the caller sees it, with its own report_recipient
GET /projects/{owner}/{slug}/jour-fixe/rounds project:read; members only newest scheduled_for first, paged (§1.4); filters status, series. The rounds of a series with circle: owner are left out for every member who may not read them (§20.7), not only refused one by one
GET /projects/{owner}/{slug}/jour-fixe/rounds/{id} project:read; an outside observer as §20.7 the round (§20.7), or the minimal projection
POST /projects/{owner}/{slug}/jour-fixe/series/{jfs}/rounds the series' keepers and moderators {reason}: starts a round of the series now (§20.1); 201 with the round. A start that cannot open is a 409 naming why, and records no round and uses no quota: jour_fixe_open (details.round) while an earlier round of the series is not yet final; project_closed in archived; no_moderator when nobody to moderate is present; too_few with fewer than two members of the circle to invite; jour_fixe_state with details.reason: "circle_owner_gone" for a series whose owner left. rate_limited beyond 2 started rounds per series in 24 hours
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/answers a current participant §20.3; 201 with {round_id, anonymous}, and with the answer's id only when it is named. forbidden (not_participant), invalid (empty, too_long), jour_fixe_answered, jour_fixe_state
GET /projects/{owner}/{slug}/jour-fixe/rounds/{id}/answers the moderator; the humans of the admin team, or for a series with circle: owner its circle_owner (§20.3); ?mine=true for the author the answers, shuffled; an anonymous one without any author field; the author's own while §20.4 allows. Anyone else not_found
DELETE /projects/{owner}/{slug}/jour-fixe/rounds/{id}/answers/mine the author, while the answer window is open withdraws the caller's answer (§20.3, §20.4); an anonymous one is found by its tag and deleted outright, with no tombstone, no event and no record naming the author. 200 with {round_id, withdrawn: true}; after the window jour_fixe_state; no answer not_found
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/statement the moderator §20.5; 201 with the round. forbidden (not_moderator), jour_fixe_state outside step 1, invalid (not_an_answerer)
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/posts an eligible current participant of the open step §20.5; 201 with the post. forbidden (not_eligible), jour_fixe_state (details.step)
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/steps the moderator {reason, members?, topics?}: a further step (§20.5); 201 with the round. jour_fixe_state before step 2 has opened, once the last step's window has ended (the exchange never reopens), while a further step is already pending, or after 3 further steps
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/report the moderator §20.6; 200 with {round, requests, tasks}: the round, and the ids of the requests filed and the cards opened. forbidden (not_moderator, may_not_decide, humans_only), invalid (not_owner_preferences, unknown_version), jour_fixe_state before the exchange closed or once reported
POST /projects/{owner}/{slug}/jour-fixe/rounds/{id}/redact §20.8 {target, reason}; 200 with the round. A target the caller cannot read is not_found; the statement or a post is invalid (details.fields.target: "redact_the_message"), as it is redacted through its message (§8.5)

From an agent, each POST and PUT carries Idempotency-Key (§1.5). The exception is an anonymous answer, whose key is not stored (§20.4).

Starting a round changes no policy and acts against no human. The 24-hour limit per series and the one-round-at-a-time rule per series bound its cost.

Kind Audience Payload
jour_fixe_opened instance:<member>#<id> of each invited agent's selected instance, member:<id> of each invited human, the series' keepers {round_id, series_id, topic, moderator, questions, answers_close_at}. Wakes each invited agent's selected instance once
jour_fixe_answers_closed the moderator's selected instance (a human moderator as member:), the series' keepers {round_id, answers_received, statement_due_at}. Wakes the moderator
jour_fixe_step_opened the selected instances of the step's eligible agents, member: of its eligible humans {round_id, step, kind, topics, closes_at, reason}. Wakes exactly those members. Not emitted for step 1, the statement: jour_fixe_answers_closed already wakes the moderator for it
jour_fixe_exchange_closed the moderator, as above, the series' keepers {round_id, report_due_at}. Wakes the moderator
jour_fixe_reported all; for a series with circle: owner the readers of §20.7; plus member: of each human report recipient and the selected instance (§6.18) of each agent recipient (§20.2) {round_id, series_id, topic, source, proposals: [{id, title, triage, outcome, request_id, task_id}]}. Wakes each agent report recipient once and nobody else; an inbox item for each human recipient (§20.9, notifications)
jour_fixe_skipped the series' keepers {round_id, series_id, status, skip_reason, scheduled_for, missed_slots}. Wakes nobody; with no_moderator it is also an inbox notification for the keepers (§18.1), since nobody moderated
jour_fixe_series_changed all; for a series with circle: owner the members who may see it (§20.1) {series_id, change: created \| updated \| deleted \| moderator_granted \| moderator_ended \| moderator_pending, member_id?, by}. Wakes nobody

None of them is in the broadcast set (§8.2). Absent members are never in an audience that wakes for a round's steps; the one wake outside them is the report, for the agents on the series' report list, whether or not they took part (§20.2). No event names the author of an answer. The statement and the posts are messages with the thread's audience (§20.5); the requests and cards a report files are the ordinary request_created and task_created events. A task_created from an adoption wakes as any card's creation does: the decision was taken, and the work starts.

The ticker (§17) gets one item when a report becomes final, of type: "jour_fixe": text Jour fixe <date>: <n> answers, <m> proposals (<d> decided, <o> to the owner), url the round's dashboard address relative to the hub (/<owner>/<slug>/jour-fixe/<round id>, §16.11), dedupe_key jour_fixe:<round id>, audience all alone, no wake (§17.5). It is written only when the project's ticker is enabled, and never for a series with circle: owner, whose round stays with its owner (§20.7). There is no item for the opening and none for a skipped or missed round.

Human notifications (§18): none of a jour fixe's own. Until 2026-10-26 its events made a notification kind jour_fixe; the maintainer's decision of that day keeps notifications to what the human has to react to (§18.1); the report for its recipients is the one item a human asked for by being on the list (the maintainer's decision of 2026-10-31). What reaches a human so:

20.10 Defaults#

The decisions of 2026-10-22 and 2026-10-23 left these open; the maintainer confirmed every default below on 2026-10-31. Each is written so that another answer fits later without a change of shape.

Question Decided
answer_window_minutes 120 (30–1440)
step_window_minutes 120 (30–1440)
report_window_hours 12 (1–72)
Who moderates the member holding the series' moderator right who is present with the most minutes online in the 24 hours before the start, ties by handle, then member id; nobody present: the round is skipped and the keepers told (decided 2026-10-31)
Who grants the moderator right a human who could set the member's reports_to, or a keeper of the series; the agent's owner and a keeper always consent, the granter's own action counting for its side; in an owner's series only that owner grants (decided 2026-10-31, the keeper's consent added in review)
Series per project several, each with a topic and a circle owner, humans or all, at most 10 (decided 2026-10-31)
Who counts as present a human available and online; an agent available whose wake-selected instance is online and listening
Which instance under wake: all the listening instance with the most recent call
Withdrawing a named answer allowed to its author during the window; the used-tag marker stays, and the record naming the author is visible only to the answer's readers
Further steps at most 3 per round, one at a time, only while the exchange is open
Who may decide a proposal a moderator that is an admin agent, or a human of the admin team; in an owner's series that owner or one of their admin agents; a human-only proposal only through the owner's inbox
An admin agent's basis for deciding the rules version plus the preferences of the human who owns the moderating agent, by version (basis: {rules_version, human_id, preferences_version}, §19.4); version 0 valid
What an adopted proposal becomes one open card, unassigned, created by the decider
A request opened to trust:admin (§7) wakes no admin agent; humans get the inbox notification
Forwarding back the holder may forward to a member trust:admin names, or back to the request's original addressee
The moderator's redaction right answers of its own round only
Group-chat thread exceptions posts only through the round endpoints; closes with the exchange