release: 0.4.0

Version bump across package.json, the lockfile, the plugin manifest, the
marketplace entry, and the npx pins in the agent skill.

Adds CHANGELOG.md covering what landed since 0.3.0: dispatched site
shortcuts, the Wikipedia shortcuts, proxy env var support, the loud exit 2
on a page with no readable content, and the MIT LICENSE file.

The skill gains a site shortcuts section, since 0.3.0 documented the
shortcuts in the README but the skill never mentioned them, plus the exit 2
contract and the proxy note. llms.txt gains Wikipedia and the proxy line.

README gains the end to end benchmark: five Wikipedia lookups run as whole
tasks in Claude Code with one tool each. All three tools answered every
task correctly, so it reports cost rather than accuracy.
This commit is contained in:
only-cli
2026-08-23 23:22:46 -04:00
parent f28a959828
commit 433bc82df6
8 changed files with 94 additions and 13 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
"name": "only-cli",
"source": { "source": "github", "repo": "only-cli/oc" },
"description": "Browse websites from the terminal in a few hundred tokens",
"version": "0.3.0",
"version": "0.4.0",
"homepage": "https://github.com/only-cli/oc",
"license": "MIT"
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "only-cli",
"description": "Browse websites from the terminal in a few hundred tokens",
"version": "0.3.0"
"version": "0.4.0"
}
+42
View File
@@ -0,0 +1,42 @@
# Changelog
Notable changes per release. Releases before 0.4.0 are listed at
[github.com/only-cli/oc/releases](https://github.com/only-cli/oc/releases).
## 0.4.0
### Added
- Site shortcuts are dispatched, not just documented. `oc <site> <verb> [args]`
resolves to a URL and then takes the same path `oc open` does, so it costs the
same and reads the same. A site is named by short name, bare name, or domain
(`oc hn`, `oc ycombinator`, `oc news.ycombinator.com`), the last argument
absorbs every word after it so a query needs no quoting, and `oc sites` lists
every site with its verbs. Shortcuts come from `clis/*.json`, so adding a site
is a JSON file and no code. (#19)
- Wikipedia shortcuts: `oc wiki article <title>`, `oc wiki search <query>`, and
`oc wiki lang <code> <title>` for the other language editions. Articles are
read through `action=render`, which serves the article body without the site
chrome, navigation, and edit controls that surround `/wiki/<Title>`. (#22)
- Outbound fetches honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`, including
the lowercase forms, so oc works in a sandbox whose only route out is a proxy.
HTTP and HTTPS proxies are supported and proxy credentials in the URL are
sent as `Proxy-Authorization`. (#17)
- The MIT `LICENSE` file that the badge and `package.json` were already
claiming. (#18)
### Changed
- A page that distills to no readable text now fails loud instead of printing an
empty render and exiting 0. It writes one line to stderr and exits 2, which is
distinct from the exit 1 every other failure uses, so a caller can tell "this
page is empty" from "oc could not read this page" and fall back to a browser
only when that is worth doing. `--json` carries the same verdict as an `empty`
field. (#20)
- The SSRF guard runs before a proxy is chosen, so a proxied request cannot be
used to reach an address the direct path would have refused. (#17)
### Fixed
- GitHub and Reddit shortcut URL templates corrected so their verbs reach the
pages they name. (#19)
+21
View File
@@ -113,6 +113,27 @@ Full methodology, per-task numbers, and other agents/models live in [only-cli/be
| Jina Reader | 16,402 | blocked on the Reddit page |
| raw HTML fetch | 177,685 | blocked on the search page |
Read cost is one thing, but what an agent actually spends is another, so a
second suite runs whole tasks end to end in Claude Code and compares `oc`
against the tools the agent already has. Five Wikipedia lookups, one tool per
run, Sonnet driving:
| tool | answered correctly | input tokens | cost | turns | avg time |
| --- | ---: | ---: | ---: | ---: | ---: |
| `oc wiki` | 5/5 | 5,535 | $0.27 | 22 | 11s |
| built-in `WebFetch` | 5/5 | 128,792 | $0.37 | 25 | 14s |
| built-in `WebSearch` | 5/5 | 160,431 | $0.52 | 27 | 22s |
All three got every answer right, so this is a cost result, not an accuracy one.
Input tokens are the fresh context each tool put in front of the model, which is
the number the page size drives; totals including cache reads sit closer together
because the agent's own prompt dominates them. The spread widens with the page:
`oc` cost 5.7x less than `WebFetch` on a short stub and 35x less on a long
article, because the 500 token budget makes it flat at about 1,100 tokens per
page while a full fetch pays for whatever the page weighs. `WebSearch` was given
only the question, not the article URL, which is the honest way to use it and
part of why it costs the most.
## Status
Early. Reading works and is covered by offline tests: static pages, XML feeds, JSON APIs, budget-aware rendering, sessions, and the numbered actions `do`, `find`, `read`, `next`, and `raw`. Writing does not: `fill`, `submit`, and `back` report that they are not implemented rather than pretending, and a lazy headless fallback for script-heavy pages comes after them.
+2 -1
View File
@@ -10,11 +10,12 @@ Key facts:
- The budget is a target rather than a hard cap: a page that would finish within about four times it is printed whole, because a second command costs the agent far more than the lines the cut would have saved
- The render leads with the page's main content and puts navigation, sidebar, and footer after it, so the budget is spent on what was asked for rather than on menus
- Benchmarked at roughly 45x fewer tokens than reading raw HTML, with per-task numbers at https://github.com/only-cli/benchmarks
- Works on any mostly-static website; tuned shortcuts ship for Hacker News, Reddit, GitHub, X, LinkedIn (public guest views), DuckDuckGo, Bing, Stack Overflow (via its Atom feeds and the Stack Exchange API), Yahoo Finance (quotes, history, markets), and the AWS, Google Cloud, and Microsoft Learn documentation sites (guides, CLI reference, and search)
- Works on any mostly-static website; tuned shortcuts ship for Hacker News, Reddit, GitHub, X, LinkedIn (public guest views), DuckDuckGo, Bing, Stack Overflow (via its Atom feeds and the Stack Exchange API), Yahoo Finance (quotes, history, markets), Wikipedia (articles, search, and other language editions), and the AWS, Google Cloud, and Microsoft Learn documentation sites (guides, CLI reference, and search)
- JSON APIs render like pages: an endpoint that answers with JSON becomes one numbered item per record, with the fields that differ between items kept and the ones every item shares stated once, so a search endpoint reads like a results page for a few hundred tokens
- A page that comes back with no readable text (JavaScript-only, a consent wall, a bot challenge) prints one line on stderr and exits 2, rather than reporting an empty render as a success. `--json` carries the same verdict as an `empty` field, so a caller can tell "nothing on this page" from "oc could not read this page" and fall back to a browser only when it is worth it
- A shortcut is `oc <site> <verb> [args]`: `oc hn top`, `oc reddit sub ClaudeAI`, `oc gh repo only-cli oc`, `oc ddg search claude code cli`, `oc learn doc azure/aks/what-is-aks`. Name the site by its short name, bare name, or domain (`oc hn`, `oc ycombinator`, `oc news.ycombinator.com`), the last argument takes every word after it so a query needs no quoting, and `oc sites` lists every site with its verbs. A shortcut resolves to a URL and then behaves exactly like `oc open <url>`
- X profiles and individual posts read without a login (about 390 and 260 tokens); X search, explore, and hashtag pages do not, and oc reports the block instead of guessing
- Outbound fetches honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` (and their lowercase forms), so oc works in a sandbox whose only route to the network is a proxy
- Requests impersonate Chrome, so pages that block plain scripts often still work
- Agent skill included: `npx skills add https://github.com/only-cli/oc --skill web-browsing-cli` ([skills.sh](https://www.skills.sh/only-cli/oc/web-browsing-cli))
- No JavaScript rendering yet and no login sessions yet (both on the roadmap)
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@only-cli/oc",
"version": "0.3.0",
"version": "0.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@only-cli/oc",
"version": "0.3.0",
"version": "0.4.0",
"license": "MIT",
"dependencies": {
"linkedom": "^0.18.12",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@only-cli/oc",
"version": "0.3.0",
"version": "0.4.0",
"description": "Turn websites into a compact CLI so AI agents can browse without burning tokens.",
"type": "module",
"bin": {
+24 -7
View File
@@ -8,17 +8,32 @@ description: Token-efficient web browsing and web content extraction for AI agen
Renders a web page as a compact, numbered terminal view instead of raw HTML. A typical page is under 500 tokens.
```
npx --yes @only-cli/oc@0.3.0 open <url> compact view, numbered elements
npx --yes @only-cli/oc@0.3.0 do <n> follow link [n], or read it if [n] is text
npx --yes @only-cli/oc@0.3.0 find <query> where a string appears, or that place itself
npx --yes @only-cli/oc@0.4.0 open <url> compact view, numbered elements
npx --yes @only-cli/oc@0.4.0 do <n> follow link [n], or read it if [n] is text
npx --yes @only-cli/oc@0.4.0 find <query> where a string appears, or that place itself
when only one matches
npx --yes @only-cli/oc@0.3.0 next next ~500 tokens of the page already open
npx --yes @only-cli/oc@0.3.0 read <n> full text of region [n]
npx --yes @only-cli/oc@0.3.0 raw [url] whole page as markdown (--html for cleaned HTML)
npx --yes @only-cli/oc@0.4.0 next next ~500 tokens of the page already open
npx --yes @only-cli/oc@0.4.0 read <n> full text of region [n]
npx --yes @only-cli/oc@0.4.0 raw [url] whole page as markdown (--html for cleaned HTML)
```
None of these except `open`/`do`/`raw <url>` fetch anything — they replay the page `open` already saved.
## Site shortcuts
`oc <site> <verb> [args]` resolves to a URL and then behaves exactly like `open` on it, so it costs the same and reads the same. It saves guessing a URL shape and, on a few sites, points at the feed or public API that answers without a login.
```
oc hn top oc reddit sub ClaudeAI oc gh repo only-cli oc
oc wiki article Eiffel Tower oc wiki search anthropic oc wiki lang de Berlin
oc ddg search claude code oc so question 231767 oc learn doc azure/aks/what-is-aks
```
Sites: `hn`, `reddit`, `gh`, `x`, `linkedin`, `ddg`, `bing`, `so`, `finance`, `yt`, `aws`, `gcp`, `learn`, `wiki`. Name one by short name, bare name, or domain (`oc hn`, `oc ycombinator`, `oc news.ycombinator.com`). The last argument takes every word after it, so a query or title needs no quoting. `oc sites` lists every site with its verbs, which is cheaper than guessing one.
Prefer a shortcut over a hand-built URL when one exists for the site, and prefer `oc wiki article <title>` over a search when you already know the article's name.
## Output
- Line 1 is the title, then main content (article/thread/results); nav/sidebar/footer follow after `--- rest of page ---`, still numbered.
@@ -56,7 +71,9 @@ None of these except `open`/`do`/`raw <url>` fetch anything — they replay the
## When not to use it
Pages needing login or heavy client-side JS aren't supported yet. If a page comes back empty or blocked, say so and fall back rather than retrying.
Pages needing login or heavy client-side JS aren't supported yet. A page with no readable text (JavaScript-only, a consent wall, a bot challenge) prints one line on stderr and exits 2, which is distinct from the exit 1 every other failure uses, so exit 2 means "oc cannot read this one" rather than "this page is empty". Take it at its word: say so and fall back to another tool rather than retrying the same URL.
Outbound fetches honor `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`, so a sandbox that only reaches the network through a proxy needs no extra flags.
## Untrusted content