@wrenautomation/birdwatch 0.36.0 → 0.36.1
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/.claude-plugin/plugin.json +4 -0
- package/README.md +1 -1
- package/package.json +5 -3
- package/skills/birdwatch/SKILL.md +238 -0
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Research from the open web, driven by an agent one step per command. The agent plans, triages,
|
|
4
4
|
reviews and stops; birdwatch searches, opens pages, extracts findings behind a quote gate, checks
|
|
5
5
|
them, and keeps every record in a ledger. Every finding is a sentence with a quote on a page the
|
|
6
|
-
run read. `skills/birdwatch/SKILL.md`
|
|
6
|
+
run read. `skills/birdwatch/SKILL.md` is how an agent drives it. The package is a Claude Code plugin: `--plugin-dir <package>` loads the skill.
|
|
7
7
|
|
|
8
8
|
Reading the web and files (the fetch ladder, HTML and PDF to text, video) is
|
|
9
9
|
[`@wrenautomation/read`](https://github.com/wrenautomation/engine/tree/main/packages/read)'s. Every model call goes through
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrenautomation/birdwatch",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.1",
|
|
4
4
|
"description": "Research from the open web, driven by an agent one step per command: plan, search, triage, open, extract behind a quote gate, check, review, every record in a ledger. The agent decides; the engine runs the fixed steps. The ask and plan files, the document side (Document, Finding, Proof, the claim extractor), the sources (SearXNG, Exa, Perplexity, Hacker News, Google, arXiv, YouTube, Reddit, LinkedIn, Facebook, the fetch ladder) and the ledger. One CLI, `birdwatch`, with the readers of @wrenautomation/read on it.",
|
|
5
5
|
"license": "PolyForm-Strict-1.0.0",
|
|
6
6
|
"repository": {
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
|
14
|
+
".claude-plugin",
|
|
15
|
+
"skills",
|
|
14
16
|
"!dist/**/*.test.*",
|
|
15
17
|
"README.md",
|
|
16
18
|
"LICENSE.md"
|
|
@@ -54,8 +56,8 @@
|
|
|
54
56
|
"minisearch": "7.2.0",
|
|
55
57
|
"ulid": "3.0.2",
|
|
56
58
|
"zod": "4.6.5",
|
|
57
|
-
"@wrenautomation/
|
|
58
|
-
"@wrenautomation/
|
|
59
|
+
"@wrenautomation/read": "0.36.1",
|
|
60
|
+
"@wrenautomation/models": "0.36.1"
|
|
59
61
|
},
|
|
60
62
|
"scripts": {
|
|
61
63
|
"typecheck": "tsc --noEmit",
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: birdwatch
|
|
3
|
+
description: Research a question from the open web with birdwatch, one step per command. Use when the user says "research <topic>", "find out <question>", "what do sources say about <x>", "look into <vertical>", or wants a sourced answer. You plan, triage, review and stop; the engine searches, opens pages, extracts findings behind a quote gate, checks them, and keeps every record. Every finding is a sentence with a quote on a page the run read.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# birdwatch
|
|
7
|
+
|
|
8
|
+
You drive. The engine is a CLI (`birdwatch`, `@wrenautomation/birdwatch`) that prints JSON and
|
|
9
|
+
writes a ledger. In the engine repo it is `node packages/birdwatch/dist/app/cli.js`; elsewhere
|
|
10
|
+
`npx @wrenautomation/birdwatch`. It never decides what to search next, what to read, or when to stop: you do, in your
|
|
11
|
+
own head, and you write each decision as a record with a why. The person steers you in chat;
|
|
12
|
+
their words reach the ledger through you as `--human` records.
|
|
13
|
+
|
|
14
|
+
Set `BIRDWATCH_AGENT` to your id (`claude-code`, `codex`, a name) once: every record you write
|
|
15
|
+
names it. The ledger folder is `--ledger` (before or after the command) or `BIRDWATCH_LEDGER`
|
|
16
|
+
(default `./ledger`). Sources come from the environment. `~/.config/birdwatch/config.json`
|
|
17
|
+
names the env files to read keys from, so no wrapper is needed; a set variable wins.
|
|
18
|
+
`birdwatch sources` lists what this machine can run. A Reddit thread and a Facebook
|
|
19
|
+
group post open through their own readers (`reddit`, `facebook`) before the page openers. A query pinned to `reddit.com` also searches Reddit itself, signed out (it shares a daily read cap; Exa has no Reddit index). `hn` searches Hacker News (free) and reads a thread with every comment. `youtube` lists through the YouTube Data API when `YOUTUBE_API_KEY` is set (exact views, likes and comments; 10k units a day, a search costs 100, a listing 1), else through yt-dlp. A YouTube open reads the captions only, free. `youtube-see` (with `ANTHROPIC_API_KEY`) reads what a video shows, only when you name it: `open --see`. A query pinned to `linkedin.com` searches LinkedIn posts through the desk, only as the account `BIRDWATCH_ACCOUNTS` names (`linkedin=linkedin@wren`; never the bare `linkedin`, a person's own profile). **Presets** set a search's sort and window in one grammar: `latest` or `top`, `day`, `week`, `month` or `year`, or paired (`top-week`). Set `preset` on a query or leaf (`--preset` on the CLI). A preset query goes only to sources that take presets; when none in the run does, the write fails and names them. `linkedin` takes latest, top, day, week, month and pairs (no year). `google` takes day, week, month and year (no sort). `youtube` (Data API only) and `reddit` take all of them. The open-web searchers take none. No preset: each platform's default. For content asks ("what draws now"), use `top-month` or `top-week`. A hit's `metrics` (views, likes, comments) are what the listing showed: a post's draw, before any read. The brief reads each hit's `lift` against its author's median over every run (`authors`): 54.7 is 54.7 times the author's usual, so a small account and a big one compare. `follow --as posts` on an author fills their baseline (five posts up). Reddit
|
|
20
|
+
reads signed out, then as the account `BIRDWATCH_ACCOUNTS` names (`reddit=reddit@alt`); the person
|
|
21
|
+
picks that account, never you. `google` searches Google's own page through the desk's browser:
|
|
22
|
+
each result is a hit, and the AI Overview is one hit (channel "Google AI Overview") whose
|
|
23
|
+
snippet holds its text. The Overview is a claim, never a proof: do not open it; keep and read
|
|
24
|
+
the pages it cites, which come as hits of their own.
|
|
25
|
+
|
|
26
|
+
A judge (Jev) answers cheap typed questions on every hit, page and finding: probabilities, no
|
|
27
|
+
text. It labels and routes, never judges quality (William, 11-03): it says what a page is
|
|
28
|
+
(`format`, `side`, `class`, the ask's criteria) and sends doubted findings to the check. You
|
|
29
|
+
read every hit and call each one; nothing is dropped on a judge's number. It runs when `TYPESAFE_API_KEY` is set (`--judge`,
|
|
30
|
+
`BIRDWATCH_JUDGE`; `--no-judge` for one command). `brief.judge` says what it cost and how often
|
|
31
|
+
you and the check agreed with it: a low agreement means read its hints less.
|
|
32
|
+
|
|
33
|
+
## One run
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
birdwatch recall <terms> [--not <run>] [--also <ledger>...] # what earlier runs found: quote, URL, source date, run, who wrote it
|
|
37
|
+
birdwatch plan "<the ask>" [--kind web|video|site|channel|person] [--known "<fact> (<url>)"...] [--premise "<given>"...] [--site <host>] [--reads N] # --reads: a wide root's whole-tree read cap
|
|
38
|
+
birdwatch brief <run> # read it after every step; a field with no value is left out (read it with .get)
|
|
39
|
+
birdwatch search <run> < tree.json # the round's query tree (below); or "<terms>" --why [--preset top-week], or a JSON array
|
|
40
|
+
birdwatch add call <run> <hit> keep|drop --why "<why>" # triage, one per hit; the last call wins, a flip warns, a person's call stands over yours
|
|
41
|
+
echo '[{"on":"<hit>","verdict":"keep","why":".."}]' | birdwatch add call <run> # many calls, one process
|
|
42
|
+
birdwatch open <run> [<hit>...] [--url <url>...] --why "<why>" # reads the named; no names: every kept hit without a document
|
|
43
|
+
birdwatch open <run> <hit>... --see --why "<why>" # what a video shows, frame by frame: only a strong video whose captions lean on the screen
|
|
44
|
+
birdwatch open <run> --with <source> # an opener `sources` lists but the run lacks (a ladder that came later); it joins to open, never to search
|
|
45
|
+
birdwatch show <run> <document> [--head N] # the page's text: read it yourself
|
|
46
|
+
birdwatch add finding <run> <document> --text "<sentence>" --quote "<quote on the page>"
|
|
47
|
+
birdwatch add check <run> <finding> --ok|--fail --why "<why>" # your own check; a fail drops it
|
|
48
|
+
birdwatch extract <run> [--limit N] # bulk only: a model behind the quote gate; --limit: N pages a call; a line per page on stderr
|
|
49
|
+
birdwatch check <run> [-n N] [--patterns] # bulk only: a model's check; --patterns: every finding a pattern rests on
|
|
50
|
+
birdwatch add gap <run> "<what is still missing>"
|
|
51
|
+
birdwatch add class <run> <document|finding> <class> --why "<why>" # primary_data, survey, practitioner, vendor, forum, news, other
|
|
52
|
+
birdwatch accept <run> class --min P --why "<why>" # the judge's class guesses in bulk, at your bar
|
|
53
|
+
birdwatch add pattern <run> "<what several findings say together>" --on <finding> <finding>... # findings of this run or its children
|
|
54
|
+
birdwatch add edge <run> again|stop --why "<why>" # your review of the round
|
|
55
|
+
echo '[{"title":"..","body":"..","cites":["<pattern or finding>"]}]' | birdwatch add draft <run> --for "<a decision memo>" # a rough draft, gated
|
|
56
|
+
birdwatch plan --run <run> # after again: the next round
|
|
57
|
+
birdwatch plan "<one niche>" --parent <run> --why "<why this child>" # a child run: it reads what the tree found
|
|
58
|
+
birdwatch add dead <run> <facet> --why "<why>" # give up on a facet; later tries skip it
|
|
59
|
+
birdwatch add cap <root> <reads> --why "<why>" --human # the person raises the tree's read cap; never you alone
|
|
60
|
+
birdwatch follow <run> [<url>] --as posts|similar|refs|citers [--from <document>] --why "<why>" [--with <source>...] # a good page's author's posts, or pages like it
|
|
61
|
+
birdwatch add person <run> "<name>" [--profile <url>...] [--aka <name>...] --why "<why>" # one person across sites
|
|
62
|
+
birdwatch learn <kind> [--sources ...] [--rounds N] [--age "..."] # after a good run, on the person's yes
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Each step command prints `{run, round, step, ok, note, wrote}`; `wrote` is every record it
|
|
66
|
+
wrote (a document's text as `chars`). A step that gave up exits 2 with its note: read the note,
|
|
67
|
+
fix the cause (no source, no contact, no key), run it again. A step run again skips what its
|
|
68
|
+
records show done.
|
|
69
|
+
|
|
70
|
+
## How to drive
|
|
71
|
+
|
|
72
|
+
0. **Recall.** Before the plan, `recall` the ask's words (after it, `brief.recalled` carries the
|
|
73
|
+
same for the ask's text). A recalled finding still fresh for the
|
|
74
|
+
ask (its `date`, else `found`) goes in `--known` with its URL; an old one names a query to
|
|
75
|
+
read again. A quote short of 5 words fails the gate: take the line with its label.
|
|
76
|
+
1. **Name the premises.** Before the plan, say what the ask takes as given: a buyer, an offer, a
|
|
77
|
+
price, a channel, a niche. Pass each as `--premise`. A `--known` line without a URL or ledger
|
|
78
|
+
id becomes a premise too. The guide then names a `premise` facet: one try per premise that
|
|
79
|
+
would show it wrong. `tree.uncovered` lists it until a query serves it. A premise that fails
|
|
80
|
+
changes the ask: tell the person.
|
|
81
|
+
2. **Plan the tree.** Read the ask and `brief`. `brief.guide` holds the kind's age sentence and
|
|
82
|
+
rules: heed them when you plan and when you triage. `brief.sourcesMissing` names allow-listed
|
|
83
|
+
sources this machine cannot run (they search nothing); `brief.sourcesUnused` the ones it can
|
|
84
|
+
that the run has not (not in `sources`, not let in as `opens`). Write the round's query tree: one facet per
|
|
85
|
+
side of the ask the guide names (`birdwatch plans <kind>`: a number, a how, a who, a
|
|
86
|
+
counter-view, a primary source; add a facet the ask needs), each with 2 or 3 tries in the
|
|
87
|
+
order you expect to work: the plain words first, then a narrower angle (a site, a year, a
|
|
88
|
+
synonym the trade uses, a forum, a filing). Each query's why says what it would prove. Show
|
|
89
|
+
the tree to the person before you run it. `search < tree.json` runs one tier: the first
|
|
90
|
+
time, every facet's first try. After you triage, the same command with the same file runs
|
|
91
|
+
the next try of each facet with fewer kept hits than the guide's `thin` (3); a facet at
|
|
92
|
+
`thin` is done, a facet out of tries is a gap, a facet with uncalled hits waits. So the
|
|
93
|
+
tree falls through on what you kept, never on what a searcher returned (a searcher always
|
|
94
|
+
returns a page). `--all` runs every facet's next try at once. `tree` in the output shows
|
|
95
|
+
each try, what it wrote, `kept`, `uncalled`, and which guide facets you did not cover. A
|
|
96
|
+
trade word that sits on both sides of a market ("agency", "coach", "setter") pulls the
|
|
97
|
+
other side: put a buyer marker in the terms ("coaches who hired", not "appointment
|
|
98
|
+
setting"), and read the first tries' titles in `brief` before you write the next. Each
|
|
99
|
+
facet's why names the buyer it looks for and the inverse to avoid: "owners who pay for
|
|
100
|
+
setters, not consumers who hire a coach"; "firms that buy cold email, not vendors who sell
|
|
101
|
+
it". A facet that still returns the inverse after its tries: `add dead` with the why. The
|
|
102
|
+
budget is a guard rail, not a cap.
|
|
103
|
+
|
|
104
|
+
A facet names the source classes that can prove it in `needs`: a spend or price claim
|
|
105
|
+
needs `survey` or `primary_data`, not a forum. Its tries then go where those live, not
|
|
106
|
+
only to new words: public price pages, job ads for the role the buyer would replace (the
|
|
107
|
+
wage), an ad library, a trade association's survey, a filing. Never pin every try of a
|
|
108
|
+
facet to one site: the search says so, and the facet ends with one class. `tree.facets[]`
|
|
109
|
+
shows `classes` (read pages with a kept finding) and `lacks` (none of its `needs`).
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{"facets": [
|
|
113
|
+
{"name": "number", "why": "how often it happens", "tries": [
|
|
114
|
+
[{"terms": "<plain words> rate", "why": "..."}],
|
|
115
|
+
[{"terms": "<plain words> survey 2025", "why": "..."}, {"terms": "...", "site": "reddit.com", "why": "..."}]
|
|
116
|
+
]},
|
|
117
|
+
{"name": "counter", "why": "who says it fails", "tries": [[{"terms": "...", "why": "..."}]]},
|
|
118
|
+
{"name": "spend", "why": "what the buyer pays", "needs": ["survey", "primary_data"], "tries": [[{"terms": "...", "why": "..."}]]}
|
|
119
|
+
]}
|
|
120
|
+
```
|
|
121
|
+
3. **Triage.** `brief` lists `hits.uncalled` with title, snippet, `metrics` (what the post
|
|
122
|
+
drew, as its site counts it), `lift` (each count over the author's median in `brief.authors`,
|
|
123
|
+
every run: 4.5 is 4.5 times their usual, the read for a format that worked) and `facets`: the
|
|
124
|
+
facets whose queries found it, most first, then the ask's criteria. `judge` shows its labels:
|
|
125
|
+
`format` (video, post, thread, article, paper, list, sales_page, directory, docs, other),
|
|
126
|
+
`side` (subject, seller, other) and `class`. A page two facets found is worth a look
|
|
127
|
+
first. A `side` of seller on a buyer facet is the inverse the facet's why names. Call every
|
|
128
|
+
one (the tree's next tier waits on it):
|
|
129
|
+
keep what can hold a fact that answers the ask, drop the rest (vendor pages, listicles, a
|
|
130
|
+
page the ask does not need). One why per call, short. A page you know of yourself: `open --url`.
|
|
131
|
+
Read every hit yourself, however many: the labels sort them, they never call one. There is
|
|
132
|
+
no bulk keep or drop. A drop on a rule (under 3 times the author's usual) names the rule.
|
|
133
|
+
On an ask about content (what draws, what works, a format, a hook), drop only what is off
|
|
134
|
+
the topic. A video that drew little is the comparison that shows what the strong ones did
|
|
135
|
+
differently: keep it, and say so in the why. Open every kept video: its words cost nothing (captions; after a caption 429, Cohere hears the audio).
|
|
136
|
+
4. **Read.** `open`, then `show` each document and read it. A video that failed to read
|
|
137
|
+
stays kept and unread: `open <run> <hit> --why` retries that one alone. **See a video** (`open <run> <hit>
|
|
138
|
+
--see --why`) only when all three hold: its metrics or lift put it among the run's strongest,
|
|
139
|
+
it answers the ask, and its captions lean on the screen ("as you can see", "this slide",
|
|
140
|
+
"look at this", a demo or chart the words do not describe) or leave the point unsaid. It
|
|
141
|
+
downloads the video, and Claude reads each frame: the text, then what it shows (~$0.30 for
|
|
142
|
+
10 minutes; 6 videos a run at most). The why names the test it passed. The read is a second document on the hit. Write each fact that answers the
|
|
143
|
+
ask as `add finding` with its exact quote; a quote that is not on the page fails. Say what
|
|
144
|
+
the page lacks as `add gap --on <document>`. For a run too big to read (tens of pages),
|
|
145
|
+
`extract` puts a model behind the same gate; then judge its findings in
|
|
146
|
+
`wrote` and drop what does not answer the ask (`add call <finding> drop --why`). Class each
|
|
147
|
+
page with a kept finding (`brief.documents.unclassed`): `add class <document> <class> --why`.
|
|
148
|
+
Its findings take the class. When one finding differs (a vendor page that quotes a survey),
|
|
149
|
+
class that finding too. `unclassed[].guess` is the judge's class; spot-check a few, then
|
|
150
|
+
`accept class --min 0.8 --why` (a guess at 0.8 or more held in 8 of 8 on one run; under it,
|
|
151
|
+
5 of 7 changed). A facet's `enough` counts the judge's class guess: kept hits that are all
|
|
152
|
+
the wrong class keep the facet's next try open, and `search` says "none of them <needs>".
|
|
153
|
+
After the read, a facet whose classed pages lack its `needs` (`lacks`) is never enough.
|
|
154
|
+
**Follow.** Signals cluster in people. After a page that gave kept findings, do what a person
|
|
155
|
+
does: `follow --from <document> --as posts` lists its author's own posts (a YouTube channel's
|
|
156
|
+
uploads from a video or a channel, a TikTok profile, a Reddit user's top posts and comments);
|
|
157
|
+
`--as similar` lists pages like it (Exa, off the page's own site). After a good paper,
|
|
158
|
+
`--as refs` lists what it cites and `--as citers` what cites it, most cited first (arxiv:
|
|
159
|
+
Semantic Scholar and OpenAlex; a hit is the arXiv page when there is one). The hits come back to
|
|
160
|
+
triage like a search's, under the same caps. `brief.unfollowed` lists the kept pages no
|
|
161
|
+
follow started from and no person owns, most kept findings first. When one author is good,
|
|
162
|
+
find their other places (the channel's about links, a Substack, an X account, a blog): search
|
|
163
|
+
or read, then `add person "<name>" --profile <url>... --aka <channel name>... --why`, and
|
|
164
|
+
follow each profile. `brief.people` counts the documents, kept findings and sites per person.
|
|
165
|
+
A follow no source in the run can do fails and names one that can: add it with `--with`.
|
|
166
|
+
`documents.toExtract[]` carries the judge's `format` and the criteria; the order is a sort,
|
|
167
|
+
never a skip.
|
|
168
|
+
5. **Check.** Read a sample of the kept findings again against their documents (`show`), a
|
|
169
|
+
different page each: `add check <finding> --ok|--fail --why`. A fail drops it. For a bulk
|
|
170
|
+
run, `check` does the same with a model over the budget's `checks` or a tenth of the kept
|
|
171
|
+
findings, whichever is more, plus each finding the judge doubts. A fail's narrower
|
|
172
|
+
sentence on the same quote comes back as a new finding with `fixes` once a second check
|
|
173
|
+
backs it. Put a finding back with `add call <finding> keep --why` only if you read the page
|
|
174
|
+
and the check is wrong.
|
|
175
|
+
6. **Patterns.** When kept findings from different sites say one thing, write it once:
|
|
176
|
+
`add pattern` with the finding ids, from this run or its children. The engine counts the distinct sites; one site is a
|
|
177
|
+
claim, not a pattern, and it warns. A pattern is your sentence; the findings are its proof.
|
|
178
|
+
`brief.patterns[].classes` counts its sources per class: a site, but each forum thread on
|
|
179
|
+
its own. Three vendor pages are weaker than one survey: weigh the classes, not the total.
|
|
180
|
+
`echo` says every classed source is a vendor: vendors cite each other, so find the source
|
|
181
|
+
they cite or call it a claim. `cites` lists the findings the judge says credit another
|
|
182
|
+
source: search for that source by name. Every finding a pattern rests on gets checked: `check
|
|
183
|
+
--patterns` (bulk) or your own `add check`; `brief.patterns[].unchecked` lists the rest.
|
|
184
|
+
7. **Review.** Ask: does what is kept answer the ask? What is missing? Write each hole as a gap.
|
|
185
|
+
Then the edge: `again` with a why that names the hole (the next round's plan reads it), or
|
|
186
|
+
`stop` with a why that says what the run has and what it still lacks. The budget's rounds
|
|
187
|
+
are a guard rail: past them, say in the why why one more round is worth it. A facet still
|
|
188
|
+
thin after its tries, or one that searches the wrong buyer: `add dead <facet> --why`.
|
|
189
|
+
8. **Children.** A wide ask (which niche, which offer) goes deep in child runs, one per option
|
|
190
|
+
worth it: `plan "<the option's ask>" --parent <run> --why "<why this one>"`. The child's plan
|
|
191
|
+
reads what the parent and its siblings found; its budget is never more than the parent's.
|
|
192
|
+
The plan file's `runs.depth` (2: the root and its children) is a guard rail: a deeper child
|
|
193
|
+
warns, and its why says why it beats a sibling. A facet to try again needs no run: add a try
|
|
194
|
+
to `tree.json`, or `add edge again` and plan the next round. Two caps stop: the children per
|
|
195
|
+
round, and the whole tree's reads (`runs.reads` on the root's plan file; by default the
|
|
196
|
+
root's reads times its rounds times children plus one). `open` stops or cuts its hits at the
|
|
197
|
+
tree's cap. `brief.lineage` lists the ancestors, root first, with their asks and whys;
|
|
198
|
+
`brief.treeRoom` says the cap, what the tree read and what is left. Out of room: ask the
|
|
199
|
+
person; on their yes, `add cap <root> <reads> --why --human`. Drive each child to its
|
|
200
|
+
stop. Then `add edge again` on the parent: its next plan reads each stopped
|
|
201
|
+
child's stop, patterns (with sites per class) and dead ends, and lists a child still going
|
|
202
|
+
as open. The parent decides: drop an option, add one, or stop. `brief.children` shows the
|
|
203
|
+
tree; `brief.treeCost` what all of it cost.
|
|
204
|
+
9. **Report.** From `brief`: the patterns first, each with its site count per class and its findings;
|
|
205
|
+
then the kept findings no pattern rests on, each with its quote, URL and date; the gaps; the
|
|
206
|
+
cost line. Nothing in the report that is not a finding. When the person wants prose (a memo,
|
|
207
|
+
an SOP outline), write a rough draft with `add draft`: each item cites kept patterns or
|
|
208
|
+
findings, and each number comes from a cited quote, or the gate drops the item. A draft is
|
|
209
|
+
never final: the person writes the SOP or the decision.
|
|
210
|
+
10. **Learn.** If the run was good and the person agrees, `birdwatch learn <kind>` with what it
|
|
211
|
+
taught: a source order that yielded, a budget that fit, an age sentence, a rule for the
|
|
212
|
+
kind (`--rule`, every line), a `--thin` that fits the kind, a facet the guide should name
|
|
213
|
+
(`--tree <file>`). The next run of that kind starts there. Never change a rule without
|
|
214
|
+
showing the person the diff.
|
|
215
|
+
|
|
216
|
+
Stop when the ask is answered or two rounds in a row added nothing that changed the answer.
|
|
217
|
+
Say so in the edge's why.
|
|
218
|
+
|
|
219
|
+
## The person
|
|
220
|
+
|
|
221
|
+
Their words are theirs: `birdwatch add steer <run> "<their words>" --human <name>`. A steer is
|
|
222
|
+
shown first in every later brief and snapshot. Their keep or drop on a hit or finding:
|
|
223
|
+
`add call ... --human <name>`; their gap, `add gap ... --human <name>`; a step they want rerun,
|
|
224
|
+
`add edge <run> back --to <step> --why "<their why>" --human <name>`. Never put your words in a `--human` record.
|
|
225
|
+
|
|
226
|
+
When they ask a question mid-run, answer from `brief` (kept findings, gaps, cost); run no step
|
|
227
|
+
they did not ask for.
|
|
228
|
+
|
|
229
|
+
## Records
|
|
230
|
+
|
|
231
|
+
Every record carries `from` (ai, human, tool), `by` (your id, their name, a source or model
|
|
232
|
+
id), its round, and on a decision, a why. `birdwatch trace <run>` prints them all;
|
|
233
|
+
`birdwatch trace <run> --type finding` one type. A run from before 0.30.0 that the old runner
|
|
234
|
+
made reads the same way in `brief`.
|
|
235
|
+
|
|
236
|
+
To let a person watch or check a run, start `birdwatch serve` (same `--ledger`) in the background
|
|
237
|
+
and tell them to open the portal's Research page on this Mac. It updates live as you write.
|
|
238
|
+
Stop it when they are done.
|