feat(scheduler): wire mission autopush to main bot on completion#46
Open
jsmninvest wants to merge 9 commits intoearlyaidopters:mainfrom
Open
feat(scheduler): wire mission autopush to main bot on completion#46jsmninvest wants to merge 9 commits intoearlyaidopters:mainfrom
jsmninvest wants to merge 9 commits intoearlyaidopters:mainfrom
Conversation
- Add migrations/v1.2.1/add-model-to-scheduled-tasks.ts: ALTER TABLE adds model TEXT column (NULL = agent default) - Add src/model-aliases.ts: resolveModelAlias() maps haiku|sonnet|opus to full claude-* IDs, passes through claude-* IDs unchanged - Update src/db.ts: ScheduledTask interface + createScheduledTask() accepts optional model param - Update src/scheduler.ts: pass resolveModelAlias(task.model) into runAgent() at fire time - Update src/schedule-cli.ts: --model flag with validation; list shows model per task Co-Authored-By: Oz <oz-agent@warp.dev>
…2-6 paused) - 44 enabled source jobs processed (20 disabled skipped) - Original Proactive Builder (Sunday) replaced by brain/muscle split: Planner (opus, 21:55 nightly) + Executor (sonnet, 22:00 nightly) - Phase 1 active (6): Morning Brief, Daily Summary Check, Daily Reflection, eod-report, Proactive Builder Planner, Proactive Builder Executor - Phases 2-6 paused (39): all other imported jobs - Agent routing: heartbeat/main->main, scout->research, content-creator->content, speed-to-lead->comms - Model routing: gpt-5.4->opus (DION Planner only), all others->sonnet; 4 jobs downgraded by name override - Non-standard cron (everyMs) normalised to standard cron expressions - Script is idempotent: re-run skips existing tasks by prompt+schedule+agent_id fingerprint Co-Authored-By: Oz <oz-agent@warp.dev>
- Add migrations/v1.3.0/add-dion-slide-cache.ts: creates dion_slide_cache table with lookup index (fragrance_id, slide_type, invalidated) and hash index - Add to src/db.ts: CachedSlide interface, getCachedSlide(), cacheSlide(), invalidateSlide() getCachedSlide respects expires_at TTL and invalidated flag invalidateSlide() accepts optional slideType to invalidate one type or all for a fragrance - Pipeline wiring deferred until DION scripts are ported into this repo Co-Authored-By: Oz <oz-agent@warp.dev>
Port kanban_tasks, agent_heartbeats, agent_events from Supabase to local SQLite. fragrance_catalog and bot_kv stay in Supabase because DION app and PM2 trading bots depend on them externally. Co-Authored-By: Oz <oz-agent@warp.dev>
…udge
Five cherry-picks from claudeclaw-os, wired end to end:
1. loadMcpServers (src/agent.ts)
- Adds McpHttpConfig union so `url`-based entries (e.g. context7) are
passed to the SDK as HTTP transport instead of being silently dropped.
- Expands ${VAR} placeholders in env, headers, command, and args against
process.env so secrets like N8N_CLOUD_API_KEY and CONTEXT7_API_KEY can
live in the shell environment rather than .claude/settings.json.
2. Exfiltration guard (src/exfiltration-guard.ts + test)
- Scans outbound Telegram replies for Anthropic keys, generic sk- keys,
Slack/GitHub/AWS tokens, 40+ char hex (excluding git SHAs), and the
base64/url-encoded variants of PROTECTED_ENV_VARS.
- Redacts matches to [REDACTED] before the text leaves the process.
- Gated by EXFILTRATION_GUARD_ENABLED (default on).
3. Message complexity classifier (src/message-classifier.ts + test)
- Pure string check: acknowledgements ("ok", "thanks") classify as
simple, everything else as complex.
- Bot routes simple messages to SMART_ROUTING_CHEAP_MODEL (default
haiku) when SMART_ROUTING_ENABLED=true and the user has no explicit
model override. Off by default.
4. Memory nudge (src/memory.ts, src/db.ts, src/bot.ts)
- getLastMemorySaveTime + getTurnCountSinceTimestamp DB helpers.
- shouldNudgeMemory fires when N turns or M hours have elapsed since
the last memory save (MEMORY_NUDGE_INTERVAL_TURNS=10,
MEMORY_NUDGE_INTERVAL_HOURS=2 by default).
- Injects MEMORY_NUDGE_TEXT into the pre-agent context block so the
model is reminded to persist anything worth remembering.
- Returns false on fresh installs (no memories yet) to avoid nagging.
5. Config surface (src/config.ts)
- New env knobs: MEMORY_NUDGE_INTERVAL_TURNS/HOURS,
EXFILTRATION_GUARD_ENABLED, PROTECTED_ENV_VARS,
SMART_ROUTING_ENABLED, SMART_ROUTING_CHEAP_MODEL.
Tests: typecheck clean, build clean. 37/37 new unit tests pass
(21 exfiltration-guard + 16 message-classifier). Full suite: 259/260
(one pre-existing scheduler truncation assertion unrelated to this
change).
Co-Authored-By: Oz <oz-agent@warp.dev>
readEnvFile is opt-in per key (keeps secrets out of process.env), so my
first pass at expansion only saw variables that happened to be exported
in the ambient shell. MCP keys like CONTEXT7_API_KEY and N8N_CLOUD_API_KEY
live in .env only, so context7 and n8n launched with literal
"\${CONTEXT7_API_KEY}" and "\${N8N_CLOUD_API_KEY}" strings and failed auth.
Fix: scan the parsed mcpServers JSON for every \${VAR} reference, call
readEnvFile for just those keys, and build a merge map where process.env
takes precedence but .env is the fallback. Unresolved names are left as
literal \${...} so a missing secret surfaces as a clear auth error rather
than a silent empty-value connection.
Verified against the real settings.json:
CONTEXT7_API_KEY source=.env len=43
N8N_CLOUD_API_KEY source=.env len=272
Both expand into the HTTP header / stdio env respectively.
Co-Authored-By: Oz <oz-agent@warp.dev>
Two-bug hotfix unblocking Watchdog v2:
1. mission-watchdog-cli and qa-audit-cli never called initDatabase(),
so the shared db handle used by createMissionTask() (via auto-triage)
was undefined — first DB write blew up with "Cannot read properties
of undefined (reading 'prepare')".
2. qa-audit.ts eagerly called applyQaAgentOverrides() -> loadAgentConfig('qa')
at the top of runQaAudit(), which throws when QA_BOT_TOKEN is unset —
before checking if there was anything to audit. Moved the overrides
call to AFTER the candidate query; early-return exits 0 cleanly when
mission_verifications is empty, even with QA_BOT_TOKEN unset.
Also commits the rest of the v2 body that was stranded in the working
tree: alert-router, auto-triage, mission-watchdog, migrations v1.4–v1.7,
anti-idle orchestrator, memory import/backfill scripts, and the v2
updates to scheduler / dashboard / db / index / mission-cli /
oauth-health / notify.sh / version.json.
Verified end-to-end:
- mission-watchdog-cli exits 0, queued 9 auto-triage missions on @main
(4 failed + 5 scheduled_task_failed) from real historical failures.
- qa-audit-cli exits 0 silently with 0 candidates.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the monolithic call-processing mission that kept hitting the 30-min wall-clock and 60-turn ceiling with a staged pipeline. Stages (all Sonnet): A. Extract — parse GHL transcript, write STAGE_A_FACTS note + fields B. RAG — Pinecone shortlist + rule-based rerank, STAGE_B_RECOMMENDATION C. Borrower draft — Gmail draft, STAGE_C_BORROWER with draftId D. AE draft — C21 Outlook draft, STAGE_D_AE with draftId Each stage is a separate mission_task with acceptance criteria. Stage N creates stage N+1 when acceptance passes. Watchdog v2 can retry any stage independently. No transcribe stage; GHL already handles that. Durability: call_pipeline_runs table, (call_msg_id, stage) PRIMARY KEY enforces idempotency across retries. Artifacts: - src/call-pipeline/orchestrator.ts - src/call-pipeline/stage-prompts.ts - src/call-pipeline/orchestrator.test.ts (5/5 pass) - src/call-pipeline/stage-a.integration.test.ts - scripts/start-call-pipeline.mjs - src/db.ts migration (legacy + fresh install paths) Builder mission 640e22d6 hit 60-turn ceiling before wiring the /clawd call-worker hook and before running Stage A integration against Ashley. Follow-up mission dispatched for those two gaps. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Restores the mission-autopush module (dropped during rebuild in 111d22a) and wires notifyMissionCompletion into scheduler.ts so every completeMissionTask() call in runDueMissionTasks also fires the autopush hook. Why: missions created by Rudy (created_by='main') would complete silently. Aditya had no visibility unless he polled the CLI. This closes the loop. Exactly-once delivery is guaranteed by db.markMissionAutopushed(), which CAS-stamps the autopushed_at column iff currently NULL. 4 call sites added in scheduler.ts (timeout, acceptance-pass, acceptance-fail, catch-block) — the CAS absorbs any double-invocation. Restored from 1906b01: - src/mission-autopush.ts + src/mission-autopush.test.ts (13 tests, all pass) - db.ts: markMissionAutopushed, RetryReason, autopushed_at on MissionTask, autopushed_at column + idempotent migration Canary mission 878dee40 (priority 5, ops) completed with autopushed_at set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
autopushed_atcolumn,markMissionAutopushed()CAS, andRetryReasontype to db.tsnotifyMissionCompletion(mission.id)into all 4 completion paths in scheduler.ts (timeout, acceptance-pass, acceptance-fail, catch-block)Why
Missions queued by Rudy (
created_by='main') were completing silently — Aditya had no visibility unless he polled. This closes the loop by pushing a short Telegram notification to the main bot chat whenever a main-created mission finishes.Exactly-once delivery is guaranteed by
markMissionAutopushed(), which CAS-stampsautopushed_atiff currently NULL. The 4 call sites all go through the same CAS, so even if the completion path is re-entered, Telegram is pinged exactly once.Test plan
npm run buildcleannpm test -- --run src/mission-autopush.test.ts— 13/13 passautopushed_at=1776884052🤖 Generated with Claude Code