@cohortapp/agent-sdk 2.3.0
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/.claude/commands/init-agent.md +104 -0
- package/.claude/commands/init-maestro.md +1187 -0
- package/.claude/settings.json +161 -0
- package/.env.example +216 -0
- package/README.md +632 -0
- package/agents/browser-operator/agent.md +52 -0
- package/agents/calendar-ops/agent.md +50 -0
- package/agents/communications/agent.md +96 -0
- package/agents/decision-log/agent.md +65 -0
- package/agents/desktop-operator/agent.md +59 -0
- package/agents/gmail-operator/agent.md +62 -0
- package/agents/inbound-dispatcher/agent.md +66 -0
- package/agents/inbox-processor/agent.md +39 -0
- package/agents/pmo-execution/agent.md +60 -0
- package/agents/session-spawner/agent.md +64 -0
- package/agents/slack-operator/agent.md +60 -0
- package/agents/whatsapp-operator/agent.md +60 -0
- package/agents/workflow-automation/agent.md +61 -0
- package/archetypes/altitudes/c-suite.yaml +58 -0
- package/archetypes/altitudes/founder.yaml +68 -0
- package/archetypes/altitudes/senior-manager.yaml +63 -0
- package/archetypes/altitudes/svp.yaml +60 -0
- package/archetypes/altitudes/vp.yaml +50 -0
- package/archetypes/archetype.schema.json +77 -0
- package/archetypes/base.yaml +47 -0
- package/archetypes/capabilities/commercial-leader.yaml +159 -0
- package/archetypes/capabilities/compliance-officer.yaml +159 -0
- package/archetypes/capabilities/executive-operator.yaml +169 -0
- package/archetypes/capabilities/finance-leader.yaml +162 -0
- package/archetypes/capabilities/operations-leader.yaml +154 -0
- package/archetypes/capabilities/product-leader.yaml +148 -0
- package/archetypes/capabilities/technical-leader.yaml +146 -0
- package/archetypes/functions/commercial-leader.yaml +62 -0
- package/archetypes/functions/compliance-officer.yaml +64 -0
- package/archetypes/functions/executive-operator.yaml +70 -0
- package/archetypes/functions/finance-leader.yaml +70 -0
- package/archetypes/functions/operations-leader.yaml +62 -0
- package/archetypes/functions/product-leader.yaml +61 -0
- package/archetypes/functions/technical-leader.yaml +57 -0
- package/bin/cohort-mcp.mjs +81 -0
- package/bin/maestro.mjs +3516 -0
- package/bin/maestro.test.mjs +1015 -0
- package/desktop-control/README.md +56 -0
- package/desktop-control/app-profiles/gmail.yaml +120 -0
- package/desktop-control/app-profiles/slack.yaml +315 -0
- package/desktop-control/app-profiles/whatsapp.yaml +107 -0
- package/docs/architecture/agent-topology.md +2239 -0
- package/docs/architecture/archetype-agent-factory.md +110 -0
- package/docs/architecture/collective-memory-and-org-mesh.md +115 -0
- package/docs/architecture/continuous-monitoring.md +221 -0
- package/docs/architecture/mcp-capability-map.md +585 -0
- package/docs/architecture/system-architecture.md +1272 -0
- package/docs/company-context/README.md +40 -0
- package/docs/guides/agent-persona-setup.md +600 -0
- package/docs/guides/agents-observe-setup.md +64 -0
- package/docs/guides/billing-console-keys.md +88 -0
- package/docs/guides/ccxray-diagnostics.md +65 -0
- package/docs/guides/channel-bus.md +127 -0
- package/docs/guides/claude-mem-setup.md +79 -0
- package/docs/guides/claude-pace-setup.md +56 -0
- package/docs/guides/claudraband-sessions.md +98 -0
- package/docs/guides/clawteam-swarm.md +116 -0
- package/docs/guides/code-review-graph-setup.md +86 -0
- package/docs/guides/email-setup.md +431 -0
- package/docs/guides/mac-mini.md +119 -0
- package/docs/guides/media-generation-setup.md +349 -0
- package/docs/guides/model-routing.md +162 -0
- package/docs/guides/observability-otel.md +265 -0
- package/docs/guides/org-onboarding.md +132 -0
- package/docs/guides/outbound-governance-setup.md +437 -0
- package/docs/guides/pdf-generation-setup.md +315 -0
- package/docs/guides/poller-daemon-setup.md +563 -0
- package/docs/guides/rag-context-setup.md +459 -0
- package/docs/guides/self-optimization-pattern.md +82 -0
- package/docs/guides/setup-wizard.md +178 -0
- package/docs/guides/slack-setup.md +350 -0
- package/docs/guides/telegram-setup.md +227 -0
- package/docs/guides/twilio-subaccounts-setup.md +223 -0
- package/docs/guides/verification.md +128 -0
- package/docs/guides/voice-mode.md +188 -0
- package/docs/guides/voice-sms-setup.md +698 -0
- package/docs/guides/webhook-relay-setup.md +349 -0
- package/docs/guides/whatsapp-setup.md +288 -0
- package/docs/prompts/board-pack-cover-template.md +36 -0
- package/docs/prompts/decision-recommendation-template.md +88 -0
- package/docs/prompts/followup-message-template.md +141 -0
- package/docs/prompts/investor-letter-template.md +52 -0
- package/docs/prompts/morning-brief-template.md +82 -0
- package/docs/prompts/presentation-template.md +58 -0
- package/docs/prompts/weekly-strategic-memo-template.md +104 -0
- package/docs/research/hallucinated-tool-output-investigation.md +151 -0
- package/docs/runbooks/backup-restore.md +205 -0
- package/docs/runbooks/cohort-cutover.md +129 -0
- package/docs/runbooks/fleet-operations.md +200 -0
- package/docs/runbooks/incident-response.md +226 -0
- package/docs/runbooks/mac-mini-bootstrap.md +431 -0
- package/docs/runbooks/perpetual-operations.md +509 -0
- package/docs/runbooks/recovery-and-failover.md +260 -0
- package/framework-features.json +267 -0
- package/ingest/README.md +87 -0
- package/lib/action-executor.js +689 -0
- package/lib/action-executor.test.mjs +871 -0
- package/lib/agent-root.mjs +37 -0
- package/lib/archetype.mjs +236 -0
- package/lib/archetype.test.mjs +132 -0
- package/lib/autonomy.mjs +114 -0
- package/lib/autonomy.test.mjs +66 -0
- package/lib/backlog.mjs +358 -0
- package/lib/backlog.test.mjs +266 -0
- package/lib/budget-guard.mjs +279 -0
- package/lib/budget-guard.test.mjs +291 -0
- package/lib/cadence-bus-schedule.test.mjs +194 -0
- package/lib/cadence-bus.mjs +1120 -0
- package/lib/cadence-bus.test.mjs +720 -0
- package/lib/cadences.mjs +205 -0
- package/lib/cadences.test.mjs +125 -0
- package/lib/capability.mjs +154 -0
- package/lib/capability.test.mjs +78 -0
- package/lib/channels/base-adapter.mjs +719 -0
- package/lib/channels/base-adapter.test.mjs +590 -0
- package/lib/channels/channel.mjs +128 -0
- package/lib/channels/channels.test.mjs +371 -0
- package/lib/channels/contract.mjs +215 -0
- package/lib/channels/contract.test.mjs +137 -0
- package/lib/channels/conversation-resolver.mjs +95 -0
- package/lib/channels/gmail/adapter.mjs +87 -0
- package/lib/channels/inbox-item.mjs +255 -0
- package/lib/channels/inbox-item.test.mjs +335 -0
- package/lib/channels/index.mjs +94 -0
- package/lib/channels/orgmail/adapter.mjs +353 -0
- package/lib/channels/orgmail/adapter.test.mjs +311 -0
- package/lib/channels/pairing.mjs +363 -0
- package/lib/channels/pairing.test.mjs +270 -0
- package/lib/channels/registry.mjs +164 -0
- package/lib/channels/slack/adapter.mjs +317 -0
- package/lib/channels/slack-adapter.test.mjs +212 -0
- package/lib/channels/sms/adapter.mjs +43 -0
- package/lib/channels/telegram/adapter.mjs +432 -0
- package/lib/channels/telegram-adapter.test.mjs +306 -0
- package/lib/channels/voice/adapter.mjs +301 -0
- package/lib/channels/voice/adapter.test.mjs +278 -0
- package/lib/channels/whatsapp/adapter-baileys.mjs +587 -0
- package/lib/channels/whatsapp/adapter-baileys.test.mjs +359 -0
- package/lib/channels/whatsapp/adapter-twilio.mjs +65 -0
- package/lib/channels/whatsapp/baileys-typing.test.mjs +154 -0
- package/lib/charter.mjs +256 -0
- package/lib/charter.test.mjs +89 -0
- package/lib/claude-bin.mjs +134 -0
- package/lib/claude-bin.test.mjs +75 -0
- package/lib/collective/capture.mjs +185 -0
- package/lib/collective/capture.test.mjs +121 -0
- package/lib/collective/cards.mjs +201 -0
- package/lib/collective/cards.test.mjs +114 -0
- package/lib/collective/config.mjs +186 -0
- package/lib/collective/config.test.mjs +123 -0
- package/lib/collective/global-config.mjs +113 -0
- package/lib/collective/global-config.test.mjs +75 -0
- package/lib/collective/presence.mjs +201 -0
- package/lib/collective/presence.test.mjs +95 -0
- package/lib/collective/recall.mjs +215 -0
- package/lib/collective/recall.test.mjs +116 -0
- package/lib/comms/send-gate.mjs +554 -0
- package/lib/comms/send-gate.test.mjs +577 -0
- package/lib/comms.mjs +67 -0
- package/lib/comms.test.mjs +41 -0
- package/lib/diagnostics/alerts.mjs +424 -0
- package/lib/diagnostics/alerts.test.mjs +318 -0
- package/lib/diagnostics/backup-freshness.mjs +188 -0
- package/lib/diagnostics/backup-freshness.test.mjs +185 -0
- package/lib/diagnostics/counters.mjs +269 -0
- package/lib/diagnostics/counters.test.mjs +206 -0
- package/lib/diagnostics/events.mjs +188 -0
- package/lib/diagnostics/events.test.mjs +290 -0
- package/lib/diagnostics/otel.mjs +237 -0
- package/lib/diagnostics/otel.test.mjs +196 -0
- package/lib/diagnostics/trace.mjs +216 -0
- package/lib/diagnostics/trace.test.mjs +251 -0
- package/lib/env-compat.mjs +74 -0
- package/lib/env-compat.test.mjs +104 -0
- package/lib/feature-init.mjs +331 -0
- package/lib/fs-atomic.mjs +112 -0
- package/lib/fs-atomic.test.mjs +72 -0
- package/lib/fs-ownership.mjs +111 -0
- package/lib/fs-ownership.test.mjs +158 -0
- package/lib/hooks/bus.mjs +347 -0
- package/lib/hooks/bus.test.mjs +387 -0
- package/lib/index.js +16 -0
- package/lib/learning/config.mjs +106 -0
- package/lib/learning/config.test.mjs +75 -0
- package/lib/learning/counters.mjs +156 -0
- package/lib/learning/counters.test.mjs +69 -0
- package/lib/learning/curator-consolidate.test.mjs +238 -0
- package/lib/learning/curator.mjs +453 -0
- package/lib/learning/curator.test.mjs +106 -0
- package/lib/learning/log.mjs +40 -0
- package/lib/learning/reflect.mjs +534 -0
- package/lib/learning/reflect.test.mjs +0 -0
- package/lib/learning/session-index.mjs +352 -0
- package/lib/learning/session-index.test.mjs +125 -0
- package/lib/learning/skill-writer.mjs +474 -0
- package/lib/learning/skill-writer.test.mjs +210 -0
- package/lib/mcp/server.mjs +328 -0
- package/lib/mcp/server.test.mjs +400 -0
- package/lib/model-router/auth-profiles.mjs +758 -0
- package/lib/model-router/auth-profiles.test.mjs +580 -0
- package/lib/model-router/catalog/anthropic.yaml +153 -0
- package/lib/model-router/catalog/deepseek.yaml +86 -0
- package/lib/model-router/catalog/moonshot.yaml +81 -0
- package/lib/model-router/catalog/qwen.yaml +114 -0
- package/lib/model-router/catalog.mjs +925 -0
- package/lib/model-router/catalog.test.mjs +385 -0
- package/lib/model-router/economics.mjs +564 -0
- package/lib/model-router/economics.test.mjs +344 -0
- package/lib/model-router/failover.mjs +298 -0
- package/lib/model-router/failover.test.mjs +439 -0
- package/lib/model-router/health.mjs +453 -0
- package/lib/model-router/health.test.mjs +338 -0
- package/lib/model-router/integration-coverage.test.mjs +829 -0
- package/lib/model-router/integration.test.mjs +564 -0
- package/lib/model-router/ledger.mjs +402 -0
- package/lib/model-router/ledger.test.mjs +382 -0
- package/lib/model-router/llm-task.mjs +515 -0
- package/lib/model-router/llm-task.test.mjs +392 -0
- package/lib/model-router/org-credentials.mjs +260 -0
- package/lib/model-router/org-credentials.test.mjs +265 -0
- package/lib/model-router/pricing-refresh.mjs +463 -0
- package/lib/model-router/pricing-refresh.test.mjs +286 -0
- package/lib/model-router/reconcile.mjs +429 -0
- package/lib/model-router/reconcile.test.mjs +316 -0
- package/lib/model-router/repair.mjs +471 -0
- package/lib/model-router/repair.test.mjs +180 -0
- package/lib/model-router/resolve.mjs +1206 -0
- package/lib/model-router/spawn.mjs +497 -0
- package/lib/model-router/spawn.test.mjs +425 -0
- package/lib/model-router/taxonomy.mjs +893 -0
- package/lib/model-router/taxonomy.test.mjs +410 -0
- package/lib/model-router.mjs +677 -0
- package/lib/model-router.test.mjs +907 -0
- package/lib/org/activity.mjs +211 -0
- package/lib/org/activity.test.mjs +134 -0
- package/lib/org/approvals.mjs +448 -0
- package/lib/org/approvals.test.mjs +216 -0
- package/lib/org/awareness.mjs +222 -0
- package/lib/org/awareness.test.mjs +159 -0
- package/lib/org/board.mjs +229 -0
- package/lib/org/board.test.mjs +177 -0
- package/lib/org/bootstrap-context.mjs +169 -0
- package/lib/org/bootstrap-context.test.mjs +153 -0
- package/lib/org/client.mjs +1628 -0
- package/lib/org/client.test.mjs +1107 -0
- package/lib/org/cohort-client.mjs +67 -0
- package/lib/org/cohort-client.test.mjs +126 -0
- package/lib/org/cost-sync.mjs +227 -0
- package/lib/org/cost-sync.test.mjs +153 -0
- package/lib/org/doctor.mjs +212 -0
- package/lib/org/doctor.test.mjs +212 -0
- package/lib/org/handoff.mjs +293 -0
- package/lib/org/handoff.test.mjs +269 -0
- package/lib/org/integration-tools.mjs +182 -0
- package/lib/org/integration-tools.test.mjs +160 -0
- package/lib/org/keys.mjs +131 -0
- package/lib/org/keys.test.mjs +92 -0
- package/lib/org/knowledge.mjs +463 -0
- package/lib/org/knowledge.test.mjs +319 -0
- package/lib/org/leases.mjs +335 -0
- package/lib/org/leases.test.mjs +235 -0
- package/lib/org/mesh-integration.test.mjs +127 -0
- package/lib/org/mesh.mjs +459 -0
- package/lib/org/mesh.test.mjs +345 -0
- package/lib/org/messaging.mjs +503 -0
- package/lib/org/messaging.test.mjs +238 -0
- package/lib/org/policy.mjs +345 -0
- package/lib/org/policy.test.mjs +237 -0
- package/lib/org/protocol.checksum +1 -0
- package/lib/org/protocol.checksum.test.mjs +90 -0
- package/lib/org/protocol.mjs +967 -0
- package/lib/org/protocol.test.mjs +264 -0
- package/lib/org/registry.mjs +194 -0
- package/lib/org/registry.test.mjs +100 -0
- package/lib/org/tool-surface-integration.test.mjs +120 -0
- package/lib/org/tool-surface.mjs +2535 -0
- package/lib/org/tool-surface.test.mjs +589 -0
- package/lib/org/ui-parity.mjs +3236 -0
- package/lib/org/ui-parity.test.mjs +348 -0
- package/lib/org/verify.mjs +176 -0
- package/lib/org/verify.test.mjs +194 -0
- package/lib/rag/embed.mjs +188 -0
- package/lib/rag/indexer.mjs +425 -0
- package/lib/rag/rag.test.mjs +505 -0
- package/lib/rag/search.mjs +475 -0
- package/lib/rate-guard.mjs +246 -0
- package/lib/rate-guard.test.mjs +201 -0
- package/lib/render.mjs +112 -0
- package/lib/render.test.mjs +68 -0
- package/lib/resource-governor.mjs +297 -0
- package/lib/resource-governor.test.mjs +262 -0
- package/lib/scheduling/dynamic-jobs.mjs +675 -0
- package/lib/scheduling/dynamic-jobs.test.mjs +344 -0
- package/lib/scheduling/jitter.mjs +0 -0
- package/lib/scheduling/jitter.test.mjs +140 -0
- package/lib/secrets/broker.mjs +315 -0
- package/lib/secrets/broker.test.mjs +280 -0
- package/lib/secrets/providers.mjs +461 -0
- package/lib/secrets/providers.test.mjs +274 -0
- package/lib/security/audit-engine.mjs +684 -0
- package/lib/security/audit-engine.test.mjs +389 -0
- package/lib/security/coerce-args.mjs +552 -0
- package/lib/security/coerce-args.test.mjs +281 -0
- package/lib/security/dangerous-tools.mjs +97 -0
- package/lib/security/dangerous-tools.test.mjs +68 -0
- package/lib/security/external-content.mjs +145 -0
- package/lib/security/external-content.test.mjs +67 -0
- package/lib/security/redact.mjs +592 -0
- package/lib/security/redact.test.mjs +441 -0
- package/lib/security/secret-equal.mjs +73 -0
- package/lib/security/secret-equal.test.mjs +55 -0
- package/lib/session-permissions.mjs +101 -0
- package/lib/session-permissions.test.mjs +100 -0
- package/lib/setup/claude-probe.mjs +74 -0
- package/lib/setup/completeness.mjs +175 -0
- package/lib/setup/completeness.test.mjs +110 -0
- package/lib/setup/context-pack.mjs +173 -0
- package/lib/setup/context-pack.test.mjs +89 -0
- package/lib/setup/enrich.mjs +277 -0
- package/lib/setup/enrich.test.mjs +115 -0
- package/lib/setup/enroll-from-cohort.mjs +441 -0
- package/lib/setup/enroll-from-cohort.test.mjs +233 -0
- package/lib/setup/integration.test.mjs +162 -0
- package/lib/setup/io.mjs +360 -0
- package/lib/setup/io.test.mjs +77 -0
- package/lib/setup/run-generator.mjs +81 -0
- package/lib/setup/runner.mjs +244 -0
- package/lib/setup/runner.test.mjs +132 -0
- package/lib/setup/sections/comms.mjs +173 -0
- package/lib/setup/sections/company.mjs +120 -0
- package/lib/setup/sections/enrich.mjs +138 -0
- package/lib/setup/sections/identity.mjs +182 -0
- package/lib/setup/sections/identity.test.mjs +140 -0
- package/lib/setup/sections/learning.mjs +153 -0
- package/lib/setup/sections/learning.test.mjs +81 -0
- package/lib/setup/sections/messaging.mjs +219 -0
- package/lib/setup/sections/messaging.test.mjs +127 -0
- package/lib/setup/sections/model.mjs +102 -0
- package/lib/setup/sections/operating-model.mjs +78 -0
- package/lib/setup/sections/org.mjs +475 -0
- package/lib/setup/sections/org.test.mjs +313 -0
- package/lib/setup/sections/orgmail.mjs +173 -0
- package/lib/setup/sections/orgmail.test.mjs +118 -0
- package/lib/setup/sections/recovery.mjs +159 -0
- package/lib/setup/sections/recovery.test.mjs +98 -0
- package/lib/setup/sections/tools.mjs +132 -0
- package/lib/setup/sections/verify.mjs +97 -0
- package/lib/setup/sot.mjs +205 -0
- package/lib/setup/sot.test.mjs +81 -0
- package/lib/setup/state.mjs +151 -0
- package/lib/setup/state.test.mjs +92 -0
- package/lib/singleton.js +229 -0
- package/lib/singleton.test.mjs +135 -0
- package/lib/telemetry/alerts.mjs +216 -0
- package/lib/telemetry/alerts.test.mjs +109 -0
- package/lib/telemetry/collect.mjs +512 -0
- package/lib/telemetry/collect.test.mjs +202 -0
- package/lib/tool-definitions-integration.test.mjs +83 -0
- package/lib/tool-definitions.js +738 -0
- package/lib/tool-definitions.test.mjs +437 -0
- package/lib/util/fetch-timeout.mjs +136 -0
- package/lib/util/fetch-timeout.test.mjs +202 -0
- package/lib/util/reconnect.mjs +343 -0
- package/lib/util/reconnect.test.mjs +369 -0
- package/lib/util/unhandled.mjs +205 -0
- package/lib/util/unhandled.test.mjs +216 -0
- package/lib/voice/context-loader.mjs +466 -0
- package/lib/voice/index.mjs +100 -0
- package/lib/voice/openai-realtime.mjs +510 -0
- package/lib/voice/outbound.mjs +542 -0
- package/lib/voice/outbound.test.mjs +69 -0
- package/lib/voice/post-call-brief.mjs +428 -0
- package/lib/voice/provider.mjs +52 -0
- package/lib/voice/session-rotation.mjs +257 -0
- package/lib/voice/stt.mjs +161 -0
- package/lib/voice/stt.test.mjs +226 -0
- package/lib/voice/tool-bridge.mjs +370 -0
- package/lib/voice/tts.mjs +104 -0
- package/lib/voice/twilio-sip-bridge.mjs +288 -0
- package/lib/voice/voice.test.mjs +990 -0
- package/mcp/README.md +80 -0
- package/package.json +151 -0
- package/plugins/maestro-skills/plugin.json +139 -0
- package/plugins/maestro-skills/skills/agents-observe.md +110 -0
- package/plugins/maestro-skills/skills/board-deck.md +68 -0
- package/plugins/maestro-skills/skills/books-close.md +77 -0
- package/plugins/maestro-skills/skills/brand-steward.md +121 -0
- package/plugins/maestro-skills/skills/calendar-plan.md +57 -0
- package/plugins/maestro-skills/skills/call-working-sessions.md +124 -0
- package/plugins/maestro-skills/skills/ccxray-diagnostics.md +91 -0
- package/plugins/maestro-skills/skills/claude-pace.md +61 -0
- package/plugins/maestro-skills/skills/code-review-graph.md +99 -0
- package/plugins/maestro-skills/skills/crm-pipeline.md +65 -0
- package/plugins/maestro-skills/skills/decision-brief.md +89 -0
- package/plugins/maestro-skills/skills/directory-hygiene.md +125 -0
- package/plugins/maestro-skills/skills/draft-comms.md +84 -0
- package/plugins/maestro-skills/skills/evening-wrap.md +53 -0
- package/plugins/maestro-skills/skills/files-find.md +65 -0
- package/plugins/maestro-skills/skills/generative-ui.md +228 -0
- package/plugins/maestro-skills/skills/hiring-triage.md +74 -0
- package/plugins/maestro-skills/skills/inbox-triage.md +61 -0
- package/plugins/maestro-skills/skills/mail-triage.md +86 -0
- package/plugins/maestro-skills/skills/morning-brief.md +54 -0
- package/plugins/maestro-skills/skills/native-artifacts.md +157 -0
- package/plugins/maestro-skills/skills/org-board.md +133 -0
- package/plugins/maestro-skills/skills/org-credential.md +68 -0
- package/plugins/maestro-skills/skills/org-recall.md +81 -0
- package/plugins/maestro-skills/skills/pipeline-review.md +76 -0
- package/plugins/maestro-skills/skills/regulatory-status.md +81 -0
- package/plugins/maestro-skills/skills/router-why.md +78 -0
- package/plugins/maestro-skills/skills/schedule-meeting.md +91 -0
- package/plugins/maestro-skills/skills/session-search.md +71 -0
- package/plugins/maestro-skills/skills/set-reminder.md +93 -0
- package/plugins/maestro-skills/skills/slack-followup.md +64 -0
- package/plugins/maestro-skills/skills/team-activity.md +86 -0
- package/plugins/maestro-skills/skills/weekly-memo.md +70 -0
- package/policies/action-classification.yaml +114 -0
- package/policies/ai-disclosure.yaml +294 -0
- package/policies/communication-style.md +139 -0
- package/policies/information-barriers.yaml +118 -0
- package/policies/prompt-injection-defence.yaml +138 -0
- package/public/assets/icon-dark.png +0 -0
- package/public/assets/icon-dark.svg +9 -0
- package/public/assets/icon-light.svg +9 -0
- package/public/assets/logo-dark.svg +15 -0
- package/public/assets/logo-light.svg +15 -0
- package/scaffold/.mcp.json +7 -0
- package/scaffold/CLAUDE.md +368 -0
- package/scaffold/config/agent.json +55 -0
- package/scaffold/config/agent.ts +76 -0
- package/scaffold/config/agent.ts.example +89 -0
- package/scaffold/config/alerts.yaml +23 -0
- package/scaffold/config/allowlist.yaml.example +25 -0
- package/scaffold/config/caller-id-map.yaml +46 -0
- package/scaffold/config/collective.yaml +49 -0
- package/scaffold/config/company.json +20 -0
- package/scaffold/config/known-agents.json +6 -0
- package/scaffold/config/learning.yaml +55 -0
- package/scaffold/config/model-routing.yaml.example +104 -0
- package/scaffold/config/org.yaml +25 -0
- package/scaffold/config/orgmail.yaml.example +19 -0
- package/scaffold/config/recovery.yaml +72 -0
- package/scaffold/config/secrets.yaml +27 -0
- package/scaffold/config/slack.yaml.example +35 -0
- package/scaffold/config/telegram.yaml.example +38 -0
- package/scaffold/config/voice.yaml.example +89 -0
- package/scaffold/config/whatsapp.yaml.example +39 -0
- package/schedules/README.md +49 -0
- package/schedules/triggers/backlog-executor.md +102 -0
- package/schedules/triggers/brand-steward.md +72 -0
- package/schedules/triggers/daily-evening-wrap.md +159 -0
- package/schedules/triggers/daily-midday-sweep.md +58 -0
- package/schedules/triggers/daily-morning-brief.md +55 -0
- package/schedules/triggers/directory-hygiene.md +81 -0
- package/schedules/triggers/dynamic-jobs.md +40 -0
- package/schedules/triggers/inbox-processor.md +115 -0
- package/schedules/triggers/meeting-action-capture.md +60 -0
- package/schedules/triggers/meeting-prep.md +69 -0
- package/schedules/triggers/messaging-inbound.md +50 -0
- package/schedules/triggers/org-pulse.md +24 -0
- package/schedules/triggers/quarterly-self-assessment.md +54 -0
- package/schedules/triggers/weekly-engineering-health.md +37 -0
- package/schedules/triggers/weekly-execution.md +65 -0
- package/schedules/triggers/weekly-hiring.md +53 -0
- package/schedules/triggers/weekly-priorities.md +38 -0
- package/schedules/triggers/weekly-strategic-memo.md +124 -0
- package/scripts/archive-email.sh +55 -0
- package/scripts/cadence/cadence-status.mjs +36 -0
- package/scripts/cadence/enqueue-cadence-tick.mjs +174 -0
- package/scripts/cadence/enqueue-cadence-tick.test.mjs +187 -0
- package/scripts/cadence/launchd-cadence-wrapper.sh +85 -0
- package/scripts/cadence/launchd-cloud-relay-wrapper.sh +95 -0
- package/scripts/cadence/launchd-socket-mode-wrapper.sh +95 -0
- package/scripts/ci/check-docs-accuracy.mjs +493 -0
- package/scripts/ci/check-docs-accuracy.test.mjs +409 -0
- package/scripts/ci/check-exports-exist.mjs +140 -0
- package/scripts/ci/check-files-exist.mjs +107 -0
- package/scripts/ci/check-no-build-artifacts.mjs +111 -0
- package/scripts/ci/check-no-build-artifacts.test.mjs +71 -0
- package/scripts/ci/check-no-confidential.mjs +198 -0
- package/scripts/ci/check-no-conflict-markers.mjs +169 -0
- package/scripts/ci/check-no-residual-identity.mjs +163 -0
- package/scripts/ci/check-no-residual-identity.test.mjs +89 -0
- package/scripts/ci/check-tarball-fidelity.mjs +205 -0
- package/scripts/ci/check-unresolved-tokens.mjs +83 -0
- package/scripts/ci/check.mjs +109 -0
- package/scripts/ci/check.test.mjs +194 -0
- package/scripts/ci/run-coverage.mjs +82 -0
- package/scripts/ci/run-tests.mjs +71 -0
- package/scripts/cloud-relay/README.md +59 -0
- package/scripts/cloud-relay/index.mjs +233 -0
- package/scripts/cloud-relay/package.json +15 -0
- package/scripts/cloud-relay/railway.json +13 -0
- package/scripts/cloud-relay/voice/README.md +94 -0
- package/scripts/cloud-relay/voice/package-lock.json +39 -0
- package/scripts/cloud-relay/voice/package.json +16 -0
- package/scripts/cloud-relay/voice/railway.json +13 -0
- package/scripts/cloud-relay/voice/server.mjs +532 -0
- package/scripts/collective/hook-runner.mjs +211 -0
- package/scripts/collective/hook-runner.test.mjs +90 -0
- package/scripts/collective/org-pulse.mjs +72 -0
- package/scripts/collective/org-sync.mjs +61 -0
- package/scripts/collective/recall.mjs +45 -0
- package/scripts/collective/who.mjs +30 -0
- package/scripts/comms-monitor.sh +288 -0
- package/scripts/configure-whatsapp-sandbox.sh +201 -0
- package/scripts/continuous-monitor.sh +91 -0
- package/scripts/cost/fleet-digest.mjs +407 -0
- package/scripts/cost/fleet-digest.test.mjs +207 -0
- package/scripts/cost/track-claude-usage.mjs +169 -0
- package/scripts/daemon/agent-daemon.mjs +989 -0
- package/scripts/daemon/agent-daemon.test.mjs +525 -0
- package/scripts/daemon/cadence-consumer-governance.test.mjs +220 -0
- package/scripts/daemon/cadence-consumer.mjs +1080 -0
- package/scripts/daemon/cadence-consumer.test.mjs +770 -0
- package/scripts/daemon/cadence-handlers.mjs +1121 -0
- package/scripts/daemon/cadence-handlers.test.mjs +617 -0
- package/scripts/daemon/classifier.mjs +704 -0
- package/scripts/daemon/classifier.test.mjs +238 -0
- package/scripts/daemon/classify-kind.mjs +54 -0
- package/scripts/daemon/classify-kind.test.mjs +40 -0
- package/scripts/daemon/context-compiler.mjs +605 -0
- package/scripts/daemon/context-compiler.test.mjs +300 -0
- package/scripts/daemon/dispatcher-cooldown.test.mjs +122 -0
- package/scripts/daemon/dispatcher-governance.test.mjs +886 -0
- package/scripts/daemon/dispatcher.mjs +1516 -0
- package/scripts/daemon/health.mjs +72 -0
- package/scripts/daemon/inbox-deferral.mjs +210 -0
- package/scripts/daemon/inbox-deferral.test.mjs +242 -0
- package/scripts/daemon/integration.test.mjs +149 -0
- package/scripts/daemon/launchd-wrapper-generic.sh +96 -0
- package/scripts/daemon/launchd-wrapper-slack-events.sh +37 -0
- package/scripts/daemon/launchd-wrapper.sh +91 -0
- package/scripts/daemon/lib/session-router.mjs +274 -0
- package/scripts/daemon/lib/session-router.test.mjs +295 -0
- package/scripts/daemon/maestro-daemon.mjs +275 -0
- package/scripts/daemon/prompt-builder.mjs +685 -0
- package/scripts/daemon/prompt-builder.test.mjs +213 -0
- package/scripts/daemon/responder.mjs +854 -0
- package/scripts/daemon/session-lock.mjs +721 -0
- package/scripts/daemon/session-lock.test.mjs +252 -0
- package/scripts/daemon/session-outcomes.mjs +640 -0
- package/scripts/daemon/session-outcomes.test.mjs +533 -0
- package/scripts/daemon/typing-registry.mjs +90 -0
- package/scripts/daemon/typing-registry.test.mjs +77 -0
- package/scripts/daemon/voice-webhook-server.mjs +804 -0
- package/scripts/decisions/capture-decision.mjs +116 -0
- package/scripts/disclosure_assessment.py +873 -0
- package/scripts/disclosure_boundaries.py +562 -0
- package/scripts/email-signature-principal.html +52 -0
- package/scripts/email-signature.html +60 -0
- package/scripts/email_quote_thread.py +167 -0
- package/scripts/email_thread_dedup.py +362 -0
- package/scripts/emergency-stop.sh +81 -0
- package/scripts/healthcheck.sh +116 -0
- package/scripts/hooks/block-mcp-cohort-send.sh +15 -0
- package/scripts/hooks/block-mcp-slack-send.sh +7 -0
- package/scripts/hooks/post-action-log.sh +126 -0
- package/scripts/hooks/pre-send-audit.sh +174 -0
- package/scripts/hooks/pre-send-audit.test.mjs +215 -0
- package/scripts/hooks/session-end-log.sh +27 -0
- package/scripts/hooks/session-start-banner.sh +115 -0
- package/scripts/huddle/audio-bridge.mjs +664 -0
- package/scripts/huddle/boot-slack-cdp.sh +102 -0
- package/scripts/huddle/huddle-controller.mjs +942 -0
- package/scripts/huddle/huddle-server.mjs +1229 -0
- package/scripts/huddle/launch-slack.sh +232 -0
- package/scripts/huddle/openai-realtime-bridge.mjs +462 -0
- package/scripts/huddle/package-lock.json +62 -0
- package/scripts/huddle/package.json +22 -0
- package/scripts/huddle/setup-audio.sh +239 -0
- package/scripts/huddle/start-call.mjs +318 -0
- package/scripts/huddle/test-pipeline.mjs +263 -0
- package/scripts/learning/consolidate-skills.mjs +72 -0
- package/scripts/learning/session-search.mjs +125 -0
- package/scripts/llm_email_dedup.py +442 -0
- package/scripts/local-triggers/generate-plists.sh +432 -0
- package/scripts/local-triggers/generate-plists.test.mjs +413 -0
- package/scripts/local-triggers/install-all.sh +49 -0
- package/scripts/local-triggers/plists/.gitkeep +0 -0
- package/scripts/local-triggers/run-trigger.sh +63 -0
- package/scripts/local-triggers/templates/rag-reindex.plist.template +47 -0
- package/scripts/local-triggers/templates/voice-relay-poller.plist.template +54 -0
- package/scripts/local-triggers/templates/voice-tunnel.plist.template +55 -0
- package/scripts/local-triggers/templates/voice-webhook.plist.template +51 -0
- package/scripts/maintenance/backup-to-cloud.sh +124 -0
- package/scripts/maintenance/health-check.sh +377 -0
- package/scripts/media-generation/README.md +105 -0
- package/scripts/media-generation/gemini-image-client.mjs +173 -0
- package/scripts/media-generation/generate-assets.mjs +289 -0
- package/scripts/media-generation/veo-video-client.mjs +219 -0
- package/scripts/org/send-orgmail.mjs +227 -0
- package/scripts/outbound-dedup-cleanup.sh +43 -0
- package/scripts/outbound-dedup.sh +477 -0
- package/scripts/outbound_dedup.py +115 -0
- package/scripts/parse-voice-transcript.mjs +481 -0
- package/scripts/pdf-generation/README.md +63 -0
- package/scripts/pdf-generation/build-document.mjs +247 -0
- package/scripts/pdf-generation/templates/board-pack.latex +136 -0
- package/scripts/pdf-generation/templates/corporate-letter.latex +126 -0
- package/scripts/pdf-generation/templates/memo.latex +114 -0
- package/scripts/poll-slack-events.sh +35 -0
- package/scripts/poller/calendar-poller.mjs +12 -0
- package/scripts/poller/gmail-poller.mjs +192 -0
- package/scripts/poller/imap-client.mjs +289 -0
- package/scripts/poller/inbox-scan-poller.mjs +156 -0
- package/scripts/poller/inbox-scan-poller.test.mjs +231 -0
- package/scripts/poller/index.mjs +73 -0
- package/scripts/poller/intra-session-check.mjs +285 -0
- package/scripts/poller/lib/cloud-relay-dedup.mjs +88 -0
- package/scripts/poller/lib/cloud-relay-dedup.test.mjs +133 -0
- package/scripts/poller/lib/slash-command-handlers.mjs +177 -0
- package/scripts/poller/secondary-gmail-poller.mjs +132 -0
- package/scripts/poller/slack-cloud-relay-client.mjs +368 -0
- package/scripts/poller/slack-poller.mjs +854 -0
- package/scripts/poller/slack-socket-mode.mjs +917 -0
- package/scripts/poller/slack-socket-mode.test.mjs +753 -0
- package/scripts/poller/trigger.mjs +75 -0
- package/scripts/poller/utils.mjs +371 -0
- package/scripts/poller/voice-cloud-relay-client.mjs +179 -0
- package/scripts/poller/voice-poller.mjs +236 -0
- package/scripts/poller-launchd/install.sh +66 -0
- package/scripts/poller-launchd/poller.plist.template +40 -0
- package/scripts/poller-launchd/whatsapp-handler.plist.template +39 -0
- package/scripts/post-interaction-indexer.py +1598 -0
- package/scripts/pre-draft-context.py +994 -0
- package/scripts/pre_draft_lookup.py +258 -0
- package/scripts/rag/build-index.mjs +47 -0
- package/scripts/rag/ingest.mjs +111 -0
- package/scripts/rag/search.mjs +119 -0
- package/scripts/rag-indexer.py +629 -0
- package/scripts/restore-from-backup.sh +248 -0
- package/scripts/restore-from-backup.test.mjs +178 -0
- package/scripts/resume-operations.sh +80 -0
- package/scripts/search-secondary-inbox.py +181 -0
- package/scripts/secondary-inbox-poller.py +437 -0
- package/scripts/self-optimization/compute-metrics.py +398 -0
- package/scripts/send-email-as-principal.py +369 -0
- package/scripts/send-email-threaded.py +392 -0
- package/scripts/send-email-with-attachment.py +377 -0
- package/scripts/send-email.sh +131 -0
- package/scripts/send-sms.sh +175 -0
- package/scripts/send-whatsapp.sh +292 -0
- package/scripts/session-start.sh +106 -0
- package/scripts/setup/boot-claude-session.sh +94 -0
- package/scripts/setup/configure-macos.sh +674 -0
- package/scripts/setup/configure-twilio-sip-trunk.mjs +207 -0
- package/scripts/setup/configure-voice-tunnel.mjs +182 -0
- package/scripts/setup/generate-agent-env.mjs +92 -0
- package/scripts/setup/generate-agent-package-json.mjs +222 -0
- package/scripts/setup/generate-agent-package-json.test.mjs +143 -0
- package/scripts/setup/generate-autonomy.mjs +60 -0
- package/scripts/setup/generate-backlog.mjs +101 -0
- package/scripts/setup/generate-cadences.mjs +92 -0
- package/scripts/setup/generate-capability.mjs +162 -0
- package/scripts/setup/generate-charter.mjs +76 -0
- package/scripts/setup/generate-comms.mjs +59 -0
- package/scripts/setup/generate-company.mjs +92 -0
- package/scripts/setup/init-agent.sh +547 -0
- package/scripts/setup/init-agent.test.mjs +151 -0
- package/scripts/setup/init-archetype.mjs +74 -0
- package/scripts/setup/init-backup.mjs +54 -0
- package/scripts/setup/init-cadence-bus.mjs +60 -0
- package/scripts/setup/init-channel-bus.mjs +46 -0
- package/scripts/setup/init-cost-tracking.mjs +45 -0
- package/scripts/setup/init-decision-capture.mjs +66 -0
- package/scripts/setup/init-known-agents.mjs +57 -0
- package/scripts/setup/init-learning.mjs +70 -0
- package/scripts/setup/init-memory-executive.mjs +45 -0
- package/scripts/setup/init-model-router.mjs +124 -0
- package/scripts/setup/init-rag.mjs +174 -0
- package/scripts/setup/init-session-router.mjs +38 -0
- package/scripts/setup/init-slack-socket-mode.mjs +260 -0
- package/scripts/setup/init-telegram.mjs +165 -0
- package/scripts/setup/init-voice-realtime.mjs +204 -0
- package/scripts/setup/init-whatsapp-baileys.mjs +77 -0
- package/scripts/setup/install-dev-tools.sh +150 -0
- package/scripts/setup/lib/install-plist.mjs +95 -0
- package/scripts/setup/migrate-agent-to-sot.mjs +192 -0
- package/scripts/setup/render-environment-yaml.mjs +133 -0
- package/scripts/slack-events-ctl.sh +177 -0
- package/scripts/slack-events-server.mjs +1045 -0
- package/scripts/slack-react.mjs +89 -0
- package/scripts/slack-responded.sh +232 -0
- package/scripts/slack-send.sh +287 -0
- package/scripts/slack-typing.mjs +196 -0
- package/scripts/slack-upload-v2.py +95 -0
- package/scripts/sms-handler.mjs +450 -0
- package/scripts/spawn-session.sh +120 -0
- package/scripts/sync-protocol.mjs +217 -0
- package/scripts/system-verify.sh +184 -0
- package/scripts/test-email-thread-dedup.py +239 -0
- package/scripts/test-information-barriers.py +484 -0
- package/scripts/test-llm-email-dedup.py +251 -0
- package/scripts/test-pre-draft-integration.py +203 -0
- package/scripts/test-rag-phase2.sh +442 -0
- package/scripts/test-rag-search.sh +251 -0
- package/scripts/test-voice-parser.mjs +316 -0
- package/scripts/user-context-search.py +659 -0
- package/scripts/validate_outbound.py +1504 -0
- package/scripts/watchdog/ai.maestro.memory-watchdog.plist +41 -0
- package/scripts/watchdog/force-reboot.sh +157 -0
- package/scripts/watchdog/memory-watchdog.sh +473 -0
- package/scripts/whatsapp-handler.mjs +538 -0
- package/teams/desktop-operations.yaml +34 -0
- package/teams/executive-office.yaml +27 -0
- package/teams/legal-and-regulatory.yaml +24 -0
- package/teams/platform-and-engineering.yaml +23 -0
- package/teams/strategy-and-growth.yaml +29 -0
- package/workflows/continuous/backlog-executor.yaml +141 -0
- package/workflows/continuous/inbound-monitor.yaml +168 -0
- package/workflows/daily/applicant-triage.yaml +197 -0
- package/workflows/daily/comms-triage.yaml +80 -0
- package/workflows/daily/evening-wrap.yaml +105 -0
- package/workflows/daily/morning-brief.yaml +164 -0
- package/workflows/daily/slack-followup-sweep.yaml +87 -0
- package/workflows/event-driven/README.md +50 -0
- package/workflows/event-driven/agent-failure-investigation.yaml +137 -0
- package/workflows/event-driven/pr-review.yaml +107 -0
- package/workflows/monthly/board-readiness.yaml +76 -0
- package/workflows/quarterly/strategic-scenario-analysis.yaml +85 -0
- package/workflows/session-protocol.md +171 -0
- package/workflows/weekly/engineering-health.yaml +154 -0
- package/workflows/weekly/hiring-review.yaml +169 -0
- package/workflows/weekly/rollup-pipeline-review.yaml +76 -0
- package/workflows/weekly/strategic-memo.yaml +79 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Telegram Setup Guide
|
|
2
|
+
|
|
3
|
+
How to enable Telegram messaging for a Maestro agent: creating a bot with
|
|
4
|
+
BotFather, wiring the token, the in-daemon grammY long-poll adapter, inbound event
|
|
5
|
+
mapping (DMs, groups, forum topics, reactions, media, voice→STT), default-deny DM
|
|
6
|
+
pairing, and outbound sending.
|
|
7
|
+
|
|
8
|
+
**Prerequisites**: A working agent repo (`maestro create` + `maestro setup`
|
|
9
|
+
identity done) and a Telegram account to talk to BotFather.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Architecture Overview
|
|
14
|
+
|
|
15
|
+
Unlike WhatsApp/SMS (which use Twilio webhooks behind a Cloudflare tunnel),
|
|
16
|
+
Telegram runs entirely **inside the daemon** via grammY long-polling — there is
|
|
17
|
+
**no relay, no tunnel, and no extra process**:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
21
|
+
│ INBOUND │
|
|
22
|
+
│ │
|
|
23
|
+
│ Telegram user ──▶ Telegram Bot API │
|
|
24
|
+
│ │ (long-poll: getUpdates) │
|
|
25
|
+
│ ▼ │
|
|
26
|
+
│ lib/channels/telegram/adapter.mjs (grammY) │
|
|
27
|
+
│ │ _toEvent → MessageEvent │
|
|
28
|
+
│ ▼ │
|
|
29
|
+
│ writeInboxItem → state/inbox/telegram/*.yaml │
|
|
30
|
+
│ (classifier / dispatcher route — unchanged) │
|
|
31
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
32
|
+
│ OUTBOUND │
|
|
33
|
+
│ │
|
|
34
|
+
│ adapter._send ──▶ Telegram Bot API ──▶ Telegram user │
|
|
35
|
+
│ (typing heartbeat via sendChatAction while a session runs) │
|
|
36
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
37
|
+
│ PAIRING (default-deny) │
|
|
38
|
+
│ │
|
|
39
|
+
│ Unknown DM ──▶ "pair <code>" gate ──▶ config/allowlist.yaml │
|
|
40
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
grammY is a **dynamic dependency** (like Baileys): the package installs without
|
|
44
|
+
it, and the daemon only loads the Telegram adapter when `config/telegram.yaml`
|
|
45
|
+
exists. Flip the gate file off to disable the channel.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 1. Create a Bot with BotFather
|
|
50
|
+
|
|
51
|
+
1. Open Telegram and message **@BotFather**.
|
|
52
|
+
2. Send `/newbot`. Choose a display name and a username ending in `bot`.
|
|
53
|
+
3. BotFather replies with an HTTP API token like `123456789:ABCdef...`. Keep it secret.
|
|
54
|
+
|
|
55
|
+
### (Optional) Let the bot read all group messages
|
|
56
|
+
|
|
57
|
+
By default a bot only sees `@mentions`, replies, and commands in groups. To let it
|
|
58
|
+
read every message in a group:
|
|
59
|
+
|
|
60
|
+
1. @BotFather → `/setprivacy` → pick your bot → **Disable**.
|
|
61
|
+
|
|
62
|
+
Leave privacy **enabled** if you only want the agent to react when addressed.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 2. Wire the Token and Activate the Channel
|
|
67
|
+
|
|
68
|
+
Run the idempotent init script (mirrors `init-whatsapp-baileys.mjs`):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node scripts/setup/init-telegram.mjs
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
It will:
|
|
75
|
+
|
|
76
|
+
1. Walk you through the BotFather steps above.
|
|
77
|
+
2. Prompt for the token and append `TELEGRAM_BOT_TOKEN=...` to `.env` (never
|
|
78
|
+
overwriting an existing value; it skips the prompt when stdin is non-interactive).
|
|
79
|
+
3. **Validate the token** via the Telegram `getMe` API (no grammY needed) and print
|
|
80
|
+
the resolved bot username.
|
|
81
|
+
4. Activate `config/telegram.yaml` from the scaffold example (the gate file).
|
|
82
|
+
5. Check for the optional `grammy` npm package and print an install hint if missing.
|
|
83
|
+
|
|
84
|
+
Install grammY in the agent repo so the daemon can load the adapter:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm i grammy
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
You can also set the token by hand in `.env`:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Telegram (grammY long-poll, in-daemon)
|
|
94
|
+
TELEGRAM_BOT_TOKEN=123456789:ABCdef...
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Wiring through `maestro setup`
|
|
98
|
+
|
|
99
|
+
The `comms` section of the setup wizard wires Telegram alongside the other
|
|
100
|
+
channels and verifies it:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
maestro setup comms
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
It runs the same init flow, confirms `config/telegram.yaml` is present, and
|
|
107
|
+
includes Telegram in the capability table (the verify probe checks `getMe`).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 3. Inbound — Event Mapping
|
|
112
|
+
|
|
113
|
+
The adapter's `_toEvent` translates each grammY update into the unified
|
|
114
|
+
`MessageEvent` contract (`lib/channels/contract.mjs`). Mapping:
|
|
115
|
+
|
|
116
|
+
| Telegram update | `MessageEvent` |
|
|
117
|
+
|---|---|
|
|
118
|
+
| Private message (DM) | `kind: "message"`, `source: telegram`, thread keyed to the DM |
|
|
119
|
+
| Group / supergroup message | `kind: "message"` with the chat as the conversation |
|
|
120
|
+
| Forum **topic** (`message_thread_id`) | `kind: "message"` with `thread_context` set to the topic |
|
|
121
|
+
| Reaction (`message_reaction`) | `kind: "reaction"` (resolves the target message text) |
|
|
122
|
+
| Photo / document / audio | `kind: "message"` with the media attached |
|
|
123
|
+
| **Voice note** | `kind: "voice_note"` — audio is run through STT and the transcript becomes the message body |
|
|
124
|
+
|
|
125
|
+
Because `MessageEvent` is serialized to the same on-disk inbox-item bytes as the
|
|
126
|
+
legacy poller (`lib/channels/inbox-item.mjs`), the classifier, directed-gate, and
|
|
127
|
+
dispatcher handle Telegram items with no special-casing.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 4. DM Pairing (default-deny)
|
|
132
|
+
|
|
133
|
+
Telegram DMs are **default-deny**: an unknown sender cannot reach the agent until
|
|
134
|
+
they pair. Pairing is enforced in `BaseAdapter` (so every channel inherits it) via
|
|
135
|
+
`lib/channels/pairing.mjs` and the cross-channel allowlist `config/allowlist.yaml`.
|
|
136
|
+
|
|
137
|
+
- An unknown DM is intercepted **before** the classifier; the agent does not act on it.
|
|
138
|
+
- The sender pairs by sending exactly `pair <code>` (matched by `^pair <code>$`).
|
|
139
|
+
- Once redeemed, their Telegram id is added to the allowlist and subsequent messages flow normally.
|
|
140
|
+
- You can also seed allowlisted ids ahead of time under the `telegram:` key in `config/allowlist.yaml`.
|
|
141
|
+
|
|
142
|
+
Groups follow the bot's privacy setting (see §1); pairing applies to direct
|
|
143
|
+
messages.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 5. Outbound — Sending and Typing
|
|
148
|
+
|
|
149
|
+
Outbound goes through the adapter's `_send`. While a session is working on a
|
|
150
|
+
Telegram conversation, `BaseAdapter`'s typing heartbeat calls `sendChatAction`
|
|
151
|
+
(`typing`) every few seconds so the user sees the agent "typing…" until the reply
|
|
152
|
+
lands — the same holding behaviour as Slack/WhatsApp. SMS/Gmail have no typing
|
|
153
|
+
capability and are no-ops there.
|
|
154
|
+
|
|
155
|
+
Outbound messages pass through the standard pre-send pipeline (content-hash dedup,
|
|
156
|
+
factual validation, audit logging) like every other channel.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 6. Testing
|
|
161
|
+
|
|
162
|
+
| # | Test | How to Verify |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| 1 | Token valid | `node scripts/setup/init-telegram.mjs` prints `token valid — bot is @yourbot` |
|
|
165
|
+
| 2 | Gate file present | `config/telegram.yaml` exists |
|
|
166
|
+
| 3 | grammY installed | `ls node_modules/grammy` |
|
|
167
|
+
| 4 | Daemon loads adapter | Start the daemon; check logs for the Telegram adapter connecting |
|
|
168
|
+
| 5 | Inbound DM | DM the bot; check `state/inbox/telegram/` for a YAML item |
|
|
169
|
+
| 6 | Pairing blocks unknown | DM from an unpaired account → no agent action until `pair <code>` |
|
|
170
|
+
| 7 | Group mention | @mention the bot in a group; verify it's captured |
|
|
171
|
+
| 8 | Reaction captured | React to a message the bot can see; verify `kind: reaction` |
|
|
172
|
+
| 9 | Voice note → STT | Send a voice note; verify the transcript appears as the message body |
|
|
173
|
+
| 10 | Verify probe | `maestro setup comms` (or `maestro doctor`) shows Telegram passing |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 7. Troubleshooting
|
|
178
|
+
|
|
179
|
+
### `getMe` validation fails
|
|
180
|
+
|
|
181
|
+
1. Re-copy the token from BotFather — a trailing space or missing digits breaks it.
|
|
182
|
+
2. The token format is `digits:alphanumerics` (e.g. `123456789:ABCdef...`).
|
|
183
|
+
3. If you regenerated the token via `/revoke`, update `TELEGRAM_BOT_TOKEN` in `.env`.
|
|
184
|
+
|
|
185
|
+
### Bot doesn't see group messages
|
|
186
|
+
|
|
187
|
+
1. Privacy mode is **enabled** by default — the bot only sees mentions/replies/commands.
|
|
188
|
+
2. @BotFather → `/setprivacy` → your bot → **Disable**, then re-add the bot to the group.
|
|
189
|
+
|
|
190
|
+
### Daemon starts but Telegram never connects
|
|
191
|
+
|
|
192
|
+
1. Confirm `config/telegram.yaml` exists (the gate file) — without it the adapter never loads.
|
|
193
|
+
2. Confirm `grammy` is installed in the **agent** repo: `npm i grammy`.
|
|
194
|
+
3. Check the daemon logs for a token or network error from `getUpdates`.
|
|
195
|
+
|
|
196
|
+
### Unknown sender can't reach the agent
|
|
197
|
+
|
|
198
|
+
That's the default-deny pairing working as designed. Have them send `pair <code>`,
|
|
199
|
+
or seed their id under `telegram:` in `config/allowlist.yaml`.
|
|
200
|
+
|
|
201
|
+
### Conflict: "terminated by other getUpdates request"
|
|
202
|
+
|
|
203
|
+
Two processes are long-polling the same bot token. Telegram allows only one. Make
|
|
204
|
+
sure you aren't running a second daemon (or a stray script) with the same
|
|
205
|
+
`TELEGRAM_BOT_TOKEN`.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Key Files
|
|
210
|
+
|
|
211
|
+
| File | Purpose |
|
|
212
|
+
|---|---|
|
|
213
|
+
| `lib/channels/telegram/adapter.mjs` | grammY long-poll adapter (`_connect/_toEvent/_send/_react/_setTyping`) |
|
|
214
|
+
| `scripts/setup/init-telegram.mjs` | Idempotent init: BotFather walkthrough, token → `.env`, `getMe` validation, gate-file activation |
|
|
215
|
+
| `config/telegram.yaml` | Channel gate file (activated from the scaffold example) |
|
|
216
|
+
| `config/allowlist.yaml` | Cross-channel default-deny DM allowlist (the `telegram:` key) |
|
|
217
|
+
| `lib/channels/contract.mjs` | The unified `MessageEvent` contract `_toEvent` maps onto |
|
|
218
|
+
| `lib/channels/base-adapter.mjs` | Session-keying, typing heartbeat, and pairing gate inherited by the adapter |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Related Documents
|
|
223
|
+
|
|
224
|
+
- [Setup Wizard](setup-wizard.md) — the `comms` section that wires Telegram
|
|
225
|
+
- [Channel bus](channel-bus.md) — the unified messaging layer and `MessageEvent` contract
|
|
226
|
+
- [WhatsApp Setup](whatsapp-setup.md) — the Baileys channel this guide mirrors
|
|
227
|
+
- [Poller & Daemon Setup](poller-daemon-setup.md) — how channel events integrate with the event loop
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Twilio Sub-Accounts Setup Guide
|
|
2
|
+
|
|
3
|
+
How to create a dedicated Twilio sub-account for each Maestro agent under a single parent Twilio account. This is required for per-agent WhatsApp segregation because the **Twilio WhatsApp Sandbox webhook is account-wide** — only one URL per Twilio account.
|
|
4
|
+
|
|
5
|
+
**Prerequisites**: A parent Twilio account already exists (the company's root account). You have its `Account SID` and `Auth Token`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why sub-accounts?
|
|
10
|
+
|
|
11
|
+
Each agent runs as a separate identity (one per principal) and needs:
|
|
12
|
+
|
|
13
|
+
- Its own phone number (for SMS)
|
|
14
|
+
- Its own WhatsApp sandbox webhook URL (the constraint)
|
|
15
|
+
- Its own auth token (so the agent's webhook relay can verify Twilio HMAC signatures independently)
|
|
16
|
+
- Its own usage logs and cost attribution
|
|
17
|
+
|
|
18
|
+
Sub-accounts give you all of this while still rolling up to the parent account for billing.
|
|
19
|
+
|
|
20
|
+
| Constraint | Sharing parent account | Per-agent sub-account |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| WhatsApp sandbox webhook | One URL for ALL agents — only the latest agent's webhook works | Each agent has their own sandbox + webhook |
|
|
23
|
+
| Phone numbers | Mixed across agents on one account | Each agent has their own |
|
|
24
|
+
| Auth Token | Shared — every agent's relay can verify everything (security risk) | Per-agent token, isolated verification |
|
|
25
|
+
| Cost attribution | Aggregated — hard to attribute to a specific agent | Sub-account usage rolls up but is separately reportable |
|
|
26
|
+
| Suspension | Suspending the parent kills all agents | Suspend just the affected agent |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Create the sub-account
|
|
31
|
+
|
|
32
|
+
Run from the agent's repo (or anywhere with `TWILIO_PARENT_ACCOUNT_SID` and `TWILIO_PARENT_AUTH_TOKEN` set):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
TWILIO_PARENT_ACCOUNT_SID=AC... # parent
|
|
36
|
+
TWILIO_PARENT_AUTH_TOKEN=... # parent
|
|
37
|
+
AGENT_NAME="jordan-lee-northwind" # whatever friendly name you want
|
|
38
|
+
|
|
39
|
+
curl -s -u "$TWILIO_PARENT_ACCOUNT_SID:$TWILIO_PARENT_AUTH_TOKEN" -X POST \
|
|
40
|
+
"https://api.twilio.com/2010-04-01/Accounts.json" \
|
|
41
|
+
--data-urlencode "FriendlyName=$AGENT_NAME" \
|
|
42
|
+
| python3 -m json.tool
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Capture from the response:
|
|
46
|
+
|
|
47
|
+
- `sid` — the new sub-account SID (starts with `AC...`)
|
|
48
|
+
- `auth_token` — the sub-account's auth token (use this for HMAC verification on the agent's webhook relay)
|
|
49
|
+
- `owner_account_sid` — confirms it's a child of the parent account
|
|
50
|
+
|
|
51
|
+
Save both to the agent's `.env`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Jordan's dedicated Twilio sub-account
|
|
55
|
+
TWILIO_ACCOUNT_SID=ACf2... # the new sub-account SID
|
|
56
|
+
TWILIO_AUTH_TOKEN=c1da... # the new sub-account auth token
|
|
57
|
+
|
|
58
|
+
# Parent account — only used for sub-account management API calls
|
|
59
|
+
TWILIO_PARENT_ACCOUNT_SID=AC36...
|
|
60
|
+
TWILIO_PARENT_AUTH_TOKEN=af86...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 2. Buy a phone number under the sub-account
|
|
66
|
+
|
|
67
|
+
Search for available numbers:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
source .env
|
|
71
|
+
curl -s -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
|
|
72
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/AvailablePhoneNumbers/US/Local.json?AreaCode=628&SmsEnabled=true&VoiceEnabled=true&PageSize=5"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Buy one (irreversible — costs ~$1.15/mo + per-message charges):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
PHONE="+16283454599"
|
|
79
|
+
curl -s -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" -X POST \
|
|
80
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/IncomingPhoneNumbers.json" \
|
|
81
|
+
--data-urlencode "PhoneNumber=$PHONE" \
|
|
82
|
+
--data-urlencode "FriendlyName=Jordan Lee - Northwind"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Save the returned `sid` (starts with `PN...`) to `.env` as `TWILIO_PHONE_SID`.
|
|
86
|
+
|
|
87
|
+
### Transferring an existing number from the parent
|
|
88
|
+
|
|
89
|
+
If the agent already has a number under the parent account that you want to move to the sub-account:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
PARENT_SID="AC36..." # parent account SID
|
|
93
|
+
PARENT_AUTH="af86..." # parent account auth token
|
|
94
|
+
PHONE_SID="PN1eb30e..." # the number to move
|
|
95
|
+
SUBACCOUNT_SID="ACf2..." # destination sub-account
|
|
96
|
+
|
|
97
|
+
curl -s -u "$PARENT_SID:$PARENT_AUTH" -X POST \
|
|
98
|
+
"https://api.twilio.com/2010-04-01/Accounts/$PARENT_SID/IncomingPhoneNumbers/$PHONE_SID.json" \
|
|
99
|
+
--data-urlencode "AccountSid=$SUBACCOUNT_SID"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The number, all its webhook configuration, and message history move to the sub-account in one API call.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 3. Configure the SMS webhook
|
|
107
|
+
|
|
108
|
+
After the sub-account owns the number, configure the SMS webhook to point at the agent's Railway webhook relay:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
source .env
|
|
112
|
+
RELAY_URL="https://${AGENT_FIRSTNAME_LOWER}-webhook-relay-production.up.railway.app"
|
|
113
|
+
curl -s -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" -X POST \
|
|
114
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/IncomingPhoneNumbers/$TWILIO_PHONE_SID.json" \
|
|
115
|
+
--data-urlencode "SmsUrl=$RELAY_URL/sms" \
|
|
116
|
+
--data-urlencode "SmsMethod=POST"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 4. Configure the WhatsApp sandbox
|
|
122
|
+
|
|
123
|
+
This is the whole reason we use sub-accounts. Each sub-account has its own independent WhatsApp sandbox.
|
|
124
|
+
|
|
125
|
+
**Important**: WhatsApp sandbox webhook configuration is **UI-only** — Twilio does not expose an API for this. You must use Playwright or the user must configure it manually.
|
|
126
|
+
|
|
127
|
+
1. Log in to the Twilio Console (the sandbox UI uses a different login session than the API)
|
|
128
|
+
2. **Switch to the sub-account** via the account selector top-left (the dropdown shows all sub-accounts under the parent)
|
|
129
|
+
3. Navigate to: `https://console.twilio.com/us1/develop/sms/try-it-out/whatsapp-learn?frameUrl=%2Fconsole%2Fsms%2Fwhatsapp%2Flearn`
|
|
130
|
+
4. Click **Sandbox settings** tab
|
|
131
|
+
5. Set the inbound webhook URL: `https://{firstname}-webhook-relay-production.up.railway.app/whatsapp`
|
|
132
|
+
6. Set the status callback URL: `https://{firstname}-webhook-relay-production.up.railway.app/whatsapp/status`
|
|
133
|
+
7. Set both methods to HTTP POST
|
|
134
|
+
8. Save
|
|
135
|
+
|
|
136
|
+
Note the **sandbox join code** shown on the page (e.g. `join follow-arm`). Users must send `join {code}` from their WhatsApp to `+1 415 523 8886` to enroll their number for testing with this agent's sandbox.
|
|
137
|
+
|
|
138
|
+
### Production WhatsApp (post-sandbox)
|
|
139
|
+
|
|
140
|
+
For production WhatsApp (real WABA business number, not the shared sandbox number), each sub-account can register its own WABA. This requires Facebook Business verification per sub-account — Twilio provides a self-sign-up flow at https://www.twilio.com/docs/whatsapp/self-sign-up. Same pattern: each agent's sub-account → its own WABA → its own webhook URL.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 5. Update the Railway webhook relay
|
|
145
|
+
|
|
146
|
+
The agent's relay verifies Twilio HMAC signatures using the sub-account's auth token (NOT the parent's). After creating the sub-account, update the Railway env var:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
source .env
|
|
150
|
+
cd services/webhook-relay
|
|
151
|
+
railway variables --service ${AGENT_FIRSTNAME_LOWER}-webhook-relay \
|
|
152
|
+
--set "TWILIO_AUTH_TOKEN=$TWILIO_AUTH_TOKEN"
|
|
153
|
+
railway up --service ${AGENT_FIRSTNAME_LOWER}-webhook-relay --detach
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Wait until `/health` reports `twilio_signature: true` again.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 6. Add to init-maestro Phase 4
|
|
161
|
+
|
|
162
|
+
When `/init-maestro` runs Phase 4 Service Configuration, the Twilio step should:
|
|
163
|
+
|
|
164
|
+
1. Check whether `TWILIO_PARENT_ACCOUNT_SID` is set in `.env` (from a previous agent's setup or org config)
|
|
165
|
+
2. If yes: create a sub-account for this agent via the API (Step 1 above), then bypass the "buy new account" flow
|
|
166
|
+
3. If no: this is the first agent in the org — use `TWILIO_ACCOUNT_SID` as both parent and main, and document that future agents will need sub-accounts under it
|
|
167
|
+
4. Buy a phone number under the sub-account
|
|
168
|
+
5. Configure SMS webhook → Railway
|
|
169
|
+
6. (Manual or Playwright) Configure WhatsApp sandbox → Railway
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Verification
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# 1. Sub-account exists and is active
|
|
177
|
+
source .env
|
|
178
|
+
curl -s -u "$TWILIO_PARENT_ACCOUNT_SID:$TWILIO_PARENT_AUTH_TOKEN" \
|
|
179
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID.json" \
|
|
180
|
+
| python3 -m json.tool
|
|
181
|
+
|
|
182
|
+
# 2. Phone number is owned by the sub-account
|
|
183
|
+
curl -s -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
|
|
184
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/IncomingPhoneNumbers.json"
|
|
185
|
+
|
|
186
|
+
# 3. SMS webhook points at Railway
|
|
187
|
+
curl -s -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
|
|
188
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/IncomingPhoneNumbers/$TWILIO_PHONE_SID.json" \
|
|
189
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print('SMS URL:', d.get('sms_url'))"
|
|
190
|
+
|
|
191
|
+
# 4. Send a test SMS using the sub-account credentials
|
|
192
|
+
bash scripts/send-sms.sh --to "+1...your_test_number" --body "Sub-account test from {AgentName}"
|
|
193
|
+
|
|
194
|
+
# 5. Send a WhatsApp message after joining the sandbox
|
|
195
|
+
bash scripts/send-whatsapp.sh --to "whatsapp:+1...your_number" --body "WhatsApp test from {AgentName}"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Closing / suspending a sub-account
|
|
201
|
+
|
|
202
|
+
When an agent is decommissioned:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
source .env
|
|
206
|
+
curl -s -u "$TWILIO_PARENT_ACCOUNT_SID:$TWILIO_PARENT_AUTH_TOKEN" -X POST \
|
|
207
|
+
"https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID.json" \
|
|
208
|
+
--data-urlencode "Status=closed"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Closing is irreversible. Use `Status=suspended` for temporary suspension (can be reactivated).
|
|
212
|
+
|
|
213
|
+
Before closing, decide what to do with the agent's phone number:
|
|
214
|
+
- Transfer back to the parent account (if you want to retain the number for re-use)
|
|
215
|
+
- Release it (Twilio will free up the number, you stop being charged)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Related guides
|
|
220
|
+
|
|
221
|
+
- [Webhook Relay Setup](webhook-relay-setup.md) — How the Railway relay uses `TWILIO_AUTH_TOKEN` to verify HMAC signatures
|
|
222
|
+
- [Voice & SMS Setup](voice-sms-setup.md) — End-to-end SMS pipeline
|
|
223
|
+
- [WhatsApp Setup](whatsapp-setup.md) — Sandbox vs production WhatsApp
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Verifying Maestro
|
|
2
|
+
|
|
3
|
+
How to prove the framework works — from the zero-credential automated suite to a
|
|
4
|
+
full live agent. Use the fast path for every change; use the live sections when
|
|
5
|
+
you've wired real channel/model credentials.
|
|
6
|
+
|
|
7
|
+
## 1. Fast path — automated suite (no credentials, ~7s)
|
|
8
|
+
|
|
9
|
+
From the framework checkout (`~/maestro`):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install # once
|
|
13
|
+
npm test # full suite — 862 tests across every subsystem
|
|
14
|
+
npm run check # 6 zero-dependency guards (conflict markers, exports,
|
|
15
|
+
# files-exist, no-confidential, unresolved tokens, identity)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`npm test` is the single source of truth for the logic of all four workstreams
|
|
19
|
+
(it runs hermetically — every channel socket, `claude --print`, and `os`-stat is
|
|
20
|
+
injected, so there's no network or real spawn). Green here means the wizard,
|
|
21
|
+
channel contract, learning loop, governor, rate-guard, budget-guard, cadence bus,
|
|
22
|
+
and recovery paths all behave.
|
|
23
|
+
|
|
24
|
+
Scoped subsets (all defined in `package.json`):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm run test:setup # the maestro setup wizard (lib/setup/*)
|
|
28
|
+
npm run test:channels # channel abstraction
|
|
29
|
+
npm run test:cadence # cadence bus + consumer + enqueue
|
|
30
|
+
npm run test:voice # voice
|
|
31
|
+
npm run test:cli # bin/maestro.mjs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Run one file directly while iterating:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node --test lib/learning/curator-consolidate.test.mjs
|
|
38
|
+
node --test lib/channels/whatsapp/baileys-typing.test.mjs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 2. The setup wizard (deterministic — safe to dry-run anywhere)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
node bin/maestro.mjs setup --help # command + flag reference
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Inside an **agent instance repo** (one created by `maestro create`):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
maestro setup --status # per-section detect(): unconfigured / partial / complete
|
|
51
|
+
maestro setup --dry-run # show what each section would do; writes nothing
|
|
52
|
+
maestro setup --only comms # (re)run a single section
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Unattended / CI config (no prompts, no LLM unless you drop `--no-enrich`):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
maestro setup --headless --answers answers.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`lib/setup/integration.test.mjs` already exercises this end-to-end: it copies the
|
|
62
|
+
`scaffold/`, runs the wizard headless on a fixture answers file, asserts a green
|
|
63
|
+
completeness gate, and re-runs to prove idempotency. That test is the canonical
|
|
64
|
+
"the wizard actually configures an agent" proof.
|
|
65
|
+
|
|
66
|
+
## 3. `maestro doctor` — runtime health of a configured agent
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
maestro doctor # identity + operating-model completeness, channels,
|
|
70
|
+
# cadence-bus arch, watchdog heartbeat, .emergency-stop
|
|
71
|
+
# (human-only now), governor ceiling vs RAM, open rate
|
|
72
|
+
# breaker, pmset autorestart, resume-pending strikes,
|
|
73
|
+
# today's budget band
|
|
74
|
+
maestro doctor --fix # apply the auto-fixable findings
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 4. Live, per-subsystem (needs the relevant credentials)
|
|
78
|
+
|
|
79
|
+
### Messaging (real-time)
|
|
80
|
+
- **Telegram** — set `TELEGRAM_BOT_TOKEN`, then `node scripts/setup/init-telegram.mjs`
|
|
81
|
+
(validates via `getMe`, writes `config/telegram.yaml`). DM the bot; unknown DMs
|
|
82
|
+
are default-denied → reply `pair <code>` to pair. Long-poll runs inside the
|
|
83
|
+
daemon (no relay/tunnel).
|
|
84
|
+
- **Slack** — `node scripts/setup/init-slack-socket-mode.mjs`; enable reactions /
|
|
85
|
+
thread-context / CC'd channels via `config/slack.yaml`. The dedicated launchd
|
|
86
|
+
socket process is the single owner (do **not** also set the daemon adapter).
|
|
87
|
+
- **WhatsApp (Baileys)** — `npm i baileys` in the agent repo, scan the QR
|
|
88
|
+
(`state/whatsapp/auth/pending-qr.txt`); the agent now shows a real "typing…"
|
|
89
|
+
presence while it composes a reply.
|
|
90
|
+
- **Verify inbound actually works** — `maestro setup comms` runs a per-channel
|
|
91
|
+
probe that drops a sentinel and asserts a matching inbox-item / connect-log
|
|
92
|
+
appears within a timeout (it prints the `tail -f` command on failure).
|
|
93
|
+
|
|
94
|
+
### Self-learning loop
|
|
95
|
+
- End a Claude Code session in an agent repo → the global `Stop` hook spawns the
|
|
96
|
+
detached reflect worker. Confirm:
|
|
97
|
+
- `plugins/agent-skills/skills/<id>.md` — any newly authored skill (live on disk
|
|
98
|
+
immediately; the next session loads it).
|
|
99
|
+
- `logs/audit/skills.jsonl` — every create/patch/abort/consolidate row.
|
|
100
|
+
- `state/learning/counters.json` — the nudge counters.
|
|
101
|
+
- **Verbatim recall** — invoke the `session-search` skill (discovery / scroll /
|
|
102
|
+
read / browse) over `state/learning/sessions.db`.
|
|
103
|
+
- **Skill curator** — `node scripts/learning/consolidate-skills.mjs` runs the LLM
|
|
104
|
+
umbrella consolidation on demand (no-op below `consolidation.minSkills`); it
|
|
105
|
+
otherwise fires as a detached worker from the `skill-curator` cadence when due.
|
|
106
|
+
|
|
107
|
+
### Recovery & resource governance
|
|
108
|
+
- **Governor** — `lib/resource-governor.test.mjs` drives ADMIT/QUEUE/DEFER with
|
|
109
|
+
injected `os` stats; in production it gates every `dispatcher.spawnSession`.
|
|
110
|
+
- **Never-brick watchdog** — `bash -n scripts/watchdog/memory-watchdog.sh`; the
|
|
111
|
+
tiers are SOFT (`state/throttle.json`) → HARD (kill youngest) → CRITICAL (clean
|
|
112
|
+
restart) → graceful reboot. OOM never writes `.emergency-stop`.
|
|
113
|
+
- **At-most-once cron / outage** — `lib/cadence-bus-schedule.test.mjs` proves a
|
|
114
|
+
simulated multi-period outage yields exactly one catch-up tick.
|
|
115
|
+
|
|
116
|
+
## 5. Full end-to-end on a scratch agent
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx @cohortapp/agent-sdk create test-agent
|
|
120
|
+
cd test-agent
|
|
121
|
+
npm install
|
|
122
|
+
maestro setup --headless --answers answers.json # or run it interactively
|
|
123
|
+
maestro doctor # confirm green
|
|
124
|
+
npm install -g baileys # (optional) per channel you enable
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This goes from an empty directory to a configured, self-verifying agent using the
|
|
128
|
+
same code the suite covers.
|