Now data matches what I already collected. Verify data_store rows count and complete goal.
Let me verify data_store list (5 rows) and then complete goal.
历史思考 1
1/16
The user wants to collect the top 5 posts from Hacker News homepage: title, score, comment count, link, one-sentence highlight. Then create a Skill "HN 热帖速览".
Let me start by opening Hacker News. This is a multi-step task with a deliverable plus skill creation. Let me create a goal? It's a moderate task. Maybe a goal is appropriate (collect + write table + create skill). Let's do it.
First open the tab.
历史思考 2
2/16
Now observe the page. Use run_script to parse the HN table structure, which is well known: tr.athing with a.titlelink, following tr with .score, .subtext .comment link.
Let me do a script that extracts top 5 with title, score, comments, link, and maybe the subtext. For "一句话看点" I need to generate a short highlight — I can derive from title, but better to be genuine. I could fetch each linked page? That may be heavy. A one-sentence highlight could be derived from the title/domain topic with a brief note. Better: attempt to read each article's meta description briefly for a factual highlight. That's 5 HTTP fetches. Doable via run_script page fetch? Cross-origin fetch may be blocked by CORS. Instead, I can open each URL... too heavy. Alternative: use the external discussion or the title to write a highlight myself (my own synthesis, marked as such).
Let me first extract data, then decide. Maybe fetch og:description via run_script with no-cors won't give body. Could use open_tab for each of 5 links — 5 tabs is acceptable but heavy. Hmm, "一句话看点" — a brief takeaway. I could produce based on title + domain, clearly derived. But quality better with actual content. Let me try fetching via a CORS-friendly approach... Not reliable.
Compromise: extract data from HN, then open each article tab quickly and read meta description via read_dom or run_script, close tab. 5 iterations. That's reasonable but could take a while. Alternatively I can use run_script's tools to open tabs? tools doesn't include navigate? Actually tools proxy includes available tools like find_elements etc. Probably includes navigate? Unclear. Simpler: do it sequentially with open_tab + run_script reading meta description, then close_tab.
Let me first get HN data.
历史思考 3
3/16
Now I need one-sentence highlights. To be grounded, let me fetch each article's description. I can try fetching in page mode with fetch; cross-origin fetch to arbitrary sites will likely fail CORS. But HN page... Actually I could use the HN item page to get the text? No.
Better approach: open each URL in tab and read meta description. But 5 opens. Alternatively try fetch with mode 'cors' — many blog sites don't send CORS headers. Let me just try one quick test via run_script with inner? inner has no page access and network restrictions maybe. Let me test page fetch of one URL.
Actually I could use tools.open_tab? not available in tools list maybe. Let's just do sequential open_tab + run_script to grab meta description, close tab. Let's try the first one.
Actually maybe more efficient: run_script page mode fetch with `fetch(url, {mode:'cors'})` in the HN origin. Test quickly for all 5 with Promise.allSettled and see. If blocked, fall back to tabs.
历史思考 4
4/16
CORS blocks. Fall back: open each tab and read meta description. 5 tabs sequentially. Let's do the first: open_tab, then run_script to read description + first paragraph, then close.
Let me do them one at a time but efficiently: open_tab returns tabId; then run_script with tabId param to read meta. Then close.
I can do open_tab and then run_script — dependent calls.
Let's start with #1.
历史思考 5
5/16
Good. Now #2.
历史思考 6
6/16
README not found — maybe lazy loaded. Let me try read_article on that tab briefly, or query for 'readme' text. Let me try read_article with limit 2500.
历史思考 7
7/16
Now I have all info. Let me close the extra tabs (1887199124-1887199128)? Might keep them? Better close to tidy up, keeping HN tab.
Now write data to data_store table "hn_top5_20261023" with columns: 排名, 标题, 得分, 评论数, 链接, HN 讨论, 站点, 看点, 采集时间.
Then generate a skill. For skill creation, need load_skill("skill-workbench").
Let me do data_store insert (5 rows) — small, can call directly. Use table name "HN 热帖速览"? Better English-ish: hn_top5. I'll name table "hn_home_top5" with column 采集日期.
Let me write.
历史思考 8
8/16
Now checkpoint goal, then create skill. Load skill-workbench for the skill authoring protocol.
历史思考 9
9/16
Now create the skill. Name: hn-top5-brief, displayName: HN 热帖速览, scope: site with domains news.ycombinator.com, urlPatterns maybe "/". Content should be the SOP: open HN, parse via run_script, verify counts, optionally read article meta, write to data_store.
Should I add a plugin.json with a script tool? A skill tool could be useful: "collect_top" script that parses HN page and returns rows with table renderer. That is a nice deliverable. But the user just asked to generate the Skill. Adding a tool makes it more useful. The workbench says only create plugin.json if needed. For this case, a script tool that extracts top N posts is a stable, boundary-clear local action — good fit. I'll create the skill with content only first, then add plugin.json + script, and validate.
Hmm — risk of complexity. But it's genuinely useful: tool "collect_top_posts" returns rows (table renderer). Also the one-sentence highlight requires LLM reading, so script returns title/score/comments/url and content SOP tells agent to read each article page for highlight.
Let's do it: create skill then add plugin.json and script.
Let me check renderer table requirements: need rows with fields matching columns; script return {rows:[...]}. Fine.
Create skill content in Chinese.
Also renderers require "category" in plugin.json — new skill's category handled by create_skill? The create_skill tool params don't include category. plugin.json includes category; set "category": {"id":"research","label":"研究"}.
Let me write content.
Content outline:
# HN 热帖速览
适用:news.ycombinator.com 首页热帖速览、采集前 N 条帖子。
前置:桌面模式;无需登录。
步骤1 打开首页 open_tab https://news.ycombinator.com/
步骤2 调用 Skill 工具 hn_top_posts(或 run_script)解析 tr.athing
- 标题 .titleline > a;站点 .sitestr;副行 tr.athing 的 nextElementSibling:.score、.age、评论链接 a[href^="item?id="]
步骤3 校验:返回 count 与目标 N 一致;score/comments 缺失时标注"未显示"(新帖无 score)
步骤4 一句话看点:同源 fetch 会被 CORS 拦截(实测 Failed to fetch),必须用 open_tab 打开文章页,读 meta[name=description]/og:description + 首段,然后 close_tab;不要把 URL 拼成猜测摘要
步骤5 落库 data_store 表 hn_home_top5,字段顺序,dedupField=链接
步骤6 输出:Markdown 表格 + footnote 链接
注意 HN 排序变化;评论数为 0 时显示 "0 comments" 或 "discuss"。
Now write. Tool name maybe "list_top_posts".
Actually plugin.json tool "hn_top_posts" with parameters limit (default 5). needsPage true.
Renderer table columns: 排名, 标题, 得分, 评论数, 链接, HN 讨论, 站点, 发布时间.
Script: async () => { parse }.
Let me create skill first then resources.
历史思考 10
10/16
Now add plugin.json with tool hn_top_posts and script. Need renderer info — table renderer is standard. I'll query load_available_renderers to confirm table schema? The workbench says read registry before creating UI. Let's do it quickly and in parallel write plugin.json? Dependencies: renderer schema needed for columns. Table renderer columns require {label, path}. I'm fairly confident. But instruction says call it first. Let's call it.
历史思考 11
11/16
Now write the script scripts/hn-top-posts.js. Must be async () => {...}, handle relative urls, return { rows, total, truncated }.
Note: the script runs in page on the HN tab; if user passes tabId, runtime handles. Script should verify page is HN: location.host.
Rows fields: rank, title, score (numeric string e.g. "219"), comments ("115"), site, age, url, commentsUrl, itemId.
Better return score as number? Table shows whatever. I'll return scoreText like "219 points" maybe keep raw plus numeric. Keep "score": "219" numeric-ish and "comments": "115". Actually renderer columns show 得分/评论数. Return numbers for cleanliness: score: 219, comments: 115, plus scoreText.
Let's write.
历史思考 12
12/16
Now verify skill loads and the tool works. The skill tool hn_top5_brief__hn_top_posts should appear in the tool list after refresh. Let me load_skill to verify and then call the tool (need HN tab as working tab — tab 1887199123 still exists as HN; but is it the working tab? Yes, we opened it first; then opened/closed others. Working tab might have become 1887199128 which is closed. Let me check get_working_tab / list_tabs.
Call list_tabs and load_skill in parallel.
历史思考 13
13/16
Working tab is false — need use_tab to set 1887199123 as working tab so the skill tool can run. Then test the skill tool hn_top5_brief__hn_top_posts. But wait — the tool isn't in my available tool list yet? The system tool list I was given doesn't include it; but after creating skill, tools may be registered dynamically. I called load_skill; tool exposure for site skill occurs when page matches domain or after load_skill. The tool may now be available. I can try invoking it via run_script's tools proxy? Simpler: try calling the function directly — but I can only call functions defined in the prompt. Hmm, the prompt's function list includes hn_top5_brief__hn_top_posts already! Yes it does — at the end, "hn_top5_brief__hn_top_posts". Interesting, it was pre-registered (from a previous version?). Anyway, I can call it.
First use_tab, then call the tool with limit 5 to verify.
历史思考 14
14/16
Bug: comments picked up ".age" link ("4 hours ago") because the find matched `a[href*="item?id="]` fallback. Actually the first find `/^(comment|discuss)/i` failed since text is "115 comments"? Wait it returned "4 hours ago" → num("4 hours ago") = 4. The first regex `^(comment|discuss)` doesn't match "115 comments" (starts with digits). Then fallback picks first anchor with item?id= which is the age link. Fix: match `/comments?$|^discuss$/i` on text, and compute comments from text starting with digits.
Let me fix the script logic:
- commentA = anchors.find(a => /comment/i.test(a.textContent) && /^\d/.test(a.textContent.trim())) || anchors.find(a => /^discuss$/i.test(a.textContent.trim()))
- comments = commentA ? (num(commentA.textContent) ?? 0) : 0
- avoid using age anchor.
Update the script.
历史思考 15
15/16
Also comments field: currently `comments: /^\d/.test(commentsText) ? num(commentsText) : 0`. With fixed commentA, commentsText = "115 comments" → num → 115. Good. And commentsText fallback '暂无评论'.
Retest the tool.
最近思考
16/16
Now data matches what I already collected. Verify data_store rows count and complete goal.
Let me verify data_store list (5 rows) and then complete goal.
{"count":5,"ok":true,"rows":[{"age":"4 hours ago","comments":"115 comments","commentsUrl":"item?id=50202681","hnId":"50202681","rank":1,"score":"219 points","site":"codeandcake.dev","title":"Docker is weird","url":"https://codeandcake.dev/posts/2026-10-22-docker-is-weird"},{"age":"5 hours ago","comments":"104 comments","commentsUrl":"item?id=50202217","hnId":"50202217","rank":2,"score":"193 points","site":"anthropic.com","title":"LLMs are making formal software verification feasible at a much larger scale","url":"https://www.anthropic.com/research/formal-verification"},{"age":"13 hours ago","comments":"376 comments","commentsUrl":"item?id=50195959","hnId":"50195959","rank":3,"score":"1055 points","site":"quad9.net","title":"Quad9 (DNS Resolver) to Exit France","url":"https://quad9.net/news/blog/au-revoir-france/"},{"age":"3 hours ago","comments":"14 comments","commentsUrl":"item?id=50162431","hnId":"50162431","rank":4,"score":"48 points","site":"coredump.cx","title":"The Secret Life of Circuits is now in stock everywhere","url":"https://blog.coredump.cx/p/the-secret-life-of-circuits-is-now"},{"age":"10 hours ago","comments":"172 comments","commentsUrl":"item?id=50198675","hnId":"50198675","rank":5,"score":"329 points","site":"github.com/nvidia","title":"OpenShell – A safe, private runtime for fleets of autonomous AI agents","url":"https://github.com/NVIDIA/OpenShell"}]}
[{"error":"TypeError: Failed to fetch"},{"error":"TypeError: Failed to fetch"},{"error":"TypeError: Failed to fetch"},{"error":"TypeError: Failed to fetch"},{"error":"TypeError: Failed to fetch"}]
{"desc":"","h1":"Code and Cake","paras":["I decided to make my own container runtime for fun, and even though I’m still early on, I’ve learned that Docker is weird. Here’s some weird things I learned about Docker.","Unlike VMs, containers are just processes with special restrictions on them. Your kernel is still running that process! And if you know where to look, you can even find that process in /proc.","There’s not really a linux feature that’s just “containers” either. Instead, containers are really 5 different linux kernel features in trenchcoat.","Namespaces hide what the host and container can see, cgroups limit container resource usage, and there’s a whole bunch of networking magic I don’t understand that lets you isolate a container’s network."],"title":"Code and Cake - Docker is weird"}
{"desc":"Claude formally proved security properties in the compiled code of 123 open-source libraries. Along the way, it found bugs that had eluded detection for years.","h1":"LLMs are making formal software verification feasible at a much larger scale","sample":"Skip to main content Try Claude LLMs are making formal software verification feasible at a much larger scale Published Oct 22, 2026 Team Frontier Red Team Keane Lucas, Aengus Lynch, Luna Tong, Luke Champine, Zygi Straznickas, Dino Distefano, Harshikaa Agrawal Evyatar Ben Asher, Ava Howell, Sami Jawhar, Chris Rohlf, Nickolai Zeldovich Nicholas Carlini, Rajashree Agrawal, Jason Gross Most software is riddled with bugs, which AI can now easily find and exploit. The standard defenses against cyberattacks are no longer sufficient: we need ways to prove that code is free of bugs. Formal software verification could provide this guarantee, but it has historically required years of expert effort, making it impractical for most real-world projects. In a collaboration with Theorem, however, we show this is no longer the case: LLMs can now produce formal proofs at large scale, enabling new software development workflows that include proven security guarantees. Using Claude, we proved security properties at the assembly code level (RISC-V) in over 100 real-world open-source software libraries. To our knowledge, this represents the first large-scale effort to use AI to apply formal verification to production software at the assembly code level. While writing the proofs, Claude also discovered bugs that had eluded detection for years, despite trillions of test runs. As model capabilities cont","title":"LLMs are making formal software verification feasible at a much larger scale \\ Anthropic"}
{"desc":"A public and free DNS service for a better security and privacy","h1":"Farewell, France","sample":"Service News Support About EN IPv4 9.9.9.9 149.112.112.112 IPv6 2620:fe::fe 2620:fe::9 More options Back to Blog October 22, 2026 Blog Farewell, France We have some news to share with you. Summary Starting November 24, Quad9 will no longer be able to offer its free cyberprotection service to users located in France. The French courts yesterday handed down an unfavorable ruling against Quad9 in a major case that undermines the transparency and stability of the internet. This decision in favor of beIN forces Quad9 to block the recursive DNS resolution for a number of domain names for users located in France. The good news is the court significantly reduced the financial penalty, from €580,000 to €1,000 per day. However, for Quad9, this has never been just a financial issue: it is a matter of principle. We cannot comply with this ruling over the long term while remaining faithful to our mission to protect your privacy, defend you against cyber threats, and preserve the integrity of the internet. For us, recursive DNS resolution is a neutral and passive service. We categorically refuse to alter or lie to you about the DNS responses you receive in a way that opposes your expectations. T","title":"Farewell, France | Quad9"}
{"desc":"For the past couple of weeks, you could get my latest book — The Secret Life of Circuits — directly from the publisher.","h1":"lcamtuf’s thing","sample":"lcamtuf’s thing Subscribe Sign in The Secret Life of Circuits is now in stock everywhere OCT 20, 2026 8 7 1 Share For the past couple of weeks, you could get my latest book — The Secret Life of Circuits — directly from the publisher. That said, I know that some of you don’t want Jeff Bezos to starve, so I’m happy to announce that it’s now in stock on Amazon: Buy on Amazon Prospective readers in Europe can place orders on amazon.de, amazon.fr, amazon.pl, amazon.es, amazon.nl, amazon.se, amazon.it, and amazon.co.uk. The book is also available from Barnes & Noble and other major online retailers in the US and Canada. We conducted rigorous tests to confirm the book is free of AI slop. While I have you here, a small plea: if you read The Secret Life of Circuits and have an Amazon account, please consider leaving an honest review. Reviews matter for their recommendation algorithm, and in 2026, every human author is “competing” with hundreds of AI-generated books. There’s even AI title-squatt","title":"The Secret Life of Circuits is now in stock everywhere"}
{"desc":"OpenShell is the safe, private runtime for autonomous AI agents. - NVIDIA/OpenShell","readme":"","stars":"","title":"GitHub - NVIDIA/OpenShell: OpenShell is the safe, private runtime for autonomous AI agents. · GitHub"}
GitHub - NVIDIA/OpenShell: OpenShell is the safe, private runtime for autonomous AI agents.
New in OpenShell 0.1.x: a stable release cadence, new isolation primitives, an expanded extension surface, and new APIs. Read the 0.1.0 upgrade guide.
OpenShell is the safe, private runtime for fleets of autonomous AI agents. Agents are most useful when they can read files, install packages, call APIs, and use credentials. OpenShell gives them that capability without giving them unrestricted access to your data, secrets, or network. You declare what each agent can touch in a policy, and OpenShell enforces it.
How It Works
OpenShell governs what agents can do in two ways: it instruments the kernel to enforce policy on every file access, system call, and network connection at runtime, and it uses formal verification to check what a policy change would allow before it is applied.
Kernel-level enforcement. Each agent runs in an isolated sandbox. Kernel controls confine which files it can access and which system calls it can make, and every network connection passes through a policy check before it leaves the sandbox. Agents never see real credentials; OpenShell adds them only to requests bound for approved endpoints.
Formally verified policy changes. Before a policy change is approved, OpenShell uses formal verification to flag risky new access it would grant, such as reaching a new host with credentials or calling a new API method, so those changes wait for human review.
See Architecture for how the gateway, supervisor, and sandbox fit together.
Quickstart
You need Linux, macOS on Apple Silicon, or Windows with WSL 2 (experimental), plus Docker, Podman, or host virtualization. See the Support Matrix for details.
The installer sets up the CLI and a local gateway. The default sandbox image is minimal Ubuntu with no agent installed. To run a real agent, follow Run Your First Agent: it runs OpenCode against a free OpenRouter model and shows how to approve new access as the agent needs it.