← back to Claude Email Responder
Reverse channel: directive parser bypasses Claude for 'act on X' / 'status' / 'pause loop' / 'resume loop'
a7dfc6e5e614d4856ce9d971c8e71636db6ddabd · 2026-05-08 00:35:15 -0700 · SteveStudio2
Steve can reply to any watchdog email with one of these verbs and the
directive lands in ~/Projects/_dw-batch/directives/<ts>-<verb>.json.
The next yolo tick reads the queue and acts.
Bypasses askClaude() — deterministic, free, fast. Falls through to
existing Claude-CLI conversational path for non-directive replies.
'status' verb returns ledger-tail directly in the email reply.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit a7dfc6e5e614d4856ce9d971c8e71636db6ddabd
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Fri May 8 00:35:15 2026 -0700
Reverse channel: directive parser bypasses Claude for 'act on X' / 'status' / 'pause loop' / 'resume loop'
Steve can reply to any watchdog email with one of these verbs and the
directive lands in ~/Projects/_dw-batch/directives/<ts>-<verb>.json.
The next yolo tick reads the queue and acts.
Bypasses askClaude() — deterministic, free, fast. Falls through to
existing Claude-CLI conversational path for non-directive replies.
'status' verb returns ledger-tail directly in the email reply.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
server.js | 42 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/server.js b/server.js
index 7b0c5b2..fdae68a 100644
--- a/server.js
+++ b/server.js
@@ -173,9 +173,47 @@ async function pollOnce() {
continue;
}
console.log(`[responder] handling msg ${id} from ${sender}: ${bodyText.slice(0,80)}…`);
+
+ // ─── Directive shortcut (reverse channel into yolo loop) ───
+ // Steve can reply to any watchdog email with verbs like:
+ // act on <target> — queue an action for the next yolo tick
+ // status — reply with autonomy ledger tail
+ // pause loop / resume loop
+ // This bypasses Claude (deterministic, free, fast).
+ const directiveMatch = bodyText.trim().match(/^(act on|pause loop|resume loop|status)\b\s*(.*)$/i);
let answer;
- try { answer = await askClaude(subject, bodyText, account); }
- catch (e) { console.error('[responder] claude error', e.message); errors++; continue; }
+ if (directiveMatch) {
+ const verb = directiveMatch[1].toLowerCase().replace(/\s+/g, '_');
+ const target = (directiveMatch[2] || '').trim();
+ const directive = {
+ ts: new Date().toISOString(),
+ from: sender,
+ raw: bodyText.slice(0, 300),
+ parsed: { verb, target },
+ thread_id: full.threadId || id,
+ };
+ const fname = `${Date.now()}-${verb}.json`;
+ const dirQueue = '/Users/stevestudio2/Projects/_dw-batch/directives';
+ try {
+ fs.mkdirSync(dirQueue, { recursive: true });
+ fs.writeFileSync(`${dirQueue}/${fname}`, JSON.stringify(directive, null, 2));
+ console.log(`[responder] directive queued: ${fname}`);
+ if (verb === 'status') {
+ // Quick status reply — read ledger tail
+ let tail = '';
+ try { tail = require('child_process').execSync(`/Users/stevestudio2/.claude/data/ledger-tail.sh 15`, { encoding: 'utf8' }); } catch {}
+ answer = `<p>Directive queued: <code>${fname}</code></p><pre style="font-family:monospace;font-size:11px;background:#f5f5f5;padding:10px">${tail.replace(/[<>]/g, c => c === '<' ? '<' : '>')}</pre>`;
+ } else {
+ answer = `<p>Directive queued for next yolo tick: <code>${verb}</code> · target: <code>${target || '(none)'}</code></p><p style="color:#888;font-size:11px">file: ${fname}</p>`;
+ }
+ } catch (e) {
+ console.error('[responder] directive queue failed', e.message);
+ answer = `<p>Directive parse failed: ${e.message}</p>`;
+ }
+ } else {
+ try { answer = await askClaude(subject, bodyText, account); }
+ catch (e) { console.error('[responder] claude error', e.message); errors++; continue; }
+ }
if (!answer) { state.replied[id] = { ts: Date.now(), reason: 'empty-claude-answer' }; continue; }
// Wrap with light HTML so the reply is paragraphed even if Claude returned plain.
const looksHtml = /<\w+[^>]*>/.test(answer);
← ec27116 initial snapshot — gitify all builds (CLAUDE.md rule 2026-05
·
back to Claude Email Responder
·
snapshot: 1 file(s) changed, ~1 modified 0e199d6 →