BOSSTORQUE Internal Build Doc

BT Tree Care Copilot

Private Claude-powered campaign tool for the Tree Care vertical. Replaces the ChatGPT Project that was crashing on Lazar's account. Shared team workspace, persistent memory, ICP fitness scoring, admin-managed instructions and source files, feedback loop, daily Slack report. Built end-to-end in Cowork in a single session on May 12, 2026.

Shipped May 12, 2026 · v3.1

What it is

A Cloudflare Worker that puts a private chat UI in front of Anthropic's Claude API, with the entire Tree Care campaign baked in: brand voice, ICP, all 24 LinkedIn posts (hooks + full copy), DM templates, Sperry case study facts, pricing, and the rules for what works (and what doesn't) with tree care owners.

It does what the ChatGPT Project was doing — except this one runs on infrastructure we control. No per-seat caps. No regional throttling. No "we've temporarily limited access to your conversations" errors. We own the IP, the UI, the data, and the model selection.

The numbers

URL
bt-tree-care-copilot.jason-8ce.workers.dev
Password
treecare-2026-bt
Users
Jason · Armen · Lazar
Admins
Jason · Armen
Models
Sonnet 4.6 · Haiku 4.5
Cost per chat
~$0.001–0.02
Cost per ICP run (25)
~$0.05
Daily Slack report
#tree-care-campaign · 8am PT

What's in it

🏠

Home with team chat list

Welcome screen with quick actions, all team conversations, and the explainer of how the app works.

🎯

Score ICP Fit

Upload xlsx/csv, AI scores every contact 1–10 with reasoning, downloadable graded sheet with Score / Fit / Reason / Recommend columns and coach's notes.

✉️

Draft outreach

Pre-fills a prompt for 5 LinkedIn connection request variants. Peer voice, no pitch.

💬

Reply to a prospect

Paste their message, get 3 on-brand reply options. Low-friction next step every time.

📝

Look up a post

"What's the hook for Post 7?" — full hook + angle + copy on demand.

📊

Usage view

30-day per-user breakdown: message count, tokens, cost. Daily Slack report at 8am PT to #tree-care-campaign.

💾

Shared chat history

Every chat saves. All three users see all conversations. Memory builds across the team.

👍

Feedback buttons

👍/👎 on every AI response, optional comment on thumbs-down. Feeds an AI-classified review in the daily Slack report.

📚

Admin: source files

Jason + Armen upload/edit/delete knowledge files. Concatenated into the system context with prompt caching.

📝

Admin: instructions

Edit the system prompt directly in the UI. Saves to D1. Applies to every future chat immediately.

📎

Image support

Paste screenshots with Cmd+V or click 📎. Useful for analyzing LinkedIn profiles or prospect replies.

💡

Proactive coaching

System prompt directs the AI to occasionally suggest "💡 Next move" actions when it adds value.

Help chatbot

Floating ? in lower right. Dedicated help assistant that explains the app (not campaign copy).

Build timeline (May 12, 2026)

v1 — Working gateway (1 hr)
Worker scaffold, Claude API streaming, single HTML chat UI, password gate, system prompt ported from ChatGPT project. Deployed live.
v2 — Persistence + identity (2 hrs)
D1 database, conversations + messages tables, per-user identity selector, sidebar with chat history, usage view (per-user cost), Anthropic prompt caching for the knowledge base block.
v2.1 — Home page + UX (1 hr)
Home view with quick-action cards, conversation cards with user badges, explanation panel for new users, ICP scoring modal with xlsx upload + downloadable graded sheet (SheetJS client-side).
v2.2 — Admin tools + shared workspace (1.5 hrs)
All chats now visible to all users (Jason/Armen/Lazar shared workspace). Admin section (Jason + Armen only) for editing system instructions and managing source files. Source files concatenated into system context. Help chatbot in lower-right corner.
v3 — Feedback + Slack report (1 hr)
👍/👎 feedback buttons on every AI message, persisted to D1. Daily 8am PT cron triggers AI review of last-24h feedback, classifies as BROKEN / USER_ERROR / WORKING / FEATURE_REQUEST, posts to #tree-care-campaign via bt-notify (registered as a new bt-notify channel using BOSSTORQUE Ops Slack app webhook).
QA — 3 passes (30 min)
Functional smoke test (13 checks, 1 bug found and fixed), edge cases (8 checks, all clean), production readiness (cron, secrets, D1, cache hits, HTML elements). All green.
Live demo — Lazar's daily list (45 min)
Used Chrome MCP to enrich Lazar's 30 bare LinkedIn URLs with name/company/title/location from his actual Sales Navigator output. Scored against ICP. Generated graded HTML report. Posted feedback to #tree-care-campaign via bt-notify. Result: 17/30 strong fits (57%), 4 maybe, 9 no-fit clustered in 3 clean patterns.
v2.2.1 — DM Check + sharper system prompt (30 min)
Added 🔍 DM Check quick action. Tightened opener rule: max 2 sentences, mandatory specific observation, banned phrase list. Draft Outreach now requires a specific observation before drafting. Posted DM voice audit + new rules to Lazar in #tree-care-campaign.
v3 — Warmth vs flattery + 6pm daily audit (1.5 hr)
Refined the system prompt with the warmth-vs-flattery line. Warmth is in scope (peer-friendly framing); flattery is not (transactional positive judgments). Added the 3-part opener structure: observation → reason for reaching out → low-friction question. Pulled in research benchmarks: max ~60 words / 400 chars, 22% reply lift. Stood up the 6pm daily Cowork audit task that scrapes Lazar's LinkedIn activity (DMs, comments, posts), grades against brand rules using the brand-voice-enforcement / marketing-draft-content / sales-draft-outreach skills, posts findings to #tree-care-campaign, auto-tunes the system prompt when patterns emerge, and redeploys this build doc.
v3.1 — Triage, handoff, exemplars, cost guardrails, bookmarklet, 5 more scheduled tasks (2 hr)
Big push. Added ⚡ Triage quick action for inbound reply classification + drafted response. Added 🎯 Send to Pipedrive handoff queue with Slack notifications. Auto-saved 👍-rated outputs to an exemplar library that compounds quality over time (recent exemplars injected into every system prompt). Per-user daily cost guardrails: soft cap $5 (Slack alert), hard cap $20 (blocks new requests). Drag-to-bookmark-bar DM Check bookmarklet for in-LinkedIn drafting. Specs written for 5 more Cowork scheduled tasks (morning prep brief, weekly rollup, LinkedIn analytics, connection tracker, Pipedrive processor) — Jason approves each via the Scheduled sidebar. Five new D1 tables: exemplars, lead_handoffs, linkedin_metrics, connection_stats, cost_alerts. Twelve new API endpoints.

Companion: the DM Check bookmarklet

Drag-to-bookmark-bar button that grabs your draft text from any LinkedIn DM composer (or any selected text on the page), opens the BT Tree Care Copilot's DM Check pre-filled, and gives you a strict V3 brand-voice review without leaving LinkedIn.

Get the bookmarklet

Use case: Lazar composing a reply in LinkedIn → highlights his draft → clicks 📩 BT DM Check in his bookmark bar → instant strict feedback + suggested rewrite. Cuts the "remember to check it" friction to zero.

The voice rules — V3 (current)

Warmth vs. flattery — the line

The most-broken voice rule on this campaign. The distinction:

  • Warmth is in scope. Peer-to-peer friendly tone — the way one contractor talks to another. Examples: "Good seeing tree care work get a real spotlight." "Hope the spring rush isn't crushing you." "Appreciate operators who'll talk shop straight." "Wanted to connect."
  • Flattery is out of scope. Transactional positive judgments about the prospect's work or business. Examples: "You've built a solid reputation." "Impressive operation." "Your work is solid." "Looks like a company that's been built the hard way."

The test the AI runs on every draft: "Does the line judge their work or business positively? If yes → flattery → cut. Does it acknowledge something without rating it? If yes → warmth → keep."

3-part opener structure

  1. Observation — one specific, concrete thing from their profile/post/company. Neutral statement. Not a positive judgment.
  2. Reason for reaching out — one short, transparent line. Why are we in their DMs? Frames us as value-for-them, not asking-for-them. Removes the "what does this stranger want" friction. Research benchmark: senior targets respond best when the message under-promises and reads as honest.
  3. Low-friction question — open-ended, easy to answer. Not "do you want to chat" — something they actually have an opinion on.

Hard limits: max 2 sentences / ~60 words, zero pitch in first-touch, zero flattery, mandatory specific observation.

Model openers

Pattern A — observed post + reason + question:
"Saw your post about [topic]. Working with a tree care owner in Eugene on
the business side of the operation — wanted to connect with folks
thinking about [that same problem]. How's that showing up in your work?"

Pattern B — observed service + reason + question:
"Saw [Company] is doing [specific service] in [location]. Working with
another tree care owner in OR on the business side. How's [that side of
the work] been trending for you this season?"

Pattern C — credential + reason + question:
"Saw you're [credential, e.g., 'a Certified Arborist in the PNW'].
Working with tree care owners on the systems side of the business.
Curious how you're handling [seasonal swings / database re-engagement]?"

Daily 6pm PT audit — Cowork scheduled task

A Cowork scheduled task runs every evening at 6pm PT and does the following:

  1. Fetch current system prompt via the admin endpoint (so the audit grades against whatever rules are in force at the moment of the run)
  2. Scrape Lazar's LinkedIn activity from the last 24 hours via Chrome MCP (Jason's logged-in BOSSTORQUE Chrome session): sent DMs, comments on posts, posts published
  3. Grade each artifact using the /brand-voice:brand-voice-enforcement skill — classify as BROKEN / WEAK / GOOD / EXCELLENT
  4. Suggest rewrites for anything sub-GOOD using /marketing:draft-content and /sales:draft-outreach
  5. Identify recurring failure patterns across the day and any new rule or banned phrase that should be added
  6. Post the report to #tree-care-campaign via bt-notify with quoted examples, recommended rewrites, and the pattern of the day
  7. Auto-update the system prompt via the admin endpoint if a new banned phrase or rule emerged
  8. Redeploy this build doc with a fresh timeline entry so the team always has current state

Task ID: bt-tree-care-lazar-eod-audit. Notify-on-completion is on — Jason gets pinged in Cowork after every run.

Architecture

LayerComponentPurpose
Edge runtimeCloudflare WorkerAuth, routing, Claude API gateway, admin endpoints, feedback endpoints, Slack cron handler
DataD1 (SQLite)conversations · messages · feedback · config · source_files (5 tables)
AIAnthropic API (Sonnet 4.6 / Haiku 4.5)Inference. Instructions + source files cached via ephemeral prompt cache (5-min TTL).
FrontendSingle HTML page (inline JS/CSS)Login (with user selector), home view, chat with feedback buttons, sidebar, all modals, help bubble
File parsingSheetJS (CDN)Client-side xlsx/csv parse + graded sheet generation on download
Outbound notificationsbt-notify (channel: tree-care-campaign)Daily reports route through the BOSSTORQUE Ops Slack app webhook so they push to Jason's iPhone
Profile enrichment (workflow)Chrome MCP via BOSSTORQUE Chrome profileFor one-off list scoring runs: navigate each LinkedIn URL, scrape name/company/title/location, feed enriched data to scorer

One file, ~3000 lines of code, ~32 KB gzipped. No build step. SheetJS loaded from CDN, otherwise no dependencies.

D1 schema

conversations (id, user_id, title, model, created_at, updated_at)
messages      (id, conversation_id, role, content, sent_by,
               input_tokens, output_tokens, cache_creation_tokens,
               cache_read_tokens, cost_usd, model, created_at)
feedback      (id, message_id, conversation_id, user_id, rating, comment,
               created_at, ai_classification, ai_recommendation, reviewed_at)
config        (key, value, updated_by, updated_at)
source_files  (id, filename, content, size_bytes, uploaded_by, created_at)

API endpoints

Method · PathPurpose
POST /authVerify password
GET /api/conversationsList all team conversations (shared workspace)
GET /api/conversations/:idLoad one conversation with all messages
DELETE /api/conversations/:idDelete a conversation + messages
POST /api/chatStream a Claude response, persist user + assistant messages, track usage
POST /api/icp-scoreScore N enriched contacts against ICP via Haiku, return JSON
POST /api/help-chatStream the help chatbot (in-app help)
GET /api/usagePer-user usage rollup (messages, tokens, cost)
POST /api/feedbackSubmit 👍/👎 on a message (with optional comment)
GET /api/feedback/recentList recent feedback (last N days)
GET /api/admin/instructionsGet current system instructions (admin only)
POST /api/admin/instructionsSave updated system instructions (admin only)
GET /api/admin/sourcesList uploaded source files (admin only)
POST /api/admin/sourcesUpload a source file (admin only)
DELETE /api/admin/sources/:idDelete a source file (admin only)
POST /api/cron-testManual trigger for the daily Slack report
CRON 0 15 * * *Daily 8am PT (15:00 UTC) → usage + AI feedback review → bt-notify → #tree-care-campaign

The Lazar workflow change

Today's live demo proved the value. Lazar's daily list of 30 LinkedIn URLs was un-scoreable without enrichment — bare slugs only. Using Chrome MCP to scrape each profile, we got:

  • 17 strong fits (8–10) — owners of tree care companies in target geo
  • 4 maybes (5–7) — borderline (combo landscape, consulting variants)
  • 9 no fits (1–4) — clustered in 3 clean patterns:
    • 4 wrong title (Arborist / Ops, not owner) — fix: add Job Title filter in Sales Nav
    • 2 consulting arborists (off-ICP per Jason) — fix: skip anything with "Consulting" in title or company name
    • 3 wrong vertical (Catholic Church, Tribal Council, Commercial Landscape) — fix: verify tree/arborist in headline

Full graded report (deployed as a CF worker, cardless internal reference).

Going forward: Lazar enriches the sheet with Name / Company / Title / Location during his validation pass, then uploads to the app's 🎯 Score ICP Fit button. Self-service. Jason out of the loop on day-to-day list review.

Status checklist

  • Worker deployed at bt-tree-care-copilot.jason-8ce.workers.dev
  • D1 database created and migrated (5 tables)
  • Secrets set: ANTHROPIC_API_KEY · GATEWAY_PASSWORD · BT_NOTIFY_TOKEN
  • Daily cron schedule active (0 15 UTC = 8am PT)
  • Anthropic auto-reload configured ($10 trigger / $100 refill)
  • bt-notify channel tree-care-campaign registered with BOSSTORQUE Ops webhook
  • 3-pass QA completed — functional, edge cases, production readiness all clean
  • Admin role enforced (Jason + Armen) — Lazar gets 403 on admin endpoints
  • Shared workspace: all users see all team chats
  • Feedback persistence + AI review + daily Slack report all working
  • Help chatbot deployed (lower-right ? button)
  • Lazar + Armen notified in #tree-care-campaign — migration on
  • System prompt V3 deployed — warmth/flattery distinction, 3-part opener structure, reason-for-reaching-out rule
  • Cowork scheduled task bt-tree-care-lazar-eod-audit active — daily 6pm PT audit
  • ChatGPT workspace cleanup: Jason to remove Armen + Lazar seats today
  • Run-now the scheduled task once to pre-approve Chrome MCP + bt-notify permissions so future 6pm runs don't pause

Productized IP angle

This pattern is reusable. Same codebase, different system prompt and knowledge base, ships a custom copilot for any client campaign:

  • Sperry Tree Care (this build) — tree care vertical, OR/WA/ID/NV/AZ/CA/BC, 24-post organic campaign
  • Next client — clone, replace system prompt + source files in the Admin UI, deploy as <client>-copilot.jason-8ce.workers.dev, ~30 minutes

Add-on revenue model: bundle "AI Campaign Operations Portal" into client retainers at $500–$2,000/mo. Five clients = $30K–$120K/yr of recurring revenue from an asset that gets built once. The full codebase is sellable IP at exit. The Admin UI in particular makes this productizable — client side can self-manage their voice + knowledge over time without engineering involvement.

Deploy / maintenance

Update the worker

cd /Users/Jason/Library/.../outputs/gateway
wrangler deploy

Trigger daily report manually (for testing)

curl -X POST -H "X-Auth: treecare-2026-bt" \
  https://bt-tree-care-copilot.jason-8ce.workers.dev/api/cron-test

Send a direct message via bt-notify

TOKEN=$(cat '/Users/Jason/My Drive (jason@bosstorque.ai)/4_Strategy & IP/Entrepreneurial Ideas and Assets/GiftCue/.bt_notify_token')
curl -X POST https://bt-notify.jason-8ce.workers.dev/send \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channel":"tree-care-campaign","text":"...","source":"manual"}'

Query D1 usage

wrangler d1 execute bt-tree-care-copilot --remote \
  --command "SELECT user_id, COUNT(*) AS msgs, ROUND(SUM(cost_usd),4) AS cost
             FROM messages m JOIN conversations c ON c.id=m.conversation_id
             WHERE m.role='assistant' GROUP BY user_id"

Check recent feedback

curl -H "X-Auth: treecare-2026-bt" \
  https://bt-tree-care-copilot.jason-8ce.workers.dev/api/feedback/recent?days=7