Souspli

Souspli / Docs / How

Generating letters from code

Not every letter is typed into the app. An importer turning an archive into articles, a billing system issuing invoices, a bot posting minutes — each needs to produce signed .thing files directly.

Everything required is in src/format/ (the future @souspli/format package): pure TypeScript, no Electron, no network, runs in Node and in browsers, and never holds a key — it signs through a Signer interface you supply.

import { buildBundle, admitBundle } from './src/format/index.js'

const bundle = await buildBundle(signer, {   // signer: your Signer (eth-eip191)
  program,                                   // Uint8Array — e.g. samples/memo.html
  type: 'memo',
  args: { to: 'All staff', from: 'Ops', subject: 'Friday', message: '…' },
  attachments: new Map([                     // name -> { bytes, mime? }
    ['plan.png', { bytes: png, mime: 'image/png' }],
  ]),
})
// `bundle` is the bytes of a .thing file.

Use the same program bytes as the built-in type (samples/<type>.html) if you want readers' apps to recognise the type: a type is identified by the hash of its program, so a reformatted copy is a different type.

Per-type guides

The repository carries step-by-step guides for the types most worth generating — the exact args schema, attachment rules and limits for each. They are written as Claude Code skills, so an AI coding agent working in this repository picks them up automatically, and they read fine as plain documentation:

Guide Covers
create-article Articles from a scraper or importer: blocks, media placement, provenance. Read this one first; the others build on it.
create-memo Memos and correspondence with enclosures; which attachment types render.
create-poster Photo sets: arrangements and attachment naming.
create-invoice Invoices: the integer-only money model (minor units, thousandths, basis points) that a float will break; totals derived, not supplied.

Things that bite