Artefakt Toolbox
English

Shared messages: working together with the gallery tools

So that many tools fit together without each one knowing every other, the gallery tools speak a shared language. Your own tools can speak it too.

Instead of wiring every tool to every other, there are six message kinds. Each tool speaks only the kinds that suit it. A few tools collect what others report: these are the collection points. Others can be opened with settings already in place. That way every tool can work with many others without knowing more than two or three names.

Technically nothing is new: everything runs through ARTEFAKT.senden, eingang and oeffnen, as described on the page “Linking tools”. The only new thing is the agreement on what a message looks like.

The five collection points

Collection points of the gallery
Collection pointQuestion it answersunderstands
Habit chainWhat have I done?erledigt
Reward chartWhat has the child achieved?erledigt
Shopping listWhat do I need?einkauf
Budget bookWhat does it cost?betrag
Evening reviewWhat happened today?notiz

In German they are called Gewohnheits-Kette, Belohnungstafel, Einkaufsliste, Haushaltsbuch and Tagesabschluss. The name is the address: the English version of a tool sends to the English names.

The shared envelope

Every message has the same four fields. The text field makes it understandable even for tools that do not know the kind: they can simply show the text. Who sent it and when is added by the toolbox itself (von and zeit in the inbox).

Envelope of every message
{
  typ: 'erledigt',            // one of the six kinds
  v: 1,                       // version of the kind
  id: 'lq2x9k-4f7a',          // unique, against duplicates (at most 64 characters)
  text: 'Breathing, 5 minutes', // always readable (at most 500 characters)
  /* … fields of the kind … */
}

The field names and kinds are the same in every language (they come from the toolbox’s German interface). Only contents such as text, was or artikel are in the language of the tool.

The six kinds

Message kinds
KindMeaningFields (besides the envelope)
einkauf“I need this” or “I bought this” (shopping)artikel: list of texts (required, at most 120 characters each); aktion: 'brauche' (need) or 'gekauft' (bought); anlass (occasion); posten: [{ name, menge, einheit }] for tools that calculate
erledigt“I did this” (done)was (what, required, at most 80 characters); menge (amount); einheit (unit, e.g. 'min'); datum as YYYY-MM-DD; wer (who, for the reward chart)
betrag“This is what it costs” (amount)betrag as a number (required); waehrung (currency, e.g. 'EUR'); art: 'ausgabe' (expense), 'fix' (monthly) or 'plan'; topf (pot); datum
notiz“This happened” (note)text (required); datum
personen“These people are in” (people)gruppen: [{ name, namen: [ … ] }]
start“Get ready like this”einstellung: an excerpt from the receiver’s CUSTOMIZE block; then ARTEFAKT.oeffnen(target)
One example each
{ typ: 'einkauf', v: 1, id, text: 'Lasagne: 500 g minced meat, 2 tins of tomatoes',
  aktion: 'brauche', anlass: 'Lasagne',
  artikel: ['500 g minced meat', '2 tins of tomatoes'],
  posten: [{ name: 'Minced meat', menge: 500, einheit: 'g' }, { name: 'Tomatoes', menge: 2, einheit: 'tin' }] }

{ typ: 'erledigt', v: 1, id, text: 'Practice, 20 minutes', was: 'Practice', menge: 20, einheit: 'min', datum: '2026-10-04', wer: 'Mia' }

{ typ: 'betrag', v: 1, id, text: 'Groceries, €23.40', betrag: 23.40, waehrung: 'EUR', art: 'ausgabe', topf: 'Food', datum: '2026-10-04' }

{ typ: 'notiz', v: 1, id, text: 'Decision: flat B (4.2 to 3.8 points)', datum: '2026-10-04' }

{ typ: 'personen', v: 1, id, text: 'Here today: Mia, Tom, Ali', gruppen: [{ name: 'Today', namen: ['Mia', 'Tom', 'Ali'] }] }

{ typ: 'start', v: 1, id, text: 'Metronome: 92 BPM, 3/4', einstellung: { tempo: 92, takt: '3/4' } }
// then: ARTEFAKT.oeffnen('Metronome')

Remote control with “start”

With “start” one tool sets up another for one run, for example the songbook opens the metronome at 72 beats per minute. The receiver takes over only the settings it has released in KONFIG.vonAussen, only with the matching data type and only for this run. Your stored settings stay unchanged, and a banner shows who set what, with a button to reset it.

Ten rules

  1. Every tool runs on its own

    Linking is an extra. Without window.ARTEFAKT only the send buttons disappear.

  2. Send only after an action

    A button or the end of an exercise triggers sending. Nothing is sent secretly.

  3. Receiving never triggers sending

    That way no loop can arise between two tools.

  4. Pick up on start and on return

    Call ARTEFAKT.eingang() on start and on visibilitychange so nothing is left behind.

  5. Check strictly

    Only known typ, only v up to your own version, check fields for type and length, ignore everything else. Display only with textContent.

  6. No duplicates

    The receiver remembers the last 200 ids.

  7. Targets are adjustable

    Target names live in the CUSTOMIZE block, for example KONFIG.ziele = { erledigt: 'Habit chain' }.

  8. Origin visible, takeover reversible

    Every taken-over entry shows “from …” and can be undone.

  9. Bundle

    One action is one message, for example all ingredients together. The inbox holds at most 100 entries.

  10. Islands are fine

    Not every tool has to be linked. An emergency card, for example, sends and receives nothing.

Receiving: how to check strictly

Receiver for “erledigt”, with checks and protection against duplicates
const UNDERSTANDS = 'erledigt';
const text = (v, max) => typeof v === 'string' && v.length <= max;
const num = v => v == null || (typeof v === 'number' && Number.isFinite(v));
const day = v => v == null || (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(v));

function valid(n) {
  if (!n || typeof n !== 'object' || n.typ !== UNDERSTANDS) return false;  // only our kind
  if (n.v != null && n.v > 1) return false;                               // newer version: better not
  if (n.text != null && !text(n.text, 500)) return false;
  return text(n.was, 80) && n.was.trim() !== '' && num(n.menge) && day(n.datum);
}

function pickUp() {
  if (!window.ARTEFAKT || typeof ARTEFAKT.eingang !== 'function') return;
  let list = [];
  try { list = ARTEFAKT.eingang(); } catch { return; }
  const seen = read('ids', []);
  for (const e of list) {
    const n = e && e.daten;
    if (!valid(n)) continue;                                              // ignore the unknown
    if (n.id) { if (seen.includes(n.id)) continue; seen.push(n.id); }
    addEntry({ what: n.was, amount: n.menge, date: n.datum, from: String(e.von || '?') });
  }
  write('ids', seen.slice(-200));
  render();                                                               // display with textContent
}
pickUp();
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') pickUp(); });

Prompt: your own tool that joins in

Template: tool that works together with the gallery tools
Create a tool for me as ONE single HTML file for the Artefakt Toolbox: [goal in one sentence].

Working together using the shared message format of the Artefakt gallery (field names and kinds stay exactly as written):
- Envelope of every message: { typ, v: 1, id (unique, at most 64 characters), text (readable, at most 500 characters), … }.
- The tool SENDS, after a tap on [button], a message of the kind [e.g. 'erledigt' with was, menge, einheit, datum as YYYY-MM-DD] with ARTEFAKT.senden(target, message). The target name is adjustable in the CUSTOMIZE block: KONFIG.ziele = { [kind]: '[e.g. Habit chain]' }; empty = off.
- The tool UNDERSTANDS [kind or “nothing”]: it picks up on start and on visibilitychange with ARTEFAKT.eingang(), accepts only this kind with v at most 1, checks all fields for type and length, ignores everything else, remembers the last 200 ids against duplicates, shows the origin (“from …”) and offers “Undo”.
- Receiving never triggers sending. All interaction runs through ONE object in the code (check, send, pick up, open) so that it can easily be replaced later.
- Before each use, check that window.ARTEFAKT and the function exist. Without the toolbox the tool runs fully, just without send buttons.
- Show foreign texts only with textContent, never with innerHTML.

Technical: one single HTML file, no external files, localStorage with try/catch, works offline, mobile first, dark design, tap targets at least 48 px, English. Output the complete file in one block.

See also: Linking tools · Gallery blueprint · Outlook: connection layer