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.
- shipwatch-0.1.0/LICENSE +21 -0
- shipwatch-0.1.0/PKG-INFO +323 -0
- shipwatch-0.1.0/README.md +285 -0
- shipwatch-0.1.0/pyproject.toml +86 -0
- shipwatch-0.1.0/setup.cfg +4 -0
- shipwatch-0.1.0/src/shipwatch/__init__.py +5 -0
- shipwatch-0.1.0/src/shipwatch/__main__.py +4 -0
- shipwatch-0.1.0/src/shipwatch/_version.py +3 -0
- shipwatch-0.1.0/src/shipwatch/cli.py +218 -0
- shipwatch-0.1.0/src/shipwatch/config.py +277 -0
- shipwatch-0.1.0/src/shipwatch/data/sources.yaml +172 -0
- shipwatch-0.1.0/src/shipwatch/dates.py +76 -0
- shipwatch-0.1.0/src/shipwatch/fetch/__init__.py +15 -0
- shipwatch-0.1.0/src/shipwatch/fetch/client.py +165 -0
- shipwatch-0.1.0/src/shipwatch/fetch/github.py +42 -0
- shipwatch-0.1.0/src/shipwatch/fetch/html.py +177 -0
- shipwatch-0.1.0/src/shipwatch/fetch/robots.py +36 -0
- shipwatch-0.1.0/src/shipwatch/fetch/rss.py +86 -0
- shipwatch-0.1.0/src/shipwatch/fetch/sitemap.py +86 -0
- shipwatch-0.1.0/src/shipwatch/llm.py +185 -0
- shipwatch-0.1.0/src/shipwatch/models.py +157 -0
- shipwatch-0.1.0/src/shipwatch/output/__init__.py +9 -0
- shipwatch-0.1.0/src/shipwatch/output/render.py +190 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/__init__.py +11 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/characterize.py +105 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/cluster.py +55 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/dedup.py +60 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/extract.py +56 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/run.py +370 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/score.py +155 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/synthesize.py +143 -0
- shipwatch-0.1.0/src/shipwatch/pipeline/verify.py +92 -0
- shipwatch-0.1.0/src/shipwatch/py.typed +0 -0
- shipwatch-0.1.0/src/shipwatch/storage.py +327 -0
- shipwatch-0.1.0/src/shipwatch/textutil.py +149 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/PKG-INFO +323 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/SOURCES.txt +46 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/dependency_links.txt +1 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/entry_points.txt +2 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/requires.txt +12 -0
- shipwatch-0.1.0/src/shipwatch.egg-info/top_level.txt +1 -0
- shipwatch-0.1.0/tests/test_cli.py +63 -0
- shipwatch-0.1.0/tests/test_client.py +53 -0
- shipwatch-0.1.0/tests/test_fetch_parsers.py +71 -0
- shipwatch-0.1.0/tests/test_llm.py +70 -0
- shipwatch-0.1.0/tests/test_pipeline_e2e.py +95 -0
- shipwatch-0.1.0/tests/test_pipeline_units.py +246 -0
- shipwatch-0.1.0/tests/test_storage_and_config.py +54 -0
shipwatch-0.1.0/LICENSE
ADDED
|
@@ -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.
|
shipwatch-0.1.0/PKG-INFO
ADDED
|
@@ -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.
|