@elizaos/plugin-personal-assistant 2.0.11-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/package.json +135 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # `@elizaos/plugin-personal-assistant`
2
+
3
+ LifeOps is the elizaOS app that runs the user's day: routines, goals,
4
+ calendar, email, messaging, follow-ups with people, blockers, watchers, and
5
+ the operational glue around them. This README is the architecture summary
6
+ for contributors.
7
+
8
+ ## Scheduled items, not generic tasks
9
+
10
+ Every reminder, check-in, follow-up, watcher, recap, approval surface, and
11
+ nag-the-user-when-they-go-quiet flow is a **LifeOps scheduled item** stored
12
+ as a `ScheduledTask` record and owned by the runner at
13
+ `src/lifeops/scheduled-task/runner.ts`. There is no second LifeOps scheduling
14
+ mechanism.
15
+
16
+ `ScheduledTask` is intentionally not the repository-wide "task" primitive.
17
+ Core runtime tasks are persisted `Task` rows handled by `TaskService`; coding
18
+ agent work is orchestrator/task-coordinator state; project and feature tasks
19
+ may have their own plugin-owned records. LifeOps integrates with those
20
+ surfaces through public plugin/runtime contracts instead of importing or
21
+ owning them as LifeOps primitives.
22
+
23
+ The shape:
24
+
25
+ ```ts
26
+ interface ScheduledTask {
27
+ taskId: string;
28
+ kind: "reminder" | "checkin" | "followup" | "approval" | "recap" | "watcher" | "output" | "custom";
29
+ promptInstructions: string;
30
+ contextRequest?: { /* owner facts, entities, relationships, recent task states, event payload */ };
31
+ trigger: /* once | cron | interval | relative_to_anchor | during_window | event | manual | after_task */;
32
+ priority: "low" | "medium" | "high";
33
+ shouldFire?: { compose: "all" | "any" | "first_deny"; gates: Array<{ kind: string; params? }> };
34
+ completionCheck?: { kind: string; params?: ...; followupAfterMinutes? };
35
+ escalation?: { ladderKey?: string; steps?: EscalationStep[] };
36
+ output?: { destination: ...; target?: string; persistAs?: ... };
37
+ pipeline?: { onComplete?, onSkip?, onFail? };
38
+ subject?: { kind: "entity" | "relationship" | "thread" | "document" | "calendar_event" | "self"; id: string };
39
+ idempotencyKey?: string;
40
+ respectsGlobalPause: boolean;
41
+ state: ScheduledTaskState;
42
+ source: "default_pack" | "user_chat" | "first_run" | "plugin";
43
+ createdBy: string;
44
+ ownerVisible: boolean;
45
+ metadata?: Record<string, unknown>;
46
+ }
47
+ ```
48
+
49
+ The runner pattern-matches **only** on the structural fields above
50
+ (`kind`, `trigger`, `shouldFire`, `completionCheck`, `pipeline`, `output`,
51
+ `subject`, `priority`, `respectsGlobalPause`). It never inspects
52
+ `promptInstructions` content. This is non-negotiable.
53
+
54
+ The frozen contract is defined in `src/lifeops/scheduled-task/types.ts`
55
+ (the runner imports `ScheduledTask` from there). `src/lifeops/wave1-types.ts`
56
+ is a slightly diverged copy consumed only by the `first-run` module.
57
+
58
+ ## Runtime layout
59
+
60
+ ```
61
+ src/lifeops/
62
+ scheduled-task/ Spine: runner, state log, gate registry,
63
+ completion-check registry, escalation, runtime
64
+ wiring.
65
+ entities/ Entity primitive: store, merge engine, types.
66
+ relationships/ Relationship edges: store, observation
67
+ extraction, types.
68
+ registries/ AnchorRegistry, EventKindRegistry, FamilyRegistry,
69
+ BlockerRegistry, app/website blocker contributions.
70
+ signals/ ActivitySignalBus.
71
+ channels/ ChannelRegistry, priority-posture map, default
72
+ channel pack.
73
+ connectors/ ConnectorRegistry + per-connector contributions
74
+ (calendly, discord, duffel, google, imessage,
75
+ signal, telegram, twilio, whatsapp, x).
76
+ send-policy/ Per-connector send-policy contract + registry.
77
+ owner/ OwnerFactStore.
78
+ first-run/ FirstRunService, state store, customize
79
+ questions, replay.
80
+ pending-prompts/ PendingPromptsStore (the planner-visible
81
+ "questions waiting for the user" surface).
82
+ global-pause/ GlobalPauseStore.
83
+ handoff/ HandoffStore (per-room handoff state).
84
+ i18n/ MultilingualPromptRegistry.
85
+ graph-migration/ Migration into the entity/relationship graph.
86
+ seed-routine-migration/ Migration off legacy seed routines.
87
+ ...other LifeOps-owned helpers (calendar, email, messaging, payments,
88
+ subscriptions, assistant workflows, etc.)
89
+ ```
90
+
91
+ ## Default packs
92
+
93
+ Default packs are bundles of typed scheduled-item definitions compiled into
94
+ `ScheduledTask` records (and sometimes anchor-consolidation policies,
95
+ escalation ladders, autofill whitelists). LifeOps-owned packs live in
96
+ `src/default-packs/`:
97
+
98
+ - `daily-rhythm` — gm, gn, daily check-in.
99
+ - `morning-brief` — fired on `wake.confirmed`.
100
+ - `quiet-user-watcher` — daily watcher.
101
+ - `habit-starters` — eight habits, **offered** (not auto-seeded).
102
+ - `executive-assistant` — twenty-five scheduled records covering twenty
103
+ personal/executive assistant scenario families, **offered** (not auto-seeded).
104
+ - `inbox-triage-starter` — opt-in, gated on Gmail.
105
+ - `followup-starter` — watcher firing per overdue relationship.
106
+ - `autofill-whitelist-pack`, `consolidation-policies`, `escalation-ladders`
107
+ — policy-only packs.
108
+
109
+ `@elizaos/plugin-health` ships `bedtime`, `wake-up`, `sleep-recap` and
110
+ registers them when a health connector pairs.
111
+
112
+ ### Adding a new default pack
113
+
114
+ 1. Add a file under `src/default-packs/<name>.ts` that exports a
115
+ `DefaultPack` matching `registry-types.ts`.
116
+ 2. Define `ReminderTaskDefinition`, `CheckInTaskDefinition`,
117
+ `WatcherTaskDefinition`, `ApprovalTaskDefinition`, `RecapTaskDefinition`,
118
+ or `OutputTaskDefinition` values and compile them with
119
+ `compileTaskDefinition` / `compileTaskDefinitions`. Pack files should not
120
+ construct raw `ScheduledTaskSeed` records.
121
+ 3. Import and append it to `DEFAULT_PACKS` in `src/default-packs/index.ts`.
122
+ 4. If the pack should be **auto-enabled**, list it in
123
+ `getDefaultEnabledPacks`. If it should be **offered** during first-run
124
+ customize, list it in `getOfferedDefaultPacks`. If neither, the pack
125
+ only seeds when invoked explicitly.
126
+ 5. Run `bun run lint:default-packs` (also runs as `pretest`). The lint
127
+ rules are embedded in `scripts/lint-default-packs.mjs`. CI rejects packs
128
+ that violate them, including raw `ScheduledTask` construction.
129
+ 6. Add a record-id constant export so consumers can target the records by
130
+ stable ID.
131
+
132
+ The runtime never seeds packs by name string-match; everything goes through
133
+ `getAllDefaultPacks()`.
134
+
135
+ ## Knowledge graph
136
+
137
+ `EntityStore` (nodes) and `RelationshipStore` (edges) at
138
+ `src/lifeops/entities/` and `src/lifeops/relationships/`. The graph is
139
+ per-agent. The `entityId === "self"` row is bootstrapped on first use.
140
+
141
+ - **Cadence lives on the edge.** "Pat — every 14 days" is a
142
+ `Relationship`, not an `Entity` attribute. Cadence-bearing
143
+ `ScheduledTask`s use `subject.kind = "relationship"`.
144
+ - **Identities are observed.** `(platform, handle)` pairs route through
145
+ `observeIdentity`; the merge engine in `entities/merge.ts` collapses
146
+ entities with high-confidence identity matches. Manual merges go through
147
+ `POST /api/lifeops/entities/merge` and are audited.
148
+ - **REST surface** — routes live in `src/routes/`.
149
+
150
+ ## Pause and handoff
151
+
152
+ - **Global pause** (`global-pause/store.ts`) — stops every
153
+ `ScheduledTask` with `respectsGlobalPause: true`. Toggleable via UI or
154
+ `/api/lifeops/app-state`.
155
+ - **Per-room handoff** (`handoff/store.ts`) — flips a multi-party room
156
+ into handoff after the agent says "I'll let you take it from here."
157
+ Typed resume conditions (`mention | explicit_resume | silence_minutes |
158
+ user_request_help`). The `RoomPolicyProvider` reads
159
+ `HandoffStore.status(roomId).active` and gates further agent
160
+ contributions.
161
+
162
+ ## Plugin dependencies
163
+
164
+ LifeOps consumes `@elizaos/plugin-health` for sleep/circadian/health metrics,
165
+ screen-time action planning, health action planning, health-context formatting,
166
+ and health connector contributions.
167
+ The plugin contributes through the registries listed above (`AnchorRegistry`,
168
+ `ConnectorRegistry`, `FamilyRegistry`, default packs) and public factories such
169
+ as `createHealthActionRunner`, `createScreenTimeActionRunner`, and
170
+ `createHealthProvider`. LifeOps does not import directly into the health
171
+ internals; it consumes the plugin's public exports only. See
172
+ `plugins/plugin-health/README.md`.
173
+
174
+ ## Cross-agent invariants
175
+
176
+ 1. The runner never pattern-matches `promptInstructions`.
177
+ 2. `subject.kind = "relationship"` for cadence-bearing tasks.
178
+ 3. Identities are observed, not assigned.
179
+ 4. Connectors and channels return typed `DispatchResult`. No `boolean`.
180
+ 5. `shouldFire.gates` is always an array.
181
+ 6. `acknowledged` ≠ `completed`. Pipeline `onComplete` only fires on
182
+ `completed`.
183
+ 7. Snooze resets the escalation ladder.
184
+ 8. Global pause skips tasks with `respectsGlobalPause: true`.
185
+
186
+ ## Where to look next
187
+
188
+ - Frozen interface types: `src/lifeops/scheduled-task/types.ts`.
189
+ - Prompt-content lint rules: `scripts/lint-default-packs.mjs`.
190
+ - Health domain: `plugins/plugin-health/README.md`.
191
+ - REST routes: `src/routes/`.
package/package.json ADDED
@@ -0,0 +1,135 @@
1
+ {
2
+ "name": "@elizaos/plugin-personal-assistant",
3
+ "version": "2.0.11-beta.7",
4
+ "type": "module",
5
+ "description": "Personal-assistant orchestration plugin: BRIEF, PRIORITIZE, PERSONAL_ASSISTANT cross-domain orchestration, scheduled-task owner CRUD, and default-pack composition. Slimmed from the legacy plugin-lifeops; domain-specific surfaces have moved to plugin-inbox, plugin-goals, plugin-calendar, plugin-blocker, plugin-finances, plugin-relationships, etc.",
6
+ "sideEffects": [
7
+ "./src/api/client-lifeops.ts",
8
+ "./dist/api/client-lifeops.js"
9
+ ],
10
+ "main": "./dist/index.js",
11
+ "exports": {
12
+ "./package.json": "./package.json",
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "eliza-source": {
16
+ "types": "./src/index.ts",
17
+ "import": "./src/index.ts",
18
+ "default": "./src/index.ts"
19
+ },
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./plugin": {
24
+ "types": "./dist/plugin.d.ts",
25
+ "eliza-source": {
26
+ "types": "./src/plugin.ts",
27
+ "import": "./src/plugin.ts",
28
+ "default": "./src/plugin.ts"
29
+ },
30
+ "import": "./dist/plugin.js",
31
+ "default": "./dist/plugin.js"
32
+ },
33
+ "./*.css": "./dist/*.css",
34
+ "./*": {
35
+ "types": "./dist/*.d.ts",
36
+ "eliza-source": {
37
+ "types": "./src/*.ts",
38
+ "import": "./src/*.ts",
39
+ "default": "./src/*.ts"
40
+ },
41
+ "import": "./dist/*.js",
42
+ "default": "./dist/*.js"
43
+ }
44
+ },
45
+ "scripts": {
46
+ "lint:default-packs": "node scripts/lint-default-packs.mjs",
47
+ "verify": "bun run lint:default-packs && bun run build:types && bun run test",
48
+ "pretest": "node scripts/lint-default-packs.mjs",
49
+ "test": "vitest run --config vitest.config.ts",
50
+ "test:app-state": "vitest run --config vitest.config.ts eliza/plugins/plugin-personal-assistant/test/lifeops-app-state.test.ts",
51
+ "test:background-real": "vitest run --config vitest.background-real.config.ts test/scheduled-task-end-to-end.e2e.test.ts test/reminder-review-job.real.e2e.test.ts test/lifeops-scheduling.real.test.ts test/schedule-merged-state.real.test.ts",
52
+ "test:integration": "cd ../../.. && vitest run --config eliza/packages/test/vitest/integration.config.ts eliza/plugins/plugin-personal-assistant/test/life-smoke.integration.test.ts",
53
+ "test:scenarios": "cd ../.. && bun packages/scenario-runner/src/cli.ts list plugins/plugin-personal-assistant/test/scenarios",
54
+ "bench:work-threads": "cd ../.. && bun plugins/plugin-personal-assistant/scripts/work-thread-benchmark.ts",
55
+ "verify:live-schedule": "bun run ./scripts/verify-live-schedule-data.ts",
56
+ "build": "bun run build:js && bun run build:types",
57
+ "clean": "rm -rf dist",
58
+ "build:js": "bun run clean && tsup --config tsup.config.ts",
59
+ "build:types": "tsc --noCheck -p tsconfig.build.json"
60
+ },
61
+ "dependencies": {
62
+ "@capacitor/core": "8.4.0",
63
+ "@elizaos/agent": "2.0.11-beta.7",
64
+ "@elizaos/app-core": "2.0.11-beta.7",
65
+ "@elizaos/capacitor-calendar": "2.0.11-beta.7",
66
+ "@elizaos/capacitor-mobile-signals": "2.0.11-beta.7",
67
+ "@elizaos/core": "2.0.11-beta.7",
68
+ "@elizaos/macosreminders": "2.0.11-beta.7",
69
+ "@elizaos/native-activity-tracker": "2.0.11-beta.7",
70
+ "@elizaos/plugin-blocker": "2.0.11-beta.7",
71
+ "@elizaos/plugin-browser": "2.0.11-beta.7",
72
+ "@elizaos/plugin-calendar": "2.0.11-beta.7",
73
+ "@elizaos/plugin-calendly": "2.0.11-beta.7",
74
+ "@elizaos/plugin-discord": "2.0.11-beta.7",
75
+ "@elizaos/plugin-elizacloud": "2.0.11-beta.7",
76
+ "@elizaos/plugin-finances": "2.0.11-beta.7",
77
+ "@elizaos/plugin-goals": "2.0.11-beta.7",
78
+ "@elizaos/plugin-google": "2.0.11-beta.7",
79
+ "@elizaos/plugin-health": "2.0.11-beta.7",
80
+ "@elizaos/plugin-inbox": "2.0.11-beta.7",
81
+ "@elizaos/plugin-phone": "2.0.11-beta.7",
82
+ "@elizaos/plugin-reminders": "2.0.11-beta.7",
83
+ "@elizaos/plugin-remote-desktop": "2.0.11-beta.7",
84
+ "@elizaos/plugin-scheduling": "2.0.11-beta.7",
85
+ "@elizaos/plugin-whatsapp": "2.0.11-beta.7",
86
+ "@elizaos/plugin-x": "2.0.11-beta.7",
87
+ "@elizaos/shared": "2.0.11-beta.7",
88
+ "@elizaos/ui": "2.0.11-beta.7",
89
+ "drizzle-orm": "0.45.2",
90
+ "lucide-react": "^1.0.0",
91
+ "react-plaid-link": "^4.0.1",
92
+ "sharp": "^0.34.5",
93
+ "zod": "^4.4.3"
94
+ },
95
+ "devDependencies": {
96
+ "@electric-sql/pglite": "^0.4.0",
97
+ "@types/jsdom": "^28.0.0",
98
+ "bun-types": "1.3.14",
99
+ "dotenv": "^17.2.3",
100
+ "google-auth-library": "^10.0.0",
101
+ "jsdom": "^29.0.0",
102
+ "json5": "^2.2.3",
103
+ "react-dom": "*",
104
+ "ts-morph": "28.0.0",
105
+ "tsup": "^8.5.1",
106
+ "vite": "^8.0.0",
107
+ "vitest": "^4.0.17"
108
+ },
109
+ "peerDependencies": {
110
+ "react": "*",
111
+ "react-dom": "*"
112
+ },
113
+ "agentConfig": {
114
+ "pluginType": "elizaos:plugin:1.0.0",
115
+ "pluginParameters": {}
116
+ },
117
+ "elizaos": {
118
+ "app": {
119
+ "heroImage": "assets/hero.png",
120
+ "permissions": [
121
+ "reminders",
122
+ "calendar",
123
+ "notes"
124
+ ]
125
+ }
126
+ },
127
+ "publishConfig": {
128
+ "access": "public"
129
+ },
130
+ "types": "./dist/index.d.ts",
131
+ "files": [
132
+ "dist"
133
+ ],
134
+ "gitHead": "cdbc876f793d96073d7eb0d09715a031ce0cd32e"
135
+ }