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
4 changes: 2 additions & 2 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
# git config core.hooksPath .githooks
set -e

if [ -f data/wedding.trousseau.json ]; then
if [ -f data/wedding.knotwork.json ]; then
if [ -f dist/index.js ]; then
node scripts/validate-wedding.mjs data/wedding.trousseau.json
node scripts/validate-wedding.mjs data/wedding.knotwork.json
else
echo "pre-commit: skipping validation, dist/ is not built (npm run build)"
fi
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
Expand All @@ -35,10 +35,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ dist/

# Personal wedding data — never commit.
# Anchored to the root: data/ is the canonical home and is handled by DVC,
# which writes its own data/.gitignore. An unanchored *.trousseau.json here
# which writes its own data/.gitignore. An unanchored *.knotwork.json here
# would match that file too, and `dvc add` refuses a git-ignored path.
/*.knotwork.json
# Exported before the rename. Still real weddings, still never committed.
/*.trousseau.json
unpacked/

Expand Down
16 changes: 8 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to Trousseau
# Contributing to Knotwork

Thank you for thinking about it. Trousseau is used by real couples planning
Thank you for thinking about it. Knotwork is used by real couples planning
real weddings, so a fix here can save someone a bad evening with a
spreadsheet. Bug reports, fixes, documentation and whole new tools are all
welcome.
Expand Down Expand Up @@ -55,7 +55,7 @@ who was bringing the cake stand" beats "add a cake stand field". Then:

Some things are ruled out on purpose and will be closed with a pointer to the
reason. These include RSVP collection (Joy and similar do it well, and
Trousseau imports the result), a paid tier of any kind, and an admin panel
Knotwork imports the result), a paid tier of any kind, and an admin panel
that can browse weddings.

---
Expand All @@ -71,21 +71,21 @@ that can browse weddings.
### Install and run

```sh
git clone https://github.com/JFrusher/Trousseau.git
cd Trousseau
git clone https://github.com/JFrusher/Trousseau.git Knotwork
cd Knotwork

npm ci # installs the root package and the suite workspace
npm run build # builds the contract package into dist/
npm run dev -w suite # http://localhost:3000
```

**Do not skip `npm run build`.** The suite depends on the contract package via
`"@jfrusher/trousseau": "file:.."`, which resolves to the root `dist/`. A
`"@jfrusher/knotwork": "file:.."`, which resolves to the root `dist/`. A
fresh clone has no `dist/`, and the install succeeds anyway. The failure
turns up later as:

```
Module not found: Can't resolve '@jfrusher/trousseau'
Module not found: Can't resolve '@jfrusher/knotwork'
```

If you see that, run `npm run build` at the root and try again.
Expand Down Expand Up @@ -184,7 +184,7 @@ of their own wedding.

### Changing the contract package

`src/` is published to npm as `@jfrusher/trousseau` and other tools may
`src/` is published to npm as `@jfrusher/knotwork` and other tools may
depend on it. Changes must be additive: a new optional field, never a renamed
or removed one. `npm run verify` checks that the published build still
imports cleanly.
Expand Down
10 changes: 5 additions & 5 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
Trousseau is released under two licences, because this repository holds two
Knotwork is released under two licences, because this repository holds two
different things.

The contract package — @jfrusher/trousseau
The contract package — @jfrusher/knotwork
------------------------------------------
MIT. See LICENSE-MIT.

This is the published npm package: the schemas and the file format that
describe a wedding. It is deliberately permissive so that a tool nobody has
written yet can depend on it, which is the entire point of the format
existing. If you installed @jfrusher/trousseau from npm, this is the licence
existing. If you installed @jfrusher/knotwork from npm, this is the licence
that applies to you, and you can stop reading here.

The application — everything in suite/
--------------------------------------
GNU Affero General Public License v3.0 or later. See LICENSE-AGPL.

This is Trousseau itself: the five tools, the shell, the sync and account
layers. The AGPL is chosen deliberately. Trousseau is free and always will
This is Knotwork itself: the five tools, the shell, the sync and account
layers. The AGPL is chosen deliberately. Knotwork is free and always will
be, and the AGPL is what stops someone running a paid, closed fork of the
hosted service against the intent of everyone who worked on the free one.
Run it yourself, change it, host it for your friends — but if you host a
Expand Down
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
<div align="center">

# 💍 Trousseau
# 💍 Knotwork

### Plan a whole wedding in one place, without five tools disagreeing about it.

**Free, open source and private. No paid tier, no ads, no upsell, no sign-up to start.**

<sub>Formerly Trousseau.</sub>

[![Licence: AGPL-3.0 app, MIT contract](https://img.shields.io/badge/licence-AGPL--3.0%20app%20%C2%B7%20MIT%20contract-5b4bd5)](LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/JFrusher/Trousseau?style=flat&logo=github&label=stars)](https://github.com/JFrusher/Trousseau/stargazers)
[![CI](https://github.com/JFrusher/Trousseau/actions/workflows/ci.yml/badge.svg)](https://github.com/JFrusher/Trousseau/actions/workflows/ci.yml)
[![Self-hostable](https://img.shields.io/badge/self--hostable-Next.js%20%2B%20optional%20Supabase-2f855a)](docs/SELF-HOSTING.md)
[![No account needed](https://img.shields.io/badge/account-not%20needed-2f855a)](https://trousseau-suite.vercel.app)
[![PRs welcome](https://img.shields.io/badge/PRs-welcome-e05d44)](CONTRIBUTING.md)

[**Open Trousseau →**](https://trousseau-suite.vercel.app) &nbsp;·&nbsp;
[**Open Knotwork →**](https://trousseau-suite.vercel.app) &nbsp;·&nbsp;
[Run your own copy](#-run-your-own-copy) &nbsp;·&nbsp;
[How it works](#-how-it-works) &nbsp;·&nbsp;
[Roadmap](ROADMAP.md) &nbsp;·&nbsp;
[Contribute](CONTRIBUTING.md)

![Trousseau: the whole wedding in one place, with the front page showing where things stand](marketing/assets/images/hero-overview.png)
![Knotwork: the whole wedding in one place, with the front page showing where things stand](marketing/assets/images/hero-overview.png)

</div>

Expand All @@ -38,7 +40,7 @@ and the run sheet end up as three copies of one guest list, drifting apart.
When this project began, two apps disagreed about **what day the wedding
was**.

Trousseau is the opposite of that:
Knotwork is the opposite of that:

- **Free forever.** Not a trial, not freemium. There is no paid version to be
upsold to, and the AGPL stops anyone building a closed, paid fork of the
Expand Down Expand Up @@ -147,8 +149,8 @@ error reporting only runs if you set a Sentry DSN.
### Local only: no backend, no account

```sh
git clone https://github.com/JFrusher/Trousseau.git
cd Trousseau
git clone https://github.com/JFrusher/Trousseau.git Knotwork
cd Knotwork
npm ci # installs the contract package and the suite together
npm run build # builds the shared contract package; do not skip this
npm run dev -w suite
Expand Down Expand Up @@ -201,8 +203,8 @@ how to check your instance actually works rather than merely starting.
the `#` in the link, which browsers never send to a server. Members of the
wedding hold the key so they can republish as seats change.
- **You can always take it out.** *Download my wedding* gives you the whole
thing as one `.trousseau.json` file. That is the same format the app uses,
so it opens straight back into Trousseau, hosted or on your own copy.
thing as one `.knotwork.json` file. That is the same format the app uses,
so it opens straight back into Knotwork, hosted or on your own copy.
- **Deleting your account deletes your data.** If your partner is still on the
wedding, it stays with them. If you were the last one, it goes.

Expand Down Expand Up @@ -302,7 +304,7 @@ suite/ the web application (AGPL-3.0-or-later)
lib/ the shared document, sync, accounts, and the newer tools
components/ the shell around the tools, and the newer tools' panels
app/ routes, API, account, guest and supplier pages
src/ the data contract, published as @jfrusher/trousseau (MIT)
src/ the data contract, published as @jfrusher/knotwork (MIT)
supabase/ database migrations
docs/ self-hosting, building a tool, and dated specs and plans
```
Expand All @@ -320,7 +322,7 @@ anyone's personal details.
- **Want to change something?** Design decisions are written down in
`docs/superpowers/specs/`, so you can tell whether an idea fits before
writing code.
- **Want to build a tool?** A job nothing in Trousseau does for you yet is the
- **Want to build a tool?** A job nothing in Knotwork does for you yet is the
best reason to. **[docs/BUILDING-A-TOOL.md](docs/BUILDING-A-TOOL.md)** walks
through the whole journey.

Expand All @@ -336,12 +338,12 @@ milestones and the issues to pick up.

## 🌱 Where this came from

Trousseau was built for one specific wedding. That is the only reason its
Knotwork was built for one specific wedding. That is the only reason its
constraints were ever honest: real guest names and dietary requirements,
tools that genuinely must not overwrite each other, and a date that does not
move.

That wedding has happened. Trousseau is now being built for other couples,
That wedding has happened. Knotwork is now being built for other couples,
which is why it grew accounts, real cloud storage and a self-hosting story.
The design did not change, because the design was the part that was working.

Expand All @@ -355,7 +357,7 @@ Two licences, because this repository holds two different things.
**[AGPL-3.0-or-later](LICENSE-AGPL)**. Run it, change it, host it for
friends. If you host a modified version for other people, they are entitled
to your source too.
- The **contract package**, `@jfrusher/trousseau`, is **[MIT](LICENSE-MIT)**.
- The **contract package**, `@jfrusher/knotwork`, is **[MIT](LICENSE-MIT)**.
It holds the schemas and the file format, kept permissive on purpose so that
a tool nobody has written yet can depend on it.

Expand All @@ -366,6 +368,6 @@ There is no paid tier and there never will be. That is the reason this exists.

<div align="center">

**If Trousseau saves you an evening with a spreadsheet, a ⭐ helps other couples find it.**
**If Knotwork saves you an evening with a spreadsheet, a ⭐ helps other couples find it.**

</div>
8 changes: 4 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Roadmap

Where Trousseau is, and where it could go next. This page is the short
Where Knotwork is, and where it could go next. This page is the short
version for contributors. The full record of every decision, and why it was
made, is in **[docs/PRODUCT-ROADMAP.md](docs/PRODUCT-ROADMAP.md)** and the
dated specs in `docs/superpowers/specs/`.
Expand All @@ -18,7 +18,7 @@ The core promise: a set of planning tools that share one document, so nothing
is retyped and nothing disagrees.

- ✅ **The shared document.** One owner per slice, unknown keys preserved, and
a published MIT data contract (`@jfrusher/trousseau`).
a published MIT data contract (`@jfrusher/knotwork`).
- ✅ **Guests.** One guest list, one importer (Joy, Zola, The Knot, any CSV),
with a preview before anything is written.
- ✅ **Seating.** A room drawn to scale, groups, families, keep-together and
Expand Down Expand Up @@ -47,7 +47,7 @@ is retyped and nothing disagrees.
works offline on a phone.
- ✅ **Guest seat links** and **supplier links** with confirmation.
- ✅ **Guided tour** with an example wedding, and the ⌘/Ctrl-K palette.
- ✅ **Download my wedding** as a single `.trousseau.json` file, and account
- ✅ **Download my wedding** as a single `.knotwork.json` file, and account
deletion that really deletes.
- ✅ **Retention.** An account wedding nobody writes to for 24 months is
deleted by a daily sweep, as the Privacy Policy states.
Expand Down Expand Up @@ -102,7 +102,7 @@ So nobody spends a weekend on something that will be declined:

- **A paid tier, premium features or upsells.** This is the reason the
project exists.
- **RSVP collection.** Joy and similar services do this well. Trousseau
- **RSVP collection.** Joy and similar services do this well. Knotwork
imports the result and never unseats or silently deletes a guest.
- **An admin panel or support login** that can browse weddings.
- **An official Docker image**, for now. The app is one Node process and an
Expand Down
2 changes: 2 additions & 0 deletions data/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/wedding.knotwork.json
Comment thread
JFrusher marked this conversation as resolved.
# The same file under its name before the rename, still on existing checkouts.
/wedding.trousseau.json
/exports

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
outs:
- md5: 3d1e6a1f0d401cd24bc3a70033d28f6f
size: 456154
hash: md5
path: wedding.trousseau.json
outs:
- md5: 3d1e6a1f0d401cd24bc3a70033d28f6f
size: 456154
hash: md5
path: wedding.knotwork.json
10 changes: 5 additions & 5 deletions docs/BUILDING-A-TOOL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Building a tool

Trousseau grows one tool at a time, and most of the good ideas come from
Knotwork grows one tool at a time, and most of the good ideas come from
someone planning their own wedding and finding a job nothing did for them.
That is how the processional planner, Boxes and the Bar arrived. This guide
covers the whole journey, from "would this be a tool?" to a merged pull request
Expand Down Expand Up @@ -51,7 +51,7 @@ these instead:
- a check (see [What is left](#what-is-left-checks-between-tools));
- a view inside an existing tool.

**4. Would many weddings use it?** Trousseau is for couples and the planners
**4. Would many weddings use it?** Knotwork is for couples and the planners
who help them. An idea that fits one wedding's quirk is better as a note in an
existing tool. An idea a good share of couples would switch on is a tool.
New tools start switched off (see [the rules](#3-the-rules-every-tool-keeps)),
Expand Down Expand Up @@ -206,9 +206,9 @@ Bar is the example throughout. Its id is `bar`, and its pieces are in

### The data

1. **The contract** (`src/`, published as `@jfrusher/trousseau`):
1. **The contract** (`src/`, published as `@jfrusher/knotwork`):
- add `barSchema = z.looseObject({}).default(() => ({}))` to `src/slices.ts`;
- add `"bar"` to `SLICE_NAMES` and `trousseauSchema` in `src/envelope.ts`;
- add `"bar"` to `SLICE_NAMES` and `knotworkSchema` in `src/envelope.ts`;
- export it from `src/index.ts`;
- update the list in `src/envelope.test.ts`.

Expand Down Expand Up @@ -350,7 +350,7 @@ Planners reuse work across weddings. To let them keep your tool's work:

### The example wedding

`suite/public/fixtures/example-wedding.trousseau.json` is what the tour and
`suite/public/fixtures/example-wedding.knotwork.json` is what the tour and
the tests load, and it shows every tool. A test enforces that. Add your id to
`tools.shown` and give it believable data.

Expand Down
10 changes: 5 additions & 5 deletions docs/DATA.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# The wedding data, and where it lives

Trousseau holds the canonical wedding. The four apps hold working copies.
Knotwork holds the canonical wedding. The four apps hold working copies.

Git carries the schemas, the scripts and the **pointers**. DVC carries the data
itself, to a private OneDrive folder. Nothing with a guest's name on it has ever
reached a public repo, and this arrangement is what keeps that true.

```
data/
wedding.trousseau.json <- canonical. DVC-tracked, git-ignored.
wedding.trousseau.json.dvc <- the pointer. 4 lines of md5, committed.
wedding.knotwork.json <- canonical. DVC-tracked, git-ignored.
wedding.knotwork.json.dvc <- the pointer. 4 lines of md5, committed.
exports/ <- derived PDFs and CSVs. DVC-tracked, git-ignored.
exports.dvc <- the pointer. Committed.
.gitignore <- written by DVC. Committed.
Expand Down Expand Up @@ -54,7 +54,7 @@ schema and exact bytes together.
## Setting up a new device

```sh
git clone https://github.com/JFrusher/Trousseau && cd Trousseau
git clone https://github.com/JFrusher/Trousseau Knotwork && cd Knotwork
npm install

# The remote URL is per-device and deliberately not committed — it names a path
Expand Down Expand Up @@ -96,7 +96,7 @@ directory:

```sh
node scripts/bundle.mjs pack ~/Desktop/state.json ~/Desktop/day.cadence.json \
-o data/wedding.trousseau.json
-o data/wedding.knotwork.json
```

`dvc pull` only ever writes `data/`. The apps' own working copies are not
Expand Down
Loading
Loading