As more apps move out of PIM core into their own pimi modules, the question of exactly where the line falls has come up often enough that it’s worth writing down as a real rule, not something each extraction re-decides from scratch.
PIM core keeps anything with no app identity — the generic orchestration engine and the
capability contracts any app plugs into, like JournalBaseEventService’s shared
conversation-lifecycle routing. None of it knows what “Diary” or “Notes” actually is; it’s the
framework every app is built on.
Everything else — an app’s persistence shape, its business logic, its context handler, its AI skill, and the class that wires all of that together and listens for its events — moves into that app’s own pimi module.
The one wrinkle: that second bucket shouldn’t always collapse into a single class per app, because
some apps will eventually have more than one variant. Diary is the model for this — it already
splits into BaseDiaryEventService, an abstract class holding the shared conversation-lifecycle
wiring, and DefaultDiaryEventService, one concrete implementation on top of it. That split
exists so a second Diary variant — a more guided, question-first mode is the one on the table —
can subclass the shared base and override only what’s different, instead of duplicating the
plumbing or, worse, growing branching logic back inside PIM core to pick between variants.
So the rule of thumb: if an app might grow a second variant someday, give it that same base/default split inside its own pimi module — never in core, since the base class is still app-specific, just shared across that one app’s variants. If no variant is planned, a single class extending the core framework directly, the way Notes is built today, is the right amount of structure until there’s an actual second variant to justify more.