notefeed

Oct 30

  1. freundebuch 0.7.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.6.0...v0.7.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.7.0
    

    The release on GitHub

  2. freundebuch 0.6.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.5.1...v0.6.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.6.0
    

    The release on GitHub

  3. freundebuch 0.5.1

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.5.0...v0.5.1

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.5.1
    

    The release on GitHub

Oct 29

  1. freundebuch 0.5.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.4.0...v0.5.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.5.0
    

    The release on GitHub

  2. freundebuch 0.4.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.3.0...v0.4.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.4.0
    

    The release on GitHub

Oct 28

  1. freundebuch 0.3.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.2.0...v0.3.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.3.0
    

    The release on GitHub

  2. freundebuch 0.2.0

    What's Changed

    Full Changelog: https://github.com/Marceltov/freundebuch/compare/v0.1.0...v0.2.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.2.0
    

    The release on GitHub

Oct 27

  1. How freundebuch releases reach this feed

    Until today freundebuch had no releases: every merge to main updated the :main image, and if you ran it you got whatever was newest. Now there are versioned releases, and each one shows up here on its own. The first, 0.1.0, is the note just below this one.

    What happens on a release

    I push a tag such as v0.2.0. GitHub Actions runs the same pipeline as on main: lint, typecheck, the unit tests, the Playwright tests and a smoke test that starts the container and waits for it to report healthy, while it builds the image for amd64 and arm64. Only when all of that passes:

    1. The image gets its version: ghcr.io/marceltov/freundebuch:0.2.0, :0.2 and :latest. A pre-release like v0.2.0-rc.1 only gets its own tag, so latest never points at one.
    2. A GitHub release is made, with GitHub's generated list of the pull requests merged since the previous tag and a docker pull line.
    3. The same notes are posted here, tagged release and with the version, plus a link to the GitHub release.
    flowchart LR
      T[tag v0.2.0] --> C[tests and smoke test]
      T --> B[image build, amd64 + arm64]
      C --> I[image tags 0.2.0, 0.2, latest]
      B --> I
      I --> R[GitHub release]
      R --> N[note on this feed]
    

    For 0.1.0 the whole run took about 11 minutes from the tag to the note. A re-run doesn't post twice: it first asks notefeed whether a note with that version tag is already there.

    Pinning a version

    To upgrade only when you choose, pin a version in your compose.yaml:

    services:
      freundebuch:
        image: ghcr.io/marceltov/freundebuch:0.1
    

    :main stays as it is, for everyone who wants every merge.

    Good to know

    The first release has no earlier tag to count from, so its notes list every pull request since the start (26 of them). From 0.2.0 on, each release lists only what's new. The notes are PR titles, which are written for me more than for you; I'll post a note in my own words alongside the bigger releases, like the two earlier ones on this feed.

    The workflow is in .github/workflows/ci.yml. This feed has RSS at https://notefeed.me/r/freundebuch/feed.xml. If something about the release notes doesn't work for you, tell me.

  2. freundebuch 0.1.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/Marceltov/freundebuch/commits/v0.1.0

    Image

    docker pull ghcr.io/marceltov/freundebuch:0.1.0
    

    The release on GitHub

  3. Roles, situations and a calendar feed

    Over the last two days freundebuch learned the difference between who someone is to us and what's going on in their life. It also got a calendar feed, and Claude now gets told what to do after each call.

    Roles are relationships now

    "Our landlady" used to be filed as a fact, right next to the news about her new sink. Now it's a relationship to the household: to "me" or to "us". It's written in plain German words for both ends ("Vermieterin" / "Mieter:in") instead of a fixed type. People can have an optional gender, so the page reads "Unsere Vermieterin". Claude only sets a gender when I say it or use a pronoun, never from the name. When a gender changes, Claude is told which words need regendering. That's now only the neutral ones: setting 11 genders on my data listed 2 words to fix instead of 18.

    Situations that nudge

    Facts are split into two kinds. Gut zu wissen holds lasting ones (job, kids, allergies). Gerade los holds situations (a trip, a renovation). Each situation has a day to check in again. On that day it moves to the top of the page and into the daily push: "💬 Frag mal nach: Anna – sucht ein Auto". Without a date it's six weeks. When there's news, Claude suggests a new day and agrees it with me before filing.

    The person page also draws a small network: the household on top, the person in the middle, their people below, with a label on every line.

    Tool results say what's next

    Every MCP tool result now carries next: short instructions built from what the call actually did. One example: "this situation nudges on 8 December, a default; tell the user." Another: "two people match, ask which one." Before, that guidance lived in the tool descriptions, where Claude had to remember it before it knew what the call had done. Now it arrives right after the call.

    Also new

    • Calendar feed: birthdays (with the age when the year is known), other dates, and your own promises that have a due date, as an ICS URL you can subscribe to. Google refreshes it only every few hours, sometimes once a day.
    • Either of us can fix a shared item, not just whoever recorded it. Making an item private stays with the person who recorded it.
    • Softer background: slow colour bubbles that stand still if you've turned motion off.

    Changelog on GitHub. Tell me what you'd want from the nudges.

  4. freundebuch: a personal CRM you talk to

    You meet a friend and can't remember whether her new job has started, what her kid is called, or that you promised to send her a contact. I wanted something for that moment that doesn't ask me to fill in forms. So I built freundebuch, a personal CRM for one household, where Claude does all the typing.

    How it works

    After a dinner I ramble about it to the Claude app, by voice or text. Claude files it through freundebuch's built-in MCP endpoint: who was there, what's new, what I promised, gift ideas, birthdays, who is related to whom. The full transcript is kept. Before I see someone again I ask "I'm seeing Anna tomorrow, what's new?" and get a briefing: the last meetings, what's going on, open promises, upcoming dates.

    MCP is the main interface. Every feature works there first. A REST API (with OpenAPI) and a German web app sit on the same domain layer. The web app is mostly for looking things up on my phone:

    • The orbit: me in the middle, friends on rings by how long it's been. Anyone overdue for their check-in interval drifts outward.
    • A page per person: what's going on, what's good to know, promises, dates, and the people around them.
    • Erzählen: a chat with Claude inside the app, using the same tools, for when I'm not in the Claude app.
    • Reminders once a day to a webhook such as ntfy: birthdays, promises, overdue friends.

    Shared, with private parts

    Two people in a household share one freundebuch. Anything said in confidence can be private to whoever recorded it, down to a single fact. Claude asks before filing when something sounds sensitive (health, money, relationship trouble). In the code, privacy is one function that every read goes through, so a private item can't leak through a count or a summary. Tests check that by seeding a household.

    What's in it so far

    I started on 23 October, and 44 PRs are merged as of today. Besides the core:

    • Groups with other names ("Kollegen" is "Arbeit").
    • Screenshots from social media: share a friend's Instagram or LinkedIn post and it lands on their page ("Urlaub in Lissabon · Instagram, 12. Oktober"). If Claude isn't sure who it is, or it looks sensitive, it waits for me to check.
    • A calendar feed of birthdays and dates that Google Calendar can subscribe to.
    • Roles and situations: "our landlady" is a relationship to us, not a fact. "Renovating the bathroom" is a situation that nudges me to ask about it later.

    What it isn't

    It isn't a contact book (no phone numbers or addresses) and it isn't multi-tenant: one instance per household, signed in through your own identity provider (authentik). It's one container with one SQLite file, and it's licensed AGPL-3.0.

    The code is on GitHub, and the docs explain self-hosting. This feed is where I'll post what changes. If you try it, I'd like to hear how the rambling feels.