Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

9.0 KiB

LifeOps OWNER vs AGENT live-validation matrix

Tracks issue #8833 §2/§5. This document is the single source of truth for the live, account-backed validation of the split LifeOps surface (@elizaos/plugin-personal-assistant plus the per-domain plugins) across OWNER and AGENT identities. It records the account/device/scope/env prerequisites and the repeatable run instructions so the matrix can be re-exercised on demand.

The static/code-level split is already validated (see the issue body and docs/lifeops-cleanup-review.md). The remaining work is live validation with real accounts, devices, and OAuth/provider state. This doc + the credential-gated harness (test/owner-agent-permission-matrix.integration.test.ts) cover the parts that can be exercised repeatably; the native-device items (iOS/macOS/Android) are tracked separately because they cannot run in CI.


1. The nine permission states

For every owner-gated action/connector surface, the validation exercises these nine states (issue §2):

# State Expected behavior
1 Unauthenticated connector / no world context Owner-only operation denied; no sender role resolves above GUEST.
2 OWNER authenticated and authorized Allowed through the planned-tool gate and the direct handler.
3 AGENT authenticated but not owner-authorized Denied with a clear permission error on both paths.
4 Expired / revoked grant Owner-side grant no longer resolves; the operation surfaces a reconnect-required state.
5 Missing required scope The granted capability set does not advertise the write/send capability; the action returns the matching unavailable message rather than acting.
6 Multiple grants — owner-side selection must win An owner-only operation resolves the side="owner" grant; the side="agent" grant never leaks in.
7 Planned-tool execution path satisfiesRoleGate(userRoles, action.roleGate) denies non-owner callers.
8 Direct handler-invocation path hasLifeOpsAccesshasOwnerAccesshasRoleAccess(..., "OWNER") denies non-owner callers.
9 UI-triggered path from the relevant view The view dispatches the same gated action; the gate above applies unchanged.

Where each state is enforced (source of truth)

  • Planned-tool gate (state 7): packages/core/src/runtime/execute-planned-tool-call.tsgetGateFailure()satisfiesRoleGate() (packages/core/src/runtime/context-gates.ts).
  • Handler guard (state 8): each owner action calls hasLifeOpsAccess() (src/lifeops/access.ts) → hasOwnerAccess() (@elizaos/agent security) → hasRoleAccess(..., "OWNER") (packages/core/src/roles.ts), returning PERMISSION_DENIED on failure.
  • Owner-side grant resolution (states 4/5/6): LifeOpsRepository.getConnectorGrant() (src/lifeops/repository.ts) filters by side (default "owner"), so an owner-only operation never resolves the agent-side grant.
  • Typed dispatch (no swallowed failures): connector send returns DispatchResult (@elizaos/plugin-scheduling), surfaced through the CONNECTOR action; never a bare boolean.

2. Owner-gated action surfaces

The harness covers the four cross-cutting owner-gated umbrella actions; the same gate applies to every action carrying roleGate: { minRole: "OWNER" }:

Action File Notes
CONNECTOR src/actions/connector.ts Connect/disconnect/verify/status/list across Google, X, Telegram, Signal, Discord, iMessage, WhatsApp, health, browser.
CREDENTIALS src/actions/credentials.ts Credential lookup + autofill.
PERSONAL_ASSISTANT src/actions/owner-surfaces.ts Cross-domain assistant orchestration.
VOICE_CALL src/actions/voice-call.ts Outbound Twilio voice.

Other owner surfaces (CALENDAR, INBOX, OWNER_*, ENTITY, BLOCK, SCHEDULED_TASKS, …) share the identical roleGate + hasLifeOpsAccess mechanism; see test/lifeops-action-gating.integration.test.ts for the full registered-surface inventory.


3. Account / device / scope / env prerequisites

The credential-gated harness runs against a local PGLite-backed runtime with no external accounts. The live connector smoke (send/read/sync against real providers) and the native-device items require the identities below. Provide them, set LIFEOPS_PERMISSION_MATRIX=1, and (for the live-LLM journeys) ELIZA_LIVE_TEST=1 plus a provider key.

Surface OWNER identity AGENT identity Required scopes / env Run gate
Google Calendar OWNER Google acct, Calendar enabled Separate AGENT Google acct or non-owner grant google.calendar.read / .write (OAuth) LIFEOPS_PERMISSION_MATRIX=1 + live OAuth
Gmail / inbox OWNER Gmail AGENT Gmail google.gmail.triage / .send / .manage as above
Telegram OWNER Telegram AGENT Telegram @elizaos/plugin-telegram configured as above
Discord OWNER Discord AGENT Discord DISCORD_BOT_TOKEN (@elizaos/plugin-discord) as above
Signal OWNER paired number AGENT paired number @elizaos/plugin-signal paired as above
WhatsApp OWNER WhatsApp AGENT WhatsApp ELIZA_WHATSAPP_ACCESS_TOKEN, ELIZA_WHATSAPP_PHONE_NUMBER_ID as above
X OWNER X AGENT X @elizaos/plugin-x configured as above
iMessage OWNER macOS bridge n/a macOS host; ELIZA_IMESSAGE_BACKEND native (not CI)
Phone / SMS / voice Twilio number recipient allowlist @elizaos/plugin-phone/twilio env LIFEOPS_PERMISSION_MATRIX=1
Health Apple Health / Google Fit / Fitbit / Oura / Strava / Withings n/a per-provider OAuth / ELIZA_HEALTHKIT_CLI_PATH, ELIZA_GOOGLE_FIT_ACCESS_TOKEN native / live OAuth
Blocker / focus macOS SelfControl / admin n/a SELFCONTROL_HOSTS_FILE_PATH native (not CI)
Finances Gmail billing corpus / CSV / Plaid sandbox n/a CSV fixture or sandbox creds LIFEOPS_PERMISSION_MATRIX=1

Native iOS/macOS/Android permission flows (HealthKit, Family Controls, Usage Access, SelfControl admin) are out of scope for CI and must be exercised on a real device; capture redacted screenshots/logs per the issue §5.


4. Repeatable run instructions

Credential-free (default CI) — proves clean skip

The permission-matrix harness is gated behind LIFEOPS_PERMISSION_MATRIX. With the flag unset it skips cleanly (one skipped suite, zero failures), so the default suite stays green without any accounts:

# Runs in the integration lane; skips when LIFEOPS_PERMISSION_MATRIX is unset.
bun run --cwd plugins/plugin-personal-assistant test:integration

Credential-backed — exercises the matrix

LIFEOPS_PERMISSION_MATRIX=1 \
  bun run --cwd plugins/plugin-personal-assistant test:integration

With the flag set, the harness boots a real AgentRuntime + PGLite + the LifeOps schema, establishes genuine OWNER and non-owner identities via setEntityRole, and asserts all nine states across the planned-tool gate, the handler guard, and the owner-side grant resolution — no role mocks.

Live connector smoke (real providers)

Add the provider accounts/env from §3, then run the existing live connector suites (each describeIf-gates on its own credentials and skips otherwise):

ELIZA_LIVE_TEST=1 LIFEOPS_PERMISSION_MATRIX=1 \
  bun run --cwd plugins/plugin-personal-assistant test:background-real

5. Evidence checklist (issue §5 acceptance criteria)

For each connector family, record OWNER and AGENT evidence: a redacted log / screenshot of the planned-tool path, the direct handler path, and the UI-triggered path, for each of the nine states it can reach. The harness covers the role-gate and grant-resolution states deterministically; live send/read and native-permission states are captured manually against the §3 identities.

Stage session artifacts under the local scratch dir reports/lifeops-live-validation/<session>/ (gitignored — evidence is never committed to the repo) and attach the redacted screenshots / logs inline in the PR/issue per CONTRIBUTING.md.

Connector family Owner evidence Agent evidence Status
Google Calendar attach attach pending live accounts
Gmail / inbox attach attach pending live accounts
Telegram / Discord / Signal / WhatsApp / X attach attach pending live accounts
Phone / voice / SMS attach n/a pending Twilio env
Health attach n/a pending native device
Blocker / focus attach n/a pending native device
Finances attach n/a pending sandbox data

The harness in this PR satisfies the role-gate / grant-selection rows deterministically (run it with LIFEOPS_PERMISSION_MATRIX=1). The remaining rows require the live accounts/devices from §3 and are filled in as those are provisioned. Any bug discovered while exercising the matrix gets a linked issue/PR before #8833 is closed.