@scribe-platform/cli 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +15 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/proof.d.ts +5 -0
- package/dist/commands/proof.d.ts.map +1 -0
- package/dist/commands/proof.js +440 -0
- package/dist/commands/proof.js.map +1 -0
- package/dist/commands/prospect.d.ts +27 -0
- package/dist/commands/prospect.d.ts.map +1 -0
- package/dist/commands/prospect.js +222 -0
- package/dist/commands/prospect.js.map +1 -0
- package/dist/commands/request.d.ts +38 -0
- package/dist/commands/request.d.ts.map +1 -0
- package/dist/commands/request.js +214 -0
- package/dist/commands/request.js.map +1 -0
- package/dist/commands/site.d.ts +11 -0
- package/dist/commands/site.d.ts.map +1 -1
- package/dist/commands/site.js +41 -3
- package/dist/commands/site.js.map +1 -1
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +128 -31
- package/dist/commands/update.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/claude-hook.d.ts +74 -0
- package/dist/lib/claude-hook.d.ts.map +1 -0
- package/dist/lib/claude-hook.js +108 -0
- package/dist/lib/claude-hook.js.map +1 -0
- package/dist/lib/client.d.ts +351 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +159 -0
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/proof-folder.d.ts +86 -0
- package/dist/lib/proof-folder.d.ts.map +1 -0
- package/dist/lib/proof-folder.js +226 -0
- package/dist/lib/proof-folder.js.map +1 -0
- package/dist/lib/proof-preview.d.ts +39 -0
- package/dist/lib/proof-preview.d.ts.map +1 -0
- package/dist/lib/proof-preview.js +318 -0
- package/dist/lib/proof-preview.js.map +1 -0
- package/dist/lib/proof-push.d.ts +42 -0
- package/dist/lib/proof-push.d.ts.map +1 -0
- package/dist/lib/proof-push.js +91 -0
- package/dist/lib/proof-push.js.map +1 -0
- package/dist/lib/skill.d.ts +13 -0
- package/dist/lib/skill.d.ts.map +1 -1
- package/dist/lib/skill.js +33 -2
- package/dist/lib/skill.js.map +1 -1
- package/dist/lib/update-check.d.ts +46 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +103 -0
- package/dist/lib/update-check.js.map +1 -0
- package/package.json +5 -3
- package/runtime/proof.js +139 -0
- package/skills/scribe-site-builder/SKILL.md +175 -33
- package/skills/scribe-site-builder/recipes/README.md +11 -3
- package/skills/scribe-site-builder/recipes/domains.md +151 -0
- package/skills/scribe-site-builder/recipes/forms.md +5 -2
- package/skills/scribe-site-builder/recipes/proofs.md +311 -0
- package/skills/scribe-site-builder/recipes/prospects.md +192 -0
- package/skills/scribe-site-builder/recipes/requests.md +145 -0
- package/skills/scribe-site-builder/recipes/schema.md +24 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Recipe: proofs
|
|
2
|
+
|
|
3
|
+
A **Proof** is work the Agency sends a Client to look at — a board of logo
|
|
4
|
+
ideas, two colour schemes, a homepage mockup (RFC 0029). The Client opens a
|
|
5
|
+
link, reacts to the ideas with a thumbs up or down, comments, and approves or
|
|
6
|
+
asks for changes.
|
|
7
|
+
It replaces emailing a PDF and digging through the replies.
|
|
8
|
+
|
|
9
|
+
It is the mirror image of a Request, and conflating them is the mistake to
|
|
10
|
+
avoid:
|
|
11
|
+
|
|
12
|
+
| | Who starts it | Who owes the next move | Command |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| **Request** | the Client, asking for work | the Agency | `scribe request …` |
|
|
15
|
+
| **Proof** | the Agency, showing work | **the Client** | `scribe proof …` |
|
|
16
|
+
|
|
17
|
+
§6 and §10 are the parts to actually read. The rest is mechanics.
|
|
18
|
+
|
|
19
|
+
## 1. Three rules that aren't negotiable
|
|
20
|
+
|
|
21
|
+
1. **Never run `scribe proof send` without Ashley saying yes to that send.**
|
|
22
|
+
It emails a real person and freezes a version. Say who it is going to and
|
|
23
|
+
what the note says, then wait. Every other command here is reversible;
|
|
24
|
+
this one is not.
|
|
25
|
+
2. **Never use Claude's Artifact tool for client review work.** If asked to
|
|
26
|
+
"send them an artifact", that means a Proof. An artifact lives on
|
|
27
|
+
claude.ai, is branded Claude, needs an account to open, and nothing it
|
|
28
|
+
collects reaches the client's record — which is the whole problem Proofs
|
|
29
|
+
exist to solve.
|
|
30
|
+
3. **No Proof without a client.** A Proof belongs to a prospect or client. If
|
|
31
|
+
they don't exist yet, offer `scribe prospect create` first (see
|
|
32
|
+
[`prospects.md`](./prospects.md)).
|
|
33
|
+
|
|
34
|
+
## 2. The folder
|
|
35
|
+
|
|
36
|
+
One folder per Proof, inside the client's folder:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Acme Bakery/
|
|
40
|
+
research/
|
|
41
|
+
proofs/
|
|
42
|
+
logos/ ← one Proof
|
|
43
|
+
.scribe-proof.json ← written by `proof create`; links folder → Proof
|
|
44
|
+
index.html
|
|
45
|
+
images/
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`scribe proof create --client acme-bakery --title "Logo concepts" --dir proofs/logos`
|
|
49
|
+
makes the Proof and writes `.scribe-proof.json`. Every later command run
|
|
50
|
+
**inside that folder** needs no arguments — `scribe proof push`, not
|
|
51
|
+
`scribe proof push acme-bakery/logo-concepts`.
|
|
52
|
+
|
|
53
|
+
**The folder holds the latest version only.** Scribe keeps the history, so
|
|
54
|
+
never make `logos-v1/`, `logos-v2/` copies. To get an old one back:
|
|
55
|
+
`scribe proof pull --version 1 --dir <somewhere-new>`.
|
|
56
|
+
|
|
57
|
+
## 3. The markup contract
|
|
58
|
+
|
|
59
|
+
Anything the Client should be able to react to or comment on gets
|
|
60
|
+
`data-proof-option`:
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<figure data-proof-option="logo-5" data-proof-label="Bold serif, navy">
|
|
64
|
+
<img src="images/logo-5.svg" alt="">
|
|
65
|
+
</figure>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- **`data-proof-option`** is the id. Letters, numbers, `-` and `_`, up to 64.
|
|
69
|
+
It is what feedback is recorded against, so `logo-5` means logo-5 in every
|
|
70
|
+
version it appears in. **Keep ids stable across versions** — renaming one
|
|
71
|
+
orphans its feedback.
|
|
72
|
+
- **`data-proof-label`** is what Ashley and the Client see next to it. Write
|
|
73
|
+
it for a human: "Bold serif, navy", not "Option 5".
|
|
74
|
+
- **`data-proof-from="logo-5"`** on a revision records what it came from, so
|
|
75
|
+
the console can group "logo-5 → 5a, 5b, 5c".
|
|
76
|
+
|
|
77
|
+
No script, import or stylesheet is needed for any of this. Scribe injects the
|
|
78
|
+
runtime that draws the **👍 / 👎** and **Comment** affordances.
|
|
79
|
+
|
|
80
|
+
**Give the main sections an `id`.** Pinned comments anchor to the nearest
|
|
81
|
+
element with an `id`, so `<section id="hero">` makes "the button under the
|
|
82
|
+
hero feels small" land on the hero rather than on a CSS path that moves.
|
|
83
|
+
|
|
84
|
+
### Paths must be relative
|
|
85
|
+
|
|
86
|
+
`src="images/logo.svg"`, never `src="/images/logo.svg"`. A Proof is served
|
|
87
|
+
under a token prefix, so a root-absolute path 404s for the Client. `check`
|
|
88
|
+
refuses these, and that refusal is correct — fix the path rather than
|
|
89
|
+
passing `--force`.
|
|
90
|
+
|
|
91
|
+
### No HTML at all
|
|
92
|
+
|
|
93
|
+
If the folder holds only images (or PDFs), skip the page entirely. Scribe
|
|
94
|
+
builds a gallery and names an Option after each file: `logo-5.png` →
|
|
95
|
+
`logo-5`. "Send Acme these four PNGs as menu-board options" needs no markup.
|
|
96
|
+
|
|
97
|
+
A hand-built page is still better when presentation matters — logos on a
|
|
98
|
+
mocked storefront, light and dark grounds. The gallery is the floor.
|
|
99
|
+
|
|
100
|
+
## 4. The loop
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
scribe proof check # what a push would refuse or warn about
|
|
104
|
+
scribe proof preview # open it locally, exactly as the client sees it
|
|
105
|
+
scribe proof push --note "…" # upload as the unsent draft. Sends nothing
|
|
106
|
+
scribe proof send # ← asks Ashley first. Emails the client
|
|
107
|
+
scribe proof show # status, versions, staff preview link
|
|
108
|
+
scribe proof link # the client's link; --rotate replaces it
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`preview` is a rehearsal: reactions, comments and pins all work, nothing is
|
|
112
|
+
saved and nobody is emailed. Run it before every push and offer Ashley the
|
|
113
|
+
URL.
|
|
114
|
+
|
|
115
|
+
One thing it will show you: **while a Proof is open for feedback, a click
|
|
116
|
+
anywhere on the work leaves a comment there** — the page's own links and
|
|
117
|
+
buttons don't fire, the same bargain Figma makes. So a Proof is one page of
|
|
118
|
+
work to talk about, not a clickable prototype; don't build one that needs
|
|
119
|
+
navigating, and don't tell Ashley a Client can click through it. Read-only
|
|
120
|
+
views (a closed Proof, an older version, the staff preview) behave like an
|
|
121
|
+
ordinary page again.
|
|
122
|
+
|
|
123
|
+
A **drag** rather than a click comments about a whole area: the box is drawn
|
|
124
|
+
out as it's pulled, and the comment remembers it as a fraction of whatever
|
|
125
|
+
element contains it, so it still covers the right thing after the page
|
|
126
|
+
reflows on a narrower screen. Hovering such a comment's pin outlines the area
|
|
127
|
+
again. That means a Proof wants real structure to hang those fractions off —
|
|
128
|
+
a page built out of one absolutely positioned layer gives every area the same
|
|
129
|
+
anchor, and the outlines drift together when the layout moves.
|
|
130
|
+
|
|
131
|
+
`push` replaces the single unsent draft each time, so tinkering doesn't burn
|
|
132
|
+
version numbers. **Only `send` creates a version the Client sees.** Push as
|
|
133
|
+
often as you like.
|
|
134
|
+
|
|
135
|
+
`check` before `push` — `push` runs it anyway, but reading the warnings
|
|
136
|
+
first is cheaper than a rejected upload.
|
|
137
|
+
|
|
138
|
+
## 5. Sending
|
|
139
|
+
|
|
140
|
+
Confirm, then send:
|
|
141
|
+
|
|
142
|
+
> "This sends *Logo concepts v1* to Dana (dana@acme.test) with the note
|
|
143
|
+
> 'Six directions'. Send it?"
|
|
144
|
+
|
|
145
|
+
- No `--to` sends to the client's primary contact. `--to a@b.com c@d.com`
|
|
146
|
+
replaces that list and is remembered for next time.
|
|
147
|
+
- `--message "…"` overrides the push note for the email.
|
|
148
|
+
- A Client replying to the email reaches whoever sent it, not an unattended
|
|
149
|
+
mailbox.
|
|
150
|
+
|
|
151
|
+
If the client has no contact email, `send` fails **before** freezing
|
|
152
|
+
anything — fix the contact, or pass `--to`, then send again.
|
|
153
|
+
|
|
154
|
+
## 6. The next round — the reason Proofs exist
|
|
155
|
+
|
|
156
|
+
**Read the feedback before changing anything:**
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
scribe proof feedback # grouped by option: who reacted how, what they said
|
|
160
|
+
scribe proof feedback --json # same shape, for reading programmatically
|
|
161
|
+
scribe proof feedback --version 1 # an older version
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Then work the revision from what it actually says. Treat the new version as
|
|
165
|
+
**the current working set** — what's still genuinely in play — not an archive
|
|
166
|
+
of every option any version has ever shown. History isn't lost by leaving
|
|
167
|
+
something out: it's still sitting on its own version, and the Client (or
|
|
168
|
+
Ashley) can flip back to it with one tap, feedback and all (§2). So the
|
|
169
|
+
question for each option is "does the Client still need to be looking at
|
|
170
|
+
this?", not "did we ever show this?":
|
|
171
|
+
|
|
172
|
+
- An option **nobody reacted to and nobody mentioned** is a candidate to drop.
|
|
173
|
+
Dropping is normal — `check` reports dropped ids as one neutral line, not a
|
|
174
|
+
warning.
|
|
175
|
+
- An option with a **👍 and a comment** is the one to iterate on. Usually that
|
|
176
|
+
means the revision replaces it in the new version — mark it
|
|
177
|
+
`data-proof-from="<original>"` so the console shows the lineage — since the
|
|
178
|
+
Client already decided they liked the direction and is now just reacting to
|
|
179
|
+
the refinement. Keep both around instead if they genuinely still read as
|
|
180
|
+
two live contenders (two different directions both still being weighed,
|
|
181
|
+
say) rather than one superseded by the other.
|
|
182
|
+
- A **👎** is one worth asking about rather than guessing — a thumbs-down with
|
|
183
|
+
no words is still an answer, and worth Ashley's phone call. What she learns
|
|
184
|
+
decides whether it's dropped, revised, or (if the room's split) left in
|
|
185
|
+
for now.
|
|
186
|
+
- Push with a `--note` that says what changed in the Client's words ("Three
|
|
187
|
+
simpler takes on the one you liked"), because that note is what they read
|
|
188
|
+
in the email.
|
|
189
|
+
|
|
190
|
+
Then ask before sending, as always. The new version keeps the **same link**;
|
|
191
|
+
the Client lands on it with the older ones one tap away.
|
|
192
|
+
|
|
193
|
+
`scribe proof reply <event-id> "…"` answers one comment. The id is printed
|
|
194
|
+
beside every comment in `feedback`. The Client sees a reply the next time
|
|
195
|
+
they open the Proof — **Scribe never emails a reviewer**, because it only
|
|
196
|
+
ever asks their name. If a reply is urgent, tell Ashley to call.
|
|
197
|
+
|
|
198
|
+
A Client replies back by clicking the pin on the work itself, which opens the
|
|
199
|
+
thread with the box ready to type in — so a thread can run several turns
|
|
200
|
+
without a new version. Those replies come through `feedback` like any other
|
|
201
|
+
comment. The comment column beside the work is an index: clicking a row there
|
|
202
|
+
opens that thread on the work rather than answering in place.
|
|
203
|
+
|
|
204
|
+
Ashley can also reply by hand in the staff console, on the Proof's **Design**
|
|
205
|
+
tab, the same way — a pin, or a row in the column, opens the thread on the
|
|
206
|
+
work with a box to answer. Worth pointing her there when she wants to see the
|
|
207
|
+
thing being talked about while she answers, or when she's on a phone. The
|
|
208
|
+
**Feedback** tab answers in a list instead, grouped by idea. It is the same
|
|
209
|
+
event as `scribe proof reply` whichever she uses.
|
|
210
|
+
|
|
211
|
+
A **Reaction** is a comment that carries a thumb, which is why it reads in the
|
|
212
|
+
same list as everything else and takes replies the same way. One per Reviewer
|
|
213
|
+
per Option: a second thumb changes the first rather than adding to it, keeping
|
|
214
|
+
the words and the answers already under it. The badge on an Option is both
|
|
215
|
+
tools and marker — two thumbs and Comment until that Reviewer has used one,
|
|
216
|
+
then their own thumb with everyone's faces beside it, opening the whole list on
|
|
217
|
+
a click. A Reaction with an empty `body` is somebody who reacted without saying
|
|
218
|
+
why; report it as the answer it is rather than skipping it.
|
|
219
|
+
|
|
220
|
+
Whoever wrote a comment can **delete** it — the Client their own, Ashley her
|
|
221
|
+
own replies — from the thread on the work or from the column. Neither can
|
|
222
|
+
delete the other's. Clearing a Reaction (the same control, better named) takes
|
|
223
|
+
the thumb, the words and the replies together. Deleting the comment a thread
|
|
224
|
+
started with takes the whole thread with it, replies included, since a thread is one conversation and an
|
|
225
|
+
answer to a withdrawn question reads as noise.
|
|
226
|
+
|
|
227
|
+
A deleted comment leaves `feedback` entirely and leaves no event behind, so
|
|
228
|
+
never quote one back at Ashley as still outstanding, and don't be surprised
|
|
229
|
+
when a comment id from an earlier `feedback` run stops resolving — re-read the
|
|
230
|
+
feedback rather than assuming the proof changed underneath you.
|
|
231
|
+
|
|
232
|
+
## 7. More than one person deciding
|
|
233
|
+
|
|
234
|
+
Owners forward the link to a business partner or spouse. That is supported and
|
|
235
|
+
usually good news: the second person types their own name and shows up as a
|
|
236
|
+
second reviewer, with their own reactions and comments.
|
|
237
|
+
|
|
238
|
+
What it means when reading `feedback`:
|
|
239
|
+
|
|
240
|
+
- **`👍` and `👎` list every reviewer who reacted that way**, so two people on
|
|
241
|
+
opposite sides of one option is a disagreement to surface *before* Ashley
|
|
242
|
+
calls, not during.
|
|
243
|
+
- **The status follows the most recent decision.** If one approves and the
|
|
244
|
+
other asks for changes, the Proof reads `changes-requested` — but both
|
|
245
|
+
decisions are listed, and the status is not the whole story. Say both.
|
|
246
|
+
- A new name appearing is worth mentioning once ("Marco's looked at it too"),
|
|
247
|
+
because it tells Ashley who is actually deciding.
|
|
248
|
+
|
|
249
|
+
Don't try to reconcile them. Report who said what and let Ashley decide.
|
|
250
|
+
|
|
251
|
+
## 8. Working the queue
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
scribe proof list # every Proof, most recently active first
|
|
255
|
+
scribe proof list --status changes-requested
|
|
256
|
+
scribe proof list --client acme-bakery
|
|
257
|
+
scribe proof list --unopened # sent 2+ days ago, never opened — call them
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
In the browser, **Proofs** in the staff console has the same three views:
|
|
261
|
+
*Needs you*, *Waiting on client*, *Sent, not opened*. A due prospect in the
|
|
262
|
+
follow-up list also carries one line about a Proof waiting on them, so it is
|
|
263
|
+
in front of Ashley when she dials.
|
|
264
|
+
|
|
265
|
+
## 9. Finishing, and housekeeping
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
scribe proof close --reason "delivered" # stays readable on the same link forever
|
|
269
|
+
scribe proof reopen # carry on the same history with a new version
|
|
270
|
+
scribe proof link --rotate # the old URL stops working. Then send again
|
|
271
|
+
scribe proof link --expires 2026-12-31 # or "never" to clear it
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Close when the work is delivered. A closed Proof still opens, read-only, so a
|
|
275
|
+
Client hunting for "the logo we picked" next year finds it.
|
|
276
|
+
|
|
277
|
+
**A Proof can't be deleted from the CLI**, only closed — same as a prospect.
|
|
278
|
+
If one genuinely has to go, that's Dave.
|
|
279
|
+
|
|
280
|
+
## 10. What to tell Ashley, and what not to
|
|
281
|
+
|
|
282
|
+
**Say:** who a send is going to, before sending. What the Client actually
|
|
283
|
+
said, in their words, before you change anything. That a link rotation
|
|
284
|
+
breaks the old URL.
|
|
285
|
+
|
|
286
|
+
**Don't say:** version numbers she didn't ask about, option ids as the
|
|
287
|
+
primary way of naming things (use the labels — "the wheat star one", not
|
|
288
|
+
"logo-5"), or anything about tokens, manifests or hashes. She asked for logo
|
|
289
|
+
ideas, not a build report.
|
|
290
|
+
|
|
291
|
+
**The one thing worth interrupting for:** a Client asked for changes, or
|
|
292
|
+
approved. That is the moment the work moves.
|
|
293
|
+
|
|
294
|
+
## 11. Clients who already have a site
|
|
295
|
+
|
|
296
|
+
A Proof can be attached to one of the client's sites, and then asks them to
|
|
297
|
+
**sign in** with their normal Scribe login instead of typing a name:
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
scribe proof create --client rods-auto --title "Homepage hero" --site rods-auto-body
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
`--site` defaults the access mode to `sign-in`, and the Proof appears under
|
|
304
|
+
**Proofs** in that site's dashboard. If the person deciding has no login —
|
|
305
|
+
the owner's spouse, say — switch it:
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
scribe proof link --access link
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Everything else is identical.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Recipe: prospects
|
|
2
|
+
|
|
3
|
+
Ashley's calling pipeline lives in Scribe as Clients with `status: 'prospect'`.
|
|
4
|
+
This recipe is about **recording and nurturing prospects she already has** —
|
|
5
|
+
logging what happened on a call, scheduling the next touch, and moving one
|
|
6
|
+
through the funnel. Finding new leads is not covered here: wherever a name comes
|
|
7
|
+
from (a Places sweep, a referral, a drive-by), this recipe starts once it exists.
|
|
8
|
+
|
|
9
|
+
The same operations are available two ways — `scribe prospect …` on the command
|
|
10
|
+
line, and the `list_prospects` / `get_prospect` / `create_prospect` /
|
|
11
|
+
`log_prospect_call` / `set_prospect_status` MCP tools. They are the same
|
|
12
|
+
endpoints; use whichever the session has.
|
|
13
|
+
|
|
14
|
+
§3 is the part to actually read. Everything else is mechanics.
|
|
15
|
+
|
|
16
|
+
## 1. The pipeline
|
|
17
|
+
|
|
18
|
+
Four statuses, and a prospect only ever sits in the first one:
|
|
19
|
+
`prospect` → `active` (won) or `lost`, with `active` ↔ `churned` afterwards for
|
|
20
|
+
a real client. Nothing is deleted on the way through — a lost prospect keeps its
|
|
21
|
+
whole call log, because the reason it was lost is the point of recording it.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
scribe prospect create "A+ Plumbing" \
|
|
25
|
+
--contact-name "Dana" --phone "555-0101" \
|
|
26
|
+
--note "Found on the Yelp sweep — no website, 4.6 stars over 90 reviews"
|
|
27
|
+
|
|
28
|
+
scribe prospect list --due # who to call today
|
|
29
|
+
scribe prospect show <id> # the full call log before dialling
|
|
30
|
+
|
|
31
|
+
scribe prospect log <id> \
|
|
32
|
+
--note "Left a voicemail, no callback yet" \
|
|
33
|
+
--outcome left-message \
|
|
34
|
+
--next 2026-10-14
|
|
35
|
+
|
|
36
|
+
scribe prospect status <id> active # won
|
|
37
|
+
scribe prospect status <id> lost --reason "Nephew builds their sites"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`list` defaults to a table and takes `--json` for parsing; so does every other
|
|
41
|
+
subcommand. `--status` and `--search` filter, and the default list is
|
|
42
|
+
due-sorted — soonest or most overdue first, undated prospects last.
|
|
43
|
+
|
|
44
|
+
## 1b. Always pass `--outcome` on a real call
|
|
45
|
+
|
|
46
|
+
`--outcome` is how far the attempt got, shallowest to deepest:
|
|
47
|
+
|
|
48
|
+
| Outcome | Use when |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `no-answer` | Nobody picked up |
|
|
51
|
+
| `left-message` | Voicemail, or a message left with someone |
|
|
52
|
+
| `gatekeeper` | Spoke to a person, but not the decision-maker |
|
|
53
|
+
| `reached` | Spoke to the decision-maker |
|
|
54
|
+
| `meeting-set` | Spoke to them **and** got a forward commitment |
|
|
55
|
+
|
|
56
|
+
**It is optional in the CLI and should be treated as required for any note that
|
|
57
|
+
describes a contact attempt.** It is the only input to the prospect's warmth, so
|
|
58
|
+
a call logged without it leaves the pipeline reading colder and less-worked than
|
|
59
|
+
it really is — and a prospect that was genuinely called three times without an
|
|
60
|
+
outcome recorded will never show as `stalled`, so Ashley keeps calling a dead
|
|
61
|
+
number.
|
|
62
|
+
|
|
63
|
+
Leave it off only for a note that wasn't an attempt: research, a finding from a
|
|
64
|
+
sweep, a reminder to self.
|
|
65
|
+
|
|
66
|
+
## 1c. Reading warmth
|
|
67
|
+
|
|
68
|
+
Every prospect carries a derived `warmth` plus an attempt count. Nothing stores
|
|
69
|
+
it — it is computed from the call log every time it's read, so it changes on its
|
|
70
|
+
own as a prospect goes quiet.
|
|
71
|
+
|
|
72
|
+
| Warmth | Means | Worth more effort? |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `hot` | Meeting set, recently | Yes — this is the closest to a sale |
|
|
75
|
+
| `warm` | Real conversation, recently | Yes |
|
|
76
|
+
| `untouched` | Nobody has called yet | Yes — needs a first attempt |
|
|
77
|
+
| `cold` | Tried a few times, or a conversation that went quiet | Yes — re-warmable |
|
|
78
|
+
| `stalled` | Called repeatedly and **never once** reached a human | No — this one is spent |
|
|
79
|
+
|
|
80
|
+
`stalled` is the only warmth that means stop. Note that a prospect you once
|
|
81
|
+
reached can never stall, however many no-answers follow — a conversation
|
|
82
|
+
happened, so going quiet is re-warmable rather than unreachable.
|
|
83
|
+
|
|
84
|
+
Sort with `--sort warm` to rank by likelihood to buy, or `--sort neglected` to
|
|
85
|
+
find prospects nobody has followed up on. `--sort neglected` is worth running
|
|
86
|
+
periodically: a prospect with no follow-up date never appears in `--due` at all,
|
|
87
|
+
so it's the only way those surface.
|
|
88
|
+
|
|
89
|
+
## 1d. "Do I need more leads?"
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
scribe prospect pipeline
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Reports counts per warmth and a **workable** total, which is everything except
|
|
96
|
+
`stalled`. Read the shape, not the total — a wall of `cold` that hasn't hit the
|
|
97
|
+
stall cutoff is a calling backlog and the answer is "go call them", while a wall
|
|
98
|
+
of `stalled` with workable near zero is a real shortage and the answer is "go
|
|
99
|
+
find names". A low workable count is the signal to prospect; a low total with
|
|
100
|
+
healthy warmth is not.
|
|
101
|
+
|
|
102
|
+
## 2. Logging a call is the only way to reschedule
|
|
103
|
+
|
|
104
|
+
`scribe prospect log` is the one command that moves `nextFollowUpAt`. There is
|
|
105
|
+
no "set the follow-up date" command, deliberately: a date that changed with no
|
|
106
|
+
note is a reschedule nobody can explain a month later. Every change to when
|
|
107
|
+
Ashley next calls someone arrives attached to a dated note saying why.
|
|
108
|
+
|
|
109
|
+
- `--note <text>` is **required**. A reschedule with nothing to say is still
|
|
110
|
+
worth a sentence ("no answer, trying again Tuesday").
|
|
111
|
+
- `--next <date>` (re)schedules; `--clear-next` removes the scheduled follow-up
|
|
112
|
+
entirely. They're mutually exclusive.
|
|
113
|
+
- Omit both and the note is appended with the existing follow-up untouched.
|
|
114
|
+
|
|
115
|
+
Notes are append-only. Nothing edits or deletes one, from either surface.
|
|
116
|
+
|
|
117
|
+
## 3. What to do unprompted, and what to ask about first
|
|
118
|
+
|
|
119
|
+
Nothing below is enforced by the CLI or the API — there is no approval flag to
|
|
120
|
+
set and no permission that blocks any of it. It is a judgment call every time,
|
|
121
|
+
and this table is the judgment. Ashley's use of Claude here is a long-term
|
|
122
|
+
mixture of "just handle it" and "check with me first"; getting this wrong in the
|
|
123
|
+
cautious direction wastes a message, and getting it wrong in the other direction
|
|
124
|
+
means she finds out a prospect was written off without her.
|
|
125
|
+
|
|
126
|
+
| Action | Do it, or propose it? |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `prospect log` — recording a call, a voicemail, a reschedule | **Do it.** This is the routine nurture action. It's additive, it's reversible by logging again, and asking first defeats the point. Include `--outcome`. |
|
|
129
|
+
| `prospect list` / `prospect show` / `prospect pipeline` | **Do it.** Read-only. |
|
|
130
|
+
| `prospect create` | **Check for a near-duplicate first** — `prospect list --search "<part of the name>"`. A clean miss means create it. Anything that looks like the same business under a different spelling, propose it rather than creating a second record. |
|
|
131
|
+
| `prospect update` — a name fix, a new phone number | **Do it** when the correction is unambiguous (a typo, a number from a call she just logged). Propose a wholesale rename. |
|
|
132
|
+
| `prospect status … lost` | **Propose it, with the reason, and wait for a yes.** It removes the prospect from her working list. Being wrong here looks identical to her forgetting about them. |
|
|
133
|
+
| `prospect status … active` | **Always Ashley's call.** A won deal is a business fact she knows and the data doesn't. Never infer it from an enthusiastic note. |
|
|
134
|
+
|
|
135
|
+
The two `status` rows are the load-bearing ones. When proposing either, say which
|
|
136
|
+
prospect, which reason, and what the last note said — enough that she can answer
|
|
137
|
+
without opening the console.
|
|
138
|
+
|
|
139
|
+
## 4. Where this is a contract, and where it's advice
|
|
140
|
+
|
|
141
|
+
| Contract | Advice |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `nextFollowUpAt` changes **only** through `prospect log` — nothing else writes it | How far out to schedule a follow-up |
|
|
144
|
+
| Notes are append-only; no surface edits or deletes one | How much detail to put in a note |
|
|
145
|
+
| A status move never deletes anything, including `lost` | When to give up on a prospect |
|
|
146
|
+
| Deletion isn't in the CLI or the API at all — it's console-only | — |
|
|
147
|
+
| Warmth is derived from the call log; there's no field to set | Which warmth is worth your attention today |
|
|
148
|
+
| `outcome` is a **contact result** only — there is no `demo-sent` | Whether a given note needs an outcome at all |
|
|
149
|
+
|
|
150
|
+
## Gotchas
|
|
151
|
+
|
|
152
|
+
- **A prospect's demo site is a real Scribe Site.** Ashley builds it in the CMS
|
|
153
|
+
because the CMS is what she's selling — own repo in the org, same as a
|
|
154
|
+
production site (RFC 0006). Create it with the normal `scribe site add`
|
|
155
|
+
flow; a won deal provisions nothing new, it just points `site.clientId` at the
|
|
156
|
+
now-`active` Client. RFC 0001's original summary describes a shared static
|
|
157
|
+
`demos` repo — that is historical and was never built. Don't repeat it.
|
|
158
|
+
- **Attaching that Site to the Client is console-only.** There is no `scribe`
|
|
159
|
+
command and no `--client` flag on `site add`: it's the **Client** box on
|
|
160
|
+
Staff console → **Sites** → the site. So "they bought" is two actions — the
|
|
161
|
+
status move, which you can run, and the attach, which you hand over as a step
|
|
162
|
+
for Ashley to click. Say both; an `active` Client whose Site is still attached
|
|
163
|
+
to nobody reads as "nobody is being billed for it" on that page.
|
|
164
|
+
- **`lost` is a status, not a delete.** A lost prospect keeps its whole call log
|
|
165
|
+
and gains a `lostReason`. It also stays in the default list — both
|
|
166
|
+
`prospect list` and the console's prospects view cover `prospect` **and**
|
|
167
|
+
`lost` — so narrow with `--status prospect` to see only live ones. What a
|
|
168
|
+
lost prospect does drop out of is the due queue: `--due` is prospect-only.
|
|
169
|
+
- **There is no `scribe prospect delete`**, and no `DELETE` under
|
|
170
|
+
`/api/v1/prospects`. Deleting a Client is reachable only from the staff
|
|
171
|
+
console, behind its confirmation dialog. If something genuinely needs
|
|
172
|
+
removing, that's a thing to hand to Ashley, not to work around.
|
|
173
|
+
- **Every prospect command needs a staff-role API key.** A non-staff key gets a
|
|
174
|
+
403 from the whole `/api/v1/prospects` surface, and a read-only key gets one
|
|
175
|
+
from everything except `list` and `show`.
|
|
176
|
+
- **`--due` is "now or overdue", not "upcoming".** A prospect scheduled for next
|
|
177
|
+
week won't appear until the date arrives. Use `prospect list` for the whole
|
|
178
|
+
funnel.
|
|
179
|
+
- **A prospect with no follow-up scheduled sorts last, not first.** Undated
|
|
180
|
+
isn't urgent — but it does mean nobody has decided what happens next, so it's
|
|
181
|
+
worth surfacing to Ashley if one sits there. `--sort neglected` is how.
|
|
182
|
+
- **`demo-sent` is not an outcome**, and neither is `not-interested`. The first
|
|
183
|
+
is just a note; the second is `prospect status <id> lost --reason ...`.
|
|
184
|
+
Outcomes record how far a *contact attempt* got, nothing else.
|
|
185
|
+
- **Warmth decays on its own.** A `hot` prospect you don't log anything against
|
|
186
|
+
becomes `warm` and then `cold` with no action from anyone, because the clock
|
|
187
|
+
moved. That's intended — it's what stops a stale meeting looking like your
|
|
188
|
+
best lead — but it means warmth you read last week may differ today.
|
|
189
|
+
- **Don't treat warmth as a prediction.** It's a triage order. The real buying
|
|
190
|
+
signal is usually in the note prose ("lost a bid because the GC couldn't find
|
|
191
|
+
them online"), which the enum flattens. Read the notes before telling Ashley
|
|
192
|
+
who's closest to buying; use the sort to decide where to start reading.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Recipe: requests
|
|
2
|
+
|
|
3
|
+
A **Request** is a Client asking the Agency to do work — a content change, a new
|
|
4
|
+
page, a bug report, a question (RFC 0005). It is the mirror image of a
|
|
5
|
+
submission, and conflating the two is the mistake to avoid:
|
|
6
|
+
|
|
7
|
+
| | Who wrote it | Who owes the answer | Where it lives |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| **Submission** | a Visitor, through the Client's form | the Client | `scribe submission …`, per site + collection |
|
|
10
|
+
| **Request** | the Client, through their dashboard | **the Agency — you** | `scribe request …`, one queue across every site |
|
|
11
|
+
|
|
12
|
+
Requests belong to the relationship rather than to a repo: nothing about one is
|
|
13
|
+
in the site's files, and archiving a site doesn't touch them.
|
|
14
|
+
|
|
15
|
+
§4 is the part to actually read. The rest is mechanics.
|
|
16
|
+
|
|
17
|
+
## 1. The queue
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
scribe request list # the queue, oldest activity first
|
|
21
|
+
scribe request list --unassigned # nobody has picked these up
|
|
22
|
+
scribe request list --mine # claimed by this key's owner
|
|
23
|
+
scribe request list --site rods-auto-body # one site's requests
|
|
24
|
+
scribe request list --status done --all # finished ones, normally hidden
|
|
25
|
+
scribe request show <id> # the ask + the whole thread
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`list` is the staff queue, so it defaults to **oldest first** — a queue is worked
|
|
29
|
+
from the end that has waited longest — and **hides `done`/`cancelled`**. Asking
|
|
30
|
+
for a closed status by name shows it anyway, so `--status done` doesn't come back
|
|
31
|
+
empty. `--json` on anything; the table prints the ids you need.
|
|
32
|
+
|
|
33
|
+
`total` in the JSON (and the line under the table) is the whole result, not the
|
|
34
|
+
page. A queue quietly showing 25 of 60 is how one stops being believed.
|
|
35
|
+
|
|
36
|
+
**Every command here needs a staff-role key.** A site user's key gets a 403 from
|
|
37
|
+
the whole surface, because a thread carries internal notes and claiming one only
|
|
38
|
+
means something from inside the Agency. A key restricted to specific sites must
|
|
39
|
+
pass `--site`, rather than being handed a "queue" that is silently a subset.
|
|
40
|
+
|
|
41
|
+
## 2. The statuses, and the one that reads backwards
|
|
42
|
+
|
|
43
|
+
Fixed by the platform — unlike a form's workflow, there is nothing per-site to
|
|
44
|
+
read out of `.scribe.yml`.
|
|
45
|
+
|
|
46
|
+
| Status | Means | Who owes the next action |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `open` | Filed, nobody has picked it up | **The Agency** |
|
|
49
|
+
| `in-progress` | Picked up, and the Client has been told | The Agency |
|
|
50
|
+
| `waiting-on-you` | **Waiting on the *Client*** | The Client |
|
|
51
|
+
| `done` | Finished | Nobody |
|
|
52
|
+
| `cancelled` | Dropped | Nobody |
|
|
53
|
+
|
|
54
|
+
**`waiting-on-you` is phrased from the Client's side**, because they read it on
|
|
55
|
+
their own dashboard — it is the Client who is being waited on, not Ashley. Read
|
|
56
|
+
as an agency instruction it means the opposite of what it says, and it is the one
|
|
57
|
+
status an agent will get backwards. The CLI prints "Waiting on client" beside it
|
|
58
|
+
for exactly this reason.
|
|
59
|
+
|
|
60
|
+
Use it only when the work genuinely cannot continue without an answer: it puts a
|
|
61
|
+
"needs you" badge on the Client's dashboard. When they reply, the request comes
|
|
62
|
+
back to `open` on its own.
|
|
63
|
+
|
|
64
|
+
## 3. Working one
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
scribe request claim <id> # take it; --release hands it back
|
|
68
|
+
scribe request reply <id> --message "On it — today."
|
|
69
|
+
scribe request reply <id> --message "DNS still at their old host" --internal
|
|
70
|
+
scribe request status <id> waiting-on-you
|
|
71
|
+
scribe request status <id> done
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The loop that matches how the queue is meant to read:
|
|
75
|
+
|
|
76
|
+
1. `request show <id>` — the whole thread, before touching anything.
|
|
77
|
+
2. `request claim <id>`.
|
|
78
|
+
3. A short visible reply saying it's picked up. **A reply on an `open` request
|
|
79
|
+
moves it to `in-progress` by itself** — don't follow it with a `status` call.
|
|
80
|
+
4. Do the work. Usually this is an ordinary content/design change in the site's
|
|
81
|
+
repo: the request names its site, and `page` often names the page.
|
|
82
|
+
5. Reply with what changed, including the URL, **then** `status done`.
|
|
83
|
+
|
|
84
|
+
**Never mark a request done without a visible reply.** From the Client's side a
|
|
85
|
+
request that silently turns Done is indistinguishable from being ignored, and
|
|
86
|
+
they have no way to see what was changed.
|
|
87
|
+
|
|
88
|
+
An **internal note** (`--internal`) is Agency-only: filtered out of every read a
|
|
89
|
+
Client can reach, and it emails nobody. It also moves no status — thinking out
|
|
90
|
+
loud isn't picking something up. Use it for what you found, especially anything
|
|
91
|
+
that needs Dave.
|
|
92
|
+
|
|
93
|
+
## 4. What to do unprompted, and what to show her first
|
|
94
|
+
|
|
95
|
+
Nothing below is enforced. There is no approval flag on any of these commands,
|
|
96
|
+
and the API will do whatever it is asked.
|
|
97
|
+
|
|
98
|
+
| Action | Do it, or propose it? |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `request list` / `request show` | **Do it.** Read-only. |
|
|
101
|
+
| `request claim` | **Do it.** It's a label saying someone is on this, and `--release` undoes it. |
|
|
102
|
+
| `request reply --internal` | **Do it.** The Client never sees it, nothing is emailed, and a note nobody needed is harmless. |
|
|
103
|
+
| The actual work — a content change, a fix, a new page | **Do it**, to the same standard as any other edit: preview before publishing, and say what you changed. |
|
|
104
|
+
| `request reply` (visible) | **Show her the text first**, unless she has said otherwise this session. It is emailed to the Client the moment it's sent, it is permanent, and it speaks for her business. |
|
|
105
|
+
| `request status done` / `cancelled` | **Propose it.** Closing a request is a claim that the work is finished, and the Client reads the close. |
|
|
106
|
+
| `request status waiting-on-you` | **Propose it**, and say what you'd be asking for. It parks the request on the Client's desk. |
|
|
107
|
+
|
|
108
|
+
The visible-reply row is the load-bearing one, and it is the difference between
|
|
109
|
+
a useful agent and an embarrassing one. "Draft it and let me read it" is the
|
|
110
|
+
default posture; she can and will say "just send them" for a run of routine
|
|
111
|
+
ones, which is a fine thing to honour for that session.
|
|
112
|
+
|
|
113
|
+
A good way to offer the whole thing, if she asks you to work the queue: do the
|
|
114
|
+
changes, show each reply before sending, propose each close.
|
|
115
|
+
|
|
116
|
+
## 5. Where this is a contract, and where it's advice
|
|
117
|
+
|
|
118
|
+
| Contract | Advice |
|
|
119
|
+
|---|---|
|
|
120
|
+
| A Request is created **only** by the Client — there is no `scribe request create`, and no POST on `/api/v1/requests` | What to do when they ask by phone instead |
|
|
121
|
+
| A visible reply on an `open` request moves it to `in-progress` | How quickly to acknowledge |
|
|
122
|
+
| Internal notes are filtered server-side from every Client-reachable read | How much to put in one |
|
|
123
|
+
| Messages are append-only — nothing edits or deletes one | — |
|
|
124
|
+
| A visible reply or a status change emails the Client; an internal note does not | — |
|
|
125
|
+
| `assignTo` is only ever "me" or "nobody" — assigning someone else isn't built | When to release one |
|
|
126
|
+
| Nothing is ever deleted, including a cancelled request | — |
|
|
127
|
+
|
|
128
|
+
## Gotchas
|
|
129
|
+
|
|
130
|
+
- **There is no `create`.** A Request filed by the Agency on the Client's behalf
|
|
131
|
+
would put words in their mouth and make the queue a measure of us rather than
|
|
132
|
+
of them. If a Client asks for something by phone, either do it as an ordinary
|
|
133
|
+
edit or ask them to file it so there's a thread. Say that rather than looking
|
|
134
|
+
for a flag.
|
|
135
|
+
- **A reply is email.** Each one reaches the Client's inbox immediately; there is
|
|
136
|
+
no draft state and no recall. Compose it as the message it is.
|
|
137
|
+
- **Claiming is Agency-private.** The Client never sees who holds their request —
|
|
138
|
+
the assignment writes an internal note, not a thread message, so "why isn't
|
|
139
|
+
Ashley on this one?" is a question they can't ask.
|
|
140
|
+
- **Re-running a status change is safe.** A no-op transition writes no message
|
|
141
|
+
and sends no email, so setting `done` twice doesn't double-notify.
|
|
142
|
+
- **`--all` is history, not a wider filter.** It only adds `done` and
|
|
143
|
+
`cancelled`; everything else is in the default list already.
|
|
144
|
+
- **Requests survive their site being archived**, and are unreachable through
|
|
145
|
+
anything in the repo. Don't go looking for them in the site's files.
|