Bid Center — Path 2 · direct chat

As of 2026-05-27 · Operator drives BC live via chat tools → 11 skill workflows → HITL on every write

Operator drives the Bid Center live via chat tools (add customer, update pricing, fill regional, compare quotes). Session opens three ways: /gfsbidsandprices slash command, drop the Bids_and_Customer_Pricing folder into Claude.ai, or invoke a chat tool directly via /api/tools/invoke. The operator picks one of the 11 skill workflows (see step 7). The skill reads STATUS.json, applies edits to the folder, builds outputs. On skill completion, scripts/post-session-sync.js runs and pushes every changed file to /api/tools/invoke with the X-Sync-Source: customer-pricing-folder header. R614 added a post-sync self-check (calls /api/healthcheck + verifies table-count deltas). Per ADR-031 every write lands in proposed_actions; Mike approves via the admin dashboard before the write is committed to D1 / NS. Per ADR-039 the operator writes ONLY through the folder — no direct API writes from the chat UI — enforced at runtime by R603's edit_mode_guard.ts.

D1-mirrored 11 skill workflows HITL on every write (ADR-031) Folder-only writes (ADR-039 · R603 edit_mode_guard) post-session-sync + R614 self-check

Pipeline — chat-initiated review

idle
Bid Center path 2 - Mike opens chat - intent stated - bid PDF attached - customer resolved - SY-version picked - context preloaded - skill chosen - 11-skill dispatcher runs - bid_* writes - .docx regen - STATUS.json refresh - dashboard rerender - events emitted - thread carried through LANE A / Mike kicks off in chat LANE B / Worker resolves customer + SY-version + preloads context LANE C / 11-skill dispatch + D1 writes LANE D / Outputs (.docx, STATUS.json, dashboard, events) WHAT THIS DOES: Operator opens session three ways: 1. /gfsbidsandprices slash command (~/.claude/commands/gfsbidsandprices.md) 2. Drop the Bids_and_Customer_Pricing folder into Claude.ai 3. Direct chat tool invocation via /api/tools/invoke D1 TABLE: chat_session (INSERT on first message) TECHNICAL DETAILS: OPERATOR OPENS SESSION SURFACES admin-dashboard.html (chat panel) chat.ai-globalfoodsolutions.co /gfsbidsandprices slash command folder drop in Claude.ai direct POST /api/tools/invoke STATUS: REAL operator opens session /gfsbidsandprices · folder drop · /api/tools/invoke 3 entry points, same dispatcher EXTERNAL · chat UI i WHAT THIS DOES: Mike states the intent: load a bid PDF and run a review for a specific customer. The chat router routes to the bid_center handler. D1 TABLE: chat_message (INSERT) TECHNICAL DETAILS: MIKE TYPES INTENT EXAMPLES "load bid PDF + run review for ACC Distributors" "compare ACC quotes v2.4 vs v2.5" "log this external bid for NYC DOE B5875" ROUTER intent_router -> bid_center handler STATUS: REAL Mike states intent "load bid + run review for <customer>" routes to bid_center handler BACKEND i WHAT THIS DOES: Mike drag-drops a bid PDF (or pastes text). The document_converter normalizes to markdown. D1 TABLE: chat_message attachment; R2 bid-attachments TECHNICAL DETAILS: ATTACH BID PDF HANDLERS drag-drop -> upload to R2 bid-attachments paste -> treat as bid_markdown document_converter PDF/XLSX -> markdown STATUS: REAL attach bid PDF or paste content document_converter -> markdown source -> R2 bid-attachments BACKEND i WHAT THIS DOES: Customer is resolved via name_synonyms. If ambiguous, the chat asks Mike to confirm. Mike is in the loop already so no proposed_action is staged. D1 TABLES: bid_customers (READ), customers (READ) TECHNICAL DETAILS: RESOLVE CUSTOMER (in chat) ALGORITHM exact -> alias -> fuzzy AMBIGUOUS ask Mike inline: "do you mean ACC Distributors or ACC Foods?" STATUS: REAL resolve customer (inline confirm) name_synonyms.json fuzzy match no proposed_action wait DATABASE i WHAT THIS DOES: Pick the customer's SY-version. Mike can bump the version explicitly (v2.5 -> v2.6) or accept the suggestion. D1 TABLE: bid_quote_versions (READ) TECHNICAL DETAILS: PICK SY-VERSION LOGIC latest = SELECT sy_version FROM bid_quote_versions WHERE customer_id=? AND is_latest=1 ask Mike: "bump to next version?" STATUS: REAL pick SY-version (trace thread) latest is_latest=1 OR bump e.g. SY2627-v2.5 -> v2.6 DATABASE i WHAT THIS DOES: The chat session is hydrated with the bid markdown, the customer's customer.json, and the latest bid_quote_versions row. The LLM context now has all the facts needed to run the review. D1 TABLE: chat_message (system role) with preloaded payload TECHNICAL DETAILS: PRELOAD CONTEXT CONTEXT bid_markdown customer.json (region, terms, notes) bid_quote_versions latest row bid_price_snapshots for that version STATUS: REAL preload context (customer.json + bid markdown + latest SY) LLM context fully hydrated no proposed_action - Mike is the loop step CLOUD i WHAT THIS DOES: Mike picks (or LLM suggests) one of 11 skills. Most common from chat: ADD_UPDATE_CUSTOMER_PRICING, COMPARE_CUSTOMER_QUOTES, LOG_EXTERNAL_BID. D1 TABLE: chat_message (router decision) TECHNICAL DETAILS: DECIDE SKILL SKILLS CREATE_NEW_CUSTOMER · ADD_UPDATE_CUSTOMER_PRICING · ADD_UPDATE_ITEM · FILL_REGIONAL_PRICES · REBUILD_REGIONAL_SHEETS · COMPARE_CUSTOMER_QUOTES · LOG_EXTERNAL_BID · BID_PIPELINE · ARCHIVE_CUSTOMER · SYSTEM_HEALTH_CHECK · PREPARE_NEXT_SCHOOL_YEAR STATUS: REAL decide skill (1 of 11) Mike picks OR LLM suggests; common: ADD_UPDATE_CUSTOMER_PRICING BACKEND · skill picker i WHAT THIS DOES: The 11-skill dispatcher runs the chosen skill. Same dispatcher used by Path 1 and Path 3 - one canonical implementation. D1 TABLES: bid_* (UPSERT as appropriate to the skill) TECHNICAL DETAILS: DISPATCHER.RUN CONTRACT inputs: customer_id, sy_version, bid_markdown, extra_args outputs: bid_* writes, .docx render, STATUS.json patch SHARED same code path as Path 1 + Path 3 STATUS: REAL 11-skill dispatcher runs canonical implementation shared with Path 1 + Path 3 BACKEND i WHAT THIS DOES: Skill reads STATUS.json then applies edits to the Bids_and_Customer_Pricing folder (customer.json, prices, External_Bids/bids_log.json, .docx quotes). Folder is the source-of-truth per ADR-039; enforced at runtime by src/lib/edit_mode_guard.ts (R603). FILES: Bids_and_Customer_Pricing/<customer>/customer.json + quotes/<sy_version>.docx + External_Bids/bids_log.json + STATUS.json TECHNICAL DETAILS: SKILL EDITS FOLDER INVARIANT ADR-039 folder-only (no direct API writes from chat UI) R603 edit_mode_guard.ts enforces at runtime STATUS: REAL skill edits folder + builds outputs ADR-039 folder-only · R603 edit_mode_guard.ts enforces DATABASE · folder SOT i WHAT THIS DOES: On skill completion run: node scripts/post-session-sync.js --skill <name>. It POSTs folder changes to /api/tools/invoke with header X-Sync-Source: customer-pricing-folder. R614 added a post-sync self-check that calls /api/healthcheck and verifies expected D1 table-count deltas. Per ADR-031 every write lands in proposed_actions; Mike approves via admin dashboard before commit. NS-bound writes still deferred to Path 3 (Jul 1). SCRIPT: source-documents/Bids_and_Customer_Pricing/scripts/post-session-sync.js ENDPOINT: POST /api/tools/invoke HEADER: X-Sync-Source: customer-pricing-folder SELF-CHECK (R614): /api/healthcheck + table-count delta verification D1 TABLES (after HITL approval): bid_customers, bid_items, bid_quote_versions, bid_price_snapshots, bid_external_pipeline, bid_reviews, bid_programs, bid_regional_prices TECHNICAL DETAILS: POST-SESSION-SYNC + R614 VERIFY + HITL QUEUE INVARIANT ADR-031 every write -> proposed_actions Mike approves via admin dashboard (HITL gate) NS push deferred to Path 3 STATUS: REAL post-session-sync.js → /api/tools/invoke → proposed_actions (HITL) X-Sync-Source: customer-pricing-folder · R614 self-check · ADR-031 HITL on every write SECURITY · HITL gate (Mike approves in admin dashboard) i WHAT THIS DOES: .docx quote regenerates for the new SY-version. FILE: Customer-Pricing/<customer>/quotes/<sy_version>.docx TECHNICAL DETAILS: .docx REGEN TRIGGER bid_quote_versions write STATUS: REAL .docx regen per customer / SY-version CLOUD i WHAT THIS DOES: STATUS.json updated. FILE: Customer-Pricing/STATUS.json TECHNICAL DETAILS: STATUS.json REFRESH STATUS: REAL STATUS.json refresh last_touched_at + sy_version CLOUD i WHAT THIS DOES: Dashboard re-renders. URL: gfs-pricing.pages.dev TECHNICAL DETAILS: DASHBOARD RERENDER STATUS: REAL dashboard rerender gfs-pricing.pages.dev CLOUD i WHAT THIS DOES: Events fire for downstream subscribers. D1 TABLE: events TECHNICAL DETAILS: EVENTS bid.chat_review_completed bid.quote_versioned STATUS: REAL events emitted bid.chat_review_completed · bid.quote_versioned MESSAGEBUS i WHAT THIS DOES: The trace thread (customer + SY-version) carries into every row written by this path: chat_session, bid_quote_versions, bid_price_snapshots. Same thread as Path 1 - they converge. EXAMPLE: ACC Distributors / SY2627-v2.5 TECHNICAL DETAILS: TRACE THREAD CARRIED KEY customer_id + sy_version SHARED WITH Path 1 email + Path 3 rollover STATUS: REAL customer + SY-version threading e.g. ACC Distributors / SY2627-v2.5 FINANCE-KEY · trace thread i "load PDF" markdown ready customer + SY-version context loaded dispatch parity
Glossary
Database / folder JSON
Backend
Cloud (dashboard, .docx)
Messagebus (events)
Trace thread (customer + SY-version)
HITL on every write: ADR-031 — every write → proposed_actions → Mike approves in admin dashboard
Folder-only writes: ADR-039 enforced by R603 edit_mode_guard.ts
NS writes deferred: only Path 3 (Jul 1) pushes to NS

11 skill workflows

Verified against source-documents/Bids_and_Customer_Pricing/Prompts/ on 2026-05-27. Each .md file is one workflow. Count: 11.

#workflowpurpose (one-liner)
1ADD_UPDATE_CUSTOMER_PRICINGupsert pricing for a customer + SY-version
2ADD_UPDATE_ITEMupsert an item / spec across customers
3ARCHIVE_CUSTOMERretire a customer; freeze quote history
4BID_PIPELINEregister an active bid in the pipeline
5COMPARE_CUSTOMER_QUOTESdiff two SY-versions for a customer
6CREATE_NEW_CUSTOMERonboard a new customer (folder + bid_customers)
7FILL_REGIONAL_PRICESregional price fill across SKUs
8LOG_EXTERNAL_BIDappend a competitor / 3P bid to External_Bids/bids_log.json
9PREPARE_NEXT_SCHOOL_YEARroll customer to next SY-version baseline
10REBUILD_REGIONAL_SHEETSregenerate regional sheets from D1 + folder
11SYSTEM_HEALTH_CHECKverify folder ↔ D1 parity + freshness

Tables, endpoints, code paths

kindnamepurpose
Entry point/gfsbidsandpricesslash command at ~/.claude/commands/gfsbidsandprices.md
Entry pointfolder drop in Claude.aidrop Bids_and_Customer_Pricing folder
Entry pointPOST /api/tools/invokedirect chat tool invocation
Code pathchat-pipeline.htmlchat UI
Code pathsrc/chat_tools/impls.tschat tool routing
Code pathsrc/lib/edit_mode_guard.tsR603 · enforces ADR-039 folder-only writes
Scriptscripts/post-session-sync.jspushes folder changes; R614 added /api/healthcheck + table-count self-check
HTTP headerX-Sync-Source: customer-pricing-foldermarks sync requests from the folder
R2 bucketbid-attachmentsPDF / XLSX
D1 tablechat_sessionsession identity
D1 tableproposed_actionsHITL queue for every write (ADR-031)
D1 tablebid_customerscustomer match
D1 tablebid_quote_versionsSY-version source-of-truth
D1 tablebid_price_snapshotsline-level
Eventbid.chat_review_completeddownstream
ADRADR-031HITL: every write → proposed_actions
ADRADR-039folder-only: operator writes only via Bids_and_Customer_Pricing folder