Reading a public website and changing something inside a signed-in account are not the same kind of job.
I wanted an AI agent to collect the first 10 Hacker News stories, explain how it gathered them, and place that work inside my DEV editor.
Save the article as a draft. Do not publish it.
The hard part was not finding the stories. It was giving the agent enough access to finish inside my signed-in account without giving it permission to publish.
That instruction contained two jobs with different access needs:
- Read public data from Hacker News.
- Change private account state by creating a draft in my signed-in DEV account.
Using a full browser for the first job would add machinery and access that the result did not need. The public fetch path had neither the authenticated context nor the authority required for the second job. The useful question was not “Which browser tool should do everything?” It was “Where does this task actually cross into a browser?”
Disclosure: I work on Unchained, SearchAgentSky, and Unbrowser. This article was prepared with AI assistance and reviewed before publication.
The public step needed only fetch
I initially opened Hacker News in a lightweight page session and queried its story links. It worked—but that did not mean it was necessary.
Hacker News has a public API. The same result could be produced with ordinary HTTP:
const base = "https://hacker-news.firebaseio.com/v0";
const ids = await fetch(`${base}/topstories.json`).then(r => r.json());
const stories = await Promise.all(ids.slice(0, 10).map(async (id, index) => {
const story = await fetch(`${base}/item/${id}.json`).then(r => r.json());
return {
rank: index + 1,
title: story.title,
url: story.url ?? `https://news.ycombinator.com/item?id=${id}`
};
}));
console.log(JSON.stringify(stories, null, 2));
At 2026-07-19T03:19:04Z, the page query returned 30 Hacker News story anchors. At 2026-07-19T03:35:29.670Z, fetch returned 10 shaped records. After normalizing the first 10 ranks, titles, and URLs, the two results matched exactly.
So I had initially reached for more capability than the output required. For the public-data step, fetch was enough.
The signed-in step needed Unchained
The job changed when the result had to be saved inside DEV. The public fetch path could return data, but it did not have the authenticated editor context or authority to create that durable draft state.
Unchained is a guided browser workspace for tasks whose outcome must happen inside a real website—not merely come back as text. Its guided path launches a dedicated, persistent Chrome workspace. It does not attach to the Chrome profile or tabs you already have open.
Unchained drives. You navigate.
You define the outcome, the boundaries, and the review point. Unchained carries out the browser steps inside that contract.
For this task, the contract was explicit:
- Outcome: put the completed article into the signed-in DEV editor.
- Boundary: select Save Draft, never Publish.
- Review: return an Unpublished Post for the owner to inspect.
Earlier in the drafting process, Unchained opened the authenticated editor, placed the then-current article version, and selected Save Draft. The resulting page displayed Unpublished Post. Publishing was outside the task, so the run stopped.
The valuable part was not the click itself. It was being able to hand off authenticated browser work without silently expanding the agent’s authority.
You call the shots. Unchained runs the steps.
Why not just use DEV's API?
DEV has an authenticated Create Article endpoint, and published: false creates a draft. If a DEV API key were already available in a credential vault, that would usually be the cleaner route for this one-site action: one structured request, no editor selectors, and potentially less account surface than a whole signed-in browser. The tradeoff is that each additional service or account may require another integration and authorization context, and the API may not expose the needed UI action.
A browser profile makes the opposite trade. It is not a password vault. Once the user signs into the sites a job needs, the selected workspace holds the cookies and session state. Extend this actual task by one step: after saving the DEV draft, check its related GitHub issue and read the signed-in campaign dashboard. The API route may now need a separate integration—and, for private data, authorization—for each service. One Unchained workspace already signed into those services can cross all three. On the developer/MCP path, separate named workspaces can run simultaneously to isolate personal, work, client, or social identities and target the one the job needs. That is the multi-account power: the user has already assembled the login context in Chrome.
That convenience may come with broader authority, expiring sessions, and more exposure to UI changes than an API route built for one operation. Use the API when it cleanly exposes the required operation. Use a browser profile when the bounded job depends on signed-in UI or crosses services. Limit each workspace to the accounts the job needs, and keep send, buy, delete, account-change, and publish actions behind explicit review.
The rule I will use next time
- If public JSON or HTML completes a step, start with
fetch. - If the job needs navigation or cookies but not a full signed-in browser, use a lighter session tool.
- If the outcome must happen inside a rendered or authenticated website, escalate to a full browser such as Unchained.
- If the next action sends, buys, deletes, changes an account, or publishes, make that authority explicit.
The lesson is simple: use the least powerful tool that can complete each step, then escalate only when the task crosses a real capability boundary.
fetch collected the public facts. Unchained completed the account-bound work. The agent stopped exactly where I told it to.
Captured output
For completeness, this is the 10-story JSON used in the comparison:
[
{
"rank": 1,
"title": "Transcribe.cpp",
"url": "https://workshop.cjpais.com/projects/transcribe-cpp"
},
{
"rank": 2,
"title": "Speech Recognition and TTS in less than 500kb",
"url": "https://github.com/moonshine-ai/moonshine/tree/main/micro"
},
{
"rank": 3,
"title": "Better and Cheaper Than IPTV",
"url": "https://github.com/stupside/castor"
},
{
"rank": 4,
"title": "Classic Amiga titles, free to download",
"url": "https://amigafreeware.downer.tech/"
},
{
"rank": 5,
"title": "Mathematicians still don't know the fastest way to multiply numbers",
"url": "https://www.scientificamerican.com/article/mathematicians-still-dont-know-the-fastest-way-to-multiply-numbers/"
},
{
"rank": 6,
"title": "If You Build It, They Will Come",
"url": "https://www.benlandautaylor.com/p/if-you-build-it-they-will-come"
},
{
"rank": 7,
"title": "GPT-5.6 used a prompt to close a 30-year gap in convex optimization",
"url": "https://old.reddit.com/r/math/comments/1uxj3cy/after_openais_cdc_proof_announcement_gpt56_used_a/"
},
{
"rank": 8,
"title": "Mayor Mamdani Says Landlords Can't Use AI Images to Advertise",
"url": "https://petapixel.com/2026/07/16/mayor-mamdani-says-landlords-cant-secretly-use-ai-images-to-advertise-properties/"
},
{
"rank": 9,
"title": "I'm Making Strandfall, a Solarpunk Orienteering Larp",
"url": "https://mssv.net/2026/04/29/im-making-strandfall-a-solarpunk-orienteering-larp/"
},
{
"rank": 10,
"title": "Harness Engineering",
"url": "https://github.com/lopopolo/harness-engineering"
}
]
Top comments (0)