shipwatch 0.1.0__tar.gz

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.
Files changed (48) hide show
  1. shipwatch-0.1.0/LICENSE +21 -0
  2. shipwatch-0.1.0/PKG-INFO +323 -0
  3. shipwatch-0.1.0/README.md +285 -0
  4. shipwatch-0.1.0/pyproject.toml +86 -0
  5. shipwatch-0.1.0/setup.cfg +4 -0
  6. shipwatch-0.1.0/src/shipwatch/__init__.py +5 -0
  7. shipwatch-0.1.0/src/shipwatch/__main__.py +4 -0
  8. shipwatch-0.1.0/src/shipwatch/_version.py +3 -0
  9. shipwatch-0.1.0/src/shipwatch/cli.py +218 -0
  10. shipwatch-0.1.0/src/shipwatch/config.py +277 -0
  11. shipwatch-0.1.0/src/shipwatch/data/sources.yaml +172 -0
  12. shipwatch-0.1.0/src/shipwatch/dates.py +76 -0
  13. shipwatch-0.1.0/src/shipwatch/fetch/__init__.py +15 -0
  14. shipwatch-0.1.0/src/shipwatch/fetch/client.py +165 -0
  15. shipwatch-0.1.0/src/shipwatch/fetch/github.py +42 -0
  16. shipwatch-0.1.0/src/shipwatch/fetch/html.py +177 -0
  17. shipwatch-0.1.0/src/shipwatch/fetch/robots.py +36 -0
  18. shipwatch-0.1.0/src/shipwatch/fetch/rss.py +86 -0
  19. shipwatch-0.1.0/src/shipwatch/fetch/sitemap.py +86 -0
  20. shipwatch-0.1.0/src/shipwatch/llm.py +185 -0
  21. shipwatch-0.1.0/src/shipwatch/models.py +157 -0
  22. shipwatch-0.1.0/src/shipwatch/output/__init__.py +9 -0
  23. shipwatch-0.1.0/src/shipwatch/output/render.py +190 -0
  24. shipwatch-0.1.0/src/shipwatch/pipeline/__init__.py +11 -0
  25. shipwatch-0.1.0/src/shipwatch/pipeline/characterize.py +105 -0
  26. shipwatch-0.1.0/src/shipwatch/pipeline/cluster.py +55 -0
  27. shipwatch-0.1.0/src/shipwatch/pipeline/dedup.py +60 -0
  28. shipwatch-0.1.0/src/shipwatch/pipeline/extract.py +56 -0
  29. shipwatch-0.1.0/src/shipwatch/pipeline/run.py +370 -0
  30. shipwatch-0.1.0/src/shipwatch/pipeline/score.py +155 -0
  31. shipwatch-0.1.0/src/shipwatch/pipeline/synthesize.py +143 -0
  32. shipwatch-0.1.0/src/shipwatch/pipeline/verify.py +92 -0
  33. shipwatch-0.1.0/src/shipwatch/py.typed +0 -0
  34. shipwatch-0.1.0/src/shipwatch/storage.py +327 -0
  35. shipwatch-0.1.0/src/shipwatch/textutil.py +149 -0
  36. shipwatch-0.1.0/src/shipwatch.egg-info/PKG-INFO +323 -0
  37. shipwatch-0.1.0/src/shipwatch.egg-info/SOURCES.txt +46 -0
  38. shipwatch-0.1.0/src/shipwatch.egg-info/dependency_links.txt +1 -0
  39. shipwatch-0.1.0/src/shipwatch.egg-info/entry_points.txt +2 -0
  40. shipwatch-0.1.0/src/shipwatch.egg-info/requires.txt +12 -0
  41. shipwatch-0.1.0/src/shipwatch.egg-info/top_level.txt +1 -0
  42. shipwatch-0.1.0/tests/test_cli.py +63 -0
  43. shipwatch-0.1.0/tests/test_client.py +53 -0
  44. shipwatch-0.1.0/tests/test_fetch_parsers.py +71 -0
  45. shipwatch-0.1.0/tests/test_llm.py +70 -0
  46. shipwatch-0.1.0/tests/test_pipeline_e2e.py +95 -0
  47. shipwatch-0.1.0/tests/test_pipeline_units.py +246 -0
  48. shipwatch-0.1.0/tests/test_storage_and_config.py +54 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andy McCutcheon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,323 @@
1
+ Metadata-Version: 2.4
2
+ Name: shipwatch
3
+ Version: 0.1.0
4
+ Summary: Know what AI companies actually shipped this week: changelogs in, a cited briefing out.
5
+ Author: Andy McCutcheon
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/andymccutcheon/shipwatch
8
+ Project-URL: Repository, https://github.com/andymccutcheon/shipwatch
9
+ Project-URL: Issues, https://github.com/andymccutcheon/shipwatch/issues
10
+ Project-URL: Changelog, https://github.com/andymccutcheon/shipwatch/blob/main/CHANGELOG.md
11
+ Keywords: changelog,release-notes,briefing,rss,llm,openai,grounding,newsletter
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: pydantic>=2.0
28
+ Requires-Dist: pyyaml>=6.0
29
+ Requires-Dist: feedparser>=6.0
30
+ Requires-Dist: beautifulsoup4>=4.12
31
+ Requires-Dist: lxml>=5.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.6; extra == "dev"
35
+ Requires-Dist: build>=1.2; extra == "dev"
36
+ Requires-Dist: twine>=5.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # shipwatch
40
+
41
+ **Know what AI companies actually shipped this week.**
42
+
43
+ Changelogs and release notes go in. A scored briefing comes out, with a
44
+ source for every claim.
45
+
46
+ ```text
47
+ pip install shipwatch
48
+ ```
49
+
50
+ shipwatch is a small, local pipeline for people who write (or just read)
51
+ weekly notes on the AI and developer-tool ecosystem. It is a clean-room
52
+ open "lite" cousin of a private newsletter research stack: fetch, normalize,
53
+ extract, characterize, dedup, cluster, score, brief, then **verify every
54
+ sentence against the evidence**.
55
+
56
+ No hosted service. One SQLite file. Works with `--no-llm`, or with any
57
+ OpenAI-compatible endpoint.
58
+
59
+ ## 60-second quickstart
60
+
61
+ ```bash
62
+ python -m venv .venv && source .venv/bin/activate
63
+ pip install shipwatch
64
+ shipwatch init
65
+ shipwatch sources check # offline validation of the YAML pack
66
+ shipwatch --no-llm run --since 7d --html
67
+ ```
68
+
69
+ Outputs land in `out/`:
70
+
71
+ | File | What |
72
+ | --- | --- |
73
+ | `briefing.md` | Cited Markdown briefing |
74
+ | `briefing.json` | Same data, machine-readable |
75
+ | `briefings.xml` | RSS of stored briefings |
76
+ | `index.html` | Optional static page (`--html`) |
77
+
78
+ `shipwatch fetch` only updates the archive. `shipwatch brief --since 7d`
79
+ re-briefs items already in SQLite. `shipwatch stats` prints counts.
80
+
81
+ ## Sample briefing (fictional fixtures)
82
+
83
+ Unmodified `--no-llm` pipeline output from the invented-company fixtures
84
+ in `tests/fixtures/` (Acme AI, Contoso Models, Northwind Agents, Fabrikam
85
+ Docs). Scores, citations, and grounding are genuine. Companies and
86
+ products are invented. Regenerate with
87
+ `python examples/generate_sample_briefing.py`.
88
+
89
+ ```
90
+ 9 claims · 9 supported · 0 flagged · 0 dropped · coverage 100%
91
+ ```
92
+
93
+ ```markdown
94
+ # Shipwatch briefing — 27 Sep 2026 – 11 Oct 2026
95
+
96
+ Window: `14d` · mode: `heuristic` · generated 2026-10-11 12:00 UTC
97
+
98
+ Every bullet cites a source item. Flagged claims did not fully match the source text.
99
+
100
+ > Sample briefing generated from fictional fixtures; companies and products are invented.
101
+
102
+ ## Contoso Models News: Atlas ships computer use in the EU · score 1.00
103
+
104
+ - Contoso Models expanded computer use for Atlas to customers in the European Union. ([Contoso Models News](https://contoso.example/news#atlas-ships-computer-use))
105
+
106
+ ## Contoso Models News: Legacy Completions API sunset date · score 0.95
107
+
108
+ - Contoso Models will deprecate the legacy Completions API on 15 January 2027. ([Contoso Models News](https://contoso.example/news#legacy-completions-api-sunset-date))
109
+
110
+ ## Acme AI News: Acme AI cuts API prices for Helio-7 mini · score 0.95
111
+
112
+ - Acme AI announced a 50% price reduction for Helio-7 mini input tokens in the API, effective immediately for all prepaid and monthly billing accounts. ([Acme AI News](https://acme.example/index/helio-7-mini-price-cut))
113
+ - Acme AI announced a 50% price reduction for Helio-7 mini input tokens in the API. ([Mirror](https://mirror.example/acme-price-cut))
114
+
115
+ ## Northwind Agents: northwind 1.2.1 · score 0.89
116
+
117
+ - Security advisory CVE-2026-4242: a vulnerability in the tool-calling sandbox is patched. ([Northwind Agents](https://github.com/example/northwind/releases/tag/v1.2.1))
118
+
119
+ ## Acme AI News: Introducing Helio-8, now generally available · score 0.88
120
+
121
+ - Acme AI is launching Helio-8, a new foundation model generally available on the API for all customers. ([Acme AI News](https://acme.example/index/helio-8-ga))
122
+
123
+ ## Northwind Agents: northwind 1.2.0 · score 0.75
124
+
125
+ - Northwind Agents 1.2.0 adds a stable tool-calling interface and removes the deprecated DeskRetrievalChain. ([Northwind Agents](https://github.com/example/northwind/releases/tag/v1.2.0))
126
+
127
+ ## Fabrikam Docs: New docs page: batch · score 0.74
128
+
129
+ - New page listed on the Fabrikam Docs sitemap: https://docs.fabrikam.example/atlas-api/docs/batch ([Fabrikam Docs](https://docs.fabrikam.example/atlas-api/docs/batch))
130
+
131
+ ## Acme AI News: New fine-tuning recipes for structured outputs · score 0.70
132
+
133
+ - The API now ships official fine-tuning recipes for structured outputs so teams can keep JSON schemas stable across model upgrades. ([Acme AI News](https://acme.example/index/structured-outputs-recipes))
134
+
135
+ ---
136
+
137
+ **Grounding:** 9 claims · 9 supported · 0 flagged · 0 dropped · coverage 100%
138
+ ```
139
+
140
+ JSON, HTML, and RSS copies live in `examples/`. A Contoso “how Northwind
141
+ ships faster” case study and a webinar are in the same fixture set; they
142
+ are characterized as `non_shipment` and fall below this top eight.
143
+
144
+ ## How scoring works
145
+
146
+ Each item (and then each topic cluster) gets a 0–1 materiality score from
147
+ a configurable rubric in `shipwatch.yaml`:
148
+
149
+ | Signal | Default weight | What it measures |
150
+ | --- | --- | --- |
151
+ | Novelty | 0.25 | How distinct the title is from other items in the window |
152
+ | Impact | 0.30 | Characterization (model release / launch / …) plus keyword cues |
153
+ | Breadth | 0.20 | API / enterprise / “all customers” style audience |
154
+ | Recency | 0.25 | Exponential decay; default half-life 7 days |
155
+
156
+ Pricing changes, deprecations, and security items get an extra boost
157
+ (defaults 0.15 / 0.15 / 0.10) so a quiet price cut does not lose to a
158
+ generic blog post. Customer case studies, “how X ships faster” stories,
159
+ promo, webinars, hiring, and opinion posts are characterized as
160
+ `non_shipment` and take a configurable penalty (default 0.40) so real
161
+ shipments rank first. Tune the knobs; do not treat the number as a
162
+ universal “importance” unit.
163
+
164
+ Kinds: `launch`, `model_release`, `pricing_change`, `deprecation`,
165
+ `api_change`, `availability`, `security`, `non_shipment`, `other`.
166
+
167
+ ## How grounding works
168
+
169
+ This is the product.
170
+
171
+ 1. Synthesis may only emit claims that cite one or more **item ids**.
172
+ 2. The verifier walks each claim, loads the cited source text, and checks
173
+ content-word overlap.
174
+ 3. ≥50% overlap → **supported**. 25–49% → **flagged** (kept, marked).
175
+ below that, or a missing citation → **dropped**.
176
+ 4. The briefing footer reports
177
+ `N claims · supported · flagged · dropped · coverage`.
178
+
179
+ `--no-llm` is extractive: claims are sentences already in the source, so
180
+ they almost always verify. Paragraphs and glued marketing cards are split
181
+ before a claim is taken; mashed one-liners should not appear. An LLM
182
+ brief is more readable and more likely to drift — that is why the
183
+ verifier runs either way.
184
+
185
+ No accuracy or quality percentages are published here. None have been
186
+ measured on a labeled set. If you add an eval, say what the labels were
187
+ and how the score was computed.
188
+
189
+ ## LLM layer (optional)
190
+
191
+ Default docs point at **[freewhirr](https://github.com/andymccutcheon/freewhirr)**
192
+ (`pip install freewhirr`), Andy's free-first OpenRouter router.
193
+
194
+ ```bash
195
+ pip install freewhirr
196
+ # needs an OpenRouter key only so freewhirr can see the free catalog
197
+ export OPENROUTER_API_KEY=...
198
+ freewhirr serve --port 8787
199
+ ```
200
+
201
+ ```bash
202
+ export SHIPWATCH_BASE_URL=http://127.0.0.1:8787/v1
203
+ export SHIPWATCH_MODEL=freewhirr
204
+ export SHIPWATCH_API_KEY=not-used
205
+ shipwatch run --since 7d
206
+ ```
207
+
208
+ **Cost note:** shipwatch does not bill you. Tokens go to whatever endpoint
209
+ you configured. Through freewhirr, that is free OpenRouter models until
210
+ you opt into paid fallback in *freewhirr's* config. Direct OpenRouter or
211
+ OpenAI is billed by those providers. shipwatch still runs without any of
212
+ this via `--no-llm`.
213
+
214
+ Plain OpenRouter:
215
+
216
+ ```bash
217
+ export SHIPWATCH_BASE_URL=https://openrouter.ai/api/v1
218
+ export SHIPWATCH_MODEL=meta-llama/llama-3.3-70b-instruct:free
219
+ export OPENROUTER_API_KEY=...
220
+ ```
221
+
222
+ Plain OpenAI:
223
+
224
+ ```bash
225
+ export SHIPWATCH_BASE_URL=https://api.openai.com/v1
226
+ export SHIPWATCH_MODEL=gpt-4o-mini
227
+ export OPENAI_API_KEY=...
228
+ ```
229
+
230
+ Calls use `response_format=json_object`. The client validates the payload
231
+ with Pydantic and retries with the validator error. After retries it falls
232
+ back to the extractive brief.
233
+
234
+ ## Adding sources
235
+
236
+ `shipwatch init` copies the bundled pack to `sources.yaml`. Kinds:
237
+
238
+ | `kind` | Required | Notes |
239
+ | --- | --- | --- |
240
+ | `rss` | `url` | RSS or Atom (`feedparser`) |
241
+ | `html` | `url` | Optional `selector`; else heading-split / readability |
242
+ | `github` | `repo` | `owner/name` via the Releases API |
243
+ | `sitemap` | `url` | New `loc` values become “new docs page” items |
244
+
245
+ The shipped pack is ~26 AI and developer-tool changelogs (OpenAI,
246
+ Anthropic, Google AI / Gemini, Mistral, Cursor, Vercel, Hugging Face,
247
+ LangChain, OpenRouter, LlamaIndex, Groq, Cohere, Pinecone, Replicate,
248
+ Cloudflare, Next.js, FastAPI, Pydantic, Supabase, GitHub, xAI, DeepSeek,
249
+ Together). Each URL returned HTTP 200 on 2026-10-11 with the shipwatch
250
+ user agent. Some HTML marketing pages are JS-rendered and will extract
251
+ thinly; prefer RSS or GitHub when a site offers them.
252
+
253
+ ```bash
254
+ shipwatch sources check # schema / URL shape
255
+ shipwatch sources check --live # polite HEAD/GET; not used in CI
256
+ ```
257
+
258
+ ## Fetch manners
259
+
260
+ Every request sends
261
+ `User-Agent: shipwatch/0.1.0 (+https://github.com/andymccutcheon/shipwatch)`.
262
+ Conditional GET uses stored `ETag` / `Last-Modified`. Hosts are paced
263
+ (`min_interval_seconds`, default 1s). `robots.txt` is checked unless you
264
+ turn it off. GitHub Releases send `GITHUB_TOKEN` when present.
265
+
266
+ ## Scheduling
267
+
268
+ Cron (see `examples/cron.sh`):
269
+
270
+ ```cron
271
+ 0 9 * * 1 cd /path/to/project && .venv/bin/shipwatch --no-llm run --since 7d --out briefs
272
+ ```
273
+
274
+ A GitHub Actions workflow that runs weekly and commits `briefs/` lives at
275
+ `.github/workflows/weekly-briefing.yml`. `examples/weekly-briefing.yml`
276
+ shows the same job plus a GitHub Pages sketch.
277
+
278
+ ## Storage
279
+
280
+ `.shipwatch/shipwatch.db` holds items, facts, clusters, briefings, fetch
281
+ state, and sitemap URL history. Nothing else is required.
282
+
283
+ ## CLI
284
+
285
+ ```text
286
+ shipwatch init
287
+ shipwatch fetch [--source ID]
288
+ shipwatch run [--since 7d] [--top 12] [--out DIR] [--html]
289
+ shipwatch brief --since 7d
290
+ shipwatch sources check [--live]
291
+ shipwatch stats
292
+ ```
293
+
294
+ `--no-llm` is a global flag.
295
+
296
+ ## Limitations
297
+
298
+ - HTML extraction loses to client-rendered changelog UIs.
299
+ - Heuristic characterization and scoring are keyword-based. They will
300
+ mis-tag some posts.
301
+ - Semantic near-dup uses token Jaccard, not embeddings.
302
+ - Sitemap mode records new URLs; it does not fetch each new page body.
303
+ - The verifier is lexical overlap, not a human editor. Flagged is not
304
+ “wrong”; dropped is “we would not stand behind this sentence.”
305
+ - Live source URLs rot. Re-run `sources check --live` when you edit the pack.
306
+
307
+ ## Development
308
+
309
+ ```bash
310
+ pip install -e ".[dev]"
311
+ ruff check src tests examples
312
+ ruff format src tests examples
313
+ pytest
314
+ python -m build && twine check --strict dist/*
315
+ ```
316
+
317
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and [RELEASING.md](RELEASING.md).
318
+ Version is single-sourced in `src/shipwatch/_version.py` (`0.1.0`).
319
+ Publishing is PyPI Trusted Publishing only.
320
+
321
+ ## License
322
+
323
+ MIT. © 2026 Andy McCutcheon.
@@ -0,0 +1,285 @@
1
+ # shipwatch
2
+
3
+ **Know what AI companies actually shipped this week.**
4
+
5
+ Changelogs and release notes go in. A scored briefing comes out, with a
6
+ source for every claim.
7
+
8
+ ```text
9
+ pip install shipwatch
10
+ ```
11
+
12
+ shipwatch is a small, local pipeline for people who write (or just read)
13
+ weekly notes on the AI and developer-tool ecosystem. It is a clean-room
14
+ open "lite" cousin of a private newsletter research stack: fetch, normalize,
15
+ extract, characterize, dedup, cluster, score, brief, then **verify every
16
+ sentence against the evidence**.
17
+
18
+ No hosted service. One SQLite file. Works with `--no-llm`, or with any
19
+ OpenAI-compatible endpoint.
20
+
21
+ ## 60-second quickstart
22
+
23
+ ```bash
24
+ python -m venv .venv && source .venv/bin/activate
25
+ pip install shipwatch
26
+ shipwatch init
27
+ shipwatch sources check # offline validation of the YAML pack
28
+ shipwatch --no-llm run --since 7d --html
29
+ ```
30
+
31
+ Outputs land in `out/`:
32
+
33
+ | File | What |
34
+ | --- | --- |
35
+ | `briefing.md` | Cited Markdown briefing |
36
+ | `briefing.json` | Same data, machine-readable |
37
+ | `briefings.xml` | RSS of stored briefings |
38
+ | `index.html` | Optional static page (`--html`) |
39
+
40
+ `shipwatch fetch` only updates the archive. `shipwatch brief --since 7d`
41
+ re-briefs items already in SQLite. `shipwatch stats` prints counts.
42
+
43
+ ## Sample briefing (fictional fixtures)
44
+
45
+ Unmodified `--no-llm` pipeline output from the invented-company fixtures
46
+ in `tests/fixtures/` (Acme AI, Contoso Models, Northwind Agents, Fabrikam
47
+ Docs). Scores, citations, and grounding are genuine. Companies and
48
+ products are invented. Regenerate with
49
+ `python examples/generate_sample_briefing.py`.
50
+
51
+ ```
52
+ 9 claims · 9 supported · 0 flagged · 0 dropped · coverage 100%
53
+ ```
54
+
55
+ ```markdown
56
+ # Shipwatch briefing — 27 Sep 2026 – 11 Oct 2026
57
+
58
+ Window: `14d` · mode: `heuristic` · generated 2026-10-11 12:00 UTC
59
+
60
+ Every bullet cites a source item. Flagged claims did not fully match the source text.
61
+
62
+ > Sample briefing generated from fictional fixtures; companies and products are invented.
63
+
64
+ ## Contoso Models News: Atlas ships computer use in the EU · score 1.00
65
+
66
+ - Contoso Models expanded computer use for Atlas to customers in the European Union. ([Contoso Models News](https://contoso.example/news#atlas-ships-computer-use))
67
+
68
+ ## Contoso Models News: Legacy Completions API sunset date · score 0.95
69
+
70
+ - Contoso Models will deprecate the legacy Completions API on 15 January 2027. ([Contoso Models News](https://contoso.example/news#legacy-completions-api-sunset-date))
71
+
72
+ ## Acme AI News: Acme AI cuts API prices for Helio-7 mini · score 0.95
73
+
74
+ - Acme AI announced a 50% price reduction for Helio-7 mini input tokens in the API, effective immediately for all prepaid and monthly billing accounts. ([Acme AI News](https://acme.example/index/helio-7-mini-price-cut))
75
+ - Acme AI announced a 50% price reduction for Helio-7 mini input tokens in the API. ([Mirror](https://mirror.example/acme-price-cut))
76
+
77
+ ## Northwind Agents: northwind 1.2.1 · score 0.89
78
+
79
+ - Security advisory CVE-2026-4242: a vulnerability in the tool-calling sandbox is patched. ([Northwind Agents](https://github.com/example/northwind/releases/tag/v1.2.1))
80
+
81
+ ## Acme AI News: Introducing Helio-8, now generally available · score 0.88
82
+
83
+ - Acme AI is launching Helio-8, a new foundation model generally available on the API for all customers. ([Acme AI News](https://acme.example/index/helio-8-ga))
84
+
85
+ ## Northwind Agents: northwind 1.2.0 · score 0.75
86
+
87
+ - Northwind Agents 1.2.0 adds a stable tool-calling interface and removes the deprecated DeskRetrievalChain. ([Northwind Agents](https://github.com/example/northwind/releases/tag/v1.2.0))
88
+
89
+ ## Fabrikam Docs: New docs page: batch · score 0.74
90
+
91
+ - New page listed on the Fabrikam Docs sitemap: https://docs.fabrikam.example/atlas-api/docs/batch ([Fabrikam Docs](https://docs.fabrikam.example/atlas-api/docs/batch))
92
+
93
+ ## Acme AI News: New fine-tuning recipes for structured outputs · score 0.70
94
+
95
+ - The API now ships official fine-tuning recipes for structured outputs so teams can keep JSON schemas stable across model upgrades. ([Acme AI News](https://acme.example/index/structured-outputs-recipes))
96
+
97
+ ---
98
+
99
+ **Grounding:** 9 claims · 9 supported · 0 flagged · 0 dropped · coverage 100%
100
+ ```
101
+
102
+ JSON, HTML, and RSS copies live in `examples/`. A Contoso “how Northwind
103
+ ships faster” case study and a webinar are in the same fixture set; they
104
+ are characterized as `non_shipment` and fall below this top eight.
105
+
106
+ ## How scoring works
107
+
108
+ Each item (and then each topic cluster) gets a 0–1 materiality score from
109
+ a configurable rubric in `shipwatch.yaml`:
110
+
111
+ | Signal | Default weight | What it measures |
112
+ | --- | --- | --- |
113
+ | Novelty | 0.25 | How distinct the title is from other items in the window |
114
+ | Impact | 0.30 | Characterization (model release / launch / …) plus keyword cues |
115
+ | Breadth | 0.20 | API / enterprise / “all customers” style audience |
116
+ | Recency | 0.25 | Exponential decay; default half-life 7 days |
117
+
118
+ Pricing changes, deprecations, and security items get an extra boost
119
+ (defaults 0.15 / 0.15 / 0.10) so a quiet price cut does not lose to a
120
+ generic blog post. Customer case studies, “how X ships faster” stories,
121
+ promo, webinars, hiring, and opinion posts are characterized as
122
+ `non_shipment` and take a configurable penalty (default 0.40) so real
123
+ shipments rank first. Tune the knobs; do not treat the number as a
124
+ universal “importance” unit.
125
+
126
+ Kinds: `launch`, `model_release`, `pricing_change`, `deprecation`,
127
+ `api_change`, `availability`, `security`, `non_shipment`, `other`.
128
+
129
+ ## How grounding works
130
+
131
+ This is the product.
132
+
133
+ 1. Synthesis may only emit claims that cite one or more **item ids**.
134
+ 2. The verifier walks each claim, loads the cited source text, and checks
135
+ content-word overlap.
136
+ 3. ≥50% overlap → **supported**. 25–49% → **flagged** (kept, marked).
137
+ below that, or a missing citation → **dropped**.
138
+ 4. The briefing footer reports
139
+ `N claims · supported · flagged · dropped · coverage`.
140
+
141
+ `--no-llm` is extractive: claims are sentences already in the source, so
142
+ they almost always verify. Paragraphs and glued marketing cards are split
143
+ before a claim is taken; mashed one-liners should not appear. An LLM
144
+ brief is more readable and more likely to drift — that is why the
145
+ verifier runs either way.
146
+
147
+ No accuracy or quality percentages are published here. None have been
148
+ measured on a labeled set. If you add an eval, say what the labels were
149
+ and how the score was computed.
150
+
151
+ ## LLM layer (optional)
152
+
153
+ Default docs point at **[freewhirr](https://github.com/andymccutcheon/freewhirr)**
154
+ (`pip install freewhirr`), Andy's free-first OpenRouter router.
155
+
156
+ ```bash
157
+ pip install freewhirr
158
+ # needs an OpenRouter key only so freewhirr can see the free catalog
159
+ export OPENROUTER_API_KEY=...
160
+ freewhirr serve --port 8787
161
+ ```
162
+
163
+ ```bash
164
+ export SHIPWATCH_BASE_URL=http://127.0.0.1:8787/v1
165
+ export SHIPWATCH_MODEL=freewhirr
166
+ export SHIPWATCH_API_KEY=not-used
167
+ shipwatch run --since 7d
168
+ ```
169
+
170
+ **Cost note:** shipwatch does not bill you. Tokens go to whatever endpoint
171
+ you configured. Through freewhirr, that is free OpenRouter models until
172
+ you opt into paid fallback in *freewhirr's* config. Direct OpenRouter or
173
+ OpenAI is billed by those providers. shipwatch still runs without any of
174
+ this via `--no-llm`.
175
+
176
+ Plain OpenRouter:
177
+
178
+ ```bash
179
+ export SHIPWATCH_BASE_URL=https://openrouter.ai/api/v1
180
+ export SHIPWATCH_MODEL=meta-llama/llama-3.3-70b-instruct:free
181
+ export OPENROUTER_API_KEY=...
182
+ ```
183
+
184
+ Plain OpenAI:
185
+
186
+ ```bash
187
+ export SHIPWATCH_BASE_URL=https://api.openai.com/v1
188
+ export SHIPWATCH_MODEL=gpt-4o-mini
189
+ export OPENAI_API_KEY=...
190
+ ```
191
+
192
+ Calls use `response_format=json_object`. The client validates the payload
193
+ with Pydantic and retries with the validator error. After retries it falls
194
+ back to the extractive brief.
195
+
196
+ ## Adding sources
197
+
198
+ `shipwatch init` copies the bundled pack to `sources.yaml`. Kinds:
199
+
200
+ | `kind` | Required | Notes |
201
+ | --- | --- | --- |
202
+ | `rss` | `url` | RSS or Atom (`feedparser`) |
203
+ | `html` | `url` | Optional `selector`; else heading-split / readability |
204
+ | `github` | `repo` | `owner/name` via the Releases API |
205
+ | `sitemap` | `url` | New `loc` values become “new docs page” items |
206
+
207
+ The shipped pack is ~26 AI and developer-tool changelogs (OpenAI,
208
+ Anthropic, Google AI / Gemini, Mistral, Cursor, Vercel, Hugging Face,
209
+ LangChain, OpenRouter, LlamaIndex, Groq, Cohere, Pinecone, Replicate,
210
+ Cloudflare, Next.js, FastAPI, Pydantic, Supabase, GitHub, xAI, DeepSeek,
211
+ Together). Each URL returned HTTP 200 on 2026-10-11 with the shipwatch
212
+ user agent. Some HTML marketing pages are JS-rendered and will extract
213
+ thinly; prefer RSS or GitHub when a site offers them.
214
+
215
+ ```bash
216
+ shipwatch sources check # schema / URL shape
217
+ shipwatch sources check --live # polite HEAD/GET; not used in CI
218
+ ```
219
+
220
+ ## Fetch manners
221
+
222
+ Every request sends
223
+ `User-Agent: shipwatch/0.1.0 (+https://github.com/andymccutcheon/shipwatch)`.
224
+ Conditional GET uses stored `ETag` / `Last-Modified`. Hosts are paced
225
+ (`min_interval_seconds`, default 1s). `robots.txt` is checked unless you
226
+ turn it off. GitHub Releases send `GITHUB_TOKEN` when present.
227
+
228
+ ## Scheduling
229
+
230
+ Cron (see `examples/cron.sh`):
231
+
232
+ ```cron
233
+ 0 9 * * 1 cd /path/to/project && .venv/bin/shipwatch --no-llm run --since 7d --out briefs
234
+ ```
235
+
236
+ A GitHub Actions workflow that runs weekly and commits `briefs/` lives at
237
+ `.github/workflows/weekly-briefing.yml`. `examples/weekly-briefing.yml`
238
+ shows the same job plus a GitHub Pages sketch.
239
+
240
+ ## Storage
241
+
242
+ `.shipwatch/shipwatch.db` holds items, facts, clusters, briefings, fetch
243
+ state, and sitemap URL history. Nothing else is required.
244
+
245
+ ## CLI
246
+
247
+ ```text
248
+ shipwatch init
249
+ shipwatch fetch [--source ID]
250
+ shipwatch run [--since 7d] [--top 12] [--out DIR] [--html]
251
+ shipwatch brief --since 7d
252
+ shipwatch sources check [--live]
253
+ shipwatch stats
254
+ ```
255
+
256
+ `--no-llm` is a global flag.
257
+
258
+ ## Limitations
259
+
260
+ - HTML extraction loses to client-rendered changelog UIs.
261
+ - Heuristic characterization and scoring are keyword-based. They will
262
+ mis-tag some posts.
263
+ - Semantic near-dup uses token Jaccard, not embeddings.
264
+ - Sitemap mode records new URLs; it does not fetch each new page body.
265
+ - The verifier is lexical overlap, not a human editor. Flagged is not
266
+ “wrong”; dropped is “we would not stand behind this sentence.”
267
+ - Live source URLs rot. Re-run `sources check --live` when you edit the pack.
268
+
269
+ ## Development
270
+
271
+ ```bash
272
+ pip install -e ".[dev]"
273
+ ruff check src tests examples
274
+ ruff format src tests examples
275
+ pytest
276
+ python -m build && twine check --strict dist/*
277
+ ```
278
+
279
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and [RELEASING.md](RELEASING.md).
280
+ Version is single-sourced in `src/shipwatch/_version.py` (`0.1.0`).
281
+ Publishing is PyPI Trusted Publishing only.
282
+
283
+ ## License
284
+
285
+ MIT. © 2026 Andy McCutcheon.