@vellumai/assistant 0.4.42 → 0.4.44
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 +140 -403
- package/Dockerfile +0 -1
- package/README.md +81 -92
- package/bun.lock +8 -2
- package/docs/architecture/integrations.md +81 -104
- 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 -3
- 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-asset.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 +41 -35
- 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 +7 -7
- 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 +10 -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__/error-handler-friendly-messages.test.ts +46 -0
- 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__/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 +357 -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 -12
- 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__/provider-fail-open-selection.test.ts +12 -2
- 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 -4
- 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 +17 -49
- 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 +10 -20
- 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 +7 -12
- 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 +48 -399
- 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 +475 -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/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} +14 -54
- package/src/{amazon → cli/commands/amazon}/request-extractor.ts +39 -3
- package/src/cli/commands/amazon/session.ts +108 -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} +15 -17
- 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/cli/commands/twitter/__tests__/cli-read-routing.test.ts +345 -0
- package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +252 -0
- package/src/{__tests__/twitter-oauth-client.test.ts → cli/commands/twitter/__tests__/oauth-client.test.ts} +2 -48
- package/src/cli/commands/twitter/index.ts +420 -0
- package/src/{twitter → cli/commands/twitter}/oauth-client.ts +1 -35
- package/src/cli/commands/twitter/router.ts +351 -0
- package/src/cli/commands/twitter/types.ts +30 -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 -6
- package/src/config/bundled-skills/api-mapping/SKILL.md +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +4 -9
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -4
- 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 +23 -77
- 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 -12
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +1 -90
- package/src/config/bundled-skills/doordash/doordash-cli.ts +132 -109
- package/src/config/bundled-skills/doordash/lib/session.ts +22 -19
- 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 +73 -144
- 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 +8 -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 +196 -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 +151 -105
- 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 +155 -55
- package/src/daemon/{ipc-contract.ts → message-protocol.ts} +49 -49
- package/src/daemon/{ipc-contract → message-types}/apps.ts +0 -25
- 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 +30 -20
- 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 +7 -1
- package/src/daemon/{ipc-contract → message-types}/shared.ts +0 -8
- package/src/daemon/{ipc-contract → message-types}/surfaces.ts +2 -0
- 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 +42 -14
- package/src/daemon/seed-files.ts +3 -27
- package/src/daemon/server.ts +134 -524
- package/src/daemon/session-agent-loop-handlers.ts +46 -9
- 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 -32
- package/src/daemon/session-surfaces.ts +187 -35
- package/src/daemon/session-tool-setup.ts +1 -1
- package/src/daemon/session-usage.ts +119 -18
- package/src/daemon/session.ts +11 -33
- 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 -60
- 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/schema/infrastructure.ts +0 -8
- 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 +9 -9
- 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 +44 -26
- package/src/{config → prompts}/templates/BOOTSTRAP.md +0 -3
- package/src/providers/registry.ts +2 -4
- 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__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +1 -1
- package/src/runtime/auth/__tests__/scopes.test.ts +2 -1
- package/src/runtime/auth/__tests__/subject.test.ts +32 -0
- package/src/runtime/auth/route-policy.ts +137 -25
- package/src/runtime/auth/scopes.ts +1 -0
- package/src/runtime/auth/subject.ts +9 -0
- package/src/runtime/auth/token-service.ts +12 -1
- 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 +44 -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/error-handler.ts +14 -1
- 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 +918 -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/brain-graph/brain-graph.html +1845 -0
- package/src/runtime/routes/brain-graph-routes.ts +4 -42
- 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 +20 -24
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +890 -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 +887 -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/AGENTS.md +38 -0
- package/src/tools/apps/executors.ts +0 -6
- 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/document/editor-template.ts +10 -8
- 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 +408 -0
- package/src/usage/types.ts +21 -0
- package/src/util/canonicalize-identity.ts +2 -6
- package/src/util/errors.ts +12 -0
- 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__/home-base-bootstrap.test.ts +0 -86
- 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__/prebuilt-home-base-seed.test.ts +0 -79
- 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__/twitter-cli-error-shaping.test.ts +0 -224
- package/src/__tests__/twitter-cli-routing.test.ts +0 -286
- 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/cli/twitter.ts +0 -1111
- 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 -783
- 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/home-base/app-link-store.ts +0 -78
- package/src/home-base/bootstrap.ts +0 -74
- package/src/home-base/prebuilt/brain-graph.html +0 -1483
- package/src/home-base/prebuilt/index.html +0 -702
- package/src/home-base/prebuilt/seed-metadata.json +0 -21
- package/src/home-base/prebuilt/seed.ts +0 -122
- package/src/home-base/prebuilt-home-base-updater.ts +0 -36
- 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/client.ts +0 -979
- package/src/twitter/router.ts +0 -131
- package/src/twitter/session.ts +0 -54
- package/src/util/cookie-session.ts +0 -114
- 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/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}/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}/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/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,19 +4,18 @@ 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` (
|
|
8
|
-
- Telegram webhook ingress
|
|
7
|
+
- Transport metadata arrives via `session_create.transport` (HTTP) or `/channels/inbound` (`channelId`, optional `hints`, optional `uxBrief`).
|
|
8
|
+
- Telegram webhook ingress injects deterministic channel-safe transport metadata (`hints` + `uxBrief`) so non-dashboard channels defer dashboard-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
|
-
- `OnboardingOrchestrator` derives onboarding-mode guidance (post-hatch sequence, USER.md capture
|
|
10
|
+
- `OnboardingOrchestrator` derives onboarding-mode guidance (post-hatch sequence, USER.md capture) from playbook + transport context.
|
|
11
11
|
- Session runtime assembly injects both `<channel_onboarding_playbook>` and `<onboarding_mode>` context before provider calls, then strips both from persisted conversation history.
|
|
12
|
-
-
|
|
13
|
-
- Home Base onboarding buttons relay prefilled natural-language prompts to the main assistant; permission setup remains user-initiated and hatch + first-conversation flows avoid proactive permission asks.
|
|
12
|
+
- Permission setup remains user-initiated and hatch + first-conversation flows avoid proactive permission asks.
|
|
14
13
|
|
|
15
14
|
### Guardian Actor Context (Unified Across Channels)
|
|
16
15
|
|
|
17
16
|
- Guardian/non-guardian/unverified classification is centralized in `assistant/src/runtime/trust-context-resolver.ts`.
|
|
18
17
|
- The same resolver is used by:
|
|
19
|
-
- `/channels/inbound` (Telegram/
|
|
18
|
+
- `/channels/inbound` (Telegram/WhatsApp path) before run orchestration.
|
|
20
19
|
- Inbound Twilio voice setup (`RelayConnection.handleSetup`) to seed call-time actor context.
|
|
21
20
|
- Runtime channel runs pass this as `trustContext`, and session runtime assembly injects `<inbound_actor_context>` (via `inboundActorContextFromTrustContext()`) into provider-facing prompts.
|
|
22
21
|
- 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 +40,12 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
41
40
|
|
|
42
41
|
**Subject patterns:**
|
|
43
42
|
|
|
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
|
|
43
|
+
| Pattern | Principal Type | Description |
|
|
44
|
+
| ---------------------------------------- | -------------- | ------------------------------------------- |
|
|
45
|
+
| `actor:<assistantId>:<actorPrincipalId>` | `actor` | Desktop, iOS, or CLI client |
|
|
46
|
+
| `svc:gateway:<assistantId>` | `svc_gateway` | Gateway service (ingress, webhooks) |
|
|
47
|
+
| `svc:internal:<assistantId>:<sessionId>` | `svc_internal` | Internal service connections |
|
|
48
|
+
| `svc:daemon:<identifier>` | `svc_daemon` | Daemon service token (local) |
|
|
50
49
|
|
|
51
50
|
**Scope profiles:**
|
|
52
51
|
|
|
@@ -55,17 +54,17 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
55
54
|
| `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
55
|
| `gateway_ingress_v1` | `ingress.write`, `internal.write` | Gateway channel inbound + webhook forwarding |
|
|
57
56
|
| `gateway_service_v1` | `settings.read`, `settings.write`, `internal.write` | Gateway service-to-daemon calls |
|
|
58
|
-
| `
|
|
57
|
+
| `internal_v1` | `internal.all` | Internal service connections |
|
|
59
58
|
|
|
60
59
|
**Identity lifecycle:**
|
|
61
60
|
|
|
62
|
-
1. **Bootstrap (loopback-only, macOS
|
|
61
|
+
1. **Bootstrap (loopback-only, macOS)** — On first launch, the macOS 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 }`. The CLI obtains its bearer token during `hatch` and does not perform a separate bootstrap step.
|
|
63
62
|
|
|
64
63
|
2. **iOS pairing** — iOS devices obtain JWTs through the QR pairing flow. The pairing response includes `accessToken` and `refreshToken` credentials.
|
|
65
64
|
|
|
66
|
-
3. **Refresh** — `POST /v1/
|
|
65
|
+
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
66
|
|
|
68
|
-
4. **
|
|
67
|
+
4. **Local identity** — Local connections use deterministic identity resolution without tokens.
|
|
69
68
|
|
|
70
69
|
**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
70
|
|
|
@@ -85,11 +84,11 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
|
|
|
85
84
|
| `src/runtime/auth/subject.ts` | Subject string parser (`parseSub`) |
|
|
86
85
|
| `src/runtime/auth/middleware.ts` | JWT bearer auth middleware (`authenticateRequest`) |
|
|
87
86
|
| `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/
|
|
87
|
+
| `src/runtime/routes/guardian-bootstrap-routes.ts` | `POST /v1/guardian/init` (initial JWT issuance) |
|
|
88
|
+
| `src/runtime/routes/guardian-refresh-routes.ts` | `POST /v1/guardian/refresh` (token rotation) |
|
|
90
89
|
| `src/runtime/routes/pairing-routes.ts` | JWT credential issuance in pairing flow |
|
|
91
|
-
| `src/runtime/local-actor-identity.ts` | `
|
|
92
|
-
| `src/memory/channel-
|
|
90
|
+
| `src/runtime/local-actor-identity.ts` | `resolveLocalGuardianContext` — deterministic local identity |
|
|
91
|
+
| `src/memory/channel-verification-sessions.ts` | Guardian binding types, verification session management |
|
|
93
92
|
|
|
94
93
|
### Channel-Agnostic Scoped Approval Grants
|
|
95
94
|
|
|
@@ -97,7 +96,7 @@ Scoped approval grants allow a guardian's approval decision on one channel (e.g.
|
|
|
97
96
|
|
|
98
97
|
### Guardian Decision Primitive (Dual-Mode Approval)
|
|
99
98
|
|
|
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,
|
|
99
|
+
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
100
|
|
|
102
101
|
**Core API:**
|
|
103
102
|
|
|
@@ -113,12 +112,12 @@ All guardian approval decisions — regardless of how they arrive — route thro
|
|
|
113
112
|
- `approve_always` is downgraded to `approve_once` for guardian-on-behalf requests (guardians cannot permanently allowlist tools for requesters).
|
|
114
113
|
- Scoped grant minting only fires on explicit approve for requests with tool metadata.
|
|
115
114
|
|
|
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,
|
|
115
|
+
**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
116
|
|
|
118
117
|
**Button-first path (deterministic):**
|
|
119
118
|
|
|
120
119
|
- 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`)
|
|
120
|
+
- Desktop clients submit decisions via HTTP (`POST /v1/guardian-actions/decision`), routed through `applyCanonicalGuardianDecision`.
|
|
122
121
|
- Channel adapters (Telegram inline keyboards, WhatsApp) encode actions as callback data (`apr:<requestId>:<action>`).
|
|
123
122
|
|
|
124
123
|
**Text fallback path (always available):**
|
|
@@ -137,8 +136,6 @@ All guardian approval decisions — regardless of how they arrive — route thro
|
|
|
137
136
|
| `src/approvals/guardian-decision-primitive.ts` | Unified decision application: downgrade, approval info capture, `handleChannelDecision`, record update, grant minting |
|
|
138
137
|
| `src/runtime/guardian-decision-types.ts` | Shared types: `GuardianDecisionPrompt`, `GuardianDecisionAction`, `buildDecisionActions`, `buildPlainTextFallback`, `ApplyGuardianDecisionResult` |
|
|
139
138
|
| `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
139
|
| `src/runtime/channel-approval-types.ts` | Channel-facing approval action types and `toApprovalActionOptions` bridge |
|
|
143
140
|
|
|
144
141
|
### Temporary Approval Modes (Session-Scoped Overrides)
|
|
@@ -167,17 +164,17 @@ In addition to persistent trust rules (`always_allow` / `always_deny`), the appr
|
|
|
167
164
|
|
|
168
165
|
### Canonical Guardian Request System
|
|
169
166
|
|
|
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/
|
|
167
|
+
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
168
|
|
|
172
169
|
**Architecture layers:**
|
|
173
170
|
|
|
174
171
|
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
172
|
|
|
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,
|
|
173
|
+
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
174
|
|
|
178
175
|
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
176
|
|
|
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)
|
|
177
|
+
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
178
|
|
|
182
179
|
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
180
|
|
|
@@ -198,51 +195,51 @@ The canonical guardian request system provides a channel-agnostic, unified domai
|
|
|
198
195
|
| `src/approvals/guardian-request-resolvers.ts` | Resolver registry: kind-specific side-effect dispatch after CAS resolution |
|
|
199
196
|
| `src/runtime/guardian-reply-router.ts` | Shared inbound router: callback -> code -> NL classification pipeline |
|
|
200
197
|
| `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
198
|
| `src/runtime/routes/canonical-guardian-expiry-sweep.ts` | Canonical request expiry sweep |
|
|
203
199
|
|
|
204
|
-
### Outbound
|
|
200
|
+
### Outbound Channel Verification (HTTP Endpoints)
|
|
205
201
|
|
|
206
|
-
|
|
202
|
+
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
203
|
|
|
208
204
|
**HTTP Endpoints:**
|
|
209
205
|
|
|
210
|
-
| Endpoint
|
|
211
|
-
|
|
|
212
|
-
| `/v1/
|
|
213
|
-
| `/v1/
|
|
214
|
-
| `/v1/
|
|
206
|
+
| Endpoint | Method | Description |
|
|
207
|
+
| ------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
208
|
+
| `/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? }` |
|
|
209
|
+
| `/v1/channel-verification-sessions/resend` | POST | Resend the verification code for an active outbound session. Body: `{ channel }` |
|
|
210
|
+
| `/v1/channel-verification-sessions` | DELETE | Cancel all active sessions (inbound + outbound) for a channel. Body: `{ channel }` |
|
|
211
|
+
| `/v1/channel-verification-sessions/revoke` | POST | Cancel all active sessions and revoke the guardian binding. Body: `{ channel? }` |
|
|
212
|
+
| `/v1/channel-verification-sessions/status` | GET | Check guardian binding status. Query: `?channel=<channel>` |
|
|
215
213
|
|
|
216
214
|
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
215
|
|
|
218
216
|
**Shared Business Logic:**
|
|
219
217
|
|
|
220
|
-
The HTTP route handlers (`
|
|
218
|
+
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
219
|
|
|
222
220
|
**Chat-First Orchestration Flow:**
|
|
223
221
|
|
|
224
|
-
1. The user asks the assistant (via desktop chat) to set up
|
|
225
|
-
2. The conversational routing layer detects the
|
|
222
|
+
1. The user asks the assistant (via desktop chat) to set up channel verification.
|
|
223
|
+
2. The conversational routing layer detects the verification-setup intent and loads the `guardian-verify-setup` skill via `skill_load`.
|
|
226
224
|
3. The skill guides the assistant through collecting the channel and destination, then calls the outbound HTTP endpoints using `curl`.
|
|
227
225
|
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 (
|
|
226
|
+
5. On the channel side, the verification code arrives (Telegram message or voice call) and the recipient enters it to complete the binding.
|
|
229
227
|
|
|
230
228
|
**Key Source Files:**
|
|
231
229
|
|
|
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 |
|
|
230
|
+
| File | Purpose |
|
|
231
|
+
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
232
|
+
| `src/runtime/verification-outbound-actions.ts` | Shared business logic for start/resend/cancel outbound verification |
|
|
233
|
+
| `src/runtime/routes/channel-verification-routes.ts` | HTTP route handlers for unified verification session API (`/v1/channel-verification-sessions`, `/revoke`, `/status`) |
|
|
234
|
+
| `src/config/bundled-skills/guardian-verify-setup/SKILL.md` | Skill that teaches the assistant how to orchestrate channel verification via chat |
|
|
238
235
|
|
|
239
236
|
**Guardian-Only Tool Invocation Gate:**
|
|
240
237
|
|
|
241
|
-
|
|
238
|
+
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
239
|
|
|
243
|
-
The policy is implemented in `src/tools/
|
|
240
|
+
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
241
|
|
|
245
|
-
The `guardian-verify-setup` skill is the exclusive handler for
|
|
242
|
+
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
243
|
|
|
247
244
|
### Guardian Action Timeout-to-Follow-Up Lifecycle
|
|
248
245
|
|
|
@@ -278,7 +275,7 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
|
|
|
278
275
|
|
|
279
276
|
**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
277
|
|
|
281
|
-
**Callback
|
|
278
|
+
**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
279
|
|
|
283
280
|
**Key source files:**
|
|
284
281
|
|
|
@@ -286,55 +283,18 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
|
|
|
286
283
|
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
287
284
|
| `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
285
|
| `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 `
|
|
286
|
+
| `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 |
|
|
287
|
+
| `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
288
|
| `src/daemon/guardian-action-generators.ts` | Daemon-injected generator factories: `createGuardianActionCopyGenerator` (latency-optimized text rewriting) and `createGuardianFollowUpConversationGenerator` (tool-calling intent classification) |
|
|
292
289
|
| `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
|
|
290
|
+
| `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 |
|
|
291
|
+
| `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
292
|
| `src/calls/guardian-action-sweep.ts` | Periodic sweep for stale pending requests; sends expiry notices to guardian destinations |
|
|
296
293
|
| `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
294
|
|
|
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
295
|
### WhatsApp Channel (Meta Cloud API)
|
|
336
296
|
|
|
337
|
-
The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsApp Business Cloud API. It follows the
|
|
297
|
+
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
298
|
|
|
339
299
|
**Ingress** (`GET /webhooks/whatsapp` — verification, `POST /webhooks/whatsapp` — messages):
|
|
340
300
|
|
|
@@ -365,9 +325,7 @@ These can be set via environment variables or stored in the credential vault (ke
|
|
|
365
325
|
|
|
366
326
|
**Limitations (v1)**: Rich approval UI (inline buttons) is not supported. Contacts and location message types are acknowledged but not forwarded.
|
|
367
327
|
|
|
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.
|
|
328
|
+
**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
329
|
|
|
372
330
|
### Slack Channel (Socket Mode)
|
|
373
331
|
|
|
@@ -406,14 +364,14 @@ Both `GET` and `POST` endpoints report `connected: true` only when both `hasBotT
|
|
|
406
364
|
|
|
407
365
|
**Key source files:**
|
|
408
366
|
|
|
409
|
-
| File
|
|
410
|
-
|
|
|
411
|
-
| `src/daemon/handlers/config-slack-channel.ts`
|
|
412
|
-
| `src/runtime/routes/
|
|
367
|
+
| File | Purpose |
|
|
368
|
+
| -------------------------------------------------- | --------------------------------------------------------------- |
|
|
369
|
+
| `src/daemon/handlers/config-slack-channel.ts` | Business logic for get/set/clear Slack channel config |
|
|
370
|
+
| `src/runtime/routes/integrations/slack/channel.ts` | HTTP route handlers for `/v1/integrations/slack/channel/config` |
|
|
413
371
|
|
|
414
372
|
### Trusted Contact Access (Channel-Agnostic)
|
|
415
373
|
|
|
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,
|
|
374
|
+
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
375
|
|
|
418
376
|
**Full design doc:** [`docs/trusted-contact-access.md`](docs/trusted-contact-access.md)
|
|
419
377
|
|
|
@@ -422,12 +380,12 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
422
380
|
1. Unknown user messages the assistant on any channel.
|
|
423
381
|
2. Ingress ACL (`inbound-message-handler.ts`) rejects the message and emits an `ingress.access_request` notification signal to the guardian.
|
|
424
382
|
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-
|
|
383
|
+
4. On approval, an identity-bound verification session with a 6-digit code is created (`access-request-decision.ts` → `channel-verification-service.ts`).
|
|
426
384
|
5. Guardian gives the code to the requester out-of-band.
|
|
427
385
|
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
386
|
7. All subsequent messages are accepted through the ingress ACL.
|
|
429
387
|
|
|
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,
|
|
388
|
+
**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
389
|
|
|
432
390
|
**Lifecycle states:** `requested → pending_guardian → verification_pending → active | denied | expired`
|
|
433
391
|
|
|
@@ -456,12 +414,13 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
456
414
|
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL, unknown-contact rejection, verification code interception |
|
|
457
415
|
| `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
|
|
458
416
|
| `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
|
|
459
|
-
| `src/runtime/channel-
|
|
417
|
+
| `src/runtime/channel-verification-service.ts` | Verification session lifecycle, identity binding, rate limiting |
|
|
460
418
|
| `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
|
|
461
419
|
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
|
|
462
420
|
| `src/runtime/invite-service.ts` | Business logic for invite operations |
|
|
463
421
|
| `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
|
|
464
|
-
| `src/memory/
|
|
422
|
+
| `src/memory/guardian-approvals.ts` | Approval request persistence |
|
|
423
|
+
| `src/memory/channel-verification-sessions.ts` | Verification challenge persistence |
|
|
465
424
|
| `src/config/bundled-skills/contacts/SKILL.md` | Unified skill for contact management, access control, and invite links |
|
|
466
425
|
|
|
467
426
|
### Guardian-Initiated Invite Links
|
|
@@ -480,7 +439,7 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
480
439
|
│ Registry of per-channel adapters: │
|
|
481
440
|
│ • buildShareableInvite(token) → { url, displayText } │
|
|
482
441
|
│ • extractInboundToken(payload) → token | undefined │
|
|
483
|
-
│ Registered: Telegram │ Deferred:
|
|
442
|
+
│ Registered: Telegram │ Deferred: Slack, Voice │
|
|
484
443
|
├─────────────────────────────────────────────────────────────┤
|
|
485
444
|
│ Core Redemption Engine (invite-redemption-service.ts) │
|
|
486
445
|
│ Channel-agnostic token validation, expiry, use-count, │
|
|
@@ -511,7 +470,6 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
511
470
|
| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
512
471
|
| Telegram | Shipped | Bot username resolved from credential metadata or `TELEGRAM_BOT_USERNAME` env |
|
|
513
472
|
| 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
473
|
| Slack | Deferred | Needs DM-safe ingress — Socket Mode handles channel messages but DM-initiated invite flows need routing |
|
|
516
474
|
|
|
517
475
|
### Voice Invite Flow (invite_redemption_pending)
|
|
@@ -520,7 +478,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
520
478
|
|
|
521
479
|
**Creation flow:**
|
|
522
480
|
|
|
523
|
-
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "
|
|
481
|
+
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "phone"` and `expectedExternalUserId` (E.164 phone).
|
|
524
482
|
2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
|
|
525
483
|
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
484
|
4. Guardian communicates the code to the invitee out-of-band.
|
|
@@ -550,7 +508,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
550
508
|
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
|
|
551
509
|
| `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
|
|
552
510
|
| `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
|
|
511
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by HTTP routes) |
|
|
554
512
|
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
|
|
555
513
|
| `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
|
|
556
514
|
| `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior) |
|
|
@@ -596,13 +554,13 @@ When no invite exists and no pending guardian challenge is active, the relay ent
|
|
|
596
554
|
1. The relay transitions to `awaiting_name` state and prompts the caller for their name with a timeout.
|
|
597
555
|
2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
|
|
598
556
|
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,
|
|
557
|
+
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
558
|
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
559
|
6. On denial or timeout: the caller hears a denial message and the call ends.
|
|
602
560
|
|
|
603
561
|
**Path 3: Inbound guardian verification (pending challenge)**
|
|
604
562
|
|
|
605
|
-
When a pending voice guardian challenge exists (`
|
|
563
|
+
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
564
|
|
|
607
565
|
**Canonical decision routing:**
|
|
608
566
|
|
|
@@ -630,7 +588,7 @@ Release-driven update notification system that surfaces release notes to the ass
|
|
|
630
588
|
|
|
631
589
|
**Data flow:**
|
|
632
590
|
|
|
633
|
-
1. **Bundled template** (`src/
|
|
591
|
+
1. **Bundled template** (`src/prompts/templates/UPDATES.md`) — source of release notes, maintained per-release in the repo.
|
|
634
592
|
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
593
|
3. **System prompt injection** — `buildSystemPrompt()` reads workspace `UPDATES.md` and injects it as a `## Recent Updates` section with judgment-based handling instructions.
|
|
636
594
|
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 +603,11 @@ Release-driven update notification system that surfaces release notes to the ass
|
|
|
645
603
|
|
|
646
604
|
| File | Purpose |
|
|
647
605
|
| -------------------------------------- | --------------------------------------------------------- |
|
|
648
|
-
| `src/
|
|
606
|
+
| `src/prompts/templates/UPDATES.md` | Bundled release-note template |
|
|
649
607
|
| `src/config/update-bulletin.ts` | Startup sync logic (materialize, delete-complete, merge) |
|
|
650
608
|
| `src/config/update-bulletin-format.ts` | Release block formatter/parser helpers |
|
|
651
609
|
| `src/config/update-bulletin-state.ts` | Checkpoint state helpers for active/completed releases |
|
|
652
|
-
| `src/
|
|
610
|
+
| `src/prompts/system-prompt.ts` | Prompt injection of updates section |
|
|
653
611
|
| `src/daemon/config-watcher.ts` | File watcher — evicts sessions on UPDATES.md changes |
|
|
654
612
|
| `src/permissions/defaults.ts` | Auto-allow rules for file_read/write/edit + rm UPDATES.md |
|
|
655
613
|
|
|
@@ -667,7 +625,7 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
|
|
|
667
625
|
2. Defaults registry `defaultEnabled` — from the unified registry (`meta/feature-flags/feature-flag-registry.json`, filtered to `scope: "assistant"`)
|
|
668
626
|
3. `true` — unknown/undeclared flags with no persisted override default to enabled
|
|
669
627
|
|
|
670
|
-
**Storage:** Flags are persisted in `~/.vellum/workspace/config.json
|
|
628
|
+
**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
629
|
|
|
672
630
|
**Public API:**
|
|
673
631
|
|
|
@@ -678,8 +636,8 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
|
|
|
678
636
|
|
|
679
637
|
| Enforcement Point | Module | Effect |
|
|
680
638
|
| ---------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
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 `
|
|
639
|
+
| **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. |
|
|
640
|
+
| **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
641
|
| **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
642
|
| **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
643
|
| **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 +652,11 @@ All five enforcement points use `isAssistantFeatureFlagEnabled(skillFlagKey(skil
|
|
|
694
652
|
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
695
653
|
| `src/config/assistant-feature-flags.ts` | Canonical resolver: `isAssistantFeatureFlagEnabled()`, `getAssistantFeatureFlagDefaults()`, registry loader |
|
|
696
654
|
| `src/config/skill-state.ts` | `skillFlagKey()` — derives canonical flag key for skills; `resolveSkillStates()` — enforcement point 1 |
|
|
697
|
-
| `src/
|
|
655
|
+
| `src/prompts/system-prompt.ts` | `appendSkillsCatalog()` — enforcement point 2 |
|
|
698
656
|
| `src/tools/skills/load.ts` | `executeSkillLoad()` — enforcement points 3 and 5 |
|
|
699
657
|
| `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 |
|
|
658
|
+
| `src/config/schema.ts` | `assistantFeatureFlagValues` field definition in `AssistantConfig` (Zod schema) |
|
|
659
|
+
| `src/daemon/handlers/skills.ts` | `handleSkillsList()` — uses `resolveSkillStates()` for client responses |
|
|
703
660
|
| `meta/feature-flags/feature-flag-registry.json` | Unified feature flag registry (repo root) — all declared flags with scope, label, default values, and descriptions |
|
|
704
661
|
| `src/config/feature-flag-registry.json` | Bundled copy of the unified registry for compiled binary resolution |
|
|
705
662
|
|
|
@@ -752,21 +709,16 @@ graph LR
|
|
|
752
709
|
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
710
|
end
|
|
754
711
|
|
|
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
712
|
subgraph "~/.vellum/ (Root Files)"
|
|
760
|
-
SOCK["vellum.sock<br/>Unix domain socket"]
|
|
761
713
|
TRUST["protected/trust.json<br/>Tool permission rules"]
|
|
762
714
|
FF_TOKEN["feature-flag-token<br/>Client token for feature-flag API"]
|
|
763
715
|
end
|
|
764
716
|
|
|
765
717
|
subgraph "~/.vellum/workspace/ (Workspace Files)"
|
|
766
|
-
CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes
|
|
718
|
+
CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes assistantFeatureFlagValues)"]
|
|
767
719
|
ONBOARD_PLAYBOOKS["onboarding/playbooks/<br/>[channel]_onboarding.md<br/>assistant-updatable checklists"]
|
|
768
720
|
ONBOARD_REGISTRY["onboarding/playbooks/registry.json<br/>channel-start index for fast-path + reconciliation"]
|
|
769
|
-
APPS_STORE["data/apps/<br/><app-id>.json + pages/*.html<br/>
|
|
721
|
+
APPS_STORE["data/apps/<br/><app-id>.json + pages/*.html<br/>User-created apps stored here"]
|
|
770
722
|
SKILLS_DIR["skills/<br/>managed skill directories<br/>SKILL.md + TOOLS.json + tools/"]
|
|
771
723
|
end
|
|
772
724
|
|
|
@@ -791,8 +743,8 @@ graph TB
|
|
|
791
743
|
end
|
|
792
744
|
|
|
793
745
|
subgraph "Local Mode"
|
|
794
|
-
LOCAL_CLIENT["
|
|
795
|
-
|
|
746
|
+
LOCAL_CLIENT["RuntimeClient"]
|
|
747
|
+
LOCAL_HTTP["HTTP API<br/>localhost:RUNTIME_HTTP_PORT"]
|
|
796
748
|
LOCAL_DAEMON["Local Daemon<br/>(same machine)"]
|
|
797
749
|
LOCAL_DB["~/.vellum/workspace/data/db/assistant.db"]
|
|
798
750
|
end
|
|
@@ -809,8 +761,8 @@ graph TB
|
|
|
809
761
|
AUTH --> PG
|
|
810
762
|
|
|
811
763
|
ROUTES -->|"ASSISTANT_CONNECTION_MODE=local"| LOCAL_CLIENT
|
|
812
|
-
LOCAL_CLIENT -->
|
|
813
|
-
|
|
764
|
+
LOCAL_CLIENT --> LOCAL_HTTP
|
|
765
|
+
LOCAL_HTTP --> LOCAL_DAEMON
|
|
814
766
|
LOCAL_DAEMON --> LOCAL_DB
|
|
815
767
|
|
|
816
768
|
ROUTES -->|"ASSISTANT_CONNECTION_MODE=cloud"| RUNTIME_CLIENT
|
|
@@ -821,228 +773,19 @@ graph TB
|
|
|
821
773
|
|
|
822
774
|
---
|
|
823
775
|
|
|
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.
|
|
776
|
+
## Client-Server Communication — HTTP + SSE
|
|
1032
777
|
|
|
1033
|
-
|
|
778
|
+
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
779
|
|
|
1035
|
-
|
|
780
|
+
**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
781
|
|
|
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.
|
|
782
|
+
**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
783
|
|
|
1041
784
|
---
|
|
1042
785
|
|
|
1043
786
|
## Session Errors vs Global Errors
|
|
1044
787
|
|
|
1045
|
-
The daemon emits two distinct error message types
|
|
788
|
+
The daemon emits two distinct error message types via SSE:
|
|
1046
789
|
|
|
1047
790
|
| Message type | Scope | Purpose | Payload |
|
|
1048
791
|
| --------------- | -------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
@@ -1072,7 +815,7 @@ Classification uses a two-tier strategy:
|
|
|
1072
815
|
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
816
|
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
817
|
|
|
1075
|
-
Debug details are capped at 4,000 characters to prevent oversized
|
|
818
|
+
Debug details are capped at 4,000 characters to prevent oversized payloads.
|
|
1076
819
|
|
|
1077
820
|
### Error → Toast → Recovery Flow
|
|
1078
821
|
|
|
@@ -1097,14 +840,14 @@ sequenceDiagram
|
|
|
1097
840
|
UI->>VM: retryAfterSessionError()
|
|
1098
841
|
VM->>VM: dismissSessionError()<br/>+ regenerateLastMessage()
|
|
1099
842
|
VM->>DC: regenerate {sessionId}
|
|
1100
|
-
DC->>Daemon:
|
|
843
|
+
DC->>Daemon: HTTP POST /v1/messages
|
|
1101
844
|
else User taps Dismiss
|
|
1102
845
|
UI->>VM: dismissSessionError()
|
|
1103
846
|
VM->>VM: clear sessionError + errorText
|
|
1104
847
|
end
|
|
1105
848
|
```
|
|
1106
849
|
|
|
1107
|
-
1. **Daemon** encounters a session-scoped failure, classifies it via `classifySessionError()`, and sends a `session_error`
|
|
850
|
+
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
851
|
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
852
|
3. **ChatView** observes the published `sessionError` and displays an actionable toast with a category-specific icon and accent color:
|
|
1110
853
|
- **Retry** (shown when `retryable` is true): calls `retryAfterSessionError()`, which clears the error and sends a `regenerate` message to the daemon.
|
|
@@ -1363,9 +1106,9 @@ graph TB
|
|
|
1363
1106
|
- macOS UI shows Inspect and Delete controls for managed skills only (source = "managed").
|
|
1364
1107
|
- `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
1108
|
|
|
1366
|
-
### Skills Authoring via
|
|
1109
|
+
### Skills Authoring via HTTP
|
|
1367
1110
|
|
|
1368
|
-
The Skills page in the macOS client can author managed skills through daemon
|
|
1111
|
+
The Skills page in the macOS client can author managed skills through the daemon HTTP API without going through the agent loop:
|
|
1369
1112
|
|
|
1370
1113
|
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
1114
|
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 +1206,7 @@ graph TB
|
|
|
1463
1206
|
end
|
|
1464
1207
|
|
|
1465
1208
|
subgraph "Per-Turn Projection (session-skill-tools.ts)"
|
|
1466
|
-
DERIVE["
|
|
1209
|
+
DERIVE["deriveActiveSkills(history)<br/>scan all messages for markers"]
|
|
1467
1210
|
UNION["Union: context-derived ∪ preactivated"]
|
|
1468
1211
|
DIFF["Diff vs previous turn"]
|
|
1469
1212
|
UNREGISTER["unregisterSkillTools(removedId)<br/>tear down stale tools"]
|
|
@@ -1535,7 +1278,7 @@ graph TB
|
|
|
1535
1278
|
| `assistant/src/config/skills.ts` | Skill catalog loading: bundled, managed, workspace, extra directories |
|
|
1536
1279
|
| `assistant/src/config/bundled-skills/` | Bundled skill directories (browser, gmail, claude-code, computer-use, weather, etc.) |
|
|
1537
1280
|
| `assistant/src/skills/tool-manifest.ts` | `TOOLS.json` parser and validator |
|
|
1538
|
-
| `assistant/src/skills/active-skill-tools.ts` | `
|
|
1281
|
+
| `assistant/src/skills/active-skill-tools.ts` | `deriveActiveSkills()` — scans history for `<loaded_skill>` markers |
|
|
1539
1282
|
| `assistant/src/skills/include-graph.ts` | Include graph builder: `indexCatalogById()`, `validateIncludes()`, cycle/missing detection |
|
|
1540
1283
|
| `assistant/src/daemon/session-skill-tools.ts` | `projectSkillTools()` — per-turn projection, register/unregister lifecycle |
|
|
1541
1284
|
| `assistant/src/tools/skills/skill-tool-factory.ts` | `createSkillToolsFromManifest()` — manifest entries to Tool objects |
|
|
@@ -1698,7 +1441,7 @@ For `bash` and `host_bash` tool invocations, the permission system uses parser-d
|
|
|
1698
1441
|
|
|
1699
1442
|
### Prompt UX
|
|
1700
1443
|
|
|
1701
|
-
When a permission prompt is sent to the client (via `confirmation_request`
|
|
1444
|
+
When a permission prompt is sent to the client (via `confirmation_request` SSE event), it includes:
|
|
1702
1445
|
|
|
1703
1446
|
| Field | Content |
|
|
1704
1447
|
| ------------------ | --------------------------------------------------- |
|
|
@@ -1723,7 +1466,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
|
|
|
1723
1466
|
| `assistant/src/permissions/checker.ts` | `classifyRisk()`, `check()`, `buildCommandCandidates()`, allowlist/scope generation |
|
|
1724
1467
|
| `assistant/src/permissions/shell-identity.ts` | `analyzeShellCommand()`, `deriveShellActionKeys()`, `buildShellCommandCandidates()`, `buildShellAllowlistOptions()` — parser-based shell command identity and action key derivation |
|
|
1725
1468
|
| `assistant/src/permissions/trust-store.ts` | Rule persistence, `findHighestPriorityRule()`, execution-target matching, starter bundle |
|
|
1726
|
-
| `assistant/src/permissions/prompter.ts` |
|
|
1469
|
+
| `assistant/src/permissions/prompter.ts` | Prompt flow: `confirmation_request` (SSE) → `confirmation_response` (HTTP POST) |
|
|
1727
1470
|
| `assistant/src/permissions/defaults.ts` | Default rule templates (system ask rules for host tools, CU, etc.) |
|
|
1728
1471
|
| `assistant/src/skills/version-hash.ts` | `computeSkillVersionHash()` — deterministic SHA-256 of skill source files |
|
|
1729
1472
|
| `assistant/src/skills/path-classifier.ts` | `isSkillSourcePath()`, `normalizeFilePath()`, skill root detection |
|
|
@@ -1733,7 +1476,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
|
|
|
1733
1476
|
|
|
1734
1477
|
### Permission Simulation (Tool Permission Tester)
|
|
1735
1478
|
|
|
1736
|
-
The `tool_permission_simulate`
|
|
1479
|
+
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
1480
|
|
|
1738
1481
|
**Simulation semantics:**
|
|
1739
1482
|
|
|
@@ -1829,7 +1572,7 @@ sequenceDiagram
|
|
|
1829
1572
|
User->>Chat: send message while busy
|
|
1830
1573
|
Chat->>VM: enqueue message
|
|
1831
1574
|
VM->>DC: user_message
|
|
1832
|
-
DC->>Daemon:
|
|
1575
|
+
DC->>Daemon: HTTP
|
|
1833
1576
|
Daemon-->>DC: message_queued (position)
|
|
1834
1577
|
DC-->>VM: show queue status
|
|
1835
1578
|
|
|
@@ -1852,7 +1595,7 @@ sequenceDiagram
|
|
|
1852
1595
|
|
|
1853
1596
|
## Trace System — Debug Panel Data Flow
|
|
1854
1597
|
|
|
1855
|
-
The trace system provides real-time observability of daemon session internals. Each session creates a `TraceEmitter` that emits structured `trace_event`
|
|
1598
|
+
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
1599
|
|
|
1857
1600
|
```mermaid
|
|
1858
1601
|
sequenceDiagram
|
|
@@ -1869,7 +1612,7 @@ sequenceDiagram
|
|
|
1869
1612
|
|
|
1870
1613
|
User->>Chat: send message
|
|
1871
1614
|
Chat->>DC: user_message
|
|
1872
|
-
DC->>Daemon:
|
|
1615
|
+
DC->>Daemon: HTTP
|
|
1873
1616
|
|
|
1874
1617
|
Daemon->>TE: emit(request_received)
|
|
1875
1618
|
TE-->>DC: trace_event (request_received)
|
|
@@ -1934,9 +1677,9 @@ Events emitted during a session lifecycle:
|
|
|
1934
1677
|
|
|
1935
1678
|
### Architecture
|
|
1936
1679
|
|
|
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`
|
|
1680
|
+
- **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
1681
|
- **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`
|
|
1682
|
+
- **DaemonClient** (Swift, shared): Decodes `trace_event` SSE events into `TraceEventMessage` structs and invokes the `onTraceEvent` callback.
|
|
1940
1683
|
- **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
1684
|
- **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
1685
|
|
|
@@ -1946,7 +1689,7 @@ Events emitted during a session lifecycle:
|
|
|
1946
1689
|
|
|
1947
1690
|
## Assistant Events — SSE Transport Layer
|
|
1948
1691
|
|
|
1949
|
-
The assistant-events system provides a single, shared publish path that fans out to
|
|
1692
|
+
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
1693
|
|
|
1951
1694
|
### Data Flow
|
|
1952
1695
|
|
|
@@ -1954,7 +1697,7 @@ The assistant-events system provides a single, shared publish path that fans out
|
|
|
1954
1697
|
graph TB
|
|
1955
1698
|
subgraph "Event Sources"
|
|
1956
1699
|
direction TB
|
|
1957
|
-
|
|
1700
|
+
SESSION["Session process<br/>(session-process.ts)"]
|
|
1958
1701
|
HTTP_RUN["HTTP Run path<br/>(run-orchestrator.ts)"]
|
|
1959
1702
|
end
|
|
1960
1703
|
|
|
@@ -1962,9 +1705,8 @@ graph TB
|
|
|
1962
1705
|
HUB["AssistantEventHub<br/>(assistant-event-hub.ts)<br/>──────────────────────<br/>maxSubscribers: 100<br/>FIFO eviction on overflow<br/>Synchronous fan-out"]
|
|
1963
1706
|
end
|
|
1964
1707
|
|
|
1965
|
-
subgraph "
|
|
1708
|
+
subgraph "SSE Transport"
|
|
1966
1709
|
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
1710
|
end
|
|
1969
1711
|
|
|
1970
1712
|
subgraph "Clients"
|
|
@@ -1973,13 +1715,12 @@ graph TB
|
|
|
1973
1715
|
WEB["Web / Remote clients<br/>(EventSource / fetch)"]
|
|
1974
1716
|
end
|
|
1975
1717
|
|
|
1976
|
-
|
|
1718
|
+
SESSION -->|"buildAssistantEvent()"| HUB
|
|
1977
1719
|
HTTP_RUN -->|"buildAssistantEvent()"| HUB
|
|
1978
|
-
IPC_DAEMON --> SOCK
|
|
1979
1720
|
|
|
1980
1721
|
HUB -->|"subscriber callback"| SSE_ROUTE
|
|
1981
1722
|
|
|
1982
|
-
|
|
1723
|
+
SSE_ROUTE --> MACOS
|
|
1983
1724
|
SSE_ROUTE --> IOS
|
|
1984
1725
|
SSE_ROUTE --> WEB
|
|
1985
1726
|
```
|
|
@@ -1994,7 +1735,7 @@ Every event published through the hub is wrapped in an `AssistantEvent` (defined
|
|
|
1994
1735
|
| `assistantId` | `string` | Logical assistant identifier (`"self"` for HTTP runs) |
|
|
1995
1736
|
| `sessionId` | `string?` | Resolved conversation ID when available |
|
|
1996
1737
|
| `emittedAt` | `string` (ISO-8601) | Server-side timestamp |
|
|
1997
|
-
| `message` | `ServerMessage` |
|
|
1738
|
+
| `message` | `ServerMessage` | The outbound message payload |
|
|
1998
1739
|
|
|
1999
1740
|
### SSE Frame Format
|
|
2000
1741
|
|
|
@@ -2024,12 +1765,12 @@ Keep-alive heartbeats (every 30 s by default):
|
|
|
2024
1765
|
|
|
2025
1766
|
### Key Source Files
|
|
2026
1767
|
|
|
2027
|
-
| File | Role
|
|
2028
|
-
| ----------------------------------------------- |
|
|
2029
|
-
| `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers
|
|
2030
|
-
| `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton
|
|
2031
|
-
| `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler
|
|
2032
|
-
| `assistant/src/daemon/server.ts` |
|
|
1768
|
+
| File | Role |
|
|
1769
|
+
| ----------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
1770
|
+
| `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
|
|
1771
|
+
| `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
|
|
1772
|
+
| `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler |
|
|
1773
|
+
| `assistant/src/daemon/server.ts` | Session event paths that publish to the hub (`send` → `publishAssistantEvent`) |
|
|
2033
1774
|
|
|
2034
1775
|
---
|
|
2035
1776
|
|
|
@@ -2040,7 +1781,7 @@ The notification module (`assistant/src/notifications/`) uses a signal-based arc
|
|
|
2040
1781
|
```
|
|
2041
1782
|
Producer → NotificationSignal → Candidate Generation → Decision Engine (LLM) → Deterministic Checks → Broadcaster → Conversation Pairing → Adapters → Delivery
|
|
2042
1783
|
↑ ↓
|
|
2043
|
-
Preference Summary notification_thread_created
|
|
1784
|
+
Preference Summary notification_thread_created SSE event
|
|
2044
1785
|
Thread Candidates (creation-only — not emitted on reuse)
|
|
2045
1786
|
```
|
|
2046
1787
|
|
|
@@ -2052,7 +1793,7 @@ Producer → NotificationSignal → Candidate Generation → Decision Engine (LL
|
|
|
2052
1793
|
- **`conversationStrategy`** — how the notification pipeline materializes conversations for the channel:
|
|
2053
1794
|
- `start_new_conversation` — creates a fresh conversation per delivery (e.g. vellum desktop/mobile threads)
|
|
2054
1795
|
- `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.
|
|
1796
|
+
- `not_deliverable` — channel cannot receive notifications (e.g. phone)
|
|
2056
1797
|
|
|
2057
1798
|
Helper functions: `getDeliverableChannels()`, `getChannelPolicy()`, `isNotificationDeliverable()`, `getConversationStrategy()`.
|
|
2058
1799
|
|
|
@@ -2075,23 +1816,23 @@ The pairing function (`pairDeliveryWithConversation`) is resilient — errors ar
|
|
|
2075
1816
|
|
|
2076
1817
|
The notification pipeline uses a single conversation materialization path across producers:
|
|
2077
1818
|
|
|
2078
|
-
1. **Canonical pipeline** (`emitNotificationSignal` → decision engine → broadcaster → conversation pairing → adapters): The broadcaster pairs each delivery with a conversation, then dispatches a `notification_intent`
|
|
1819
|
+
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
1820
|
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
1821
|
|
|
2081
|
-
### Thread Surfacing via `notification_thread_created`
|
|
1822
|
+
### Thread Surfacing via `notification_thread_created` (Creation-Only)
|
|
2082
1823
|
|
|
2083
|
-
The `notification_thread_created`
|
|
1824
|
+
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
1825
|
|
|
2085
|
-
When a new vellum notification thread is created (strategy `start_new_conversation`), the broadcaster emits the
|
|
1826
|
+
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
1827
|
|
|
2087
|
-
###
|
|
1828
|
+
### Thread-Created Events
|
|
2088
1829
|
|
|
2089
|
-
Two
|
|
1830
|
+
Two SSE push events surface new threads in the macOS/iOS client sidebar:
|
|
2090
1831
|
|
|
2091
1832
|
- **`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
1833
|
- **`task_run_thread_created`** — Emitted by `work-item-runner.ts` when a task run creates a conversation. Payload: `{ conversationId, workItemId, title }`.
|
|
2093
1834
|
|
|
2094
|
-
All events follow the same pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the
|
|
1835
|
+
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
1836
|
|
|
2096
1837
|
### Thread Routing Decision Flow
|
|
2097
1838
|
|
|
@@ -2101,7 +1842,7 @@ The decision engine produces per-channel thread actions using a candidate-driven
|
|
|
2101
1842
|
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
1843
|
3. **Strict validation** (`validateThreadActions`): Reuse targets must exist in the candidate set. Invalid targets are downgraded to `start_new`.
|
|
2103
1844
|
4. **Pairing execution**: `pairDeliveryWithConversation` executes the thread action — appending to an existing conversation on reuse, creating a new one otherwise.
|
|
2104
|
-
5. **
|
|
1845
|
+
5. **Creation-only gating**: `notification_thread_created` fires only on actual creation, not on reuse.
|
|
2105
1846
|
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
1847
|
|
|
2107
1848
|
### Guardian Call Thread Affinity
|
|
@@ -2121,7 +1862,7 @@ When the decision engine routes multiple guardian questions to the same conversa
|
|
|
2121
1862
|
- **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
1863
|
- **No match**: A disambiguation message is sent listing all active request codes.
|
|
2123
1864
|
|
|
2124
|
-
This invariant is enforced identically on mac/vellum (`session-process.ts`)
|
|
1865
|
+
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
1866
|
|
|
2126
1867
|
### Reminder Routing Metadata
|
|
2127
1868
|
|
|
@@ -2131,11 +1872,10 @@ Reminders carry optional `routingIntent` (`single_channel` | `multi_channel` | `
|
|
|
2131
1872
|
|
|
2132
1873
|
Notifications are delivered to three channel types:
|
|
2133
1874
|
|
|
2134
|
-
- **Vellum (always connected)**:
|
|
1875
|
+
- **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
1876
|
- **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
1877
|
|
|
2138
|
-
Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram
|
|
1878
|
+
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
1879
|
|
|
2140
1880
|
**Key modules:**
|
|
2141
1881
|
|
|
@@ -2145,13 +1885,12 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2145
1885
|
| `assistant/src/notifications/emit-signal.ts` | Single entry point for all producers; orchestrates the full pipeline |
|
|
2146
1886
|
| `assistant/src/notifications/decision-engine.ts` | LLM-based routing decisions with deterministic fallback |
|
|
2147
1887
|
| `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`
|
|
1888
|
+
| `assistant/src/notifications/broadcaster.ts` | Dispatches decisions to channel adapters; emits `notification_thread_created` SSE event (creation-only) |
|
|
2149
1889
|
| `assistant/src/notifications/conversation-pairing.ts` | Materializes conversation + message per delivery; executes thread reuse decisions |
|
|
2150
1890
|
| `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
|
|
1891
|
+
| `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via SSE with deep-link metadata |
|
|
2152
1892
|
| `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) |
|
|
1893
|
+
| `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum SSE, Telegram chat ID from guardian binding) |
|
|
2155
1894
|
| `assistant/src/notifications/copy-composer.ts` | Template-based fallback copy when LLM copy is unavailable |
|
|
2156
1895
|
| `assistant/src/notifications/preference-extractor.ts` | Detects preference statements in conversation messages |
|
|
2157
1896
|
| `assistant/src/notifications/preferences-store.ts` | CRUD for user notification preferences |
|
|
@@ -2188,7 +1927,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2188
1927
|
| Trace events | In-memory (TraceStore) | Structured events | Swift ObservableObject | Max 5,000 per session, ephemeral |
|
|
2189
1928
|
| Media embed settings | `~/.vellum/workspace/config.json` (`ui.mediaEmbeds`) | JSON | `WorkspaceConfigIO` (atomic merge) | Permanent |
|
|
2190
1929
|
| 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
1930
|
| Tasks & task runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
|
|
2193
1931
|
| Work items (Task Queue) | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; archived items retained |
|
|
2194
1932
|
| Recurrence schedules & runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; supports cron and RRULE syntax |
|
|
@@ -2199,7 +1937,7 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2199
1937
|
| Call sessions, events, pending questions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on session delete |
|
|
2200
1938
|
| Active call controllers | In-memory (CallState) | Map<callSessionId, CallController> | Manual lifecycle | Ephemeral; cleared on call end or destroy |
|
|
2201
1939
|
| Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
|
|
2202
|
-
|
|
|
1940
|
+
| Channel verification sessions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired sessions retained |
|
|
2203
1941
|
| Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
|
|
2204
1942
|
| Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
|
|
2205
1943
|
| Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
|
|
@@ -2207,7 +1945,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2207
1945
|
| Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
|
|
2208
1946
|
| Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
|
|
2209
1947
|
| 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
1948
|
|
|
2212
1949
|
### Sensitive Tool Output Placeholder Substitution
|
|
2213
1950
|
|
|
@@ -2246,7 +1983,7 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
|
|
|
2246
1983
|
|
|
2247
1984
|
**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
1985
|
|
|
2249
|
-
**Guardian bindings** (in `src/memory/channel-
|
|
1986
|
+
**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
1987
|
|
|
2251
1988
|
**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
1989
|
|
|
@@ -2254,10 +1991,10 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
|
|
|
2254
1991
|
|
|
2255
1992
|
**Key files:**
|
|
2256
1993
|
|
|
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`
|
|
1994
|
+
| File | Purpose |
|
|
1995
|
+
| --------------------------------------------- | ----------------------------------------------------- |
|
|
1996
|
+
| `src/daemon/session-runtime-assembly.ts` | `TrustContext` type definition |
|
|
1997
|
+
| `src/tools/types.ts` | `ToolContext.trustClass` (required trust gate) |
|
|
1998
|
+
| `src/runtime/channel-retry-sweep.ts` | Strict `trustClass` parser for retry sweep |
|
|
1999
|
+
| `src/memory/channel-verification-sessions.ts` | `GuardianBinding` with required `guardianPrincipalId` |
|
|
2000
|
+
| `src/__tests__/trust-context-guards.test.ts` | Guard tests enforcing trust-context type invariants |
|