@vellumai/assistant 0.4.41 → 0.4.43
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.
- package/.env.example +1 -6
- package/.prettierignore +3 -0
- package/ARCHITECTURE.md +131 -393
- package/Dockerfile +0 -1
- package/README.md +73 -83
- package/bun.lock +8 -2
- package/docs/architecture/integrations.md +16 -21
- package/docs/architecture/memory.md +1 -1
- package/docs/architecture/scheduling.md +63 -63
- package/docs/architecture/security.md +3 -3
- package/docs/runbook-trusted-contacts.md +11 -12
- package/docs/trusted-contact-access.md +39 -39
- package/package.json +5 -8
- package/src/__tests__/access-request-decision.test.ts +4 -4
- package/src/__tests__/active-skill-tools.test.ts +49 -34
- package/src/__tests__/actor-token-service.test.ts +55 -85
- package/src/__tests__/amazon-cdp-integration.test.ts +14 -26
- package/src/__tests__/app-bundler.test.ts +14 -368
- package/src/__tests__/app-compiler.test.ts +0 -1
- package/src/__tests__/app-executors.test.ts +10 -1
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +2 -4
- package/src/__tests__/approval-routes-http.test.ts +1 -1
- package/src/__tests__/asset-materialize-tool.test.ts +1 -4
- package/src/__tests__/asset-search-tool.test.ts +1 -4
- package/src/__tests__/assistant-attachments.test.ts +23 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +4 -8
- package/src/__tests__/assistant-id-boundary-guard.test.ts +5 -5
- package/src/__tests__/attachments-store.test.ts +1 -4
- package/src/__tests__/avatar-e2e.test.ts +43 -23
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -9
- package/src/__tests__/call-controller.test.ts +4 -8
- package/src/__tests__/call-conversation-messages.test.ts +1 -1
- package/src/__tests__/call-domain.test.ts +250 -8
- package/src/__tests__/call-pointer-message-composer.test.ts +14 -14
- package/src/__tests__/call-pointer-messages.test.ts +7 -11
- package/src/__tests__/call-recovery.test.ts +47 -0
- package/src/__tests__/call-routes-http.test.ts +13 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
- package/src/__tests__/callback-handoff-copy.test.ts +5 -5
- package/src/__tests__/canonical-guardian-store.test.ts +3 -3
- package/src/__tests__/channel-approval-routes.test.ts +101 -134
- package/src/__tests__/channel-approval.test.ts +0 -201
- package/src/__tests__/channel-approvals.test.ts +2 -2
- package/src/__tests__/channel-delivery-store.test.ts +16 -24
- package/src/__tests__/channel-guardian.test.ts +641 -740
- package/src/__tests__/channel-invite-transport.test.ts +1 -2
- package/src/__tests__/channel-policy.test.ts +9 -12
- package/src/__tests__/channel-readiness-service.test.ts +156 -45
- package/src/__tests__/channel-reply-delivery.test.ts +3 -3
- package/src/__tests__/channel-retry-sweep.test.ts +7 -7
- package/src/__tests__/checker.test.ts +10 -7
- package/src/__tests__/chrome-cdp.test.ts +57 -17
- package/src/__tests__/cli-help-reference-sync.test.ts +26 -0
- package/src/__tests__/compaction.benchmark.test.ts +25 -5
- package/src/__tests__/computer-use-session-lifecycle.test.ts +1 -1
- package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +310 -0
- package/src/__tests__/config-watcher.test.ts +1 -5
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +3 -5
- package/src/__tests__/connection-policy.test.ts +3 -62
- package/src/__tests__/contacts-tools.test.ts +0 -2
- package/src/__tests__/context-memory-e2e.test.ts +11 -7
- package/src/__tests__/context-overflow-policy.test.ts +2 -2
- package/src/__tests__/context-window-manager.test.ts +220 -61
- package/src/__tests__/conversation-attention-store.test.ts +178 -2
- package/src/__tests__/conversation-attention-telegram.test.ts +8 -11
- package/src/__tests__/conversation-pairing.test.ts +14 -14
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +1 -1
- package/src/__tests__/conversation-store.test.ts +2 -2
- package/src/__tests__/conversation-unread-route.test.ts +155 -0
- package/src/__tests__/credential-metadata-store.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +9 -16
- package/src/__tests__/credentials-cli.test.ts +49 -5
- package/src/__tests__/daemon-assistant-events.test.ts +4 -22
- package/src/__tests__/db-migration-rollback.test.ts +2 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +19 -19
- package/src/__tests__/dictation-mode-detection.test.ts +1 -1
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -6
- package/src/__tests__/email-cli.test.ts +12 -12
- package/src/__tests__/email-service-config-fallback.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -18
- package/src/__tests__/event-bus.test.ts +0 -1
- package/src/__tests__/followup-tools.test.ts +0 -2
- package/src/__tests__/gateway-client-managed-outbound.test.ts +6 -6
- package/src/__tests__/gateway-only-enforcement.test.ts +13 -77
- package/src/__tests__/gateway-only-guard.test.ts +5 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +3 -3
- package/src/__tests__/guardian-action-followup-executor.test.ts +29 -94
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -12
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +48 -194
- package/src/__tests__/guardian-action-late-reply.test.ts +12 -12
- package/src/__tests__/guardian-action-store.test.ts +2 -2
- package/src/__tests__/guardian-action-sweep.test.ts +5 -5
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -3
- package/src/__tests__/guardian-dispatch.test.ts +5 -46
- package/src/__tests__/guardian-grant-minting.test.ts +5 -44
- package/src/__tests__/guardian-outbound-http.test.ts +95 -114
- package/src/__tests__/guardian-question-mode.test.ts +1 -4
- package/src/__tests__/guardian-routing-invariants.test.ts +5 -13
- package/src/__tests__/guardian-routing-state.test.ts +3 -3
- package/src/__tests__/guardian-verification-voice-binding.test.ts +64 -7
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
- package/src/__tests__/handle-user-message-secret-resume.test.ts +3 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +16 -34
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +1 -1
- package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
- package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +1 -1
- package/src/__tests__/home-base-bootstrap.test.ts +0 -2
- package/src/__tests__/host-shell-tool.test.ts +3 -12
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -2
- package/src/__tests__/ingress-url-consistency.test.ts +0 -64
- package/src/__tests__/integration-status.test.ts +8 -8
- package/src/__tests__/intent-routing.test.ts +9 -13
- package/src/__tests__/invite-redemption-service.test.ts +4 -4
- package/src/__tests__/invite-routes-http.test.ts +10 -10
- package/src/__tests__/llm-usage-store.test.ts +45 -9
- package/src/__tests__/local-gateway-health.test.ts +209 -0
- package/src/__tests__/managed-avatar-client.test.ts +23 -12
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -2
- package/src/__tests__/managed-store.test.ts +29 -12
- package/src/__tests__/managed-twitter-guardrails.test.ts +353 -0
- package/src/__tests__/mcp-cli.test.ts +1 -1
- package/src/__tests__/mcp-health-check.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -4
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +9 -6
- package/src/__tests__/memory-regressions.test.ts +1 -166
- package/src/__tests__/messaging-send-tool.test.ts +8 -4
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-transport.test.ts +44 -0
- package/src/__tests__/non-member-access-request.test.ts +49 -36
- package/src/__tests__/notification-broadcaster.test.ts +15 -15
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-strategy.test.ts +4 -4
- package/src/__tests__/notification-deep-link.test.ts +3 -3
- package/src/__tests__/notification-guardian-path.test.ts +6 -44
- package/src/__tests__/notification-routing-intent.test.ts +11 -7
- package/src/__tests__/oauth-cli.test.ts +1 -1
- package/src/__tests__/onboarding-starter-tasks.test.ts +2 -6
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/platform.test.ts +168 -5
- package/src/__tests__/playbook-execution.test.ts +0 -2
- package/src/__tests__/playbook-tools.test.ts +0 -2
- package/src/__tests__/pricing.test.ts +125 -0
- package/src/__tests__/provider-error-scenarios.test.ts +9 -3
- package/src/__tests__/recording-handler.test.ts +46 -80
- package/src/__tests__/recording-state-machine.test.ts +112 -183
- package/src/__tests__/registry.test.ts +1 -1
- package/src/__tests__/relay-server.test.ts +69 -71
- package/src/__tests__/reminder-store.test.ts +3 -3
- package/src/__tests__/request-file-tool.test.ts +2 -2
- package/src/__tests__/ride-shotgun-handler.test.ts +2 -33
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -3
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +4 -4
- package/src/__tests__/schedule-store.test.ts +13 -4
- package/src/__tests__/schedule-tools.test.ts +0 -2
- package/src/__tests__/scheduler-recurrence.test.ts +3 -4
- package/src/__tests__/scoped-approval-grants.test.ts +3 -5
- package/src/__tests__/scoped-grant-security-matrix.test.ts +6 -8
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +1 -1
- package/src/__tests__/secret-response-routing.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -1
- package/src/__tests__/sequence-store.test.ts +0 -2
- package/src/__tests__/server-history-render.test.ts +2 -199
- package/src/__tests__/session-abort-tool-results.test.ts +9 -3
- package/src/__tests__/session-agent-loop.test.ts +107 -3
- package/src/__tests__/session-confirmation-signals.test.ts +10 -4
- package/src/__tests__/session-conflict-gate.test.ts +9 -3
- package/src/__tests__/session-init.benchmark.test.ts +22 -13
- package/src/__tests__/session-load-history-repair.test.ts +6 -3
- package/src/__tests__/session-pre-run-repair.test.ts +9 -3
- package/src/__tests__/session-profile-injection.test.ts +9 -3
- package/src/__tests__/session-provider-retry-repair.test.ts +10 -4
- package/src/__tests__/session-queue.test.ts +10 -4
- package/src/__tests__/session-runtime-assembly.test.ts +28 -18
- package/src/__tests__/session-skill-tools.test.ts +2 -3
- package/src/__tests__/session-slash-known.test.ts +11 -4
- package/src/__tests__/session-slash-queue.test.ts +11 -4
- package/src/__tests__/session-slash-unknown.test.ts +12 -4
- package/src/__tests__/session-surfaces-deselection.test.ts +2 -2
- package/src/__tests__/session-surfaces-task-progress.test.ts +3 -3
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
- package/src/__tests__/session-usage.test.ts +180 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +8 -2
- package/src/__tests__/session-workspace-injection.test.ts +8 -2
- package/src/__tests__/session-workspace-tool-tracking.test.ts +8 -2
- package/src/__tests__/skill-feature-flags-integration.test.ts +5 -11
- package/src/__tests__/skill-feature-flags.test.ts +1 -0
- package/src/__tests__/skill-include-graph.test.ts +1 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +3 -9
- package/src/__tests__/skill-load-tool.test.ts +90 -12
- package/src/__tests__/skill-projection-feature-flag.test.ts +14 -15
- package/src/__tests__/skills-uninstall.test.ts +131 -0
- package/src/__tests__/skills.test.ts +32 -16
- package/src/__tests__/slack-block-formatting.test.ts +1 -1
- package/src/__tests__/slack-channel-config.test.ts +71 -12
- package/src/__tests__/slack-inbound-verification.test.ts +7 -7
- package/src/__tests__/slack-share-routes.test.ts +1 -1
- package/src/__tests__/slack-skill.test.ts +2 -2
- package/src/__tests__/slash-commands-catalog.test.ts +1 -0
- package/src/__tests__/slash-commands-resolver.test.ts +1 -0
- package/src/__tests__/starter-task-flow.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +4 -8
- package/src/__tests__/task-compiler.test.ts +0 -2
- package/src/__tests__/task-management-tools.test.ts +0 -2
- package/src/__tests__/task-runner.test.ts +0 -2
- package/src/__tests__/task-scheduler.test.ts +2 -2
- package/src/__tests__/telegram-bot-username-resolution.test.ts +46 -44
- package/src/__tests__/terminal-tools.test.ts +1 -11
- package/src/__tests__/thread-seed-composer.test.ts +3 -1
- package/src/__tests__/tool-approval-handler.test.ts +5 -7
- package/src/__tests__/tool-executor.test.ts +2 -2
- package/src/__tests__/tool-grant-request-escalation.test.ts +3 -5
- package/src/__tests__/tool-notification-listener.test.ts +1 -1
- package/src/__tests__/tool-profiling-listener.test.ts +1 -1
- package/src/__tests__/tool-trace-listener.test.ts +1 -2
- package/src/__tests__/trace-emitter.test.ts +1 -1
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trust-store.test.ts +44 -395
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +6 -8
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +5 -7
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +6 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +54 -47
- package/src/__tests__/trusted-contact-verification.test.ts +12 -12
- package/src/__tests__/twilio-config.test.ts +11 -2
- package/src/__tests__/twilio-provider.test.ts +6 -4
- package/src/__tests__/twilio-routes.test.ts +408 -86
- package/src/__tests__/twitter-platform-proxy-client.test.ts +450 -0
- package/src/__tests__/update-bulletin-format.test.ts +1 -1
- package/src/__tests__/update-bulletin-state.test.ts +1 -1
- package/src/__tests__/update-bulletin.test.ts +4 -8
- package/src/__tests__/update-template-contract.test.ts +1 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +406 -0
- package/src/__tests__/usage-routes.test.ts +23 -5
- package/src/__tests__/user-reference.test.ts +1 -1
- package/src/__tests__/{guardian-control-plane-policy.test.ts → verification-control-plane-policy.test.ts} +142 -170
- package/src/__tests__/{guardian-verification-intent-routing.test.ts → verification-session-intent-routing.test.ts} +16 -16
- package/src/__tests__/view-image-tool.test.ts +0 -2
- package/src/__tests__/voice-ingress-preflight.test.ts +36 -0
- package/src/__tests__/voice-invite-redemption.test.ts +18 -18
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +7 -7
- package/src/__tests__/voice-session-bridge.test.ts +14 -16
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/approvals/AGENTS.md +4 -4
- package/src/approvals/approval-primitive.ts +2 -2
- package/src/approvals/guardian-decision-primitive.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -4
- package/src/bundler/app-bundler.ts +29 -217
- package/src/bundler/app-compiler.ts +131 -103
- package/src/bundler/compiler-tools.ts +248 -0
- package/src/calls/active-call-lease.ts +207 -0
- package/src/calls/call-constants.ts +0 -7
- package/src/calls/call-controller.ts +1 -1
- package/src/calls/call-conversation-messages.ts +6 -6
- package/src/calls/call-domain.ts +73 -38
- package/src/calls/call-pointer-message-composer.ts +6 -6
- package/src/calls/call-pointer-messages.ts +14 -13
- package/src/calls/call-recovery.ts +2 -0
- package/src/calls/call-store.ts +21 -28
- package/src/calls/guardian-action-sweep.ts +6 -8
- package/src/calls/guardian-dispatch.ts +2 -6
- package/src/calls/relay-access-wait.ts +4 -4
- package/src/calls/relay-server.ts +69 -80
- package/src/calls/relay-setup-router.ts +16 -21
- package/src/calls/relay-verification.ts +27 -28
- package/src/calls/twilio-config.ts +28 -3
- package/src/calls/twilio-provider.ts +5 -5
- package/src/calls/twilio-rest.ts +26 -27
- package/src/calls/twilio-routes.ts +67 -54
- package/src/calls/types.ts +8 -8
- package/src/calls/voice-ingress-preflight.ts +110 -0
- package/src/calls/voice-session-bridge.ts +7 -7
- package/src/channels/config.ts +1 -10
- package/src/{config/channel-permission-profiles.ts → channels/permission-profiles.ts} +1 -1
- package/src/channels/types.ts +2 -13
- package/src/cli/__tests__/notifications.test.ts +1 -1
- package/src/{amazon → cli/commands/amazon}/client.ts +99 -42
- package/src/cli/{amazon.ts → commands/amazon/index.ts} +12 -17
- package/src/{amazon → cli/commands/amazon}/request-extractor.ts +39 -3
- package/src/cli/commands/amazon/session.ts +116 -0
- package/src/cli/{audit.ts → commands/audit.ts} +2 -4
- package/src/cli/{autonomy.ts → commands/autonomy.ts} +1 -3
- package/src/cli/commands/browser-relay.ts +520 -0
- package/src/cli/commands/channel-verification-sessions.ts +442 -0
- package/src/cli/{completions.ts → commands/completions.ts} +1 -3
- package/src/cli/{config.ts → commands/config.ts} +3 -5
- package/src/cli/{contacts.ts → commands/contacts.ts} +263 -16
- package/src/cli/{credentials.ts → commands/credentials.ts} +9 -10
- package/src/cli/{default-action.ts → commands/default-action.ts} +3 -3
- package/src/cli/{dev.ts → commands/dev.ts} +4 -6
- package/src/cli/{doctor.ts → commands/doctor.ts} +36 -60
- package/src/cli/{email.ts → commands/email.ts} +2 -2
- package/src/cli/{keys.ts → commands/keys.ts} +6 -6
- package/src/cli/{map.ts → commands/map.ts} +85 -93
- package/src/cli/{mcp.ts → commands/mcp.ts} +5 -7
- package/src/cli/{memory.ts → commands/memory.ts} +6 -7
- package/src/cli/{notifications.ts → commands/notifications.ts} +8 -10
- package/src/cli/{oauth.ts → commands/oauth.ts} +2 -2
- package/src/cli/commands/platform.ts +176 -0
- package/src/cli/{sequence.ts → commands/sequence.ts} +3 -3
- package/src/cli/{sessions.ts → commands/sessions.ts} +32 -52
- package/src/cli/commands/skills.ts +498 -0
- package/src/cli/{trust.ts → commands/trust.ts} +2 -4
- package/src/{__tests__/twitter-cli-error-shaping.test.ts → cli/commands/twitter/__tests__/cli-error-shaping.test.ts} +43 -2
- package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +483 -0
- package/src/{__tests__/twitter-cli-routing.test.ts → cli/commands/twitter/__tests__/cli-routing.test.ts} +130 -4
- package/src/{__tests__/twitter-oauth-client.test.ts → cli/commands/twitter/__tests__/oauth-client.test.ts} +2 -2
- package/src/{twitter → cli/commands/twitter}/client.ts +17 -7
- package/src/cli/{twitter.ts → commands/twitter/index.ts} +322 -273
- package/src/cli/commands/twitter/router.ts +396 -0
- package/src/cli/commands/twitter/session.ts +121 -0
- package/src/cli/db.ts +1 -0
- package/src/cli/http-client.ts +87 -0
- package/src/cli/logger.ts +6 -0
- package/src/cli/main-screen.tsx +4 -3
- package/src/cli/output.ts +19 -0
- package/src/cli/program.ts +29 -27
- package/src/cli/reference.ts +27 -37
- package/src/cli.ts +452 -240
- package/src/config/assistant-feature-flags.ts +3 -15
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +3 -6
- package/src/config/bundled-skills/agentmail/SKILL.md +4 -4
- package/src/config/bundled-skills/amazon/SKILL.md +15 -5
- package/src/config/bundled-skills/api-mapping/SKILL.md +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +21 -6
- package/src/config/bundled-skills/browser/SKILL.md +4 -5
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +4 -4
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +4 -4
- package/src/config/bundled-skills/cli-discover/SKILL.md +4 -4
- package/src/config/bundled-skills/computer-use/SKILL.md +4 -4
- package/src/config/bundled-skills/contacts/SKILL.md +87 -229
- package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -3
- package/src/config/bundled-skills/document-writer/SKILL.md +4 -4
- package/src/config/bundled-skills/doordash/SKILL.md +4 -11
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +8 -16
- package/src/config/bundled-skills/doordash/doordash-cli.ts +120 -86
- package/src/config/bundled-skills/doordash/lib/session.ts +1 -2
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +26 -9
- package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +140 -0
- package/src/config/bundled-skills/email-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/followups/SKILL.md +4 -3
- package/src/config/bundled-skills/frontend-design/SKILL.md +2 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +4 -4
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +4 -6
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +26 -41
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -5
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -1
- package/src/config/bundled-skills/influencer/SKILL.md +19 -19
- package/src/{influencer → config/bundled-skills/influencer/scripts}/client.ts +73 -56
- package/src/config/bundled-skills/influencer/scripts/influencer.ts +267 -0
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -2
- package/src/config/bundled-skills/macos-automation/SKILL.md +4 -5
- package/src/config/bundled-skills/mcp-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -2
- package/src/config/bundled-skills/messaging/SKILL.md +6 -33
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -5
- package/src/config/bundled-skills/notifications/SKILL.md +4 -4
- package/src/config/bundled-skills/notion/SKILL.md +4 -4
- package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +4 -5
- package/src/config/bundled-skills/oauth-setup/SKILL.md +4 -5
- package/src/config/bundled-skills/phone-calls/SKILL.md +24 -458
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +83 -0
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +57 -0
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +67 -0
- package/src/config/bundled-skills/playbooks/SKILL.md +4 -3
- package/src/config/bundled-skills/public-ingress/SKILL.md +65 -14
- package/src/config/bundled-skills/reminder/SKILL.md +4 -3
- package/src/config/bundled-skills/restaurant-reservation/SKILL.md +4 -6
- package/src/config/bundled-skills/schedule/SKILL.md +4 -3
- package/src/config/bundled-skills/screen-recording/SKILL.md +4 -3
- package/src/config/bundled-skills/self-upgrade/SKILL.md +4 -4
- package/src/config/bundled-skills/skills-catalog/SKILL.md +4 -4
- package/src/config/bundled-skills/slack/SKILL.md +4 -8
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +1 -1
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +66 -88
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +4 -5
- package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +4 -5
- package/src/config/bundled-skills/start-the-day/SKILL.md +4 -4
- package/src/config/bundled-skills/subagent/SKILL.md +4 -3
- package/src/config/bundled-skills/tasks/SKILL.md +4 -3
- package/src/config/bundled-skills/telegram-setup/SKILL.md +63 -112
- package/src/config/bundled-skills/time-based-actions/SKILL.md +4 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -3
- package/src/config/bundled-skills/twilio-setup/SKILL.md +23 -50
- package/src/config/bundled-skills/twitter/SKILL.md +56 -14
- package/src/config/bundled-skills/typescript-eval/SKILL.md +4 -4
- package/src/config/bundled-skills/vercel-token-setup/SKILL.md +4 -5
- package/src/config/bundled-skills/voice-setup/SKILL.md +19 -45
- package/src/config/bundled-skills/watcher/SKILL.md +4 -3
- package/src/config/env-registry.ts +1 -10
- package/src/config/feature-flag-registry.json +0 -16
- package/src/config/loader.ts +78 -38
- package/src/config/schema.ts +143 -106
- package/src/config/schemas/channels.ts +80 -0
- package/src/config/schemas/heartbeat.ts +51 -0
- package/src/config/schemas/inference.ts +136 -0
- package/src/config/schemas/ingress.ts +81 -0
- package/src/config/schemas/logging.ts +21 -0
- package/src/config/schemas/memory-lifecycle.ts +67 -0
- package/src/config/schemas/memory-processing.ts +215 -0
- package/src/config/schemas/memory-retrieval.ts +222 -0
- package/src/config/schemas/memory-storage.ts +83 -0
- package/src/config/schemas/memory.ts +58 -0
- package/src/config/schemas/platform.ts +64 -0
- package/src/config/schemas/security.ts +54 -0
- package/src/config/schemas/swarm.ts +50 -0
- package/src/config/schemas/timeouts.ts +47 -0
- package/src/config/{agent-schema.ts → schemas/workspace-git.ts} +0 -97
- package/src/config/skill-state.ts +3 -13
- package/src/config/skills.ts +233 -75
- package/src/config/types.ts +1 -20
- package/src/contacts/contact-store.ts +12 -49
- package/src/contacts/contacts-write.ts +1 -5
- package/src/contacts/index.ts +0 -2
- package/src/contacts/types.ts +0 -8
- package/src/context/window-manager.ts +73 -14
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/computer-use-session.ts +3 -3
- package/src/daemon/connection-policy.ts +6 -21
- package/src/daemon/context-overflow-policy.ts +1 -1
- package/src/daemon/daemon-control.ts +46 -54
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/config-channels.ts +407 -71
- package/src/daemon/handlers/config-ingress.ts +17 -85
- package/src/daemon/handlers/config-model.ts +145 -123
- package/src/daemon/handlers/config-slack-channel.ts +43 -29
- package/src/daemon/handlers/config-telegram.ts +32 -27
- package/src/daemon/handlers/config-voice.ts +1 -4
- package/src/daemon/handlers/dictation.ts +11 -16
- package/src/daemon/handlers/identity.ts +5 -6
- package/src/daemon/handlers/pairing.ts +5 -13
- package/src/daemon/handlers/recording.ts +97 -199
- package/src/daemon/handlers/session-history.ts +110 -96
- package/src/daemon/handlers/session-user-message.ts +29 -57
- package/src/daemon/handlers/sessions.ts +240 -137
- package/src/daemon/handlers/shared.ts +62 -95
- package/src/daemon/handlers/skills.ts +492 -543
- package/src/daemon/lifecycle.ts +168 -55
- package/src/daemon/main.ts +1 -0
- package/src/daemon/{ipc-contract.ts → message-protocol.ts} +49 -49
- package/src/daemon/{ipc-contract → message-types}/computer-use.ts +0 -3
- package/src/daemon/{ipc-contract → message-types}/diagnostics.ts +0 -16
- package/src/daemon/{ipc-contract → message-types}/integrations.ts +29 -13
- package/src/daemon/{ipc-contract → message-types}/memory.ts +8 -0
- package/src/daemon/{ipc-contract → message-types}/notifications.ts +15 -1
- package/src/daemon/{ipc-contract → message-types}/sessions.ts +1 -0
- package/src/daemon/{ipc-contract → message-types}/shared.ts +0 -8
- package/src/daemon/{ipc-contract → message-types}/workspace.ts +2 -2
- package/src/daemon/providers-setup.ts +0 -5
- package/src/daemon/recording-executor.ts +0 -7
- package/src/daemon/ride-shotgun-handler.ts +9 -13
- package/src/daemon/server.ts +136 -510
- package/src/daemon/session-agent-loop-handlers.ts +22 -7
- package/src/daemon/session-agent-loop.ts +86 -24
- package/src/daemon/session-attachments.ts +1 -1
- package/src/daemon/session-error.ts +1 -1
- package/src/daemon/session-history.ts +20 -15
- package/src/daemon/session-lifecycle.ts +9 -7
- package/src/daemon/session-memory.ts +15 -1
- package/src/daemon/session-messaging.ts +10 -6
- package/src/daemon/session-notifiers.ts +10 -8
- package/src/daemon/session-process.ts +34 -25
- package/src/daemon/session-queue-manager.ts +1 -1
- package/src/daemon/session-runtime-assembly.ts +6 -25
- package/src/daemon/session-surfaces.ts +2 -2
- package/src/daemon/session-tool-setup.ts +1 -1
- package/src/daemon/session-usage.ts +119 -18
- package/src/daemon/session.ts +13 -9
- package/src/daemon/tool-side-effects.ts +6 -5
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/{guardian-verification-intent.ts → verification-session-intent.ts} +16 -16
- package/src/daemon/watch-handler.ts +2 -5
- package/src/email/service.ts +8 -8
- package/src/events/domain-events.ts +0 -1
- package/src/events/tool-notification-listener.ts +1 -1
- package/src/followups/followup-store.ts +1 -2
- package/src/followups/types.ts +0 -6
- package/src/heartbeat/heartbeat-service.ts +1 -1
- package/src/inbound/platform-callback-registration.ts +1 -1
- package/src/inbound/public-ingress-urls.ts +0 -8
- package/src/index.ts +12 -0
- package/src/mcp/client.ts +1 -1
- package/src/mcp/manager.ts +1 -1
- package/src/memory/app-store.ts +1 -42
- package/src/memory/{guardian-verification.ts → channel-verification-sessions.ts} +110 -93
- package/src/memory/conversation-attention-store.ts +154 -0
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +53 -1
- package/src/memory/conversation-display-order-migration.ts +2 -3
- package/src/memory/conversation-queries.ts +1 -29
- package/src/memory/conversation-title-service.ts +26 -21
- package/src/memory/db-connection.ts +1 -8
- package/src/memory/db-init.ts +20 -0
- package/src/memory/delivery-crud.ts +4 -34
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/format-recall.ts +47 -0
- package/src/memory/guardian-action-store.ts +4 -5
- package/src/memory/guardian-rate-limits.ts +0 -3
- package/src/memory/invite-store.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +9 -2
- package/src/memory/job-handlers/extraction.ts +2 -7
- package/src/memory/job-handlers/summarization.ts +1 -1
- package/src/memory/llm-usage-store.ts +11 -0
- package/src/memory/migrations/114-notifications.ts +12 -40
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +357 -0
- package/src/memory/migrations/141-rename-verification-table.ts +55 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +32 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +48 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +147 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +30 -0
- package/src/memory/qdrant-circuit-breaker.ts +5 -0
- package/src/memory/retriever.test.ts +707 -0
- package/src/memory/retriever.ts +120 -116
- package/src/memory/schema/calls.ts +3 -7
- package/src/memory/schema/guardian.ts +2 -2
- package/src/memory/search/lexical.ts +4 -1
- package/src/memory/search/query-expansion.test.ts +70 -0
- package/src/memory/search/query-expansion.ts +118 -0
- package/src/memory/search/types.ts +18 -17
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -1
- package/src/messaging/providers/whatsapp/adapter.ts +1 -4
- package/src/messaging/registry.ts +0 -1
- package/src/notifications/README.md +13 -22
- package/src/notifications/adapters/macos.ts +1 -1
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +2 -2
- package/src/notifications/decision-engine.ts +1 -10
- package/src/notifications/destination-resolver.ts +2 -3
- package/src/notifications/emit-signal.ts +2 -8
- package/src/notifications/guardian-question-mode.ts +5 -8
- package/src/notifications/signal.ts +1 -2
- package/src/notifications/types.ts +1 -1
- package/src/oauth/token-persistence.ts +25 -1
- package/src/permissions/checker.ts +4 -29
- package/src/permissions/defaults.ts +6 -6
- package/src/permissions/prompter.ts +1 -1
- package/src/permissions/secret-prompter.ts +1 -1
- package/src/permissions/shell-identity.ts +1 -1
- package/src/permissions/trust-store.ts +13 -76
- package/src/permissions/workspace-policy.ts +1 -1
- package/src/{config → prompts}/computer-use-prompt.ts +1 -1
- package/src/{config → prompts}/system-prompt.ts +40 -21
- package/src/runtime/AGENTS.md +6 -8
- package/src/runtime/access-request-helper.ts +36 -55
- package/src/runtime/actor-trust-resolver.ts +1 -24
- package/src/runtime/approval-message-composer.ts +6 -2
- package/src/runtime/assistant-event.ts +1 -1
- package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +1 -1
- package/src/runtime/auth/__tests__/subject.test.ts +32 -0
- package/src/runtime/auth/route-policy.ts +140 -24
- package/src/runtime/auth/subject.ts +9 -0
- package/src/runtime/auth/token-service.ts +11 -0
- package/src/runtime/auth/types.ts +1 -1
- package/src/runtime/channel-approval-types.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/channel-invite-transport.ts +0 -2
- package/src/runtime/channel-invite-transports/slack.ts +5 -19
- package/src/runtime/channel-invite-transports/telegram.ts +17 -34
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +24 -159
- package/src/runtime/channel-readiness-types.ts +5 -1
- package/src/runtime/channel-reply-delivery.ts +43 -3
- package/src/runtime/channel-retry-sweep.ts +14 -22
- package/src/runtime/{channel-guardian-service.ts → channel-verification-service.ts} +50 -53
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -3
- package/src/runtime/gateway-client.ts +12 -15
- package/src/runtime/guardian-action-followup-executor.ts +8 -73
- package/src/runtime/guardian-action-grant-minter.ts +45 -61
- package/src/runtime/guardian-action-message-composer.ts +4 -4
- package/src/runtime/guardian-reply-router.ts +3 -3
- package/src/runtime/http-server.ts +133 -24
- package/src/runtime/http-types.ts +34 -1
- package/src/runtime/invite-instruction-generator.ts +1 -3
- package/src/runtime/invite-redemption-service.ts +5 -5
- package/src/runtime/invite-service.ts +7 -7
- package/src/runtime/local-actor-identity.ts +28 -2
- package/src/runtime/local-gateway-health.ts +275 -0
- package/src/runtime/middleware/twilio-validation.ts +3 -3
- package/src/runtime/migrations/migration-transport.ts +18 -3
- package/src/runtime/migrations/rebind-secrets-screen.ts +2 -2
- package/src/runtime/nl-approval-parser.ts +2 -3
- package/src/runtime/routes/access-request-decision.ts +2 -2
- package/src/runtime/routes/app-management-routes.ts +921 -0
- package/src/runtime/routes/approval-routes.ts +76 -7
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +38 -203
- package/src/runtime/routes/channel-delivery-routes.ts +5 -4
- package/src/runtime/routes/channel-route-shared.ts +1 -3
- package/src/runtime/routes/channel-routes.ts +1 -4
- package/src/runtime/routes/channel-verification-routes.ts +257 -0
- package/src/runtime/routes/computer-use-routes.ts +595 -0
- package/src/runtime/routes/contact-routes.ts +1 -317
- package/src/runtime/routes/conversation-attention-routes.ts +6 -5
- package/src/runtime/routes/conversation-routes.ts +11 -18
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +813 -0
- package/src/runtime/routes/documents-routes.ts +227 -0
- package/src/runtime/routes/guardian-approval-interception.ts +25 -48
- package/src/runtime/routes/guardian-bootstrap-routes.ts +3 -3
- package/src/runtime/routes/guardian-expiry-sweep.ts +2 -2
- package/src/runtime/routes/guardian-refresh-routes.ts +11 -6
- package/src/runtime/routes/inbound-conversation.ts +3 -10
- package/src/runtime/routes/inbound-message-handler.ts +7 -6
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +22 -22
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +44 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +140 -22
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +4 -4
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +3 -3
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +13 -14
- package/src/runtime/routes/integrations/slack/channel.ts +72 -0
- package/src/runtime/routes/{slack-share-routes.ts → integrations/slack/share.ts} +9 -9
- package/src/runtime/routes/integrations/telegram.ts +111 -0
- package/src/runtime/routes/integrations/twilio.ts +451 -0
- package/src/runtime/routes/invite-routes.ts +2 -2
- package/src/runtime/routes/pairing-routes.ts +1 -1
- package/src/runtime/routes/recording-routes.ts +332 -0
- package/src/{daemon/handlers/config-scheduling.ts → runtime/routes/schedule-routes.ts} +91 -106
- package/src/runtime/routes/session-management-routes.ts +167 -0
- package/src/runtime/routes/session-query-routes.ts +204 -0
- package/src/runtime/routes/settings-routes.ts +977 -0
- package/src/runtime/routes/skills-routes.ts +266 -0
- package/src/runtime/routes/subagents-routes.ts +246 -0
- package/src/runtime/routes/surface-action-routes.ts +100 -10
- package/src/runtime/routes/surface-content-routes.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +809 -0
- package/src/runtime/routes/workspace-routes.test.ts +778 -0
- package/src/runtime/routes/workspace-routes.ts +410 -0
- package/src/runtime/routes/workspace-utils.ts +88 -0
- package/src/runtime/telegram-streaming-delivery.test.ts +597 -0
- package/src/runtime/telegram-streaming-delivery.ts +380 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -2
- package/src/runtime/trust-context-resolver.ts +0 -1
- package/src/runtime/{guardian-outbound-actions.ts → verification-outbound-actions.ts} +23 -188
- package/src/runtime/verification-rate-limiter.ts +2 -2
- package/src/runtime/{guardian-verification-templates.ts → verification-templates.ts} +2 -28
- package/src/schedule/integration-status.ts +2 -2
- package/src/schedule/schedule-store.ts +7 -9
- package/src/sequence/engine.ts +1 -1
- package/src/skills/active-skill-tools.ts +0 -8
- package/src/skills/clawhub.ts +1 -10
- package/src/skills/managed-store.ts +14 -4
- package/src/skills/slash-commands.ts +1 -1
- package/src/subagent/manager.ts +1 -1
- package/src/subagent/types.ts +1 -1
- package/src/tasks/SPEC.md +10 -10
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/telegram/bot-username.ts +13 -0
- package/src/tools/assets/materialize.ts +1 -1
- package/src/tools/assets/search.ts +1 -1
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/browser-manager.ts +88 -11
- package/src/tools/browser/browser-screencast.ts +1 -1
- package/src/tools/browser/headless-browser.ts +0 -17
- package/src/tools/browser/jit-auth.ts +1 -1
- package/src/tools/browser/recording-store.ts +19 -1
- package/src/tools/browser/runtime-check.ts +4 -2
- package/src/tools/calls/call-start.ts +3 -3
- package/src/tools/credentials/metadata-store.ts +0 -13
- package/src/tools/credentials/vault.ts +7 -31
- package/src/tools/followups/followup_create.ts +0 -8
- package/src/tools/mcp/mcp-tool-factory.ts +1 -1
- package/src/tools/memory/definitions.ts +32 -10
- package/src/tools/memory/handlers.test.ts +573 -0
- package/src/tools/memory/handlers.ts +222 -65
- package/src/tools/memory/register.ts +53 -24
- package/src/tools/network/script-proxy/session-manager.ts +1 -12
- package/src/tools/schedule/update.ts +0 -8
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/system/voice-config.ts +2 -14
- package/src/tools/terminal/safe-env.ts +5 -18
- package/src/tools/tool-approval-handler.ts +4 -4
- package/src/tools/tool-manifest.ts +4 -2
- package/src/tools/types.ts +1 -1
- package/src/tools/{guardian-control-plane-policy.ts → verification-control-plane-policy.ts} +37 -39
- package/src/twitter/platform-proxy-client.ts +405 -0
- package/src/usage/types.ts +21 -0
- package/src/util/canonicalize-identity.ts +2 -6
- package/src/util/cookie-session.ts +35 -51
- package/src/util/platform.ts +93 -86
- package/src/util/pricing.ts +180 -43
- package/src/work-items/work-item-runner.ts +1 -1
- package/scripts/ipc/check-contract-inventory.ts +0 -107
- package/scripts/ipc/check-swift-decoder-drift.ts +0 -184
- package/scripts/ipc/generate-swift.ts +0 -528
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -3043
- package/src/__tests__/app-migration.test.ts +0 -148
- package/src/__tests__/config-loader-migration.test.ts +0 -85
- package/src/__tests__/daemon-lifecycle.test.ts +0 -715
- package/src/__tests__/daemon-server-session-init.test.ts +0 -864
- package/src/__tests__/guardian-actions-endpoint.test.ts +0 -1452
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +0 -228
- package/src/__tests__/handlers-cu-observation-blob.test.ts +0 -397
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +0 -218
- package/src/__tests__/handlers-slack-config.test.ts +0 -140
- package/src/__tests__/handlers-telegram-config.test.ts +0 -1317
- package/src/__tests__/handlers-twitter-config.test.ts +0 -1145
- package/src/__tests__/ingress-reconcile.test.ts +0 -606
- package/src/__tests__/integrations-cli.test.ts +0 -232
- package/src/__tests__/ipc-blob-store.test.ts +0 -329
- package/src/__tests__/ipc-contract-inventory.test.ts +0 -69
- package/src/__tests__/ipc-contract.test.ts +0 -76
- package/src/__tests__/ipc-protocol.test.ts +0 -120
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +0 -250
- package/src/__tests__/ipc-snapshot.test.ts +0 -2197
- package/src/__tests__/ipc-validate.test.ts +0 -471
- package/src/__tests__/migration-cli-flows.test.ts +0 -186
- package/src/__tests__/migration-ordering.test.ts +0 -267
- package/src/__tests__/oauth-connect-handler.test.ts +0 -361
- package/src/__tests__/platform-move-helper.test.ts +0 -108
- package/src/__tests__/platform-socket-path.test.ts +0 -52
- package/src/__tests__/platform-workspace-migration.test.ts +0 -1051
- package/src/__tests__/recording-intent-handler.test.ts +0 -1155
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +0 -127
- package/src/__tests__/sms-messaging-provider.test.ts +0 -156
- package/src/__tests__/tool-permission-simulate-handler.test.ts +0 -367
- package/src/__tests__/twitter-auth-handler.test.ts +0 -561
- package/src/__tests__/work-item-output.test.ts +0 -150
- package/src/amazon/session.ts +0 -58
- package/src/cli/channels.ts +0 -51
- package/src/cli/influencer.ts +0 -319
- package/src/cli/integrations.ts +0 -372
- package/src/cli/ipc-client.ts +0 -88
- package/src/config/bundled-skills/configure-settings/SKILL.md +0 -86
- package/src/config/bundled-skills/doordash/lib/shared/ipc.ts +0 -32
- package/src/config/bundled-skills/sms-setup/SKILL.md +0 -210
- package/src/config/core-schema.ts +0 -434
- package/src/config/memory-schema.ts +0 -617
- package/src/daemon/auth-manager.ts +0 -106
- package/src/daemon/handlers/apps.ts +0 -758
- package/src/daemon/handlers/avatar.ts +0 -73
- package/src/daemon/handlers/browser.ts +0 -3
- package/src/daemon/handlers/computer-use.ts +0 -231
- package/src/daemon/handlers/config-dispatch.ts +0 -29
- package/src/daemon/handlers/config-heartbeat.ts +0 -299
- package/src/daemon/handlers/config-inbox.ts +0 -457
- package/src/daemon/handlers/config-integrations.ts +0 -409
- package/src/daemon/handlers/config-platform.ts +0 -77
- package/src/daemon/handlers/config-slack.ts +0 -41
- package/src/daemon/handlers/config-tools.ts +0 -226
- package/src/daemon/handlers/config-trust.ts +0 -135
- package/src/daemon/handlers/config.ts +0 -64
- package/src/daemon/handlers/contacts.ts +0 -193
- package/src/daemon/handlers/diagnostics.ts +0 -382
- package/src/daemon/handlers/documents.ts +0 -188
- package/src/daemon/handlers/guardian-actions.ts +0 -82
- package/src/daemon/handlers/home-base.ts +0 -82
- package/src/daemon/handlers/index.ts +0 -222
- package/src/daemon/handlers/misc.ts +0 -1139
- package/src/daemon/handlers/navigate-settings.ts +0 -29
- package/src/daemon/handlers/oauth-connect.ts +0 -202
- package/src/daemon/handlers/open-bundle-handler.ts +0 -88
- package/src/daemon/handlers/publish.ts +0 -176
- package/src/daemon/handlers/signing.ts +0 -56
- package/src/daemon/handlers/subagents.ts +0 -286
- package/src/daemon/handlers/twitter-auth.ts +0 -220
- package/src/daemon/handlers/work-items.ts +0 -796
- package/src/daemon/handlers/workspace-files.ts +0 -84
- package/src/daemon/handlers.ts +0 -16
- package/src/daemon/ipc-blob-store.ts +0 -246
- package/src/daemon/ipc-contract-inventory.json +0 -348
- package/src/daemon/ipc-contract-inventory.ts +0 -202
- package/src/daemon/ipc-handler.ts +0 -120
- package/src/daemon/ipc-protocol.ts +0 -85
- package/src/daemon/ipc-validate.ts +0 -254
- package/src/memory/app-migration.ts +0 -114
- package/src/memory/channel-delivery-store.ts +0 -40
- package/src/memory/channel-guardian-store.ts +0 -83
- package/src/memory/conversation-store.ts +0 -102
- package/src/memory/schema-migration.ts +0 -38
- package/src/messaging/providers/sms/adapter.ts +0 -232
- package/src/messaging/providers/sms/client.ts +0 -93
- package/src/messaging/providers/sms/types.ts +0 -7
- package/src/migrations/config-merge.ts +0 -62
- package/src/migrations/data-layout.ts +0 -89
- package/src/migrations/data-merge.ts +0 -44
- package/src/migrations/hooks-merge.ts +0 -118
- package/src/migrations/index.ts +0 -6
- package/src/migrations/log.ts +0 -28
- package/src/migrations/skills-merge.ts +0 -44
- package/src/migrations/workspace-layout.ts +0 -94
- package/src/notifications/adapters/sms.ts +0 -94
- package/src/runtime/channel-approval-parser.ts +0 -123
- package/src/runtime/channel-invite-transports/sms.ts +0 -53
- package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +0 -82
- package/src/runtime/routes/integration-routes.ts +0 -381
- package/src/runtime/routes/twilio-routes.ts +0 -1251
- package/src/twitter/router.ts +0 -131
- package/src/twitter/session.ts +0 -54
- package/src/watcher/providers/slack.ts +0 -282
- /package/src/{amazon → cli/commands/amazon}/cart.ts +0 -0
- /package/src/{amazon → cli/commands/amazon}/checkout.ts +0 -0
- /package/src/{amazon → cli/commands/amazon}/product-details.ts +0 -0
- /package/src/{amazon → cli/commands/amazon}/search.ts +0 -0
- /package/src/{twitter → cli/commands/twitter}/oauth-client.ts +0 -0
- /package/src/config/{calls-schema.ts → schemas/calls.ts} +0 -0
- /package/src/config/{elevenlabs-schema.ts → schemas/elevenlabs.ts} +0 -0
- /package/src/config/{mcp-schema.ts → schemas/mcp.ts} +0 -0
- /package/src/config/{notifications-schema.ts → schemas/notifications.ts} +0 -0
- /package/src/config/{sandbox-schema.ts → schemas/sandbox.ts} +0 -0
- /package/src/config/{skills-schema.ts → schemas/skills.ts} +0 -0
- /package/src/daemon/{ipc-contract → message-types}/apps.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/browser.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/contacts.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/documents.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/guardian-actions.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/inbox.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/messages.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/pairing.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/schedules.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/settings.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/skills.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/subagents.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/surfaces.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/trust.ts +0 -0
- /package/src/daemon/{ipc-contract → message-types}/work-items.ts +0 -0
- /package/src/{cli/email-guardrails.ts → email/guardrails.ts} +0 -0
- /package/src/{config → prompts}/__tests__/build-cli-reference-section.test.ts +0 -0
- /package/src/{config → prompts}/templates/BOOTSTRAP.md +0 -0
- /package/src/{config → prompts}/templates/IDENTITY.md +0 -0
- /package/src/{config → prompts}/templates/SOUL.md +0 -0
- /package/src/{config → prompts}/templates/UPDATES.md +0 -0
- /package/src/{config → prompts}/templates/USER.md +0 -0
- /package/src/{config → prompts}/update-bulletin-format.ts +0 -0
- /package/src/{config → prompts}/update-bulletin-state.ts +0 -0
- /package/src/{config → prompts}/update-bulletin-template-path.ts +0 -0
- /package/src/{config → prompts}/update-bulletin.ts +0 -0
- /package/src/{config → prompts}/user-reference.ts +0 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -4,7 +4,7 @@ This document owns assistant-runtime architecture details. The repo-level archit
|
|
|
4
4
|
|
|
5
5
|
### Channel Onboarding Playbook Bootstrap
|
|
6
6
|
|
|
7
|
-
- Transport metadata arrives via `session_create.transport` (
|
|
7
|
+
- Transport metadata arrives via `session_create.transport` (HTTP) or `/channels/inbound` (`channelId`, optional `hints`, optional `uxBrief`).
|
|
8
8
|
- Telegram webhook ingress now injects deterministic channel-safe transport metadata (`hints` + `uxBrief`) so non-dashboard channels defer Home Base-only UI tasks cleanly.
|
|
9
9
|
- `OnboardingPlaybookManager` resolves `<channel>_onboarding.md`, checks `onboarding/playbooks/registry.json`, and applies per-channel first-time fast-path onboarding.
|
|
10
10
|
- `OnboardingOrchestrator` derives onboarding-mode guidance (post-hatch sequence, USER.md capture, Home Base handoff) from playbook + transport context.
|
|
@@ -16,7 +16,7 @@ This document owns assistant-runtime architecture details. The repo-level archit
|
|
|
16
16
|
|
|
17
17
|
- Guardian/non-guardian/unverified classification is centralized in `assistant/src/runtime/trust-context-resolver.ts`.
|
|
18
18
|
- The same resolver is used by:
|
|
19
|
-
- `/channels/inbound` (Telegram/
|
|
19
|
+
- `/channels/inbound` (Telegram/WhatsApp path) before run orchestration.
|
|
20
20
|
- Inbound Twilio voice setup (`RelayConnection.handleSetup`) to seed call-time actor context.
|
|
21
21
|
- Runtime channel runs pass this as `trustContext`, and session runtime assembly injects `<inbound_actor_context>` (via `inboundActorContextFromTrustContext()`) into provider-facing prompts.
|
|
22
22
|
- Voice calls mirror the same prompt contract: `CallController` receives guardian context on setup and refreshes it immediately after successful voice challenge verification, so the first post-verification turn is grounded as `actor_role: guardian`.
|
|
@@ -41,12 +41,12 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
41
41
|
|
|
42
42
|
**Subject patterns:**
|
|
43
43
|
|
|
44
|
-
| Pattern | Principal Type | Description
|
|
45
|
-
| ---------------------------------------- | -------------- |
|
|
46
|
-
| `actor:<assistantId>:<actorPrincipalId>` | `actor` | Desktop, iOS, or CLI client
|
|
47
|
-
| `svc:gateway:<assistantId>` | `svc_gateway` | Gateway service (ingress, webhooks)
|
|
48
|
-
| `
|
|
49
|
-
| `svc:daemon
|
|
44
|
+
| Pattern | Principal Type | Description |
|
|
45
|
+
| ---------------------------------------- | -------------- | ------------------------------------------- |
|
|
46
|
+
| `actor:<assistantId>:<actorPrincipalId>` | `actor` | Desktop, iOS, or CLI client |
|
|
47
|
+
| `svc:gateway:<assistantId>` | `svc_gateway` | Gateway service (ingress, webhooks) |
|
|
48
|
+
| `svc:internal:<assistantId>:<sessionId>` | `svc_internal` | Internal service connections |
|
|
49
|
+
| `svc:daemon:<identifier>` | `svc_daemon` | Daemon service token (CLI bootstrap, local) |
|
|
50
50
|
|
|
51
51
|
**Scope profiles:**
|
|
52
52
|
|
|
@@ -55,17 +55,17 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
55
55
|
| `actor_client_v1` | `chat.{read,write}`, `approval.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `calls.{read,write}`, `feature_flags.{read,write}` | Desktop, iOS, CLI clients |
|
|
56
56
|
| `gateway_ingress_v1` | `ingress.write`, `internal.write` | Gateway channel inbound + webhook forwarding |
|
|
57
57
|
| `gateway_service_v1` | `settings.read`, `settings.write`, `internal.write` | Gateway service-to-daemon calls |
|
|
58
|
-
| `
|
|
58
|
+
| `internal_v1` | `internal.all` | Internal service connections |
|
|
59
59
|
|
|
60
60
|
**Identity lifecycle:**
|
|
61
61
|
|
|
62
|
-
1. **Bootstrap (loopback-only, macOS/CLI)** — On first launch, the client calls `POST /v1/
|
|
62
|
+
1. **Bootstrap (loopback-only, macOS/CLI)** — On first launch, the client calls `POST /v1/guardian/init` with `{ platform, deviceId }`. The endpoint is loopback-only and mints a JWT access token + refresh token pair. Returns `{ guardianPrincipalId, accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, refreshAfter, isNew }`.
|
|
63
63
|
|
|
64
64
|
2. **iOS pairing** — iOS devices obtain JWTs through the QR pairing flow. The pairing response includes `accessToken` and `refreshToken` credentials.
|
|
65
65
|
|
|
66
|
-
3. **Refresh** — `POST /v1/
|
|
66
|
+
3. **Refresh** — `POST /v1/guardian/refresh` accepts `{ refreshToken }` and returns a new access/refresh token pair. Single-use rotation with replay detection and family-based revocation.
|
|
67
67
|
|
|
68
|
-
4. **
|
|
68
|
+
4. **Local identity** — Local connections use deterministic identity resolution without tokens.
|
|
69
69
|
|
|
70
70
|
**Route policy enforcement:** Every protected endpoint declares required scopes and allowed principal types in `src/runtime/auth/route-policy.ts`. The `enforcePolicy()` function checks the AuthContext against these requirements and returns 403 when access is denied. A guard test ensures every dispatched endpoint has a corresponding policy entry.
|
|
71
71
|
|
|
@@ -85,11 +85,11 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
85
85
|
| `src/runtime/auth/subject.ts` | Subject string parser (`parseSub`) |
|
|
86
86
|
| `src/runtime/auth/middleware.ts` | JWT bearer auth middleware (`authenticateRequest`) |
|
|
87
87
|
| `src/runtime/auth/route-policy.ts` | Route-level scope/principal enforcement |
|
|
88
|
-
| `src/runtime/routes/guardian-bootstrap-routes.ts` | `POST /v1/
|
|
89
|
-
| `src/runtime/routes/guardian-refresh-routes.ts` | `POST /v1/
|
|
88
|
+
| `src/runtime/routes/guardian-bootstrap-routes.ts` | `POST /v1/guardian/init` (initial JWT issuance) |
|
|
89
|
+
| `src/runtime/routes/guardian-refresh-routes.ts` | `POST /v1/guardian/refresh` (token rotation) |
|
|
90
90
|
| `src/runtime/routes/pairing-routes.ts` | JWT credential issuance in pairing flow |
|
|
91
|
-
| `src/runtime/local-actor-identity.ts` | `
|
|
92
|
-
| `src/memory/channel-
|
|
91
|
+
| `src/runtime/local-actor-identity.ts` | `resolveLocalGuardianContext` — deterministic local identity |
|
|
92
|
+
| `src/memory/channel-verification-sessions.ts` | Guardian binding types, verification session management |
|
|
93
93
|
|
|
94
94
|
### Channel-Agnostic Scoped Approval Grants
|
|
95
95
|
|
|
@@ -97,7 +97,7 @@ Scoped approval grants allow a guardian's approval decision on one channel (e.g.
|
|
|
97
97
|
|
|
98
98
|
### Guardian Decision Primitive (Dual-Mode Approval)
|
|
99
99
|
|
|
100
|
-
All guardian approval decisions — regardless of how they arrive — route through a single unified primitive in `src/approvals/guardian-decision-primitive.ts`. This centralizes decision logic that was previously duplicated across callback button handlers, the conversational approval engine,
|
|
100
|
+
All guardian approval decisions — regardless of how they arrive — route through a single unified primitive in `src/approvals/guardian-decision-primitive.ts`. This centralizes decision logic that was previously duplicated across callback button handlers, the conversational approval engine, and the requester self-cancel path.
|
|
101
101
|
|
|
102
102
|
**Core API:**
|
|
103
103
|
|
|
@@ -113,12 +113,12 @@ All guardian approval decisions — regardless of how they arrive — route thro
|
|
|
113
113
|
- `approve_always` is downgraded to `approve_once` for guardian-on-behalf requests (guardians cannot permanently allowlist tools for requesters).
|
|
114
114
|
- Scoped grant minting only fires on explicit approve for requests with tool metadata.
|
|
115
115
|
|
|
116
|
-
**Unified interaction model — buttons first, text fallback:** All guardian approval prompts follow a canonical "buttons first, text fallback" pattern. Structured button UIs are the primary interaction surface, but every prompt also carries deterministic text fallback instructions so guardians can always act even when buttons are unavailable or not used. This applies uniformly across all request kinds (`tool_approval`, `pending_question`, `access_request`) and all channels (macOS desktop, Telegram,
|
|
116
|
+
**Unified interaction model — buttons first, text fallback:** All guardian approval prompts follow a canonical "buttons first, text fallback" pattern. Structured button UIs are the primary interaction surface, but every prompt also carries deterministic text fallback instructions so guardians can always act even when buttons are unavailable or not used. This applies uniformly across all request kinds (`tool_approval`, `pending_question`, `access_request`) and all channels (macOS desktop, Telegram, WhatsApp).
|
|
117
117
|
|
|
118
118
|
**Button-first path (deterministic):**
|
|
119
119
|
|
|
120
120
|
- Desktop clients (macOS/iOS) render `GuardianDecisionPrompt` objects as tappable card UIs with kind-aware headers and action buttons. The `GuardianDecisionBubble` renders distinct headers for each kind: "Tool Approval Required", "Question Pending", or "Access Request".
|
|
121
|
-
- Desktop clients submit decisions via HTTP (`POST /v1/guardian-actions/decision`)
|
|
121
|
+
- Desktop clients submit decisions via HTTP (`POST /v1/guardian-actions/decision`), routed through `applyCanonicalGuardianDecision`.
|
|
122
122
|
- Channel adapters (Telegram inline keyboards, WhatsApp) encode actions as callback data (`apr:<requestId>:<action>`).
|
|
123
123
|
|
|
124
124
|
**Text fallback path (always available):**
|
|
@@ -137,8 +137,6 @@ All guardian approval decisions — regardless of how they arrive — route thro
|
|
|
137
137
|
| `src/approvals/guardian-decision-primitive.ts` | Unified decision application: downgrade, approval info capture, `handleChannelDecision`, record update, grant minting |
|
|
138
138
|
| `src/runtime/guardian-decision-types.ts` | Shared types: `GuardianDecisionPrompt`, `GuardianDecisionAction`, `buildDecisionActions`, `buildPlainTextFallback`, `ApplyGuardianDecisionResult` |
|
|
139
139
|
| `src/runtime/routes/guardian-action-routes.ts` | HTTP route handlers for `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` |
|
|
140
|
-
| `src/daemon/handlers/guardian-actions.ts` | IPC handlers wrapping the same logic for desktop socket clients |
|
|
141
|
-
| `src/daemon/ipc-contract/guardian-actions.ts` | IPC message type definitions for guardian action requests/responses |
|
|
142
140
|
| `src/runtime/channel-approval-types.ts` | Channel-facing approval action types and `toApprovalActionOptions` bridge |
|
|
143
141
|
|
|
144
142
|
### Temporary Approval Modes (Session-Scoped Overrides)
|
|
@@ -167,17 +165,17 @@ In addition to persistent trust rules (`always_allow` / `always_deny`), the appr
|
|
|
167
165
|
|
|
168
166
|
### Canonical Guardian Request System
|
|
169
167
|
|
|
170
|
-
The canonical guardian request system provides a channel-agnostic, unified domain for all guardian approval and question flows. It replaces the fragmented per-channel storage with a single source of truth that works identically for voice calls, Telegram/
|
|
168
|
+
The canonical guardian request system provides a channel-agnostic, unified domain for all guardian approval and question flows. It replaces the fragmented per-channel storage with a single source of truth that works identically for voice calls, Telegram/WhatsApp, and desktop UI.
|
|
171
169
|
|
|
172
170
|
**Architecture layers:**
|
|
173
171
|
|
|
174
172
|
1. **Canonical domain (single source of truth):** All guardian requests — tool approvals, pending questions, access requests — are persisted in the `canonical_guardian_requests` table (`src/memory/canonical-guardian-store.js`). Each request has a unique ID, a short human-readable request code, and a status that follows a CAS (compare-and-swap) lifecycle: `pending` -> `approved` | `denied` | `expired` | `cancelled`. Deliveries (notifications sent to guardians) are tracked in `canonical_guardian_deliveries`.
|
|
175
173
|
|
|
176
|
-
2. **Unified apply primitive (single write path):** `applyCanonicalGuardianDecision()` in `src/approvals/guardian-decision-primitive.ts` is the single write path for all guardian decisions. It enforces identity validation, expiry checks, CAS resolution, `approve_always` downgrade (guardian-on-behalf invariant), kind-specific resolver dispatch via the resolver registry, and scoped grant minting. All callers — HTTP API,
|
|
174
|
+
2. **Unified apply primitive (single write path):** `applyCanonicalGuardianDecision()` in `src/approvals/guardian-decision-primitive.ts` is the single write path for all guardian decisions. It enforces identity validation, expiry checks, CAS resolution, `approve_always` downgrade (guardian-on-behalf invariant), kind-specific resolver dispatch via the resolver registry, and scoped grant minting. All callers — HTTP API, inbound channel router, desktop session — route decisions through this function.
|
|
177
175
|
|
|
178
176
|
3. **Shared reply router (priority-ordered routing):** `routeGuardianReply()` in `src/runtime/guardian-reply-router.ts` provides a single entry point for all inbound guardian reply processing across channels. It routes through a priority-ordered pipeline: (a) deterministic callback parsing (button presses with `apr:<requestId>:<action>`), (b) request code parsing (6-char alphanumeric prefix), (c) NL classification via the conversational approval engine. All decisions flow through `applyCanonicalGuardianDecision`.
|
|
179
177
|
|
|
180
|
-
4. **Deterministic API (prompt listing and decision endpoints):** Desktop clients and API consumers use `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` (HTTP)
|
|
178
|
+
4. **Deterministic API (prompt listing and decision endpoints):** Desktop clients and API consumers use `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` (HTTP). These endpoints surface canonical requests alongside legacy pending interactions and channel approval records, with deduplication to avoid double-rendering.
|
|
181
179
|
|
|
182
180
|
5. **Buttons first, text fallback:** All request kinds (`tool_approval`, `pending_question`, `access_request`) are rendered as structured button cards when displayed in macOS/iOS guardian threads. Each prompt also embeds deterministic text fallback instructions (request-code-based approve/reject directives, and for `access_request` the "open invite flow" phrase) so text-based channels and manual fallback always work. Code-only messages (just a request code without decision text) return clarification instead of auto-approving. Disambiguation with multiple pending requests stays fail-closed — no auto-resolve when the target is ambiguous.
|
|
183
181
|
|
|
@@ -198,51 +196,51 @@ The canonical guardian request system provides a channel-agnostic, unified domai
|
|
|
198
196
|
| `src/approvals/guardian-request-resolvers.ts` | Resolver registry: kind-specific side-effect dispatch after CAS resolution |
|
|
199
197
|
| `src/runtime/guardian-reply-router.ts` | Shared inbound router: callback -> code -> NL classification pipeline |
|
|
200
198
|
| `src/runtime/routes/guardian-action-routes.ts` | HTTP endpoints for prompt listing and decision submission |
|
|
201
|
-
| `src/daemon/handlers/guardian-actions.ts` | IPC handlers for desktop socket clients |
|
|
202
199
|
| `src/runtime/routes/canonical-guardian-expiry-sweep.ts` | Canonical request expiry sweep |
|
|
203
200
|
|
|
204
|
-
### Outbound
|
|
201
|
+
### Outbound Channel Verification (HTTP Endpoints)
|
|
205
202
|
|
|
206
|
-
|
|
203
|
+
Channel verification is initiated through gateway HTTP endpoints (which forward to runtime handlers). This enables chat-first verification where the assistant guides the user through channel verification setup via normal conversation.
|
|
207
204
|
|
|
208
205
|
**HTTP Endpoints:**
|
|
209
206
|
|
|
210
|
-
| Endpoint
|
|
211
|
-
|
|
|
212
|
-
| `/v1/
|
|
213
|
-
| `/v1/
|
|
214
|
-
| `/v1/
|
|
207
|
+
| Endpoint | Method | Description |
|
|
208
|
+
| ------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
209
|
+
| `/v1/channel-verification-sessions` | POST | Create a verification session. If `destination` is provided, starts outbound verification; if `purpose: "trusted_contact"` with `contactChannelId`, starts trusted contact verification; otherwise creates an inbound challenge. Body: `{ channel?, destination?, rebind?, purpose?, contactChannelId? }` |
|
|
210
|
+
| `/v1/channel-verification-sessions/resend` | POST | Resend the verification code for an active outbound session. Body: `{ channel }` |
|
|
211
|
+
| `/v1/channel-verification-sessions` | DELETE | Cancel all active sessions (inbound + outbound) for a channel. Body: `{ channel }` |
|
|
212
|
+
| `/v1/channel-verification-sessions/revoke` | POST | Cancel all active sessions and revoke the guardian binding. Body: `{ channel? }` |
|
|
213
|
+
| `/v1/channel-verification-sessions/status` | GET | Check guardian binding status. Query: `?channel=<channel>` |
|
|
215
214
|
|
|
216
215
|
All endpoints are JWT-authenticated via `Authorization: Bearer <jwt>`. Skills and user-facing tooling should target the gateway URL (default `http://localhost:7830`), not the runtime port.
|
|
217
216
|
|
|
218
217
|
**Shared Business Logic:**
|
|
219
218
|
|
|
220
|
-
The HTTP route handlers (`
|
|
219
|
+
The HTTP route handlers (`channel-verification-routes.ts`) delegate to action functions in `verification-outbound-actions.ts`. This module contains transport-agnostic business logic for starting, resending, and cancelling outbound verification flows across Telegram and voice channels. It returns `OutboundActionResult` objects that the transport layer maps to the HTTP response format.
|
|
221
220
|
|
|
222
221
|
**Chat-First Orchestration Flow:**
|
|
223
222
|
|
|
224
|
-
1. The user asks the assistant (via desktop chat) to set up
|
|
225
|
-
2. The conversational routing layer detects the
|
|
223
|
+
1. The user asks the assistant (via desktop chat) to set up channel verification.
|
|
224
|
+
2. The conversational routing layer detects the verification-setup intent and loads the `guardian-verify-setup` skill via `skill_load`.
|
|
226
225
|
3. The skill guides the assistant through collecting the channel and destination, then calls the outbound HTTP endpoints using `curl`.
|
|
227
226
|
4. The assistant relays verification status (code sent, resend available, expiry) back to the user conversationally.
|
|
228
|
-
5. On the channel side, the verification code arrives (
|
|
227
|
+
5. On the channel side, the verification code arrives (Telegram message or voice call) and the recipient enters it to complete the binding.
|
|
229
228
|
|
|
230
229
|
**Key Source Files:**
|
|
231
230
|
|
|
232
|
-
| File | Purpose
|
|
233
|
-
| ---------------------------------------------------------- |
|
|
234
|
-
| `src/runtime/
|
|
235
|
-
| `src/runtime/routes/
|
|
236
|
-
| `src/
|
|
237
|
-
| `src/config/bundled-skills/guardian-verify-setup/SKILL.md` | Skill that teaches the assistant how to orchestrate guardian verification via chat |
|
|
231
|
+
| File | Purpose |
|
|
232
|
+
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
233
|
+
| `src/runtime/verification-outbound-actions.ts` | Shared business logic for start/resend/cancel outbound verification |
|
|
234
|
+
| `src/runtime/routes/channel-verification-routes.ts` | HTTP route handlers for unified verification session API (`/v1/channel-verification-sessions`, `/revoke`, `/status`) |
|
|
235
|
+
| `src/config/bundled-skills/guardian-verify-setup/SKILL.md` | Skill that teaches the assistant how to orchestrate channel verification via chat |
|
|
238
236
|
|
|
239
237
|
**Guardian-Only Tool Invocation Gate:**
|
|
240
238
|
|
|
241
|
-
|
|
239
|
+
Channel verification control-plane endpoints (`/v1/channel-verification-sessions/*`) are protected by a deterministic gate in the tool executor (`src/tools/executor.ts`). Before any tool invocation proceeds, the executor checks whether the invocation targets a guardian control-plane endpoint and whether the actor role is allowed. The policy uses an allowlist: only `guardian` and `undefined` (desktop/trusted) actor roles can invoke these endpoints. Non-guardian and unverified-channel actors receive a denial message explaining the restriction.
|
|
242
240
|
|
|
243
|
-
The policy is implemented in `src/tools/
|
|
241
|
+
The policy is implemented in `src/tools/verification-control-plane-policy.ts`, which inspects tool inputs (bash commands, URLs) for verification endpoint paths. This is a defense-in-depth measure — even if the LLM attempts to call verification endpoints on behalf of a non-guardian actor, the tool executor blocks it deterministically.
|
|
244
242
|
|
|
245
|
-
The `guardian-verify-setup` skill is the exclusive handler for
|
|
243
|
+
The `guardian-verify-setup` skill is the exclusive handler for channel verification intents in the system prompt. Other skills (e.g., `phone-calls`) hand off to `guardian-verify-setup` rather than orchestrating verification directly.
|
|
246
244
|
|
|
247
245
|
### Guardian Action Timeout-to-Follow-Up Lifecycle
|
|
248
246
|
|
|
@@ -278,7 +276,7 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
|
|
|
278
276
|
|
|
279
277
|
**Generated messaging requirement:** All user-facing copy in the guardian timeout/follow-up path is generated through the `guardian-action-message-composer.ts` composition system, which uses a 2-tier priority chain: (1) daemon-injected LLM generator for natural, varied text; (2) deterministic fallback templates for reliability. No hardcoded user-facing strings exist in the flow files (call-controller, inbound-message-handler, session-process) outside of internal log messages and LLM-instruction prompts. A guard test (`guardian-action-no-hardcoded-copy.test.ts`) enforces this invariant.
|
|
280
278
|
|
|
281
|
-
**Callback
|
|
279
|
+
**Callback branch:** When the conversation engine classifies the guardian's intent as `call_back`, the executor starts an outbound call to the counterparty with context about the guardian's answer. The counterparty phone number is resolved from the original call session by call direction (inbound: `fromNumber`; outbound: `toNumber`).
|
|
282
280
|
|
|
283
281
|
**Key source files:**
|
|
284
282
|
|
|
@@ -286,55 +284,18 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
|
|
|
286
284
|
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
287
285
|
| `src/memory/guardian-action-store.ts` | Follow-up state machine with atomic transitions (`startFollowupFromExpiredRequest`, `progressFollowupState`, `finalizeFollowup`) and query helpers for pending/expired/follow-up deliveries |
|
|
288
286
|
| `src/runtime/guardian-action-message-composer.ts` | 2-tier text generation: daemon-injected LLM generator with deterministic fallback templates. Covers all scenarios from timeout acknowledgment through follow-up completion |
|
|
289
|
-
| `src/runtime/guardian-action-conversation-turn.ts` | Follow-up decision engine: classifies guardian replies into `call_back`, `
|
|
290
|
-
| `src/runtime/guardian-action-followup-executor.ts` | Action dispatch: resolves counterparty from call session, executes `
|
|
287
|
+
| `src/runtime/guardian-action-conversation-turn.ts` | Follow-up decision engine: classifies guardian replies into `call_back`, `decline`, or `keep_pending` dispositions using LLM tool calling |
|
|
288
|
+
| `src/runtime/guardian-action-followup-executor.ts` | Action dispatch: resolves counterparty from call session, executes `call_back` (outbound call via `startCall`), finalizes follow-up state |
|
|
291
289
|
| `src/daemon/guardian-action-generators.ts` | Daemon-injected generator factories: `createGuardianActionCopyGenerator` (latency-optimized text rewriting) and `createGuardianFollowUpConversationGenerator` (tool-calling intent classification) |
|
|
292
290
|
| `src/calls/call-controller.ts` | Voice timeout handling: marks requests as timed out, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for generated voice response |
|
|
293
|
-
| `src/runtime/routes/inbound-message-handler.ts` | Late reply interception for Telegram
|
|
294
|
-
| `src/daemon/session-process.ts` | Late reply interception for mac
|
|
291
|
+
| `src/runtime/routes/inbound-message-handler.ts` | Late reply interception for Telegram channels: matches late answers to expired requests, routes follow-up conversation turns, dispatches actions |
|
|
292
|
+
| `src/daemon/session-process.ts` | Late reply interception for mac channel: same logic as inbound-message-handler but using conversation-ID-based delivery lookup |
|
|
295
293
|
| `src/calls/guardian-action-sweep.ts` | Periodic sweep for stale pending requests; sends expiry notices to guardian destinations |
|
|
296
294
|
| `src/memory/migrations/030-guardian-action-followup.ts` | Schema migration adding follow-up columns (`followup_state`, `late_answer_text`, `late_answered_at`, `followup_action`, `followup_completed_at`) |
|
|
297
295
|
|
|
298
|
-
### SMS Channel (Twilio)
|
|
299
|
-
|
|
300
|
-
The SMS channel provides text-only messaging via Twilio, sharing the same telephony provider as voice calls. It follows the same ingress/egress pattern as Telegram but uses Twilio's HMAC-SHA1 signature validation instead of a secret header.
|
|
301
|
-
|
|
302
|
-
**Ingress** (`POST /webhooks/twilio/sms`):
|
|
303
|
-
|
|
304
|
-
1. Twilio delivers an inbound SMS as a form-encoded POST to the gateway.
|
|
305
|
-
2. The gateway validates the `X-Twilio-Signature` header using HMAC-SHA1 with the Twilio Auth Token against the canonical request URL (reconstructed from `INGRESS_PUBLIC_BASE_URL` when behind a tunnel).
|
|
306
|
-
3. `MessageSid` deduplication prevents reprocessing retried webhooks.
|
|
307
|
-
4. **MMS detection**: The gateway treats a message as MMS when any of: `NumMedia > 0`, any `MediaUrl<N>` key has a non-empty value, or any `MediaContentType<N>` key has a non-empty value. This catches media attachments even when Twilio omits `NumMedia`. The gateway replies with an unsupported notice and does not forward the payload. MMS payloads are explicitly rejected rather than silently dropped.
|
|
308
|
-
5. **`/new` command**: When the message body is exactly `/new` (case-insensitive, trimmed), the gateway resolves routing first. If routing is rejected, a rejection notice SMS is sent to the sender (matching Telegram `/new` rejection semantics — "This message could not be routed to an assistant"). If routing succeeds, the gateway calls `resetConversation(...)` on the runtime and sends a confirmation SMS. The message is never forwarded to the runtime.
|
|
309
|
-
6. The payload is normalized into a `GatewayInboundEvent` with `sourceChannel: "sms"` and `conversationExternalId` set to the sender's phone number (E.164).
|
|
310
|
-
7. **Routing** — Phone-number-based routing is checked first: the inbound `To` number is reverse-looked-up in `assistantPhoneNumbers` (a `Record<string, string>` mapping assistant IDs to E.164 numbers, propagated from the assistant config file). If a match is found, that assistant handles the message. Otherwise, the standard routing chain (conversation_id -> actor_id -> default/reject) is used. This allows multiple assistants to have dedicated phone numbers. The resolved route is passed as a `routingOverride` to `handleInbound()` so the already-resolved routing is used directly instead of re-running `resolveAssistant()` inside the handler.
|
|
311
|
-
8. The event is forwarded to the runtime via `POST /channels/inbound`, including SMS-specific transport hints (`chat-first-medium`, `sms-character-limits`, etc.) and a `replyCallbackUrl` pointing to `/deliver/sms`.
|
|
312
|
-
|
|
313
|
-
**Egress** (`POST /deliver/sms`):
|
|
314
|
-
|
|
315
|
-
1. The runtime calls the gateway's `/deliver/sms` endpoint with `{ to, text }` or `{ chatId, text }`. The `chatId` field is an alias for `to`, allowing the runtime channel callback (which sends `{ chatId, text }`) to work without translation. When both `to` and `chatId` are provided, `to` takes precedence.
|
|
316
|
-
2. The gateway authenticates the request via bearer token (same fail-closed model as `/deliver/telegram`).
|
|
317
|
-
3. The gateway sends the SMS via the Twilio Messages API using the configured `TWILIO_PHONE_NUMBER` as the `From` number.
|
|
318
|
-
|
|
319
|
-
**Setup**: Twilio credentials (Account SID, Auth Token) and phone number are managed via HTTP control-plane endpoints (`/v1/integrations/twilio/*`) exposed by the runtime and proxied by the gateway (see `src/runtime/routes/twilio-routes.ts`). A single phone number is shared across voice and SMS for each assistant. Both `provision` and `assign` endpoints auto-persist the number to config and secure storage, and auto-configure Twilio webhooks (voice URL, status callback, SMS URL) via the Twilio IncomingPhoneNumber API when a public ingress URL is available. When `assistantId` is provided, the number is persisted into the per-assistant mapping at `sms.assistantPhoneNumbers[assistantId]`, and the legacy `sms.phoneNumber` field is only set if it was previously empty/unset (acting as a fallback for single-assistant installs). This prevents multi-assistant assignments from clobbering each other's global outbound number. Without `assistantId`, the legacy field is always updated. Webhook configuration is best-effort — if ingress is not yet set up, the number is still assigned and webhooks can be configured later. Non-fatal webhook failures are surfaced as a `warning` field in the response.
|
|
320
|
-
|
|
321
|
-
**Phone Number Resolution**: At runtime, `getTwilioConfig()` resolves the phone number using this priority chain: (1) `TWILIO_PHONE_NUMBER` env var — highest priority, explicit override; (2) `sms.phoneNumber` in config — primary source of truth written by `provision_number`/`assign_number`; (3) `credential:twilio:phone_number` secure key — backward-compatible fallback. An error is thrown if no number is found after all sources are checked.
|
|
322
|
-
|
|
323
|
-
**Credential Clearing Semantics**: `clear_credentials` removes only the authentication credentials (Account SID and Auth Token) from secure storage. The phone number is preserved in both the config file (`sms.phoneNumber`) and the secure key (`credential:twilio:phone_number`) so that re-entering credentials resumes working without needing to reassign the number.
|
|
324
|
-
|
|
325
|
-
**Webhook Lifecycle**: Twilio webhook URLs are managed through a shared `syncTwilioWebhooks` helper in `config.ts` that computes voice, status-callback, and SMS URLs from the ingress config and pushes them to Twilio. Webhooks are synchronized at three points:
|
|
326
|
-
|
|
327
|
-
1. **Number provisioning** (`provision_number`) — immediately after purchasing a number.
|
|
328
|
-
2. **Number assignment** (`assign_number`) — when an existing number is assigned to the assistant.
|
|
329
|
-
3. **Ingress URL change** (`ingress_config` set) — when the public ingress URL is updated or enabled, the daemon automatically re-synchronizes Twilio webhooks (fire-and-forget) if credentials and an assigned number are present. This ensures tunnel URL changes (e.g., ngrok restart) propagate without manual re-assignment.
|
|
330
|
-
|
|
331
|
-
All three paths are best-effort: webhook sync failures do not prevent the primary operation from succeeding.
|
|
332
|
-
|
|
333
|
-
**Limitations (v1)**: Text-only — MMS payloads are explicitly rejected with a user-facing notice rather than silently dropped.
|
|
334
|
-
|
|
335
296
|
### WhatsApp Channel (Meta Cloud API)
|
|
336
297
|
|
|
337
|
-
The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsApp Business Cloud API. It follows the
|
|
298
|
+
The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsApp Business Cloud API. It follows the standard ingress/egress pattern with Meta's HMAC-SHA256 signature validation (`X-Hub-Signature-256`).
|
|
338
299
|
|
|
339
300
|
**Ingress** (`GET /webhooks/whatsapp` — verification, `POST /webhooks/whatsapp` — messages):
|
|
340
301
|
|
|
@@ -365,9 +326,7 @@ These can be set via environment variables or stored in the credential vault (ke
|
|
|
365
326
|
|
|
366
327
|
**Limitations (v1)**: Rich approval UI (inline buttons) is not supported. Contacts and location message types are acknowledged but not forwarded.
|
|
367
328
|
|
|
368
|
-
**Channel Readiness**: The channel readiness HTTP endpoints (`GET /v1/channels/readiness`, `POST /v1/channels/readiness/refresh`) backed by `ChannelReadinessService` in `src/runtime/channel-readiness-service.ts` provide a unified readiness subsystem for all channels. Each channel registers a `ChannelProbe` that runs synchronous local checks (credential presence,
|
|
369
|
-
|
|
370
|
-
**SMS Compliance & Admin**: The Twilio HTTP control-plane endpoints extend beyond credential and number management with compliance and admin routes: `GET /v1/integrations/twilio/sms/compliance` detects toll-free vs local number type and fetches verification status; `POST/PATCH/DELETE /v1/integrations/twilio/sms/compliance/tollfree` manage the Twilio toll-free verification lifecycle; `POST /v1/integrations/twilio/numbers/release` removes a phone number from the Twilio account and clears all local references. All compliance actions validate required fields and Twilio enum values before calling the API.
|
|
329
|
+
**Channel Readiness**: The channel readiness HTTP endpoints (`GET /v1/channels/readiness`, `POST /v1/channels/readiness/refresh`) backed by `ChannelReadinessService` in `src/runtime/channel-readiness-service.ts` provide a unified readiness subsystem for all channels. Each channel registers a `ChannelProbe` that runs synchronous local checks (credential presence, ingress config) and optional async remote checks with a 5-minute TTL cache. Built-in probes: Telegram (bot token, webhook secret, ingress). The GET endpoint returns cached snapshots; the refresh endpoint invalidates the cache first. Unknown channels return `unsupported_channel`. Route handlers live in `src/runtime/routes/channel-readiness-routes.ts`.
|
|
371
330
|
|
|
372
331
|
### Slack Channel (Socket Mode)
|
|
373
332
|
|
|
@@ -406,14 +365,14 @@ Both `GET` and `POST` endpoints report `connected: true` only when both `hasBotT
|
|
|
406
365
|
|
|
407
366
|
**Key source files:**
|
|
408
367
|
|
|
409
|
-
| File
|
|
410
|
-
|
|
|
411
|
-
| `src/daemon/handlers/config-slack-channel.ts`
|
|
412
|
-
| `src/runtime/routes/
|
|
368
|
+
| File | Purpose |
|
|
369
|
+
| -------------------------------------------------- | --------------------------------------------------------------- |
|
|
370
|
+
| `src/daemon/handlers/config-slack-channel.ts` | Business logic for get/set/clear Slack channel config |
|
|
371
|
+
| `src/runtime/routes/integrations/slack/channel.ts` | HTTP route handlers for `/v1/integrations/slack/channel/config` |
|
|
413
372
|
|
|
414
373
|
### Trusted Contact Access (Channel-Agnostic)
|
|
415
374
|
|
|
416
|
-
External users who are not the guardian can gain access to the assistant through a guardian-mediated verification flow. The flow is channel-agnostic — it works identically on Telegram,
|
|
375
|
+
External users who are not the guardian can gain access to the assistant through a guardian-mediated verification flow. The flow is channel-agnostic — it works identically on Telegram, voice, and any future channel.
|
|
417
376
|
|
|
418
377
|
**Full design doc:** [`docs/trusted-contact-access.md`](docs/trusted-contact-access.md)
|
|
419
378
|
|
|
@@ -422,12 +381,12 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
422
381
|
1. Unknown user messages the assistant on any channel.
|
|
423
382
|
2. Ingress ACL (`inbound-message-handler.ts`) rejects the message and emits an `ingress.access_request` notification signal to the guardian.
|
|
424
383
|
3. Guardian approves or denies via callback button or conversational intent (routed through `guardian-approval-interception.ts`).
|
|
425
|
-
4. On approval, an identity-bound verification session with a 6-digit code is created (`access-request-decision.ts` → `channel-
|
|
384
|
+
4. On approval, an identity-bound verification session with a 6-digit code is created (`access-request-decision.ts` → `channel-verification-service.ts`).
|
|
426
385
|
5. Guardian gives the code to the requester out-of-band.
|
|
427
386
|
6. Requester enters the code; identity binding is verified, the challenge is consumed, and an active contact channel is created in the contacts table.
|
|
428
387
|
7. All subsequent messages are accepted through the ingress ACL.
|
|
429
388
|
|
|
430
|
-
**Channel-agnostic design:** The entire flow operates on abstract `ChannelId` and `actorExternalId`/`conversationExternalId` fields (DB column names `externalUserId`/`externalChatId` are unchanged). Identity binding adapts per channel: Telegram uses chat IDs,
|
|
389
|
+
**Channel-agnostic design:** The entire flow operates on abstract `ChannelId` and `actorExternalId`/`conversationExternalId` fields (DB column names `externalUserId`/`externalChatId` are unchanged). Identity binding adapts per channel: Telegram uses chat IDs, voice uses E.164 phone numbers, HTTP API uses caller-provided identity. No channel-specific branching exists in the trusted contact code paths.
|
|
431
390
|
|
|
432
391
|
**Lifecycle states:** `requested → pending_guardian → verification_pending → active | denied | expired`
|
|
433
392
|
|
|
@@ -456,12 +415,13 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
456
415
|
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL, unknown-contact rejection, verification code interception |
|
|
457
416
|
| `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
|
|
458
417
|
| `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
|
|
459
|
-
| `src/runtime/channel-
|
|
418
|
+
| `src/runtime/channel-verification-service.ts` | Verification session lifecycle, identity binding, rate limiting |
|
|
460
419
|
| `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
|
|
461
420
|
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
|
|
462
421
|
| `src/runtime/invite-service.ts` | Business logic for invite operations |
|
|
463
422
|
| `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
|
|
464
|
-
| `src/memory/
|
|
423
|
+
| `src/memory/guardian-approvals.ts` | Approval request persistence |
|
|
424
|
+
| `src/memory/channel-verification-sessions.ts` | Verification challenge persistence |
|
|
465
425
|
| `src/config/bundled-skills/contacts/SKILL.md` | Unified skill for contact management, access control, and invite links |
|
|
466
426
|
|
|
467
427
|
### Guardian-Initiated Invite Links
|
|
@@ -480,7 +440,7 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
480
440
|
│ Registry of per-channel adapters: │
|
|
481
441
|
│ • buildShareableInvite(token) → { url, displayText } │
|
|
482
442
|
│ • extractInboundToken(payload) → token | undefined │
|
|
483
|
-
│ Registered: Telegram │ Deferred:
|
|
443
|
+
│ Registered: Telegram │ Deferred: Slack, Voice │
|
|
484
444
|
├─────────────────────────────────────────────────────────────┤
|
|
485
445
|
│ Core Redemption Engine (invite-redemption-service.ts) │
|
|
486
446
|
│ Channel-agnostic token validation, expiry, use-count, │
|
|
@@ -511,7 +471,6 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
511
471
|
| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
512
472
|
| Telegram | Shipped | Bot username resolved from credential metadata or `TELEGRAM_BOT_USERNAME` env |
|
|
513
473
|
| Voice | Shipped | Identity-bound voice code redemption via DTMF/speech in the relay state machine. Always-on canonical behavior with personalized friend/guardian name prompts. |
|
|
514
|
-
| SMS | Deferred | Needs a deep-link strategy compatible with SMS (short URL or web redemption page) |
|
|
515
474
|
| Slack | Deferred | Needs DM-safe ingress — Socket Mode handles channel messages but DM-initiated invite flows need routing |
|
|
516
475
|
|
|
517
476
|
### Voice Invite Flow (invite_redemption_pending)
|
|
@@ -520,7 +479,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
520
479
|
|
|
521
480
|
**Creation flow:**
|
|
522
481
|
|
|
523
|
-
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "
|
|
482
|
+
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "phone"` and `expectedExternalUserId` (E.164 phone).
|
|
524
483
|
2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
|
|
525
484
|
3. The one-time plaintext `voiceCode` is returned in the creation response. The raw token is NOT returned for voice invites — redemption uses the identity-bound code flow exclusively.
|
|
526
485
|
4. Guardian communicates the code to the invitee out-of-band.
|
|
@@ -550,7 +509,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
550
509
|
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
|
|
551
510
|
| `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
|
|
552
511
|
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill |
|
|
553
|
-
| `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by
|
|
512
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by HTTP routes) |
|
|
554
513
|
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
|
|
555
514
|
| `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
|
|
556
515
|
| `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior) |
|
|
@@ -596,13 +555,13 @@ When no invite exists and no pending guardian challenge is active, the relay ent
|
|
|
596
555
|
1. The relay transitions to `awaiting_name` state and prompts the caller for their name with a timeout.
|
|
597
556
|
2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
|
|
598
557
|
3. The relay transitions to `awaiting_guardian_decision` and plays hold music/messaging while polling the canonical request status.
|
|
599
|
-
4. The guardian approves or denies via any channel (Telegram,
|
|
558
|
+
4. The guardian approves or denies via any channel (Telegram, desktop). All decisions route through `applyCanonicalGuardianDecision`, which dispatches to the `access_request` resolver in `guardian-request-resolvers.ts`.
|
|
600
559
|
5. On approval: the resolver directly activates the caller as a trusted contact (sets channel `status: 'active'`, `policy: 'allow'`), the poll detects the approved status, the relay transitions to the normal call flow with the caller's guardian context updated.
|
|
601
560
|
6. On denial or timeout: the caller hears a denial message and the call ends.
|
|
602
561
|
|
|
603
562
|
**Path 3: Inbound guardian verification (pending challenge)**
|
|
604
563
|
|
|
605
|
-
When a pending voice guardian challenge exists (`
|
|
564
|
+
When a pending voice guardian challenge exists (`getPendingSession`), the caller enters the DTMF/speech verification flow to complete an outbound-initiated guardian binding. This path is for guardian identity verification, not trusted-contact access.
|
|
606
565
|
|
|
607
566
|
**Canonical decision routing:**
|
|
608
567
|
|
|
@@ -630,7 +589,7 @@ Release-driven update notification system that surfaces release notes to the ass
|
|
|
630
589
|
|
|
631
590
|
**Data flow:**
|
|
632
591
|
|
|
633
|
-
1. **Bundled template** (`src/
|
|
592
|
+
1. **Bundled template** (`src/prompts/templates/UPDATES.md`) — source of release notes, maintained per-release in the repo.
|
|
634
593
|
2. **Startup sync** (`syncUpdateBulletinOnStartup()` in `src/config/update-bulletin.ts`) — materializes the bundled template into the workspace `UPDATES.md` on daemon boot. Uses atomic write (temp + rename) for crash safety.
|
|
635
594
|
3. **System prompt injection** — `buildSystemPrompt()` reads workspace `UPDATES.md` and injects it as a `## Recent Updates` section with judgment-based handling instructions.
|
|
636
595
|
4. **Completion by deletion** — the assistant deletes `UPDATES.md` when it has actioned all updates. Next startup detects the deletion and marks those releases as completed in checkpoint state.
|
|
@@ -645,11 +604,11 @@ Release-driven update notification system that surfaces release notes to the ass
|
|
|
645
604
|
|
|
646
605
|
| File | Purpose |
|
|
647
606
|
| -------------------------------------- | --------------------------------------------------------- |
|
|
648
|
-
| `src/
|
|
607
|
+
| `src/prompts/templates/UPDATES.md` | Bundled release-note template |
|
|
649
608
|
| `src/config/update-bulletin.ts` | Startup sync logic (materialize, delete-complete, merge) |
|
|
650
609
|
| `src/config/update-bulletin-format.ts` | Release block formatter/parser helpers |
|
|
651
610
|
| `src/config/update-bulletin-state.ts` | Checkpoint state helpers for active/completed releases |
|
|
652
|
-
| `src/
|
|
611
|
+
| `src/prompts/system-prompt.ts` | Prompt injection of updates section |
|
|
653
612
|
| `src/daemon/config-watcher.ts` | File watcher — evicts sessions on UPDATES.md changes |
|
|
654
613
|
| `src/permissions/defaults.ts` | Auto-allow rules for file_read/write/edit + rm UPDATES.md |
|
|
655
614
|
|
|
@@ -667,7 +626,7 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
|
|
|
667
626
|
2. Defaults registry `defaultEnabled` — from the unified registry (`meta/feature-flags/feature-flag-registry.json`, filtered to `scope: "assistant"`)
|
|
668
627
|
3. `true` — unknown/undeclared flags with no persisted override default to enabled
|
|
669
628
|
|
|
670
|
-
**Storage:** Flags are persisted in `~/.vellum/workspace/config.json
|
|
629
|
+
**Storage:** Flags are persisted in `~/.vellum/workspace/config.json` in the `assistantFeatureFlagValues` section (managed by the gateway's `/v1/feature-flags` API — see [`gateway/ARCHITECTURE.md`](../gateway/ARCHITECTURE.md)). The daemon's config watcher hot-reloads this file, so flag changes take effect on the next tool resolution or session.
|
|
671
630
|
|
|
672
631
|
**Public API:**
|
|
673
632
|
|
|
@@ -678,8 +637,8 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
|
|
|
678
637
|
|
|
679
638
|
| Enforcement Point | Module | Effect |
|
|
680
639
|
| ---------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
681
|
-
| **1. Client skill list** | `resolveSkillStates()` in `config/skill-state.ts` | Skills with flag OFF are excluded from the resolved list returned to
|
|
682
|
-
| **2. System prompt skill catalog** | `appendSkillsCatalog()` in `
|
|
640
|
+
| **1. Client skill list** | `resolveSkillStates()` in `config/skill-state.ts` | Skills with flag OFF are excluded from the resolved list returned to clients (macOS skill list, settings UI). The skill never appears in the client. |
|
|
641
|
+
| **2. System prompt skill catalog** | `appendSkillsCatalog()` in `prompts/system-prompt.ts` | The model-visible `## Skills Catalog` section in the system prompt filters out flagged-off skills. The model cannot see or reference them. |
|
|
683
642
|
| **3. `skill_load` tool** | `executeSkillLoad()` in `tools/skills/load.ts` | If the model attempts to load a flagged-off skill by name, the tool returns an error: `"skill is currently unavailable (disabled by feature flag)"`. |
|
|
684
643
|
| **4. Runtime tool projection** | `projectSkillTools()` in `daemon/session-skill-tools.ts` | Even if a skill was previously active in a session (has `<loaded_skill>` markers in history), the per-turn projection drops it when the flag is OFF. Already-registered tools are unregistered. |
|
|
685
644
|
| **5. Included child skills** | `executeSkillLoad()` in `tools/skills/load.ts` | When a parent skill includes children via the `includes` directive, each child is independently checked against its feature flag. Flagged-off children are silently excluded from the loaded skill content. |
|
|
@@ -694,12 +653,11 @@ All five enforcement points use `isAssistantFeatureFlagEnabled(skillFlagKey(skil
|
|
|
694
653
|
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
695
654
|
| `src/config/assistant-feature-flags.ts` | Canonical resolver: `isAssistantFeatureFlagEnabled()`, `getAssistantFeatureFlagDefaults()`, registry loader |
|
|
696
655
|
| `src/config/skill-state.ts` | `skillFlagKey()` — derives canonical flag key for skills; `resolveSkillStates()` — enforcement point 1 |
|
|
697
|
-
| `src/
|
|
656
|
+
| `src/prompts/system-prompt.ts` | `appendSkillsCatalog()` — enforcement point 2 |
|
|
698
657
|
| `src/tools/skills/load.ts` | `executeSkillLoad()` — enforcement points 3 and 5 |
|
|
699
658
|
| `src/daemon/session-skill-tools.ts` | `projectSkillTools()` — enforcement point 4 |
|
|
700
|
-
| `src/config/schema.ts` | `
|
|
701
|
-
| `src/
|
|
702
|
-
| `src/daemon/handlers/skills.ts` | `handleSkillsList()` — uses `resolveSkillStates()` for IPC client responses |
|
|
659
|
+
| `src/config/schema.ts` | `assistantFeatureFlagValues` field definition in `AssistantConfig` (Zod schema) |
|
|
660
|
+
| `src/daemon/handlers/skills.ts` | `handleSkillsList()` — uses `resolveSkillStates()` for client responses |
|
|
703
661
|
| `meta/feature-flags/feature-flag-registry.json` | Unified feature flag registry (repo root) — all declared flags with scope, label, default values, and descriptions |
|
|
704
662
|
| `src/config/feature-flag-registry.json` | Bundled copy of the unified registry for compiled binary resolution |
|
|
705
663
|
|
|
@@ -752,18 +710,13 @@ graph LR
|
|
|
752
710
|
WORK_ITEMS["work_items<br/>───────────────<br/>Task Queue entries<br/>taskId (FK → tasks)<br/>title, notes, status<br/>priority_tier (0-3), sort_index<br/>last_run_id, last_run_status<br/>source_type, source_id"]
|
|
753
711
|
end
|
|
754
712
|
|
|
755
|
-
subgraph "~/.vellum/workspace/data/ipc-blobs/"
|
|
756
|
-
BLOBS["*.blob<br/>───────────────<br/>Ephemeral blob files<br/>UUID filenames<br/>Atomic temp+rename writes<br/>Consumed after daemon hydration<br/>Stale sweep every 5min (30min max age)"]
|
|
757
|
-
end
|
|
758
|
-
|
|
759
713
|
subgraph "~/.vellum/ (Root Files)"
|
|
760
|
-
SOCK["vellum.sock<br/>Unix domain socket"]
|
|
761
714
|
TRUST["protected/trust.json<br/>Tool permission rules"]
|
|
762
715
|
FF_TOKEN["feature-flag-token<br/>Client token for feature-flag API"]
|
|
763
716
|
end
|
|
764
717
|
|
|
765
718
|
subgraph "~/.vellum/workspace/ (Workspace Files)"
|
|
766
|
-
CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes
|
|
719
|
+
CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes assistantFeatureFlagValues)"]
|
|
767
720
|
ONBOARD_PLAYBOOKS["onboarding/playbooks/<br/>[channel]_onboarding.md<br/>assistant-updatable checklists"]
|
|
768
721
|
ONBOARD_REGISTRY["onboarding/playbooks/registry.json<br/>channel-start index for fast-path + reconciliation"]
|
|
769
722
|
APPS_STORE["data/apps/<br/><app-id>.json + pages/*.html<br/>prebuilt Home Base seeded here"]
|
|
@@ -791,8 +744,8 @@ graph TB
|
|
|
791
744
|
end
|
|
792
745
|
|
|
793
746
|
subgraph "Local Mode"
|
|
794
|
-
LOCAL_CLIENT["
|
|
795
|
-
|
|
747
|
+
LOCAL_CLIENT["RuntimeClient"]
|
|
748
|
+
LOCAL_HTTP["HTTP API<br/>localhost:RUNTIME_HTTP_PORT"]
|
|
796
749
|
LOCAL_DAEMON["Local Daemon<br/>(same machine)"]
|
|
797
750
|
LOCAL_DB["~/.vellum/workspace/data/db/assistant.db"]
|
|
798
751
|
end
|
|
@@ -809,8 +762,8 @@ graph TB
|
|
|
809
762
|
AUTH --> PG
|
|
810
763
|
|
|
811
764
|
ROUTES -->|"ASSISTANT_CONNECTION_MODE=local"| LOCAL_CLIENT
|
|
812
|
-
LOCAL_CLIENT -->
|
|
813
|
-
|
|
765
|
+
LOCAL_CLIENT --> LOCAL_HTTP
|
|
766
|
+
LOCAL_HTTP --> LOCAL_DAEMON
|
|
814
767
|
LOCAL_DAEMON --> LOCAL_DB
|
|
815
768
|
|
|
816
769
|
ROUTES -->|"ASSISTANT_CONNECTION_MODE=cloud"| RUNTIME_CLIENT
|
|
@@ -821,228 +774,19 @@ graph TB
|
|
|
821
774
|
|
|
822
775
|
---
|
|
823
776
|
|
|
824
|
-
##
|
|
825
|
-
|
|
826
|
-
The TypeScript file `assistant/src/daemon/ipc-contract.ts` is the **single source of truth** for all IPC message types. Swift client models are auto-generated from it.
|
|
827
|
-
|
|
828
|
-
```mermaid
|
|
829
|
-
graph LR
|
|
830
|
-
subgraph "Source of Truth"
|
|
831
|
-
CONTRACT["ipc-contract.ts<br/>───────────────<br/>All message interfaces<br/>ClientMessage union<br/>ServerMessage union"]
|
|
832
|
-
end
|
|
833
|
-
|
|
834
|
-
subgraph "Generation Pipeline"
|
|
835
|
-
TJS["typescript-json-schema<br/>───────────────<br/>TS → JSON Schema"]
|
|
836
|
-
GEN["generate-swift.ts<br/>───────────────<br/>JSON Schema → Swift<br/>Codable structs"]
|
|
837
|
-
end
|
|
838
|
-
|
|
839
|
-
subgraph "Generated Output"
|
|
840
|
-
SWIFT["IPCContractGenerated.swift<br/>───────────────<br/>clients/shared/IPC/Generated/<br/>IPC-prefixed Codable structs"]
|
|
841
|
-
end
|
|
842
|
-
|
|
843
|
-
subgraph "Hand-Written Swift"
|
|
844
|
-
ENUMS["IPCMessages.swift<br/>───────────────<br/>ClientMessage / ServerMessage<br/>discriminated union enums<br/>(custom Decodable init)"]
|
|
845
|
-
end
|
|
846
|
-
|
|
847
|
-
subgraph "Inventory Tracking"
|
|
848
|
-
INV_SRC["ipc-contract-inventory.ts<br/>───────────────<br/>AST parser for union members"]
|
|
849
|
-
INV_SNAP["ipc-contract-inventory.json<br/>───────────────<br/>Checked-in snapshot"]
|
|
850
|
-
end
|
|
851
|
-
|
|
852
|
-
subgraph "Enforcement"
|
|
853
|
-
CI["CI (GitHub Actions)<br/>bun run check:ipc-generated<br/>bun run ipc:inventory<br/>bun run ipc:check-swift-drift"]
|
|
854
|
-
HOOK["Pre-commit hook<br/>same 3 checks on staged<br/>IPC files"]
|
|
855
|
-
end
|
|
856
|
-
|
|
857
|
-
CONTRACT --> TJS
|
|
858
|
-
TJS --> GEN
|
|
859
|
-
GEN --> SWIFT
|
|
860
|
-
SWIFT --> ENUMS
|
|
861
|
-
|
|
862
|
-
CONTRACT --> INV_SRC
|
|
863
|
-
INV_SRC --> INV_SNAP
|
|
864
|
-
|
|
865
|
-
CONTRACT --> CI
|
|
866
|
-
CONTRACT --> HOOK
|
|
867
|
-
```
|
|
868
|
-
|
|
869
|
-
---
|
|
870
|
-
|
|
871
|
-
## IPC Protocol — Message Types
|
|
872
|
-
|
|
873
|
-
```mermaid
|
|
874
|
-
graph LR
|
|
875
|
-
subgraph "Client → Server"
|
|
876
|
-
direction TB
|
|
877
|
-
C0["task_submit<br/>task, screenWidth, screenHeight,<br/>attachments, source?:'voice'|'text'"]
|
|
878
|
-
C1["cu_session_create<br/>task, attachments"]
|
|
879
|
-
C2["cu_observation<br/>axTree, axDiff, screenshot,<br/>secondaryWindows, result/error,<br/>axTreeBlob?, screenshotBlob?"]
|
|
880
|
-
C3["ambient_observation<br/>screenContent, requestId"]
|
|
881
|
-
C4["session_create<br/>title, threadType?"]
|
|
882
|
-
C5["user_message<br/>text, attachments"]
|
|
883
|
-
C6["confirmation_response<br/>decision"]
|
|
884
|
-
C7["cancel / undo"]
|
|
885
|
-
C8["model_get / model_set"]
|
|
886
|
-
C9["ping"]
|
|
887
|
-
C10["ipc_blob_probe<br/>probeId, nonceSha256"]
|
|
888
|
-
C11["work_items_list / work_item_get<br/>work_item_create / work_item_update<br/>work_item_complete / work_item_run_task<br/>(planned)"]
|
|
889
|
-
C12["tool_permission_simulate<br/>toolName, input, workingDir?,<br/>isInteractive?, forcePromptSideEffects?,<br/>executionTarget?"]
|
|
890
|
-
C13["conversation_search<br/>query, limit?,<br/>maxMessagesPerConversation?"]
|
|
891
|
-
C14["ingress_invite<br/>create / list / revoke / redeem"]
|
|
892
|
-
C15["contacts<br/>list / get / update_channel"]
|
|
893
|
-
end
|
|
894
|
-
|
|
895
|
-
SOCKET["Unix Socket<br/>~/.vellum/vellum.sock<br/>───────────────<br/>Newline-delimited JSON<br/>Max 96MB per message<br/>Ping/pong every 30s<br/>Auto-reconnect<br/>1s → 30s backoff"]
|
|
896
|
-
|
|
897
|
-
subgraph "Server → Client"
|
|
898
|
-
direction TB
|
|
899
|
-
S0["task_routed<br/>interactionType, sessionId"]
|
|
900
|
-
S1["cu_action<br/>tool, input dict"]
|
|
901
|
-
S2["cu_complete<br/>summary"]
|
|
902
|
-
S3["cu_error<br/>message"]
|
|
903
|
-
S4["assistant_text_delta<br/>streaming text"]
|
|
904
|
-
S5["assistant_thinking_delta<br/>streaming thinking"]
|
|
905
|
-
S6["message_complete<br/>usage stats, attachments?"]
|
|
906
|
-
S7["ambient_result<br/>decision, summary/suggestion"]
|
|
907
|
-
S8["confirmation_request<br/>tool, risk_level,<br/>executionTarget"]
|
|
908
|
-
S9["memory_recalled<br/>source hits + relation counters<br/>ranking/debug telemetry"]
|
|
909
|
-
S10["usage_update / error"]
|
|
910
|
-
S11["generation_cancelled"]
|
|
911
|
-
S12["message_queued<br/>position in queue"]
|
|
912
|
-
S13["message_dequeued<br/>queue drained"]
|
|
913
|
-
S14["generation_handoff<br/>sessionId, requestId?,<br/>queuedCount, attachments?"]
|
|
914
|
-
S15["trace_event<br/>eventId, sessionId, requestId?,<br/>timestampMs, sequence, kind,<br/>status?, summary, attributes?"]
|
|
915
|
-
S16["session_error<br/>sessionId, code,<br/>userMessage, retryable,<br/>debugDetails?"]
|
|
916
|
-
S17["ipc_blob_probe_result<br/>probeId, ok,<br/>observedNonceSha256?, reason?"]
|
|
917
|
-
S18["session_info<br/>sessionId, title,<br/>correlationId?, threadType?"]
|
|
918
|
-
S19["session_title_updated<br/>sessionId, title"]
|
|
919
|
-
S20["session_list_response<br/>sessions[]: id, title,<br/>updatedAt, threadType?"]
|
|
920
|
-
S21["work_item_status_changed<br/>workItemId, newStatus<br/>(planned push)"]
|
|
921
|
-
S22["tool_permission_simulate_response<br/>decision, riskLevel, reason?,<br/>promptPayload?, matchedRuleId?"]
|
|
922
|
-
S23["conversation_search_response<br/>query, results[]: conversationId,<br/>title, updatedAt, matchingMessages[]"]
|
|
923
|
-
S24["ingress_invite_response<br/>invite / invites"]
|
|
924
|
-
S25["contacts_response<br/>contact / contacts"]
|
|
925
|
-
end
|
|
926
|
-
|
|
927
|
-
C0 --> SOCKET
|
|
928
|
-
C1 --> SOCKET
|
|
929
|
-
C2 --> SOCKET
|
|
930
|
-
C3 --> SOCKET
|
|
931
|
-
C4 --> SOCKET
|
|
932
|
-
C5 --> SOCKET
|
|
933
|
-
C6 --> SOCKET
|
|
934
|
-
C7 --> SOCKET
|
|
935
|
-
C8 --> SOCKET
|
|
936
|
-
C9 --> SOCKET
|
|
937
|
-
C10 --> SOCKET
|
|
938
|
-
C11 --> SOCKET
|
|
939
|
-
C12 --> SOCKET
|
|
940
|
-
C13 --> SOCKET
|
|
941
|
-
C14 --> SOCKET
|
|
942
|
-
C15 --> SOCKET
|
|
943
|
-
|
|
944
|
-
SOCKET --> S0
|
|
945
|
-
SOCKET --> S1
|
|
946
|
-
SOCKET --> S2
|
|
947
|
-
SOCKET --> S3
|
|
948
|
-
SOCKET --> S4
|
|
949
|
-
SOCKET --> S5
|
|
950
|
-
SOCKET --> S6
|
|
951
|
-
SOCKET --> S7
|
|
952
|
-
SOCKET --> S8
|
|
953
|
-
SOCKET --> S9
|
|
954
|
-
SOCKET --> S10
|
|
955
|
-
SOCKET --> S11
|
|
956
|
-
SOCKET --> S12
|
|
957
|
-
SOCKET --> S13
|
|
958
|
-
SOCKET --> S14
|
|
959
|
-
SOCKET --> S15
|
|
960
|
-
SOCKET --> S16
|
|
961
|
-
SOCKET --> S17
|
|
962
|
-
SOCKET --> S18
|
|
963
|
-
SOCKET --> S19
|
|
964
|
-
SOCKET --> S20
|
|
965
|
-
SOCKET --> S21
|
|
966
|
-
SOCKET --> S22
|
|
967
|
-
SOCKET --> S24
|
|
968
|
-
SOCKET --> S25
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
---
|
|
972
|
-
|
|
973
|
-
## Blob Transport — Large Payload Side-Channel
|
|
974
|
-
|
|
975
|
-
CU observations can carry large payloads (screenshots as JPEG, AX trees as UTF-8 text). Instead of embedding these inline as base64/text in newline-delimited JSON IPC messages, the blob transport offloads them to local files and sends only lightweight references over the socket.
|
|
976
|
-
|
|
977
|
-
### Probe Mechanism
|
|
978
|
-
|
|
979
|
-
Blob transport is opt-in per connection. On every macOS socket connect, the client writes a random nonce file to the blob directory and sends an `ipc_blob_probe` message with the SHA-256 of the nonce. The daemon reads the file, computes the hash, and responds with `ipc_blob_probe_result`. If hashes match, the client sets `isBlobTransportAvailable = true` for that connection. The flag resets to `false` on disconnect or reconnect.
|
|
980
|
-
|
|
981
|
-
On iOS (HTTP+SSE connections via the gateway), blob transport is not applicable — `isBlobTransportAvailable` stays `false` and inline payloads are always used. Over SSH-forwarded Unix sockets on macOS, the probe runs but fails because the client and daemon don't share a filesystem, so blob transport stays disabled and inline payloads are used transparently.
|
|
982
|
-
|
|
983
|
-
### Blob Directory
|
|
984
|
-
|
|
985
|
-
All blobs live at `~/.vellum/workspace/data/ipc-blobs/`. Filenames are `${uuid}.blob`. The daemon ensures this directory exists on startup. Both client and daemon use atomic writes (temp file + rename) to prevent partial reads.
|
|
986
|
-
|
|
987
|
-
### Blob Reference
|
|
988
|
-
|
|
989
|
-
```
|
|
990
|
-
IpcBlobRef {
|
|
991
|
-
id: string // UUID v4
|
|
992
|
-
kind: "ax_tree" | "screenshot_jpeg"
|
|
993
|
-
encoding: "utf8" | "binary"
|
|
994
|
-
byteLength: number
|
|
995
|
-
sha256?: string // SHA-256 hex digest for integrity check
|
|
996
|
-
}
|
|
997
|
-
```
|
|
998
|
-
|
|
999
|
-
### Transport Decision Flow
|
|
1000
|
-
|
|
1001
|
-
```mermaid
|
|
1002
|
-
graph TB
|
|
1003
|
-
HAS_DATA{"Has large payload?"}
|
|
1004
|
-
BLOB_AVAIL{"isBlobTransportAvailable?"}
|
|
1005
|
-
THRESHOLD{"Above threshold?<br/>(screenshots: always,<br/>AX trees: >8KB)"}
|
|
1006
|
-
WRITE_BLOB["Write blob file<br/>atomic temp+rename"]
|
|
1007
|
-
WRITE_OK{"Write succeeded?"}
|
|
1008
|
-
SEND_REF["Send IpcBlobRef<br/>(inline field = nil)"]
|
|
1009
|
-
SEND_INLINE["Send inline<br/>(base64 / text)"]
|
|
1010
|
-
|
|
1011
|
-
HAS_DATA -->|Yes| BLOB_AVAIL
|
|
1012
|
-
HAS_DATA -->|No| SEND_INLINE
|
|
1013
|
-
BLOB_AVAIL -->|Yes| THRESHOLD
|
|
1014
|
-
BLOB_AVAIL -->|No| SEND_INLINE
|
|
1015
|
-
THRESHOLD -->|Yes| WRITE_BLOB
|
|
1016
|
-
THRESHOLD -->|No| SEND_INLINE
|
|
1017
|
-
WRITE_BLOB --> WRITE_OK
|
|
1018
|
-
WRITE_OK -->|Yes| SEND_REF
|
|
1019
|
-
WRITE_OK -->|No| SEND_INLINE
|
|
1020
|
-
```
|
|
1021
|
-
|
|
1022
|
-
### Daemon Hydration
|
|
1023
|
-
|
|
1024
|
-
When the daemon receives a CU observation with blob refs, it attempts blob-first hydration before the CU session processes the observation:
|
|
1025
|
-
|
|
1026
|
-
1. Validate the blob ref's `kind` and `encoding` match the expected field (`axTreeBlob` must be `kind=ax_tree, encoding=utf8`; `screenshotBlob` must be `kind=screenshot_jpeg, encoding=binary`).
|
|
1027
|
-
2. Verify the blob file is a regular file (not a symlink) and its realpath stays within the blob directory.
|
|
1028
|
-
3. Read the blob file, verify actual size matches `byteLength`, and check optional `sha256`.
|
|
1029
|
-
4. For screenshots: base64-encode the bytes into the `screenshot` field.
|
|
1030
|
-
5. For AX trees: decode UTF-8 bytes into the `axTree` field.
|
|
1031
|
-
6. Delete the consumed blob file.
|
|
777
|
+
## Client-Server Communication — HTTP + SSE
|
|
1032
778
|
|
|
1033
|
-
|
|
779
|
+
All client-server communication uses HTTP for request/response operations and Server-Sent Events (SSE) for streaming server-to-client events. The runtime HTTP server (`RUNTIME_HTTP_PORT`, default 7821) is the sole transport.
|
|
1034
780
|
|
|
1035
|
-
|
|
781
|
+
**Client → Server (HTTP POST):** Clients send messages, session operations, configuration changes, and approval decisions via HTTP endpoints (e.g., `POST /v1/messages`, `POST /v1/confirm`, `POST /v1/sessions`).
|
|
1036
782
|
|
|
1037
|
-
|
|
1038
|
-
- **Stale sweep**: The daemon runs a periodic sweep (every 5 minutes) to delete blob files older than 30 minutes, catching orphans from failed sends or crashes.
|
|
1039
|
-
- **Size limits**: Screenshot blobs are capped at 10MB, AX tree blobs at 2MB. Oversized blobs are rejected.
|
|
783
|
+
**Server → Client (SSE):** The daemon streams events to clients via `GET /v1/events`. All agent events (text deltas, tool execution, confirmations, session state changes) are published through the `assistantEventHub` and delivered as SSE events.
|
|
1040
784
|
|
|
1041
785
|
---
|
|
1042
786
|
|
|
1043
787
|
## Session Errors vs Global Errors
|
|
1044
788
|
|
|
1045
|
-
The daemon emits two distinct error message types
|
|
789
|
+
The daemon emits two distinct error message types via SSE:
|
|
1046
790
|
|
|
1047
791
|
| Message type | Scope | Purpose | Payload |
|
|
1048
792
|
| --------------- | -------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
@@ -1072,7 +816,7 @@ Classification uses a two-tier strategy:
|
|
|
1072
816
|
1. **Structured provider errors**: If the error is a `ProviderError` with a `statusCode`, the status code determines the category deterministically — `429` maps to `PROVIDER_RATE_LIMIT` (retryable), `5xx` to `PROVIDER_API` (retryable), other `4xx` to `PROVIDER_API` (not retryable).
|
|
1073
817
|
2. **Regex fallback**: For non-provider errors or `ProviderError` without a status code, regex pattern matching against the error message detects network failures, rate limits, and API errors. Phase-specific overrides handle queue and regeneration contexts.
|
|
1074
818
|
|
|
1075
|
-
Debug details are capped at 4,000 characters to prevent oversized
|
|
819
|
+
Debug details are capped at 4,000 characters to prevent oversized payloads.
|
|
1076
820
|
|
|
1077
821
|
### Error → Toast → Recovery Flow
|
|
1078
822
|
|
|
@@ -1097,14 +841,14 @@ sequenceDiagram
|
|
|
1097
841
|
UI->>VM: retryAfterSessionError()
|
|
1098
842
|
VM->>VM: dismissSessionError()<br/>+ regenerateLastMessage()
|
|
1099
843
|
VM->>DC: regenerate {sessionId}
|
|
1100
|
-
DC->>Daemon:
|
|
844
|
+
DC->>Daemon: HTTP POST /v1/messages
|
|
1101
845
|
else User taps Dismiss
|
|
1102
846
|
UI->>VM: dismissSessionError()
|
|
1103
847
|
VM->>VM: clear sessionError + errorText
|
|
1104
848
|
end
|
|
1105
849
|
```
|
|
1106
850
|
|
|
1107
|
-
1. **Daemon** encounters a session-scoped failure, classifies it via `classifySessionError()`, and sends a `session_error`
|
|
851
|
+
1. **Daemon** encounters a session-scoped failure, classifies it via `classifySessionError()`, and sends a `session_error` SSE event with the session ID, typed error code, user-facing message, retryable flag, and optional debug details. Session-scoped failures emit _only_ `session_error` (never the generic `error` type) to prevent cross-session bleed.
|
|
1108
852
|
2. **ChatViewModel** receives the error via DaemonClient's `subscribe()` stream (each view model gets an independent stream), sets the `sessionError` property, and transitions out of the streaming/loading state so the UI is interactive. If the error arrives during an active cancel (`wasCancelling == true`), it is suppressed — cancel only shows `generation_cancelled` behavior.
|
|
1109
853
|
3. **ChatView** observes the published `sessionError` and displays an actionable toast with a category-specific icon and accent color:
|
|
1110
854
|
- **Retry** (shown when `retryable` is true): calls `retryAfterSessionError()`, which clears the error and sends a `regenerate` message to the daemon.
|
|
@@ -1363,9 +1107,9 @@ graph TB
|
|
|
1363
1107
|
- macOS UI shows Inspect and Delete controls for managed skills only (source = "managed").
|
|
1364
1108
|
- `skill_load` validates the recursive include graph (via `include-graph.ts`) before emitting output. Missing children and cycles produce `isError: true` with no `<loaded_skill>` marker. Valid includes produce an "Included Skills (immediate)" metadata section showing child ID, name, description, and path.
|
|
1365
1109
|
|
|
1366
|
-
### Skills Authoring via
|
|
1110
|
+
### Skills Authoring via HTTP
|
|
1367
1111
|
|
|
1368
|
-
The Skills page in the macOS client can author managed skills through daemon
|
|
1112
|
+
The Skills page in the macOS client can author managed skills through the daemon HTTP API without going through the agent loop:
|
|
1369
1113
|
|
|
1370
1114
|
1. **Draft** (`skills_draft`): The client sends source text (with optional YAML frontmatter). The daemon parses frontmatter for metadata fields (skillId, name, description, emoji), fills missing fields via a latency-optimized LLM call, and falls back to deterministic heuristics if the provider is unavailable. Returns `skills_draft_response` with the complete draft.
|
|
1371
1115
|
2. **Create** (`skills_create`): The client sends finalized skill metadata and body. The daemon calls `createManagedSkill()` from `managed-store.ts`, auto-enables the skill in config, and broadcasts `skills_state_changed`.
|
|
@@ -1463,7 +1207,7 @@ graph TB
|
|
|
1463
1207
|
end
|
|
1464
1208
|
|
|
1465
1209
|
subgraph "Per-Turn Projection (session-skill-tools.ts)"
|
|
1466
|
-
DERIVE["
|
|
1210
|
+
DERIVE["deriveActiveSkills(history)<br/>scan all messages for markers"]
|
|
1467
1211
|
UNION["Union: context-derived ∪ preactivated"]
|
|
1468
1212
|
DIFF["Diff vs previous turn"]
|
|
1469
1213
|
UNREGISTER["unregisterSkillTools(removedId)<br/>tear down stale tools"]
|
|
@@ -1535,7 +1279,7 @@ graph TB
|
|
|
1535
1279
|
| `assistant/src/config/skills.ts` | Skill catalog loading: bundled, managed, workspace, extra directories |
|
|
1536
1280
|
| `assistant/src/config/bundled-skills/` | Bundled skill directories (browser, gmail, claude-code, computer-use, weather, etc.) |
|
|
1537
1281
|
| `assistant/src/skills/tool-manifest.ts` | `TOOLS.json` parser and validator |
|
|
1538
|
-
| `assistant/src/skills/active-skill-tools.ts` | `
|
|
1282
|
+
| `assistant/src/skills/active-skill-tools.ts` | `deriveActiveSkills()` — scans history for `<loaded_skill>` markers |
|
|
1539
1283
|
| `assistant/src/skills/include-graph.ts` | Include graph builder: `indexCatalogById()`, `validateIncludes()`, cycle/missing detection |
|
|
1540
1284
|
| `assistant/src/daemon/session-skill-tools.ts` | `projectSkillTools()` — per-turn projection, register/unregister lifecycle |
|
|
1541
1285
|
| `assistant/src/tools/skills/skill-tool-factory.ts` | `createSkillToolsFromManifest()` — manifest entries to Tool objects |
|
|
@@ -1698,7 +1442,7 @@ For `bash` and `host_bash` tool invocations, the permission system uses parser-d
|
|
|
1698
1442
|
|
|
1699
1443
|
### Prompt UX
|
|
1700
1444
|
|
|
1701
|
-
When a permission prompt is sent to the client (via `confirmation_request`
|
|
1445
|
+
When a permission prompt is sent to the client (via `confirmation_request` SSE event), it includes:
|
|
1702
1446
|
|
|
1703
1447
|
| Field | Content |
|
|
1704
1448
|
| ------------------ | --------------------------------------------------- |
|
|
@@ -1723,7 +1467,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
|
|
|
1723
1467
|
| `assistant/src/permissions/checker.ts` | `classifyRisk()`, `check()`, `buildCommandCandidates()`, allowlist/scope generation |
|
|
1724
1468
|
| `assistant/src/permissions/shell-identity.ts` | `analyzeShellCommand()`, `deriveShellActionKeys()`, `buildShellCommandCandidates()`, `buildShellAllowlistOptions()` — parser-based shell command identity and action key derivation |
|
|
1725
1469
|
| `assistant/src/permissions/trust-store.ts` | Rule persistence, `findHighestPriorityRule()`, execution-target matching, starter bundle |
|
|
1726
|
-
| `assistant/src/permissions/prompter.ts` |
|
|
1470
|
+
| `assistant/src/permissions/prompter.ts` | Prompt flow: `confirmation_request` (SSE) → `confirmation_response` (HTTP POST) |
|
|
1727
1471
|
| `assistant/src/permissions/defaults.ts` | Default rule templates (system ask rules for host tools, CU, etc.) |
|
|
1728
1472
|
| `assistant/src/skills/version-hash.ts` | `computeSkillVersionHash()` — deterministic SHA-256 of skill source files |
|
|
1729
1473
|
| `assistant/src/skills/path-classifier.ts` | `isSkillSourcePath()`, `normalizeFilePath()`, skill root detection |
|
|
@@ -1733,7 +1477,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
|
|
|
1733
1477
|
|
|
1734
1478
|
### Permission Simulation (Tool Permission Tester)
|
|
1735
1479
|
|
|
1736
|
-
The `tool_permission_simulate`
|
|
1480
|
+
The `tool_permission_simulate` HTTP endpoint lets clients dry-run a tool invocation through the full permission evaluation pipeline without actually executing the tool or mutating daemon state. The macOS Settings panel exposes this as a "Tool Permission Tester" UI.
|
|
1737
1481
|
|
|
1738
1482
|
**Simulation semantics:**
|
|
1739
1483
|
|
|
@@ -1829,7 +1573,7 @@ sequenceDiagram
|
|
|
1829
1573
|
User->>Chat: send message while busy
|
|
1830
1574
|
Chat->>VM: enqueue message
|
|
1831
1575
|
VM->>DC: user_message
|
|
1832
|
-
DC->>Daemon:
|
|
1576
|
+
DC->>Daemon: HTTP
|
|
1833
1577
|
Daemon-->>DC: message_queued (position)
|
|
1834
1578
|
DC-->>VM: show queue status
|
|
1835
1579
|
|
|
@@ -1852,7 +1596,7 @@ sequenceDiagram
|
|
|
1852
1596
|
|
|
1853
1597
|
## Trace System — Debug Panel Data Flow
|
|
1854
1598
|
|
|
1855
|
-
The trace system provides real-time observability of daemon session internals. Each session creates a `TraceEmitter` that emits structured `trace_event`
|
|
1599
|
+
The trace system provides real-time observability of daemon session internals. Each session creates a `TraceEmitter` that emits structured `trace_event` SSE events as the session processes requests, makes LLM calls, and executes tools.
|
|
1856
1600
|
|
|
1857
1601
|
```mermaid
|
|
1858
1602
|
sequenceDiagram
|
|
@@ -1869,7 +1613,7 @@ sequenceDiagram
|
|
|
1869
1613
|
|
|
1870
1614
|
User->>Chat: send message
|
|
1871
1615
|
Chat->>DC: user_message
|
|
1872
|
-
DC->>Daemon:
|
|
1616
|
+
DC->>Daemon: HTTP
|
|
1873
1617
|
|
|
1874
1618
|
Daemon->>TE: emit(request_received)
|
|
1875
1619
|
TE-->>DC: trace_event (request_received)
|
|
@@ -1934,9 +1678,9 @@ Events emitted during a session lifecycle:
|
|
|
1934
1678
|
|
|
1935
1679
|
### Architecture
|
|
1936
1680
|
|
|
1937
|
-
- **TraceEmitter** (daemon, per-session): Constructed with a `sessionId` and a `sendToClient` callback. Maintains a monotonic sequence counter for stable ordering. Truncates summaries to 200 chars and attribute values to 500 chars. Each call to `emit()` sends a `trace_event`
|
|
1681
|
+
- **TraceEmitter** (daemon, per-session): Constructed with a `sessionId` and a `sendToClient` callback. Maintains a monotonic sequence counter for stable ordering. Truncates summaries to 200 chars and attribute values to 500 chars. Each call to `emit()` sends a `trace_event` SSE event to connected clients.
|
|
1938
1682
|
- **ToolTraceListener** (daemon): Subscribes to the session's `EventBus` via `onAny()` and translates tool domain events (`tool.execution.started`, `tool.execution.finished`, `tool.execution.failed`, `tool.permission.requested`, `tool.permission.decided`, `tool.secret.detected`) into trace events through the `TraceEmitter`.
|
|
1939
|
-
- **DaemonClient** (Swift, shared): Decodes `trace_event`
|
|
1683
|
+
- **DaemonClient** (Swift, shared): Decodes `trace_event` SSE events into `TraceEventMessage` structs and invokes the `onTraceEvent` callback.
|
|
1940
1684
|
- **TraceStore** (Swift, macOS): `@MainActor ObservableObject` that ingests `TraceEventMessage` structs. Deduplicates by `eventId`, maintains stable sort order (sequence, then timestampMs, then insertion order), groups events by session and requestId, and enforces a retention cap of 5,000 events per session. Each request group is classified with a terminal status: `completed` (via `message_complete`), `cancelled` (via `generation_cancelled`), `handedOff` (via `generation_handoff`), `error` (via `request_error` or any event with `status == "error"`), or `active` (no terminal event yet).
|
|
1941
1685
|
- **DebugPanel** (Swift, macOS): SwiftUI view that observes `TraceStore`. Displays a metrics strip (request count, LLM calls, total tokens, average latency, tool failures) and a `TraceTimelineView` showing events grouped by requestId with color-coded status indicators. The timeline auto-scrolls to new events while the user is at the bottom; scrolling up pauses auto-scroll and shows a "Jump to bottom" button that resumes it.
|
|
1942
1686
|
|
|
@@ -1946,7 +1690,7 @@ Events emitted during a session lifecycle:
|
|
|
1946
1690
|
|
|
1947
1691
|
## Assistant Events — SSE Transport Layer
|
|
1948
1692
|
|
|
1949
|
-
The assistant-events system provides a single, shared publish path that fans out to
|
|
1693
|
+
The assistant-events system provides a single, shared publish path that fans out to all connected clients via HTTP SSE. The `ServerMessage` payload is wrapped in an `AssistantEvent` envelope and serialised as JSON.
|
|
1950
1694
|
|
|
1951
1695
|
### Data Flow
|
|
1952
1696
|
|
|
@@ -1954,7 +1698,7 @@ The assistant-events system provides a single, shared publish path that fans out
|
|
|
1954
1698
|
graph TB
|
|
1955
1699
|
subgraph "Event Sources"
|
|
1956
1700
|
direction TB
|
|
1957
|
-
|
|
1701
|
+
SESSION["Session process<br/>(session-process.ts)"]
|
|
1958
1702
|
HTTP_RUN["HTTP Run path<br/>(run-orchestrator.ts)"]
|
|
1959
1703
|
end
|
|
1960
1704
|
|
|
@@ -1962,9 +1706,8 @@ graph TB
|
|
|
1962
1706
|
HUB["AssistantEventHub<br/>(assistant-event-hub.ts)<br/>──────────────────────<br/>maxSubscribers: 100<br/>FIFO eviction on overflow<br/>Synchronous fan-out"]
|
|
1963
1707
|
end
|
|
1964
1708
|
|
|
1965
|
-
subgraph "
|
|
1709
|
+
subgraph "SSE Transport"
|
|
1966
1710
|
SSE_ROUTE["SSE Route<br/>GET /v1/events?conversationKey=...<br/>(events-routes.ts)<br/>──────────────────────<br/>ReadableStream + CountQueuingStrategy(16)<br/>Heartbeat every 30 s<br/>Slow-consumer shed"]
|
|
1967
|
-
SOCK["Unix Socket<br/>(daemon/session-surfaces.ts)"]
|
|
1968
1711
|
end
|
|
1969
1712
|
|
|
1970
1713
|
subgraph "Clients"
|
|
@@ -1973,13 +1716,12 @@ graph TB
|
|
|
1973
1716
|
WEB["Web / Remote clients<br/>(EventSource / fetch)"]
|
|
1974
1717
|
end
|
|
1975
1718
|
|
|
1976
|
-
|
|
1719
|
+
SESSION -->|"buildAssistantEvent()"| HUB
|
|
1977
1720
|
HTTP_RUN -->|"buildAssistantEvent()"| HUB
|
|
1978
|
-
IPC_DAEMON --> SOCK
|
|
1979
1721
|
|
|
1980
1722
|
HUB -->|"subscriber callback"| SSE_ROUTE
|
|
1981
1723
|
|
|
1982
|
-
|
|
1724
|
+
SSE_ROUTE --> MACOS
|
|
1983
1725
|
SSE_ROUTE --> IOS
|
|
1984
1726
|
SSE_ROUTE --> WEB
|
|
1985
1727
|
```
|
|
@@ -1994,7 +1736,7 @@ Every event published through the hub is wrapped in an `AssistantEvent` (defined
|
|
|
1994
1736
|
| `assistantId` | `string` | Logical assistant identifier (`"self"` for HTTP runs) |
|
|
1995
1737
|
| `sessionId` | `string?` | Resolved conversation ID when available |
|
|
1996
1738
|
| `emittedAt` | `string` (ISO-8601) | Server-side timestamp |
|
|
1997
|
-
| `message` | `ServerMessage` |
|
|
1739
|
+
| `message` | `ServerMessage` | The outbound message payload |
|
|
1998
1740
|
|
|
1999
1741
|
### SSE Frame Format
|
|
2000
1742
|
|
|
@@ -2029,7 +1771,7 @@ Keep-alive heartbeats (every 30 s by default):
|
|
|
2029
1771
|
| `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
|
|
2030
1772
|
| `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
|
|
2031
1773
|
| `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler |
|
|
2032
|
-
| `assistant/src/daemon/server.ts` |
|
|
1774
|
+
| `assistant/src/daemon/server.ts` | Session event paths that publish to the hub (`send` → `publishAssistantEvent`) |
|
|
2033
1775
|
|
|
2034
1776
|
---
|
|
2035
1777
|
|
|
@@ -2040,7 +1782,7 @@ The notification module (`assistant/src/notifications/`) uses a signal-based arc
|
|
|
2040
1782
|
```
|
|
2041
1783
|
Producer → NotificationSignal → Candidate Generation → Decision Engine (LLM) → Deterministic Checks → Broadcaster → Conversation Pairing → Adapters → Delivery
|
|
2042
1784
|
↑ ↓
|
|
2043
|
-
Preference Summary notification_thread_created
|
|
1785
|
+
Preference Summary notification_thread_created SSE event
|
|
2044
1786
|
Thread Candidates (creation-only — not emitted on reuse)
|
|
2045
1787
|
```
|
|
2046
1788
|
|
|
@@ -2052,7 +1794,7 @@ Producer → NotificationSignal → Candidate Generation → Decision Engine (LL
|
|
|
2052
1794
|
- **`conversationStrategy`** — how the notification pipeline materializes conversations for the channel:
|
|
2053
1795
|
- `start_new_conversation` — creates a fresh conversation per delivery (e.g. vellum desktop/mobile threads)
|
|
2054
1796
|
- `continue_existing_conversation` — intended to append to an existing channel-scoped conversation; currently materializes a background audit conversation per delivery (e.g. Telegram)
|
|
2055
|
-
- `not_deliverable` — channel cannot receive notifications (e.g.
|
|
1797
|
+
- `not_deliverable` — channel cannot receive notifications (e.g. phone)
|
|
2056
1798
|
|
|
2057
1799
|
Helper functions: `getDeliverableChannels()`, `getChannelPolicy()`, `isNotificationDeliverable()`, `getConversationStrategy()`.
|
|
2058
1800
|
|
|
@@ -2075,23 +1817,23 @@ The pairing function (`pairDeliveryWithConversation`) is resilient — errors ar
|
|
|
2075
1817
|
|
|
2076
1818
|
The notification pipeline uses a single conversation materialization path across producers:
|
|
2077
1819
|
|
|
2078
|
-
1. **Canonical pipeline** (`emitNotificationSignal` → decision engine → broadcaster → conversation pairing → adapters): The broadcaster pairs each delivery with a conversation, then dispatches a `notification_intent`
|
|
1820
|
+
1. **Canonical pipeline** (`emitNotificationSignal` → decision engine → broadcaster → conversation pairing → adapters): The broadcaster pairs each delivery with a conversation, then dispatches a `notification_intent` SSE event via the Vellum adapter. The payload includes `deepLinkMetadata` (e.g. `{ conversationId, messageId }`) so the macOS/iOS client can deep-link to the relevant context when the user taps the notification. When `messageId` is present, the client scrolls to that specific message within the thread (message-level anchoring).
|
|
2079
1821
|
2. **Guardian bookkeeping** (`dispatchGuardianQuestion`): Guardian dispatch creates `guardian_action_request` / `guardian_action_delivery` audit rows derived from pipeline delivery results and the per-dispatch `onThreadCreated` callback — there is no separate thread-creation path.
|
|
2080
1822
|
|
|
2081
|
-
### Thread Surfacing via `notification_thread_created`
|
|
1823
|
+
### Thread Surfacing via `notification_thread_created` (Creation-Only)
|
|
2082
1824
|
|
|
2083
|
-
The `notification_thread_created`
|
|
1825
|
+
The `notification_thread_created` SSE event is emitted **only when a brand-new conversation is created** by the broadcaster. Reusing an existing thread does not trigger this event — the macOS/iOS client already knows about the conversation from the original creation. This is enforced in `broadcaster.ts` by gating on `pairing.createdNewConversation === true`.
|
|
2084
1826
|
|
|
2085
|
-
When a new vellum notification thread is created (strategy `start_new_conversation`), the broadcaster emits the
|
|
1827
|
+
When a new vellum notification thread is created (strategy `start_new_conversation`), the broadcaster emits the event **immediately** (before waiting for slower channel deliveries like Telegram). This pushes the thread to the macOS/iOS client so it can display the notification thread in the sidebar and deep-link to it.
|
|
2086
1828
|
|
|
2087
|
-
###
|
|
1829
|
+
### Thread-Created Events
|
|
2088
1830
|
|
|
2089
|
-
Two
|
|
1831
|
+
Two SSE push events surface new threads in the macOS/iOS client sidebar:
|
|
2090
1832
|
|
|
2091
1833
|
- **`notification_thread_created`** — Emitted by `broadcaster.ts` when a notification delivery **creates** a new vellum conversation (strategy `start_new_conversation`, `createdNewConversation: true`). **Not** emitted when a thread is reused. Payload: `{ conversationId, title, sourceEventName }`.
|
|
2092
1834
|
- **`task_run_thread_created`** — Emitted by `work-item-runner.ts` when a task run creates a conversation. Payload: `{ conversationId, workItemId, title }`.
|
|
2093
1835
|
|
|
2094
|
-
All events follow the same pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the
|
|
1836
|
+
All events follow the same pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the SSE event so the macOS `ThreadManager` can create a visible thread in the sidebar.
|
|
2095
1837
|
|
|
2096
1838
|
### Thread Routing Decision Flow
|
|
2097
1839
|
|
|
@@ -2101,7 +1843,7 @@ The decision engine produces per-channel thread actions using a candidate-driven
|
|
|
2101
1843
|
2. **LLM decision**: The candidate set is serialized into the system prompt. The LLM chooses `start_new` or `reuse_existing` (with a candidate `conversationId`) per channel.
|
|
2102
1844
|
3. **Strict validation** (`validateThreadActions`): Reuse targets must exist in the candidate set. Invalid targets are downgraded to `start_new`.
|
|
2103
1845
|
4. **Pairing execution**: `pairDeliveryWithConversation` executes the thread action — appending to an existing conversation on reuse, creating a new one otherwise.
|
|
2104
|
-
5. **
|
|
1846
|
+
5. **Creation-only gating**: `notification_thread_created` fires only on actual creation, not on reuse.
|
|
2105
1847
|
6. **Audit trail**: Thread actions are persisted in both `notification_decisions.validation_results` and `notification_deliveries` columns (`thread_action`, `thread_target_conversation_id`, `thread_decision_fallback_used`).
|
|
2106
1848
|
|
|
2107
1849
|
### Guardian Call Thread Affinity
|
|
@@ -2121,7 +1863,7 @@ When the decision engine routes multiple guardian questions to the same conversa
|
|
|
2121
1863
|
- **Multiple pending deliveries**: The guardian must prefix their reply with the 6-char hex request code (e.g. `A1B2C3 yes, allow it`). Case-insensitive matching.
|
|
2122
1864
|
- **No match**: A disambiguation message is sent listing all active request codes.
|
|
2123
1865
|
|
|
2124
|
-
This invariant is enforced identically on mac/vellum (`session-process.ts`)
|
|
1866
|
+
This invariant is enforced identically on mac/vellum (`session-process.ts`) and Telegram (`inbound-message-handler.ts`). All disambiguation messages are generated through the guardian action message composer (LLM with deterministic fallback).
|
|
2125
1867
|
|
|
2126
1868
|
### Reminder Routing Metadata
|
|
2127
1869
|
|
|
@@ -2131,11 +1873,10 @@ Reminders carry optional `routingIntent` (`single_channel` | `multi_channel` | `
|
|
|
2131
1873
|
|
|
2132
1874
|
Notifications are delivered to three channel types:
|
|
2133
1875
|
|
|
2134
|
-
- **Vellum (always connected)**:
|
|
1876
|
+
- **Vellum (always connected)**: SSE via the daemon's broadcast mechanism. The `VellumAdapter` emits a `notification_intent` message with rendered copy and optional `deepLinkMetadata` (includes `conversationId` for thread navigation and `messageId` for message-level scroll anchoring).
|
|
2135
1877
|
- **Telegram (when guardian binding exists)**: HTTP POST to the gateway's `/deliver/telegram` endpoint. Requires an active guardian binding for the assistant.
|
|
2136
|
-
- **SMS (when guardian binding exists)**: HTTP POST to the gateway's `/deliver/sms` endpoint. Follows the same pattern as Telegram; the `SmsAdapter` sends text-only messages via the Twilio Messages API. The `assistantId` is threaded through the delivery payload for multi-assistant phone number resolution.
|
|
2137
1878
|
|
|
2138
|
-
Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram
|
|
1879
|
+
Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram) are included only when an active guardian binding exists for the assistant.
|
|
2139
1880
|
|
|
2140
1881
|
**Key modules:**
|
|
2141
1882
|
|
|
@@ -2145,13 +1886,12 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2145
1886
|
| `assistant/src/notifications/emit-signal.ts` | Single entry point for all producers; orchestrates the full pipeline |
|
|
2146
1887
|
| `assistant/src/notifications/decision-engine.ts` | LLM-based routing decisions with deterministic fallback |
|
|
2147
1888
|
| `assistant/src/notifications/deterministic-checks.ts` | Hard invariant checks (dedupe, source-active suppression, channel availability) |
|
|
2148
|
-
| `assistant/src/notifications/broadcaster.ts` | Dispatches decisions to channel adapters; emits `notification_thread_created`
|
|
1889
|
+
| `assistant/src/notifications/broadcaster.ts` | Dispatches decisions to channel adapters; emits `notification_thread_created` SSE event (creation-only) |
|
|
2149
1890
|
| `assistant/src/notifications/conversation-pairing.ts` | Materializes conversation + message per delivery; executes thread reuse decisions |
|
|
2150
1891
|
| `assistant/src/notifications/thread-candidates.ts` | Builds per-channel candidate set of recent conversations for the decision engine |
|
|
2151
|
-
| `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via
|
|
1892
|
+
| `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via SSE with deep-link metadata |
|
|
2152
1893
|
| `assistant/src/notifications/adapters/telegram.ts` | Telegram adapter — POSTs to gateway `/deliver/telegram` |
|
|
2153
|
-
| `assistant/src/notifications/
|
|
2154
|
-
| `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum IPC, Telegram chat ID from guardian binding) |
|
|
1894
|
+
| `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum SSE, Telegram chat ID from guardian binding) |
|
|
2155
1895
|
| `assistant/src/notifications/copy-composer.ts` | Template-based fallback copy when LLM copy is unavailable |
|
|
2156
1896
|
| `assistant/src/notifications/preference-extractor.ts` | Detects preference statements in conversation messages |
|
|
2157
1897
|
| `assistant/src/notifications/preferences-store.ts` | CRUD for user notification preferences |
|
|
@@ -2188,7 +1928,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2188
1928
|
| Trace events | In-memory (TraceStore) | Structured events | Swift ObservableObject | Max 5,000 per session, ephemeral |
|
|
2189
1929
|
| Media embed settings | `~/.vellum/workspace/config.json` (`ui.mediaEmbeds`) | JSON | `WorkspaceConfigIO` (atomic merge) | Permanent |
|
|
2190
1930
|
| Media embed MIME cache | In-memory (`ImageMIMEProbe`) | `NSCache` (500 entries) | HTTP HEAD | Ephemeral; cleared on app restart |
|
|
2191
|
-
| IPC blob payloads | `~/.vellum/workspace/data/ipc-blobs/` | Binary files (UUID names) | File I/O (atomic write) | Ephemeral; consumed on hydration, stale sweep every 5min |
|
|
2192
1931
|
| Tasks & task runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
|
|
2193
1932
|
| Work items (Task Queue) | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; archived items retained |
|
|
2194
1933
|
| Recurrence schedules & runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; supports cron and RRULE syntax |
|
|
@@ -2199,7 +1938,7 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2199
1938
|
| Call sessions, events, pending questions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on session delete |
|
|
2200
1939
|
| Active call controllers | In-memory (CallState) | Map<callSessionId, CallController> | Manual lifecycle | Ephemeral; cleared on call end or destroy |
|
|
2201
1940
|
| Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
|
|
2202
|
-
|
|
|
1941
|
+
| Channel verification sessions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired sessions retained |
|
|
2203
1942
|
| Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
|
|
2204
1943
|
| Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
|
|
2205
1944
|
| Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
|
|
@@ -2207,7 +1946,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2207
1946
|
| Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
|
|
2208
1947
|
| Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
|
|
2209
1948
|
| Notification preferences | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; per-assistant conversational preferences |
|
|
2210
|
-
| IPC transport | `~/.vellum/vellum.sock` | Unix domain socket | NWConnection (Swift) / Bun net | Ephemeral |
|
|
2211
1949
|
|
|
2212
1950
|
### Sensitive Tool Output Placeholder Substitution
|
|
2213
1951
|
|
|
@@ -2246,7 +1984,7 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
|
|
|
2246
1984
|
|
|
2247
1985
|
**Explicit trust gates:** `trustClass` is a **required** field in `ToolContext` (in `src/tools/types.ts`). Every tool execution must carry a trust classification — the field is not optional. This ensures trust-gated tool policies (guardian control-plane restrictions, host-tool blocking for untrusted actors) cannot be bypassed by omitting the classification.
|
|
2248
1986
|
|
|
2249
|
-
**Guardian bindings** (in `src/memory/channel-
|
|
1987
|
+
**Guardian bindings** (in `src/memory/channel-verification-sessions.ts`) always carry `guardianPrincipalId: string` as a required, non-null field. A binding without a principal ID is invalid and cannot be created.
|
|
2250
1988
|
|
|
2251
1989
|
**Strict retry sweep parsing:** The channel retry sweep (`src/runtime/channel-retry-sweep.ts`) uses `parseTrustRuntimeContext()` which validates `trustClass` against the canonical three-value set. There is no fallback to a legacy `actorRole` field — stored payloads that lack a valid `trustClass` are rejected deterministically to prevent silent privilege escalation. When `trustCtx` is entirely absent from a stored payload (pre-guardian events), the sweep synthesizes an explicit `trustClass: 'unknown'` context so that replay never proceeds without a trust classification.
|
|
2252
1990
|
|
|
@@ -2254,10 +1992,10 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
|
|
|
2254
1992
|
|
|
2255
1993
|
**Key files:**
|
|
2256
1994
|
|
|
2257
|
-
| File
|
|
2258
|
-
|
|
|
2259
|
-
| `src/daemon/session-runtime-assembly.ts`
|
|
2260
|
-
| `src/tools/types.ts`
|
|
2261
|
-
| `src/runtime/channel-retry-sweep.ts`
|
|
2262
|
-
| `src/memory/channel-
|
|
2263
|
-
| `src/__tests__/trust-context-guards.test.ts`
|
|
1995
|
+
| File | Purpose |
|
|
1996
|
+
| --------------------------------------------- | ----------------------------------------------------- |
|
|
1997
|
+
| `src/daemon/session-runtime-assembly.ts` | `TrustContext` type definition |
|
|
1998
|
+
| `src/tools/types.ts` | `ToolContext.trustClass` (required trust gate) |
|
|
1999
|
+
| `src/runtime/channel-retry-sweep.ts` | Strict `trustClass` parser for retry sweep |
|
|
2000
|
+
| `src/memory/channel-verification-sessions.ts` | `GuardianBinding` with required `guardianPrincipalId` |
|
|
2001
|
+
| `src/__tests__/trust-context-guards.test.ts` | Guard tests enforcing trust-context type invariants |
|