Skip to content

feat(reply-drafts): prepare replies you owe across all channels#175

Open
yustme wants to merge 8 commits into
Raven-Scout:mainfrom
yustme:feat/reply-drafts
Open

feat(reply-drafts): prepare replies you owe across all channels#175
yustme wants to merge 8 commits into
Raven-Scout:mainfrom
yustme:feat/reply-drafts

Conversation

@yustme

@yustme yustme commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Scout now prepares draft replies for conversations where you owe an answer, on the background runs, so you can review them in /scout-work (or the macOS app), lightly edit, and send them yourself. Scout never sends and never creates a native Gmail/Slack draft — a text file in the vault is the only output.

What it detects

Two loop types, across every enabled channel (Gmail, Slack, Linear, GitHub, WhatsApp/Messages):

  • direct-debt — someone asked you something and you have not replied.
  • promise-answered — you promised to follow up, asked elsewhere, and the answer has now arrived (Scout pairs the promise with the answer).

How it works

  • New core phase phases/core/reply-drafts.md (briefing + consolidation) — runs after the connector scans and the action-items list, verifies the debt is real (reads the thread tail, applies the cold-outreach / leave-state filters), then writes one drafts/<TAG>.md per loop and ensures a matching action-item row with a (reply drafted → [[drafts/<TAG>]]) pointer.
  • drafts/<TAG>.md frontmatter is the contract the app + /scout-work key on: tag, channel, loop_type, to, thread_ref, subject, status, created, context_answer_ref. Status vocabulary is draft | sent | dismissed.
  • templates/drafts/README.md.tmpl documents the contract and is seeded into the vault; drafts/ + drafts/archive/ are scaffolded on install.
  • /scout-work gains a Reply item type: it shows the full drafted text and accepts sent / edit: … / dismiss / skip. It never calls a send tool.

Hard constraint

Scout only ever writes draft text and flips status:. No sending, no native drafts — that stays the user’s action.

Tests

  • Assembly: the phase lands in SKILL.md (briefing + consolidation), after action-items, and is excluded from DREAMING.md / RESEARCH.md.
  • Bootstrap: drafts/ + drafts/archive/ + drafts/README.md are scaffolded on install.
  • Full unit suite green (864 passed).

Companion

Paired with the macOS app PR (Raven-Scout/Scout) that adds a Reply Drafts section rendering these files and flipping their status.

Scout now detects open conversational loops where the user owes someone a
reply and prepares a ready-to-send draft into drafts/<TAG>.md. Two loop types:
direct-debt (someone asked, no reply yet) and promise-answered (promised ->
asked elsewhere -> answer arrived). Reviewed in /scout-work; the user always
sends himself — Scout never sends or creates native drafts.

- phases/core/reply-drafts.md: detection + drafting synthesis phase
  (mode: briefing+consolidation, runs after action-items)
- templates/drafts/README.md.tmpl: draft file contract, seeded into vault
- bootstrap: scaffold drafts/ + drafts/archive/, seed README
- commands/scout-work.md: Reply item type (show draft, sent/edit/skip/dismiss,
  no send tool ever)
- tests: assembly + scaffolding coverage
yustme added 7 commits June 30, 2026 10:26
Email/Slack/WhatsApp draft bodies are now plain sendable text (no markdown,
no headings/bullets/backticks, no HTML comments) so they look right when sent
as-is; markdown stays allowed only for linear/github. Recipients/CC/subject
live in frontmatter — adds a cc: field to preserve the thread's other
recipients instead of dropping them or listing them inline.
…ompts

Documents that each [TBD: ...] marker is surfaced as a fill-in field in the app
and /scout-work, so the phase must write each as a standalone actionable prompt
(one fact per marker) placed where the value should land in the sentence.
Each draft now carries an AI summary and the relevant thread messages after a
<!-- scout:context --> marker (## Summary + ## Thread with '- [date] Sender:
line' entries). It lives after the body marker so it is never sent or copied;
the app renders it as two collapsible sections under the draft.
…he plugin

Adds /scout-reply: the plugin-side equivalent of the app's Reply Drafts view.
Review the replies you owe, chat with the AI about a specific topic (it has the
summary + thread and can re-read the live thread/KB), fill in [TBD: ...] blanks,
refine wording, and mark sent/dismissed — all in the conversation, never sending.
Operates on the same drafts/<TAG>.md files as the app, so the full experience is
available without the native app.
Adds explicit, user-initiated delivery to /scout-reply: a slack draft can be
sent into its thread (slack_send_message, after confirming the recipient), an
email draft can be turned into a Gmail draft (create_draft, never auto-sent).
Autonomous runs still never send — delivery only happens on an explicit
instruction. Updates the command menu, phase, and drafts README accordingly.
The README delivery note changed 'never sends' -> 'never send anything'; update
the seeds-readme assertion to 'never send' so it tracks the live wording.

@jordanrburger jordanrburger left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — reply-drafts

Strong feature — the never-send constraint is enforced consistently (phase + both commands + anti-patterns + tests) and the verify-before-draft gate is genuinely rigorous. Two things I'd resolve before merge, plus a lockfile and a cross-PR note. Most of this surfaced diffing against a real (mature) vault, not from the diff alone.

🔴 Anonymization leak (inline on scout-reply.md). Real bank names (SLSP = Slovenská sporiteľňa, ČSAS = Česká spořitelna), the employer name, and real-person-shaped client names with Slovak subject text, in a public-repo command file. Needs stand-ins per the repo's anonymization rule — see inline.

🔴 drafts/ collides with existing vaults. drafts/ is not an established engine path (nothing on main references it), but a mature vault already uses drafts/ as a free-form drafting workspace — long-form proposals, weekly updates, PR reviews, long replies, none using this PR's tag/channel/status frontmatter. This PR claims the folder as its <TAG>.md namespace and seeds a drafts/README.md that declares "This directory holds prepared reply drafts," which mischaracterizes it. No data loss — the Step 0 archive bash only moves sent/dismissed files, so no-frontmatter files are skipped — but /scout-reply and /scout-work would scan a folder mixing two different "drafts" notions, and the README is wrong for it. Suggest namespacing the feature (reply-drafts/ or drafts/replies/), or making rollout aware of an existing drafts/. This is the "facet built greenfield, deployed onto a mature vault" pattern — captured in #178.

🟡 uv.lock (933 lines) looks unrelated. It's new (not on main) with no pyproject.toml change behind it — ~65% of the diff. Looks accidental, or like a first-time lockfile commit; either way it belongs in its own infra PR rather than riding in a feature PR.

🟡 Cross-PR with #176. Both PRs edit the same _INSTALL_ONLY_TEMPLATES and _CAT1_DIR_LAYOUT tuples → merge conflict for whichever lands second. And on main, upgrade() calls neither _stage_create_dirs nor _stage_install_only_seeds, so on an existing vault /scout-update assembles the phase but does not seed drafts/README.md or pre-create drafts/archive/. The feature depends on #176's upgrade-replay to fully reach existing vaults.

🟡 Autonomy surface. /scout-reply is the first place Scout gains a real send path — slack_send_message + Gmail create_draft. It's well-gated (interactive only, explicit ask, confirm recipient; autonomous runs never send; /scout-work's Reply variant is hard-no-send), but it's a real expansion worth conscious sign-off given how much weight the escalate-vs-handle contract carries.

✓ Verified correct: assembly routing (mode: [briefing, consolidation] → SKILL only, after action-items, excluded from DREAMING/RESEARCH); bootstrap wiring is correct (README in _INSTALL_ONLY_TEMPLATES, drafts/archive in the dir layout); both CLI deps exist (action-items new-prefix, parser name_lookup); 19/19 changed-area tests pass; the Step 0 archive bash is safe on no-status files.

The leak and the greenfield-drafts/ assumption are both the back-port-hygiene gap we're already discussing on #176/#178 — a standardized scrub + mature-vault-diff step in the back-port procedure would have caught both.

Comment thread commands/scout-reply.md
draft. Otherwise show a compact list of `status: draft` items:
```
Owed replies with a prepared draft:
1. [#S2DA6B] Lucia Hallonová (SLSP) — Re: Zmeny Keboola rolí · email

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real-world identifiers on a public surface. SLSP (Slovenská sporiteľňa) and ČSAS (Česká spořitelna) are real banks; combined with the employer name, real-person-shaped names, and Slovak subject text, this reads as lifted vault data rather than an example. Same on line 33 (/scout-reply SLSP).

Per the repo's CLAUDE.md anonymization rule (and the "no vault content on public surfaces" principle), these need stand-ins — the way templates/drafts/README.md.tmpl already does it (Jan Novák <jan@firma.cz>, Rozpočet Q3). Suggest: neutral names (Alex / Priya), a generic vendor noun instead of a named bank, and PROJ-####-style tags.

jordanrburger pushed a commit that referenced this pull request Jun 30, 2026
Folds two findings from the PR #175 review into the facet open-questions:
- Problem 5 gains a second flavor — namespace collision: reply-drafts claims
  a `drafts/` directory that a mature vault already uses as a free-form
  workspace; the engine has no registry of reserved vault paths.
- Problem 4 gains the hygiene angle — #175 shipped unanonymized real vault
  data into a public command file because the back-port had no scrub gate.
- Open question 5 now names the two missing back-port gates (scrub +
  mature-vault diff) and a possible reserved-paths registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants