Splits the quote attachment model along the seam that actually matters:
'operator-only references' (drawings the operator consulted, supplier
emails they filed away) vs 'customer-facing files' (supplier quotes,
drawings, NDAs that need to ride along on the email).
Schema (PB): new `internal_attachments` + `outbound_attachments` fields
on the `quotes` collection, maxSelect 10 each. Existing `attachments`
field kept for back-compat but is no longer the source of truth for
outbound emails.
API:
- GET/POST/DELETE /api/v1/quotes/[id]/internal-attachments[/{filename}]
- GET/POST/DELETE /api/v1/quotes/[id]/outbound-attachments[/{filename}]
- POST /api/v1/quotes/[id]/attachments/upload kept for legacy `attachments`
MCP: `quotes.send_email` description now correctly states
`selectedAttachmentIds` are PB file tokens from `outbound_attachments`
(supplier quotes, drawings, NDAs), not IDs of the legacy `attachments`
collection.
Frontend: `ProcessOutboundAttachmentsCard` component lets the operator
upload/remove customer-facing files during the process page; approval +
process pages now read the new fields.
Outbound Send workflow (deployed as `PIEAkPYYYZLGl6Pj`):
- Old workflow (id `WF_Email_Send_SMTP`) and stale repo file
(`WFDASH — Quote Outbound Send.json`) replaced.
- New revision intersects `quotes.outbound_attachments` with
`email_outbound_attachment_ids`, downloads each from
`/api/files/quotes/<id>/<token>`, and emits
`options.attachments: [{name, content, type}]` consumed by
`Send Email (SMTP)` (PO Send pattern).
- Failure path flipped from `send_failed` to `mail_failed` so
`retryQuoteEmail` can find failed sends (it only accepts the
latter). Previously failed sends were stranded.
Email Monitor (v5) workflow fixes:
- Reply-branch auth: any authenticated request now passes through;
pre-fix bug rejected branches that the IMAP trigger hadn't seen yet.
- Reply detection: bulletproof subject regex
(/Q-?\d{4}-?\d{2}-?\d{3}/) accepts both legacy `Q-2026-09-246`
and current `Q202609246` formats; canonicalised digits-only for
PB `~` substring match.
Delivery notes: new pricing endpoint at
/api/v1/delivery-notes/items/[id]/pricing + service-layer methods.
Snapshots kept for forensics: PRE-FIX-REPLY-{BRANCH-AUTH,DETECTION}.json
and push-payload.baseline.json are the previously-deployed workflow
shapes, retained so we can diff/rollback if regression hits.
Verified:
- PUT workflow PIEAkPYYYZLGl6Pj -> 200, active, 25 nodes
- quotes-service.test.ts: 117 pass (4 pre-existing failures unchanged)
- mcp/route.test.ts: 118 pass (2 pre-existing failures unchanged)
- node --check on new Code node JS passes
Docs: docs/quotes-outbound-attachments-deploy.md covers the deploy
procedure; docs/api-mcp-layer.md description sync.
|
||
|---|---|---|
| .. | ||
| quote-attachments-split.md | ||
| README.md | ||
| RUN-PLAN.md | ||
| TEMPLATE.md | ||
Plans folder
Cross-session handoff between the planner (Claude on cloud) and the implementer (any model — usually Minimax in a separate session). The plan file is the contract — chat history doesn't transfer, so the plan has to be self-contained.
Workflow
-
Planner writes a plan to
.claude/plans/<slug>.mdfrom theTEMPLATE.mdshape.- Use the
superpowers:writing-plansskill if available. - The plan must be self-contained — anything the implementer can't infer from the working tree goes in the Background section.
- The Background section is where the planner summarises the conversation that led to the plan: decisions, dead ends, "we tried X but Y", links to prior commits, the operator's actual intent. This is the tribal-knowledge handoff.
- Set frontmatter
status: readywhen ready to hand off.
- Use the
-
Hand off — pick one:
- File: tell the implementer session "read
.claude/plans/<slug>.mdand execute". - Git: commit the plan on a branch, switch the implementer session to that branch.
- Orca:
orca handoff --plan .claude/plans/<slug>.md(see theorca-cliskill).
- File: tell the implementer session "read
-
Implementer boots from
RUN-PLAN.md— paste it as the opening prompt of the new session, or load it via skill if the harness supports it.- Reads the plan + the repo's
CLAUDE.md/AGENTS.md. - Follows the plan, surfaces disagreements rather than improvising.
- Flips
status: in_progress→complete(orblocked) and writes a short report in the plan's Status (filled by implementer) section.
- Reads the plan + the repo's
-
Loop back — the implementer's Status section + commit messages are the planner's input for the next iteration.
File layout
| File | Purpose |
|---|---|
README.md |
This file — orientation |
TEMPLATE.md |
Copy this to start a new plan |
RUN-PLAN.md |
Paste this into the implementer session as its opening prompt |
<slug>.md |
An individual plan. Slug is short-kebab-case, matches the feature / branch name |
<slug>.status.md |
Optional. Implementer writes one of these if it needs to report back without flipping the plan's status frontmatter (e.g. mid-run questions) |
Conventions
- Commit plans with the work. They're version-controlled documentation of intent, not scratch.
- One plan per feature / branch. Split if the scope grows.
- Status lifecycle:
draft→ready→in_progress→complete(orblocked/abandoned). - Don't bypass MCP. If the implementer needs a tool that doesn't exist, surface the gap in the status file — don't fall back to direct REST calls (Hermes / n8n drops
AGENT_API_KEYon direct calls; see.claude/memory/mcp-only-no-direct-api.md).