<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: k-wada</title>
    <description>The latest articles on DEV Community by k-wada (@k-wada).</description>
    <link>https://dev.to/k-wada</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4069023%2F8cbfd45f-fe5f-43e7-9098-3cab0480a40f.png</url>
      <title>DEV Community: k-wada</title>
      <link>https://dev.to/k-wada</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/k-wada"/>
    <language>en</language>
    <item>
      <title>My Chrome Extensions Can Read the Page — So I Designed Them Not to Send It Anywhere</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Sat, 12 Sep 2026 12:21:19 +0000</pubDate>
      <link>https://dev.to/k-wada/my-chrome-extensions-can-read-the-page-so-i-designed-them-not-to-send-it-anywhere-5bp2</link>
      <guid>https://dev.to/k-wada/my-chrome-extensions-can-read-the-page-so-i-designed-them-not-to-send-it-anywhere-5bp2</guid>
      <description>&lt;p&gt;Some of my Chrome extensions need access to the page you are looking at.&lt;/p&gt;

&lt;p&gt;That sounds uncomfortable.&lt;/p&gt;

&lt;p&gt;And it should.&lt;/p&gt;

&lt;p&gt;If an extension can inspect a page before you submit a form, check a link before you open it, or look for personal information before you paste text into an AI chat, it needs enough access to do that job.&lt;/p&gt;

&lt;p&gt;The interesting question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can this extension read the page?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“What happens to the data after it reads it?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Legacy Tools, I made that distinction a design rule.&lt;/p&gt;

&lt;p&gt;The extensions may need to inspect page content.&lt;/p&gt;

&lt;p&gt;They should not need to send that content to my server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permission is capability, not data flow
&lt;/h2&gt;

&lt;p&gt;Chrome host permissions define what an extension is allowed to interact with.&lt;/p&gt;

&lt;p&gt;For example, a content script may need access to a page so it can inspect a form field or intercept a click.&lt;/p&gt;

&lt;p&gt;That permission tells you something important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the extension has the capability to access that page.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But it does not tell you where the data goes afterward.&lt;/p&gt;

&lt;p&gt;Two extensions can request similar page access and have completely different architectures.&lt;/p&gt;

&lt;p&gt;One might:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page
  ↓
Extension
  ↓
Remote API
  ↓
Analysis
  ↓
Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page
  ↓
Extension
  ↓
Local analysis
  ↓
Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Legacy Tools tries to use the second shape whenever the task allows it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small example
&lt;/h2&gt;

&lt;p&gt;Consider a tool that checks text before it is sent to an AI service.&lt;/p&gt;

&lt;p&gt;It may need to see the text currently entered in the page.&lt;/p&gt;

&lt;p&gt;The simplest server-based architecture would be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the text.&lt;/li&gt;
&lt;li&gt;Send it to an API.&lt;/li&gt;
&lt;li&gt;Analyze it on a server.&lt;/li&gt;
&lt;li&gt;Return detected personal information.&lt;/li&gt;
&lt;li&gt;Show the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That architecture can support powerful models.&lt;/p&gt;

&lt;p&gt;But it creates a strange situation for a privacy tool:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;to warn you about sending sensitive text somewhere, the tool first sends that text somewhere else.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I chose a more limited architecture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text in the browser
        ↓
Local detection
        ↓
Show possible matches
        ↓
User decides what to do
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No cloud model is required for that path.&lt;/p&gt;

&lt;p&gt;The trade-off is real: local rules cannot understand every form of personal information.&lt;/p&gt;

&lt;p&gt;That is acceptable.&lt;/p&gt;

&lt;p&gt;The goal is not to promise perfect detection.&lt;/p&gt;

&lt;p&gt;The goal is to provide one more chance to notice something before sending it.&lt;/p&gt;

&lt;h2&gt;
  
  
  I still try to reduce the permission itself
&lt;/h2&gt;

&lt;p&gt;“Everything stays local” is not a reason to request unlimited permissions.&lt;/p&gt;

&lt;p&gt;These are separate questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;What pages can the extension access?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What does it do with the data it can access?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both should be minimized.&lt;/p&gt;

&lt;p&gt;Across the extensions I built, I ended up using several patterns.&lt;/p&gt;

&lt;p&gt;Some tools genuinely need to work on many websites.&lt;/p&gt;

&lt;p&gt;Some only need a fixed list of sites.&lt;/p&gt;

&lt;p&gt;Some can request additional sites only when the user asks.&lt;/p&gt;

&lt;p&gt;And one of my extensions can use &lt;code&gt;activeTab&lt;/code&gt;, meaning it gets access only after the user explicitly invokes it on the current page.&lt;/p&gt;

&lt;p&gt;I wrote about those permission patterns separately because choosing the smallest workable permission is part of the product design.&lt;/p&gt;

&lt;p&gt;Local processing does not excuse broad access.&lt;/p&gt;

&lt;h2&gt;
  
  
  “No server” is a useful constraint
&lt;/h2&gt;

&lt;p&gt;Not having a backend removes several things I would otherwise need to think about.&lt;/p&gt;

&lt;p&gt;There is no database of user input to protect.&lt;/p&gt;

&lt;p&gt;There is no API endpoint receiving page contents.&lt;/p&gt;

&lt;p&gt;There is no retention policy for text that was never collected.&lt;/p&gt;

&lt;p&gt;There is no account containing a history of what someone checked.&lt;/p&gt;

&lt;p&gt;That does not make an extension automatically safe.&lt;/p&gt;

&lt;p&gt;A local extension can still contain bugs.&lt;/p&gt;

&lt;p&gt;It can request too much access.&lt;/p&gt;

&lt;p&gt;A future update could change its behavior.&lt;/p&gt;

&lt;p&gt;Another dependency could introduce a problem.&lt;/p&gt;

&lt;p&gt;So I avoid saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Local means safe.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more accurate statement is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Local processing removes some classes of risk by removing unnecessary data movement.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a much smaller claim, but I think it is a more useful one.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-assisted development makes this rule more important
&lt;/h2&gt;

&lt;p&gt;I use AI coding tools heavily.&lt;/p&gt;

&lt;p&gt;That creates another failure mode.&lt;/p&gt;

&lt;p&gt;An agent trying to solve a problem may reasonably decide that adding an API call, analytics package, external library, or broader host permission is the easiest implementation.&lt;/p&gt;

&lt;p&gt;Technically, it may even be a good solution.&lt;/p&gt;

&lt;p&gt;Architecturally, it may violate the product.&lt;/p&gt;

&lt;p&gt;So I treat some things as boundaries rather than implementation details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not broaden host permissions without an explicit reason.&lt;/li&gt;
&lt;li&gt;Do not add external transmission just because it makes detection easier.&lt;/li&gt;
&lt;li&gt;Do not add telemetry by default.&lt;/li&gt;
&lt;li&gt;Do not replace a local implementation with a hosted service without reviewing the privacy change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI makes producing code cheaper.&lt;/p&gt;

&lt;p&gt;It does not make architecture decisions cheaper.&lt;/p&gt;

&lt;p&gt;If anything, those boundaries need to become more explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust should come from constraints, not promises
&lt;/h2&gt;

&lt;p&gt;A privacy policy can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We respect your privacy.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is useful, but it is still a promise.&lt;/p&gt;

&lt;p&gt;I prefer being able to say something more concrete:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This feature does not require your text to leave the browser.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is an architectural property.&lt;/p&gt;

&lt;p&gt;Users still have to trust the extension package and its updates, of course.&lt;/p&gt;

&lt;p&gt;But every dependency or server you remove is one less thing they need to trust.&lt;/p&gt;

&lt;p&gt;For small browser tools, that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable permission warning is still useful
&lt;/h2&gt;

&lt;p&gt;I used to think broad-looking Chrome permission warnings were mostly a UX problem.&lt;/p&gt;

&lt;p&gt;Now I think the discomfort is healthy.&lt;/p&gt;

&lt;p&gt;If an extension can read a page, users should know that.&lt;/p&gt;

&lt;p&gt;The developer's job is not to make that capability sound harmless.&lt;/p&gt;

&lt;p&gt;The job is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request only the access the feature actually needs,&lt;/li&gt;
&lt;li&gt;explain why it needs that access,&lt;/li&gt;
&lt;li&gt;minimize what happens after access is granted,&lt;/li&gt;
&lt;li&gt;and avoid moving user data unless moving it provides enough value to justify the new risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So yes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;some of my Chrome extensions can read the page.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is how they can help before you send, click, or submit something.&lt;/p&gt;

&lt;p&gt;But being able to read the page does not mean the page needs to leave the browser.&lt;/p&gt;

&lt;p&gt;For the kind of small safety tools I am building, that distinction has become one of the most important architectural decisions.&lt;/p&gt;




&lt;p&gt;I build &lt;strong&gt;Legacy Tools&lt;/strong&gt;, a small collection of browser tools designed to give people one more chance to check something before they act.&lt;/p&gt;

&lt;p&gt;Previous article: &lt;strong&gt;8 Shipped Chrome Extensions, 4 Ways to Declare Host Permissions&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  chromeextension #privacy #webdev #indiedev
&lt;/h1&gt;

</description>
      <category>chromeextension</category>
      <category>privacy</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>I Can Build Software Faster Than Ever. Getting One Person to Use It Is Still Hard.</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Sat, 05 Sep 2026 14:35:01 +0000</pubDate>
      <link>https://dev.to/k-wada/i-can-build-software-faster-than-ever-getting-one-person-to-use-it-is-still-hard-25nm</link>
      <guid>https://dev.to/k-wada/i-can-build-software-faster-than-ever-getting-one-person-to-use-it-is-still-hard-25nm</guid>
      <description>&lt;p&gt;I published the extension.&lt;/p&gt;

&lt;p&gt;It passed review.&lt;/p&gt;

&lt;p&gt;The store page was live.&lt;/p&gt;

&lt;p&gt;The website was ready.&lt;/p&gt;

&lt;p&gt;And then, almost nothing happened.&lt;/p&gt;

&lt;p&gt;That was harder for me than any bug I had fixed while building it.&lt;/p&gt;

&lt;h2&gt;
  
  
  I thought shipping was the hard part
&lt;/h2&gt;

&lt;p&gt;Over the past few months, I've been building small browser tools.&lt;/p&gt;

&lt;p&gt;AI-assisted development changed what felt possible.&lt;/p&gt;

&lt;p&gt;An idea could become a prototype quickly.&lt;/p&gt;

&lt;p&gt;A rough prototype could become a real Chrome extension.&lt;/p&gt;

&lt;p&gt;I could ask an AI coding agent to help inspect the implementation, find edge cases, review permissions, write tests, and prepare a release.&lt;/p&gt;

&lt;p&gt;The whole process became much faster than I was used to.&lt;/p&gt;

&lt;p&gt;So naturally, I focused on shipping.&lt;/p&gt;

&lt;p&gt;Build it.&lt;/p&gt;

&lt;p&gt;Fix it.&lt;/p&gt;

&lt;p&gt;Submit it.&lt;/p&gt;

&lt;p&gt;Pass review.&lt;/p&gt;

&lt;p&gt;Publish it.&lt;/p&gt;

&lt;p&gt;I thought that was the difficult part.&lt;/p&gt;

&lt;p&gt;It wasn't.&lt;/p&gt;

&lt;p&gt;The difficult part was getting another person to care.&lt;/p&gt;

&lt;h2&gt;
  
  
  The silence after publishing feels strange
&lt;/h2&gt;

&lt;p&gt;There is something satisfying about software development.&lt;/p&gt;

&lt;p&gt;When the code works, you know it works.&lt;/p&gt;

&lt;p&gt;Tests pass.&lt;/p&gt;

&lt;p&gt;The build succeeds.&lt;/p&gt;

&lt;p&gt;A review is approved.&lt;/p&gt;

&lt;p&gt;The extension appears in the store.&lt;/p&gt;

&lt;p&gt;There is a clear result.&lt;/p&gt;

&lt;p&gt;But after publishing, the feedback becomes much less clear.&lt;/p&gt;

&lt;p&gt;You refresh the page.&lt;/p&gt;

&lt;p&gt;You check the numbers.&lt;/p&gt;

&lt;p&gt;You improve the description.&lt;/p&gt;

&lt;p&gt;You write another explanation.&lt;/p&gt;

&lt;p&gt;Maybe you submit the product to a directory.&lt;/p&gt;

&lt;p&gt;Maybe you publish an article.&lt;/p&gt;

&lt;p&gt;Maybe you change the screenshots.&lt;/p&gt;

&lt;p&gt;Maybe you rewrite the landing page because perhaps the problem is simply that people don't understand it yet.&lt;/p&gt;

&lt;p&gt;Then you wait again.&lt;/p&gt;

&lt;p&gt;Often, nothing obvious happens.&lt;/p&gt;

&lt;p&gt;There is no error message to fix.&lt;/p&gt;

&lt;p&gt;No stack trace.&lt;/p&gt;

&lt;p&gt;No failed test.&lt;/p&gt;

&lt;p&gt;Just silence.&lt;/p&gt;

&lt;p&gt;I found that much harder than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  "That sounds useful" is not the same as "I'll install it"
&lt;/h2&gt;

&lt;p&gt;This may be the biggest thing I've learned.&lt;/p&gt;

&lt;p&gt;People can understand a product and still not use it.&lt;/p&gt;

&lt;p&gt;Someone may say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That sounds useful.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They may even agree that the problem is real.&lt;/p&gt;

&lt;p&gt;But that is still very far from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'll install it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me, clicking the install button looks trivial.&lt;/p&gt;

&lt;p&gt;For the person on the other side, it isn't.&lt;/p&gt;

&lt;p&gt;They have to decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this actually useful for me?&lt;/li&gt;
&lt;li&gt;Is this developer trustworthy?&lt;/li&gt;
&lt;li&gt;Why does the extension need these permissions?&lt;/li&gt;
&lt;li&gt;Will it interfere with something?&lt;/li&gt;
&lt;li&gt;Will I remember why I installed it?&lt;/li&gt;
&lt;li&gt;Do I really need one more thing in my browser?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One click contains many decisions.&lt;/p&gt;

&lt;p&gt;As a developer, I had underestimated almost all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety tools make this even harder
&lt;/h2&gt;

&lt;p&gt;Some of the tools I'm building are meant to help people notice small risks before they act.&lt;/p&gt;

&lt;p&gt;For example, before sending text, before following a link, or before trusting information on a page.&lt;/p&gt;

&lt;p&gt;From my side, the idea feels simple.&lt;/p&gt;

&lt;p&gt;A small tool notices something worth checking.&lt;/p&gt;

&lt;p&gt;The user makes the final decision.&lt;/p&gt;

&lt;p&gt;But there is an uncomfortable contradiction.&lt;/p&gt;

&lt;p&gt;I am effectively saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Install software from a developer you don't know so that your browsing can be a little safer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The product is asking for trust before it has had any chance to earn trust.&lt;/p&gt;

&lt;p&gt;That realization changed how I looked at the whole project.&lt;/p&gt;

&lt;p&gt;At first, I thought my problem was distribution.&lt;/p&gt;

&lt;p&gt;Maybe I needed better SEO.&lt;/p&gt;

&lt;p&gt;More directories.&lt;/p&gt;

&lt;p&gt;Better copy.&lt;/p&gt;

&lt;p&gt;A clearer landing page.&lt;/p&gt;

&lt;p&gt;More screenshots.&lt;/p&gt;

&lt;p&gt;More articles.&lt;/p&gt;

&lt;p&gt;Those things matter.&lt;/p&gt;

&lt;p&gt;But underneath all of them was a more difficult question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why should someone trust this enough to let it into their browser?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not something I can solve with one better headline.&lt;/p&gt;

&lt;h2&gt;
  
  
  I kept rewriting the website
&lt;/h2&gt;

&lt;p&gt;For a while, I kept changing the site.&lt;/p&gt;

&lt;p&gt;I rewrote explanations.&lt;/p&gt;

&lt;p&gt;Added use cases.&lt;/p&gt;

&lt;p&gt;Made privacy details clearer.&lt;/p&gt;

&lt;p&gt;Explained what the tools do.&lt;/p&gt;

&lt;p&gt;Then explained what they do &lt;strong&gt;not&lt;/strong&gt; do.&lt;/p&gt;

&lt;p&gt;I created pages for families.&lt;/p&gt;

&lt;p&gt;Pages for organizations.&lt;/p&gt;

&lt;p&gt;More examples.&lt;/p&gt;

&lt;p&gt;More context.&lt;/p&gt;

&lt;p&gt;Part of that work genuinely improved the product.&lt;/p&gt;

&lt;p&gt;But at some point I noticed what I was really doing.&lt;/p&gt;

&lt;p&gt;I was trying to answer an invisible question from a person I had never met.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who are you, and why should I believe you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question is much harder than:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does this extension do?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second question can be answered with documentation.&lt;/p&gt;

&lt;p&gt;The first one can only really be answered over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI made building faster. It did not make trust faster.
&lt;/h2&gt;

&lt;p&gt;For a solo builder like me, writing the code is no longer always the slowest part.&lt;/p&gt;

&lt;p&gt;That is a huge change.&lt;/p&gt;

&lt;p&gt;AI can help me build another feature.&lt;/p&gt;

&lt;p&gt;It can help me review code.&lt;/p&gt;

&lt;p&gt;It can help me write documentation.&lt;/p&gt;

&lt;p&gt;It can help me improve a page.&lt;/p&gt;

&lt;p&gt;It can even help me think through why a product is not working.&lt;/p&gt;

&lt;p&gt;But it cannot make a stranger care.&lt;/p&gt;

&lt;p&gt;It cannot make someone believe my claims.&lt;/p&gt;

&lt;p&gt;It cannot create a history of reliable behavior.&lt;/p&gt;

&lt;p&gt;It cannot replace the time required to earn trust.&lt;/p&gt;

&lt;p&gt;That part still seems stubbornly human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe shipping is only the halfway point
&lt;/h2&gt;

&lt;p&gt;I used to think a product looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idea
  ↓
Build
  ↓
Test
  ↓
Ship
  ↓
Done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I think it looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idea
  ↓
Build
  ↓
Test
  ↓
Ship
  ↓
Explain
  ↓
Listen
  ↓
Improve
  ↓
Earn trust
  ↓
Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second half is much slower.&lt;/p&gt;

&lt;p&gt;It is also harder to measure.&lt;/p&gt;

&lt;p&gt;There is no compiler telling you what is wrong.&lt;/p&gt;

&lt;p&gt;Sometimes you change something and nothing happens.&lt;/p&gt;

&lt;p&gt;Sometimes one person finds the product weeks later.&lt;/p&gt;

&lt;p&gt;Sometimes the right improvement is not another feature at all.&lt;/p&gt;

&lt;p&gt;Maybe it is a better explanation.&lt;/p&gt;

&lt;p&gt;Maybe it is fewer claims.&lt;/p&gt;

&lt;p&gt;Maybe it is more transparency.&lt;/p&gt;

&lt;p&gt;Maybe it is simply staying around long enough to become credible.&lt;/p&gt;

&lt;h2&gt;
  
  
  One user feels different to me now
&lt;/h2&gt;

&lt;p&gt;When building products, it is easy to think in numbers.&lt;/p&gt;

&lt;p&gt;Downloads.&lt;/p&gt;

&lt;p&gt;Traffic.&lt;/p&gt;

&lt;p&gt;Conversion.&lt;/p&gt;

&lt;p&gt;Search impressions.&lt;/p&gt;

&lt;p&gt;Users.&lt;/p&gt;

&lt;p&gt;But lately, I have started thinking differently about a single install.&lt;/p&gt;

&lt;p&gt;One person installing something I made means they crossed a surprisingly large gap.&lt;/p&gt;

&lt;p&gt;They noticed it.&lt;/p&gt;

&lt;p&gt;They understood it.&lt;/p&gt;

&lt;p&gt;They decided the problem mattered.&lt;/p&gt;

&lt;p&gt;They decided my solution might help.&lt;/p&gt;

&lt;p&gt;And finally, they trusted it enough to put it inside a browser they use every day.&lt;/p&gt;

&lt;p&gt;That does not feel like a small number anymore.&lt;/p&gt;

&lt;p&gt;It feels like a significant decision made by another human being.&lt;/p&gt;

&lt;h2&gt;
  
  
  I'm still figuring this out
&lt;/h2&gt;

&lt;p&gt;I don't have a growth formula to end with.&lt;/p&gt;

&lt;p&gt;I'm still changing things.&lt;/p&gt;

&lt;p&gt;Still writing.&lt;/p&gt;

&lt;p&gt;Still improving the products.&lt;/p&gt;

&lt;p&gt;Still learning which tools deserve more attention and which ones probably should not exist.&lt;/p&gt;

&lt;p&gt;And I still have moments when building something new feels much easier than getting one person to use what I've already built.&lt;/p&gt;

&lt;p&gt;But I no longer think that means the real work has not started yet.&lt;/p&gt;

&lt;p&gt;I think this &lt;strong&gt;is&lt;/strong&gt; the real work.&lt;/p&gt;

&lt;p&gt;I used to think publishing software meant I had finished making it.&lt;/p&gt;

&lt;p&gt;Now I'm starting to think a product is not really finished when the code works.&lt;/p&gt;

&lt;p&gt;It starts becoming real when someone trusts it enough to use it.&lt;/p&gt;

</description>
      <category>indiedev</category>
      <category>productdevelopment</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>My Mother Became a Licensed Cook at 70. It Changed How I Design for Older Users.</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Mon, 31 Aug 2026 13:21:54 +0000</pubDate>
      <link>https://dev.to/k-wada/my-mother-became-a-licensed-cook-at-70-it-changed-how-i-design-for-older-users-4pl3</link>
      <guid>https://dev.to/k-wada/my-mother-became-a-licensed-cook-at-70-it-changed-how-i-design-for-older-users-4pl3</guid>
      <description>&lt;p&gt;My mother became a licensed cook at the age of 70.&lt;/p&gt;

&lt;p&gt;She studied, prepared for the exam, took it — and passed.&lt;/p&gt;

&lt;p&gt;At the same time, she sometimes asks me questions about smartphones and the internet.&lt;/p&gt;

&lt;p&gt;“How do I do this?”&lt;/p&gt;

&lt;p&gt;“Is it okay to click this?”&lt;/p&gt;

&lt;p&gt;That contrast made me question something we often assume when designing software:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are older users really “bad at technology”?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don't think that's a very useful way to think about it anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capability is not the same as familiarity
&lt;/h2&gt;

&lt;p&gt;Getting a professional qualification at 70 isn't easy.&lt;/p&gt;

&lt;p&gt;You have to learn new things, remember rules, understand procedures, and pass an exam.&lt;/p&gt;

&lt;p&gt;Clearly, the ability to learn is still there.&lt;/p&gt;

&lt;p&gt;But technology presents a different problem.&lt;/p&gt;

&lt;p&gt;When cooking, experience helps you predict what will happen.&lt;/p&gt;

&lt;p&gt;If you heat something too long, it burns.&lt;/p&gt;

&lt;p&gt;If you add too much salt, you know what the result will be.&lt;/p&gt;

&lt;p&gt;The relationship between an action and its consequence is relatively visible.&lt;/p&gt;

&lt;p&gt;On the internet, it often isn't.&lt;/p&gt;

&lt;p&gt;What happens if I click this link?&lt;/p&gt;

&lt;p&gt;Who actually operates this website?&lt;/p&gt;

&lt;p&gt;Is it okay to enter my phone number here?&lt;/p&gt;

&lt;p&gt;What exactly am I agreeing to when I click “Allow”?&lt;/p&gt;

&lt;p&gt;The action itself may be easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the consequence is the difficult part.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  “Make it simpler” isn't always the answer
&lt;/h2&gt;

&lt;p&gt;When we talk about designing software for older users, the discussion often goes in a predictable direction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bigger text&lt;/li&gt;
&lt;li&gt;Larger buttons&lt;/li&gt;
&lt;li&gt;Fewer options&lt;/li&gt;
&lt;li&gt;Simpler navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are important accessibility considerations.&lt;/p&gt;

&lt;p&gt;But I think there's another problem that receives less attention.&lt;/p&gt;

&lt;p&gt;A UI can be extremely easy to operate while still being difficult to judge.&lt;/p&gt;

&lt;p&gt;A giant “Continue” button is easy to press.&lt;/p&gt;

&lt;p&gt;The harder question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I press it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's a completely different design problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe software should support judgment
&lt;/h2&gt;

&lt;p&gt;This changed how I think about some of the small browser tools I've been building.&lt;/p&gt;

&lt;p&gt;Originally, my instinct was straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Detect something dangerous and stop the user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But that creates another problem.&lt;/p&gt;

&lt;p&gt;The software starts deciding what is correct.&lt;/p&gt;

&lt;p&gt;And real-world situations are rarely that clean.&lt;/p&gt;

&lt;p&gt;So I've gradually moved toward a different model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't make the decision for the user.&lt;br&gt;
Give them a better moment to make the decision themselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Before sending personal information.&lt;/p&gt;

&lt;p&gt;Before opening an unfamiliar link.&lt;/p&gt;

&lt;p&gt;Before trusting a website.&lt;/p&gt;

&lt;p&gt;Before submitting something that may contain sensitive information.&lt;/p&gt;

&lt;p&gt;The software doesn't necessarily need to say:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“You cannot do this.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes it only needs to say:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“You may want to check this once.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That small difference matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Friction isn't always bad UX
&lt;/h2&gt;

&lt;p&gt;Developers spend a lot of time removing friction.&lt;/p&gt;

&lt;p&gt;Fewer clicks.&lt;/p&gt;

&lt;p&gt;Faster checkout.&lt;/p&gt;

&lt;p&gt;Automatic completion.&lt;/p&gt;

&lt;p&gt;One-tap actions.&lt;/p&gt;

&lt;p&gt;And most of the time, that's good engineering.&lt;/p&gt;

&lt;p&gt;But I don't think friction is universally bad.&lt;/p&gt;

&lt;p&gt;There are moments where a tiny amount of friction creates useful thinking time.&lt;/p&gt;

&lt;p&gt;A confirmation before sending sensitive information isn't necessarily an obstacle.&lt;/p&gt;

&lt;p&gt;It can be a &lt;strong&gt;decision boundary&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That has become one of the ideas behind my small project, Legacy Tools.&lt;/p&gt;

&lt;p&gt;I'm experimenting with browser extensions that add small checks at these boundaries — without uploading the user's data somewhere else and without trying to replace their judgment.&lt;/p&gt;

&lt;p&gt;The goal isn't to make the internet “simple enough for older people.”&lt;/p&gt;

&lt;p&gt;It's something different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't remove capability. Add context.
&lt;/h2&gt;

&lt;p&gt;My mother doesn't need technology to treat her as incapable.&lt;/p&gt;

&lt;p&gt;Someone who studies for and passes a professional exam at 70 clearly isn't incapable.&lt;/p&gt;

&lt;p&gt;What she sometimes lacks online is the same thing many of us lack:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;enough context to understand what an action will cause.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that isn't really an “older people” problem.&lt;/p&gt;

&lt;p&gt;Developers click suspicious links.&lt;/p&gt;

&lt;p&gt;Employees accidentally paste confidential data.&lt;/p&gt;

&lt;p&gt;Experienced users approve permissions they haven't really inspected.&lt;/p&gt;

&lt;p&gt;We've all learned to operate software faster than we've learned to evaluate every consequence.&lt;/p&gt;

&lt;p&gt;So perhaps the broader design principle is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don't simplify users. Simplify the decision they need to make.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a very different way to think about accessibility, safety, and UX.&lt;/p&gt;

&lt;p&gt;And watching my 70-year-old mother study for a new qualification was what finally made that obvious to me.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Went to Numazu and Found an Old Food Technology</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Mon, 24 Aug 2026 14:29:59 +0000</pubDate>
      <link>https://dev.to/k-wada/i-went-to-numazu-and-found-an-old-food-technology-nki</link>
      <guid>https://dev.to/k-wada/i-went-to-numazu-and-found-an-old-food-technology-nki</guid>
      <description>&lt;p&gt;Today, no AI.&lt;br&gt;
No code.&lt;/p&gt;

&lt;p&gt;Just fish.&lt;/p&gt;

&lt;p&gt;A few days ago, I took a short trip to &lt;strong&gt;Numazu&lt;/strong&gt;, a coastal city in Shizuoka, Japan.&lt;/p&gt;

&lt;p&gt;Numazu is one of those places where fish feels very close to everyday life.&lt;/p&gt;

&lt;p&gt;You walk around, see the harbor, seafood restaurants, fish shops — and eventually, you get hungry.&lt;/p&gt;

&lt;p&gt;So I did what seemed like the obvious thing.&lt;/p&gt;

&lt;p&gt;I ate fish.&lt;/p&gt;

&lt;p&gt;More specifically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aji no himono — dried horse mackerel.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It looked very simple.&lt;/p&gt;

&lt;p&gt;A grilled fish, opened flat, with rice and grated daikon radish.&lt;/p&gt;

&lt;p&gt;But while eating it, I started thinking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is actually technology.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is himono?
&lt;/h2&gt;

&lt;p&gt;“Himono” literally means dried food, but in everyday Japanese it often refers to dried fish.&lt;/p&gt;

&lt;p&gt;For aji no himono, the fish is usually opened, salted, dried, and then grilled before eating.&lt;/p&gt;

&lt;p&gt;That's basically it.&lt;/p&gt;

&lt;p&gt;No complicated sauce.&lt;/p&gt;

&lt;p&gt;No long list of ingredients.&lt;/p&gt;

&lt;p&gt;Fish.&lt;br&gt;
Salt.&lt;br&gt;
Air.&lt;br&gt;
Time.&lt;/p&gt;

&lt;p&gt;But that simplicity hides a surprisingly clever process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The original problem: fish doesn't keep well
&lt;/h2&gt;

&lt;p&gt;Fresh fish contains a lot of water.&lt;/p&gt;

&lt;p&gt;That's one of the reasons it tastes good.&lt;/p&gt;

&lt;p&gt;It's also one of the reasons it spoils quickly.&lt;/p&gt;

&lt;p&gt;Today, we have refrigerators and freezers.&lt;/p&gt;

&lt;p&gt;People in the past didn't.&lt;/p&gt;

&lt;p&gt;So they needed another solution.&lt;/p&gt;

&lt;p&gt;One answer was simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove some of the water.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Drying lowers the amount of water available for microorganisms and slows deterioration.&lt;/p&gt;

&lt;p&gt;In modern food science, this is related to the concept of &lt;strong&gt;water activity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So himono is not just “fish left outside.”&lt;/p&gt;

&lt;p&gt;It is a method of controlling water.&lt;/p&gt;

&lt;p&gt;And that changes everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's really a tuning problem
&lt;/h2&gt;

&lt;p&gt;The interesting part is that you don't want to remove all the water.&lt;/p&gt;

&lt;p&gt;Dry too little, and preservation doesn't improve enough.&lt;/p&gt;

&lt;p&gt;Dry too much, and the fish becomes hard and unpleasant.&lt;/p&gt;

&lt;p&gt;So you're balancing several things at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preservation&lt;/li&gt;
&lt;li&gt;moisture&lt;/li&gt;
&lt;li&gt;texture&lt;/li&gt;
&lt;li&gt;saltiness&lt;/li&gt;
&lt;li&gt;flavor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That sounds familiar.&lt;/p&gt;

&lt;p&gt;It's a trade-off.&lt;/p&gt;

&lt;p&gt;You could almost describe himono as an old optimization problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preserve the fish, but keep it delicious.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;People solved that problem hundreds of years before anyone called it engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Salt isn't just seasoning
&lt;/h2&gt;

&lt;p&gt;Salt also plays more than one role.&lt;/p&gt;

&lt;p&gt;Of course it makes the fish taste good.&lt;/p&gt;

&lt;p&gt;But it also helps draw water from the fish and changes the environment in which microorganisms can grow.&lt;/p&gt;

&lt;p&gt;So salt is not just a topping.&lt;/p&gt;

&lt;p&gt;It's part of the process.&lt;/p&gt;

&lt;p&gt;The recipe is closer to this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fish + salt + controlled drying + time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And after that process, the fish is no longer quite the same food.&lt;/p&gt;

&lt;p&gt;The texture changes.&lt;/p&gt;

&lt;p&gt;The aroma changes.&lt;/p&gt;

&lt;p&gt;And the flavor changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then there is umami
&lt;/h2&gt;

&lt;p&gt;This is where Japanese food gets especially interesting.&lt;/p&gt;

&lt;p&gt;The Japanese word &lt;strong&gt;umami&lt;/strong&gt; is now widely used around the world.&lt;/p&gt;

&lt;p&gt;It is generally described as the fifth basic taste, alongside sweet, sour, salty, and bitter.&lt;/p&gt;

&lt;p&gt;Fish naturally contains compounds connected to umami, including glutamate and nucleotides such as inosinate.&lt;/p&gt;

&lt;p&gt;And an important point is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drying doesn't magically create umami from nothing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's more subtle than that.&lt;/p&gt;

&lt;p&gt;By reducing water, adding salt, changing texture, and allowing biochemical changes during processing, the experience of the flavor becomes different.&lt;/p&gt;

&lt;p&gt;The taste feels deeper.&lt;/p&gt;

&lt;p&gt;More concentrated.&lt;/p&gt;

&lt;p&gt;More satisfying.&lt;/p&gt;

&lt;p&gt;And that's one of the things I noticed while eating the fish in Numazu.&lt;/p&gt;

&lt;p&gt;There wasn't much on the plate.&lt;/p&gt;

&lt;p&gt;But it didn't feel simple at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maybe that's why I like Japanese food
&lt;/h2&gt;

&lt;p&gt;When people think of Japanese food, they often think of sushi.&lt;/p&gt;

&lt;p&gt;Or ramen.&lt;/p&gt;

&lt;p&gt;Those are great.&lt;/p&gt;

&lt;p&gt;But some of the foods I like most are much less spectacular.&lt;/p&gt;

&lt;p&gt;Grilled fish.&lt;/p&gt;

&lt;p&gt;Rice.&lt;/p&gt;

&lt;p&gt;Miso soup.&lt;/p&gt;

&lt;p&gt;Pickles.&lt;/p&gt;

&lt;p&gt;A little grated daikon.&lt;/p&gt;

&lt;p&gt;Nothing flashy.&lt;/p&gt;

&lt;p&gt;And yet, behind something as ordinary as a piece of dried fish is a long history of people experimenting with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;water, salt, time, temperature, texture, and taste.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's engineering.&lt;/p&gt;

&lt;p&gt;Just not the kind we usually write about on DEV.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small discovery in Numazu
&lt;/h2&gt;

&lt;p&gt;I went to Numazu just expecting a short trip and some good food.&lt;/p&gt;

&lt;p&gt;I came back thinking about dehydration, preservation, and umami.&lt;/p&gt;

&lt;p&gt;That might be an occupational hazard of being an engineer.&lt;/p&gt;

&lt;p&gt;But I like finding technology in ordinary things.&lt;/p&gt;

&lt;p&gt;And himono is a good example.&lt;/p&gt;

&lt;p&gt;It looks like a simple grilled fish.&lt;/p&gt;

&lt;p&gt;But behind it is an old idea:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control water, and you can control preservation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then keep improving the process until preservation and deliciousness can coexist.&lt;/p&gt;

&lt;p&gt;Humans have been optimizing systems for a very long time.&lt;/p&gt;

&lt;p&gt;Some of them just happen to be edible.&lt;/p&gt;

&lt;p&gt;So if you ever visit Japan, try sushi.&lt;/p&gt;

&lt;p&gt;Try ramen.&lt;/p&gt;

&lt;p&gt;But if you find yourself somewhere like Numazu, look for something simpler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aji no himono.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56os8dbr5gf61v66r38v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56os8dbr5gf61v66r38v.jpg" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might be eating a small piece of Japanese food engineering.&lt;/p&gt;

</description>
      <category>japan</category>
      <category>watercooler</category>
      <category>food</category>
      <category>technology</category>
    </item>
    <item>
      <title>8 Shipped Chrome Extensions, 4 Ways to Declare Host Permissions</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Fri, 21 Aug 2026 17:16:55 +0000</pubDate>
      <link>https://dev.to/k-wada/8-shipped-chrome-extensions-4-ways-to-declare-host-permissions-3n1c</link>
      <guid>https://dev.to/k-wada/8-shipped-chrome-extensions-4-ways-to-declare-host-permissions-3n1c</guid>
      <description>&lt;p&gt;I ship eight small Chrome extensions under Legacy Tools. They are all&lt;br&gt;
Manifest V3, and they all need some form of access to the pages you&lt;br&gt;
visit — that is what tools that check things before you send them do.&lt;/p&gt;

&lt;p&gt;I have written before about &lt;a href="https://dev.to/k-wada/after-shipping-8-chrome-extensions-these-are-the-5-rules-i-always-give-ai-agents-13al"&gt;the rules I give AI agents&lt;/a&gt;&lt;br&gt;
so they never broaden permissions on their own. This post is about the&lt;br&gt;
other side of that: the shapes the declarations themselves take.&lt;br&gt;
Recently I put all eight manifests side by side (the versions shipped to&lt;br&gt;
the Chrome Web Store as of 2026-08-22) and realized they ended up using&lt;br&gt;
four different shapes to declare that access. None of this was planned&lt;br&gt;
up front; each shape fell out of what the tool is. Here is the survey.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four shapes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Everywhere, all the time — five extensions.&lt;/strong&gt;&lt;br&gt;
Safe Privacy Gate, Safe Attachment Check, Safe Mail Link Check, Site&lt;br&gt;
Operator Check, Find My Age. These step in right before a send or a&lt;br&gt;
click, and there is no way to know in advance which site that will&lt;br&gt;
happen on. Interesting detail: only two of the five actually write&lt;br&gt;
&lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; into &lt;code&gt;host_permissions&lt;/code&gt;. The other three get the same&lt;br&gt;
breadth from &lt;code&gt;content_scripts.matches&lt;/code&gt; alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. One fixed site — one extension.&lt;/strong&gt;&lt;br&gt;
Safe Night Check is a Gmail-only tool, so the whole declaration is a&lt;br&gt;
single pattern: &lt;code&gt;https://mail.google.com/*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. A fixed list plus optional grants — one extension.&lt;/strong&gt;&lt;br&gt;
Safe Privacy Mask enumerates thirty &lt;code&gt;matches&lt;/code&gt; patterns for the AI chat&lt;br&gt;
sites it supports, and puts &lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; into&lt;br&gt;
&lt;code&gt;optional_host_permissions&lt;/code&gt; so that any other site is granted only when&lt;br&gt;
the user adds it, one prompt at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. &lt;code&gt;activeTab&lt;/code&gt; only — one extension.&lt;/strong&gt;&lt;br&gt;
Copy &amp;amp; Prep ships no content script at all. It touches only the tab&lt;br&gt;
where you just ran its context-menu action. Standing access: zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that surprised me
&lt;/h2&gt;

&lt;p&gt;While checking what these declarations look like from the user's side&lt;br&gt;
(on &lt;code&gt;chrome://extensions&lt;/code&gt;, with the extensions side-loaded into&lt;br&gt;
Chromium), two things stood out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Permissions section came up empty every time.&lt;/strong&gt; I measured
seven of the eight this way. Between them they use &lt;code&gt;storage&lt;/code&gt;,
&lt;code&gt;scripting&lt;/code&gt;, &lt;code&gt;contextMenus&lt;/code&gt; and &lt;code&gt;activeTab&lt;/code&gt; — none of those produces
a line in that box. "The permissions list is blank, so it must be
harmless" is not a read you can make.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;matches&lt;/code&gt; counts as a host permission.&lt;/strong&gt; Safe Attachment Check
declares no &lt;code&gt;host_permissions&lt;/code&gt; at all, and its site-access wording
was character-for-character identical to Safe Privacy Gate, which
declares &lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; explicitly. You cannot shrink the warning by
moving breadth out of &lt;code&gt;host_permissions&lt;/code&gt; and into &lt;code&gt;content_scripts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bonus: the list shown to users is deduplicated. Mask declares thirty
patterns; the screen shows fifteen. A short list does not mean narrow
coverage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I take from this
&lt;/h2&gt;

&lt;p&gt;Permission declarations are not configuration. They are UI — shown to&lt;br&gt;
the user, in their words, at install time and on the details page. The&lt;br&gt;
shape you choose is a product decision: &lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt; is honest for a&lt;br&gt;
tool that must work everywhere, a fixed list is honest for a&lt;br&gt;
single-site tool, and &lt;code&gt;activeTab&lt;/code&gt; is worth the extra design work when&lt;br&gt;
"only when I ask" is the actual contract.&lt;/p&gt;

&lt;p&gt;I wrote up the longer versions of both halves of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The structure side — what runs where in a Manifest V3 extension, and
how the manifest keys relate:
&lt;a href="https://legacy-tools.dev/en/notes/how-a-chrome-extension-works-manifest-v3/" rel="noopener noreferrer"&gt;https://legacy-tools.dev/en/notes/how-a-chrome-extension-works-manifest-v3/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The display side — what the Permissions and Site access sections
actually show, measured against our own manifests:
&lt;a href="https://legacy-tools.dev/en/notes/reading-chrome-extension-permissions/" rel="noopener noreferrer"&gt;https://legacy-tools.dev/en/notes/reading-chrome-extension-permissions/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>chromeextension</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>indiedev</category>
    </item>
    <item>
      <title>Running LM Studio Locally Doesn't Mean It Never Connects Out</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Thu, 20 Aug 2026 07:01:51 +0000</pubDate>
      <link>https://dev.to/k-wada/running-lm-studio-locally-doesnt-mean-it-never-connects-out-keb</link>
      <guid>https://dev.to/k-wada/running-lm-studio-locally-doesnt-mean-it-never-connects-out-keb</guid>
      <description>&lt;p&gt;When we say &lt;strong&gt;“local LLM,”&lt;/strong&gt; it is easy to mentally translate that into:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everything stays inside the PC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For inference, that can be true.&lt;/p&gt;

&lt;p&gt;But the application running the model is still an application with network-capable features.&lt;/p&gt;

&lt;p&gt;LM Studio, for example, may need connectivity for things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;searching for models&lt;/li&gt;
&lt;li&gt;downloading models&lt;/li&gt;
&lt;li&gt;downloading runtimes&lt;/li&gt;
&lt;li&gt;checking for application updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can also expose a local API server, connect to MCP servers, enable CORS, or serve the API to other devices on the LAN.&lt;/p&gt;

&lt;p&gt;None of those features are inherently bad.&lt;/p&gt;

&lt;p&gt;But I wanted a much narrower environment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;one approved model, local inference, and as little external connectivity as possible.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I treated “local execution” and “network isolation” as two separate problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  My target state
&lt;/h2&gt;

&lt;p&gt;For normal use, I wanted this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LM Studio
   |
   +---- 127.0.0.1 / localhost ---- allowed
   |
   +---- LAN ----------------------- blocked
   |
   +---- Internet ------------------ blocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is the loopback connection.&lt;/p&gt;

&lt;p&gt;Blocking everything blindly can also break communication that stays entirely inside the machine.&lt;/p&gt;

&lt;p&gt;So the rule became:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;deny external communication, but deliberately preserve loopback.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration is not the security boundary
&lt;/h2&gt;

&lt;p&gt;LM Studio already provides useful settings.&lt;/p&gt;

&lt;p&gt;For my baseline I disable features I do not need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serve on Local Network&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;per-request MCP&lt;/li&gt;
&lt;li&gt;MCP servers from &lt;code&gt;mcp.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;cloud features / web search&lt;/li&gt;
&lt;li&gt;automatic model switching or unexpected model loading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also keep the API server off because I do not need it for this evaluation.&lt;/p&gt;

&lt;p&gt;And my &lt;code&gt;mcp.json&lt;/code&gt; is intentionally boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I do not want the security of the environment to depend entirely on application settings.&lt;/p&gt;

&lt;p&gt;Settings can be changed.&lt;/p&gt;

&lt;p&gt;Their internal representation can also change between versions.&lt;/p&gt;

&lt;p&gt;So I use two layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LM Studio settings
        +
OS network controls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first expresses the intended configuration.&lt;/p&gt;

&lt;p&gt;The second enforces the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate setup from normal use
&lt;/h2&gt;

&lt;p&gt;This was probably the most useful design decision.&lt;/p&gt;

&lt;p&gt;LM Studio needs the network while preparing the machine.&lt;/p&gt;

&lt;p&gt;So I split operation into two phases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup phase
&lt;/h3&gt;

&lt;p&gt;Network access is temporarily available for things that genuinely require it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install LM Studio
        ↓
Download the approved runtime
        ↓
Download the approved model
        ↓
Verify the files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, normal use does not need model discovery or downloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Normal-use phase
&lt;/h3&gt;

&lt;p&gt;The environment becomes much smaller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start LM Studio
        ↓
Restore the hardened configuration
        ↓
Check MCP configuration
        ↓
Check network restrictions
        ↓
Unload previously loaded models
        ↓
Load only the approved model
        ↓
Run locally
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids trying to make installation and daily operation obey the same network policy.&lt;/p&gt;

&lt;p&gt;They are different states.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin the model at startup
&lt;/h2&gt;

&lt;p&gt;Another thing I did not want was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“LM Studio is approved, therefore any model inside LM Studio is approved.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are two different decisions.&lt;/p&gt;

&lt;p&gt;At startup I first unload existing models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lms unload &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I load the model selected for the evaluation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lms load &amp;lt;approved-model&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--context-length&lt;/span&gt; 8192 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--identifier&lt;/span&gt; approved-model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual startup wrapper also verifies that the expected model is available before continuing.&lt;/p&gt;

&lt;p&gt;If the expected state cannot be established, startup should fail rather than quietly falling back to something else.&lt;/p&gt;

&lt;p&gt;That is a small change, but it makes the environment much more reproducible.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you need the API server
&lt;/h2&gt;

&lt;p&gt;My current use case does not require it, so I leave it off.&lt;/p&gt;

&lt;p&gt;But LM Studio's CLI supports explicitly binding the server to loopback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lms server start &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bind&lt;/span&gt; 127.0.0.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 1234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is very different from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lms server start &lt;span class="nt"&gt;--bind&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first stays on localhost.&lt;/p&gt;

&lt;p&gt;The second makes the server reachable beyond localhost and changes the security boundary significantly.&lt;/p&gt;

&lt;p&gt;For a controlled local evaluation, I would not expose it unless there is a concrete reason to do so.&lt;/p&gt;

&lt;h2&gt;
  
  
  I also verify the result
&lt;/h2&gt;

&lt;p&gt;A configuration file saying “disabled” is not enough.&lt;/p&gt;

&lt;p&gt;I want to observe what actually happens.&lt;/p&gt;

&lt;p&gt;So the evaluation includes checks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which processes are listening on ports&lt;/li&gt;
&lt;li&gt;whether unexpected external connections appear&lt;/li&gt;
&lt;li&gt;whether the API server is running&lt;/li&gt;
&lt;li&gt;whether MCP configuration changed&lt;/li&gt;
&lt;li&gt;which model is actually loaded&lt;/li&gt;
&lt;li&gt;whether unexpected GGUF files appeared&lt;/li&gt;
&lt;li&gt;whether firewall rules are still present&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The distinction matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;configuration → what should happen
verification  → what actually happened
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this kind of environment, I want both.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Local” describes where inference happens
&lt;/h2&gt;

&lt;p&gt;This experiment changed how I think about the word &lt;strong&gt;local&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A local LLM tells me where the model inference runs.&lt;/p&gt;

&lt;p&gt;It does not automatically define every network behavior of the application surrounding that model.&lt;/p&gt;

&lt;p&gt;So my final model is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Local inference
      ≠
Network isolation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I care about both, I need to design for both.&lt;/p&gt;

&lt;p&gt;LM Studio already works well offline once the required model and runtime are available.&lt;/p&gt;

&lt;p&gt;What I added was a smaller operational boundary around it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;prepare while connected, then run with the outside closed and only the communication that must stay inside the machine deliberately preserved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The full implementation and notes are available in the original Legacy Tools article.&lt;/p&gt;

</description>
      <category>lmstudio</category>
      <category>security</category>
      <category>llm</category>
      <category>hardening</category>
    </item>
    <item>
      <title>I Asked AI for Chrome Extension Ideas. It Kept Saying “AI Can Already Do That.”</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Mon, 17 Aug 2026 13:52:08 +0000</pubDate>
      <link>https://dev.to/k-wada/i-asked-ai-for-chrome-extension-ideas-it-kept-saying-ai-can-already-do-that-2adi</link>
      <guid>https://dev.to/k-wada/i-asked-ai-for-chrome-extension-ideas-it-kept-saying-ai-can-already-do-that-2adi</guid>
      <description>&lt;h1&gt;
  
  
  I Asked AI for Chrome Extension Ideas. It Kept Saying “AI Can Already Do That.”
&lt;/h1&gt;

&lt;p&gt;I’ve been building small Chrome extensions lately.&lt;/p&gt;

&lt;p&gt;And, like many developers, I often ask AI for ideas.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What small browser problems are still worth solving?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answers are usually reasonable.&lt;/p&gt;

&lt;p&gt;But there’s one response I keep running into.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“You can already do that with AI.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Need to summarize some text?&lt;br&gt;
AI can do it.&lt;/p&gt;

&lt;p&gt;Need to clean up copied text?&lt;br&gt;
AI can do it.&lt;/p&gt;

&lt;p&gt;Need to compare information from several pages?&lt;br&gt;
AI can do it.&lt;/p&gt;

&lt;p&gt;Need to rewrite something before sending it?&lt;br&gt;
AI can do it.&lt;/p&gt;

&lt;p&gt;Technically, that’s true.&lt;/p&gt;

&lt;p&gt;But after building several small tools, I think it’s also the wrong question.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Can AI do it?” is a very low bar
&lt;/h2&gt;

&lt;p&gt;Almost anything involving text can now be done with an AI chat.&lt;/p&gt;

&lt;p&gt;But that often means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy something&lt;/li&gt;
&lt;li&gt;Open an AI tool&lt;/li&gt;
&lt;li&gt;Paste it&lt;/li&gt;
&lt;li&gt;Explain what you want&lt;/li&gt;
&lt;li&gt;Check the result&lt;/li&gt;
&lt;li&gt;Copy it again&lt;/li&gt;
&lt;li&gt;Go back to what you were doing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That works.&lt;/p&gt;

&lt;p&gt;But it’s still a workflow.&lt;/p&gt;

&lt;p&gt;Sometimes a tiny browser extension can turn that into:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;select → click → done&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That difference matters more than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small example
&lt;/h2&gt;

&lt;p&gt;One of the extensions I built is called &lt;strong&gt;Copy &amp;amp; Prep&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It lets me collect text from multiple pages, reorder it, clean it up, and copy everything together.&lt;/p&gt;

&lt;p&gt;Could I do that with ChatGPT?&lt;/p&gt;

&lt;p&gt;Of course.&lt;/p&gt;

&lt;p&gt;But I don’t actually want to explain the same task to ChatGPT every time.&lt;/p&gt;

&lt;p&gt;I just want the text.&lt;/p&gt;

&lt;p&gt;That made me realize something.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI capability is not the same as product UX
&lt;/h2&gt;

&lt;p&gt;When I ask AI whether an idea is useful, it tends to think in terms of capability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This task can already be performed.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Users often think differently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How many steps does this take?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are not the same question.&lt;/p&gt;

&lt;p&gt;And I think this creates a small opportunity for browser extensions.&lt;/p&gt;

&lt;p&gt;Not to compete with AI.&lt;/p&gt;

&lt;p&gt;But to remove the need to ask AI in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question I use now
&lt;/h2&gt;

&lt;p&gt;So when I think about small tool ideas, I’ve stopped asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can AI do this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, I ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should the user have to ask AI to do this every time?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is no, there may still be a useful little tool hiding there.&lt;/p&gt;

&lt;p&gt;And honestly, I find those small tools much more interesting to build.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>chromeextension</category>
      <category>ai</category>
    </item>
    <item>
      <title>Chrome Web Store Rejected My Extension for “Keyword Spam” — Here’s What I Changed</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Thu, 13 Aug 2026 12:45:08 +0000</pubDate>
      <link>https://dev.to/k-wada/chrome-web-store-rejected-my-extension-for-keyword-spam-heres-what-i-changed-18i4</link>
      <guid>https://dev.to/k-wada/chrome-web-store-rejected-my-extension-for-keyword-spam-heres-what-i-changed-18i4</guid>
      <description>&lt;h1&gt;
  
  
  I recently submitted a Chrome extension to the Chrome Web Store and got a rejection I wasn't expecting:
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Keyword Spam.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The extension itself worked.&lt;/p&gt;

&lt;p&gt;Its permissions were intentionally limited.&lt;/p&gt;

&lt;p&gt;It didn't send user data to an external server.&lt;/p&gt;

&lt;p&gt;The problem wasn't the code.&lt;/p&gt;

&lt;p&gt;It was the store listing.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Was Trying to Make the Extension Easy to Find
&lt;/h2&gt;

&lt;p&gt;When you publish a Chrome extension, you have to write several pieces of text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the extension name&lt;/li&gt;
&lt;li&gt;a short description&lt;/li&gt;
&lt;li&gt;a detailed description&lt;/li&gt;
&lt;li&gt;feature explanations&lt;/li&gt;
&lt;li&gt;privacy-related information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naturally, you want people to understand what the extension does.&lt;/p&gt;

&lt;p&gt;And you also want them to find it.&lt;/p&gt;

&lt;p&gt;That's where I made a mistake.&lt;/p&gt;

&lt;p&gt;I had repeated similar words and phrases across the listing because they accurately described the extension.&lt;/p&gt;

&lt;p&gt;From my perspective, I was being explicit.&lt;/p&gt;

&lt;p&gt;From the Chrome Web Store's perspective, the listing apparently looked too much like keyword stuffing.&lt;/p&gt;

&lt;p&gt;The submission was rejected.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Description Is Not Always Better
&lt;/h2&gt;

&lt;p&gt;This was useful because it changed how I think about Chrome Web Store listings.&lt;/p&gt;

&lt;p&gt;A product page is not a normal SEO article.&lt;/p&gt;

&lt;p&gt;When writing an article, it can make sense to explain a topic using several related terms.&lt;/p&gt;

&lt;p&gt;A store listing has a different job.&lt;/p&gt;

&lt;p&gt;It needs to explain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does this extension do?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; need to contain every phrase someone might search for.&lt;/p&gt;

&lt;p&gt;Trying to optimize too aggressively can actually make the listing worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Changed
&lt;/h2&gt;

&lt;p&gt;I went back through the listing and removed wording that existed mainly for discoverability.&lt;/p&gt;

&lt;p&gt;Instead of repeating multiple variations of the same concept, I tried to describe each function once, in plain language.&lt;/p&gt;

&lt;p&gt;The basic rule became:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Describe the product, not the search queries you want to rank for.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I also checked whether each sentence helped a person understand the extension.&lt;/p&gt;

&lt;p&gt;If removing a phrase didn't make the product harder to understand, I removed it.&lt;/p&gt;

&lt;p&gt;That made the listing shorter and clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Difficult Part: There Is No Perfect Keyword Density
&lt;/h2&gt;

&lt;p&gt;The rejection also exposed a practical problem.&lt;/p&gt;

&lt;p&gt;There isn't a simple rule like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use a keyword no more than three times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At least, that isn't a useful way to think about it.&lt;/p&gt;

&lt;p&gt;A description can contain repeated terminology for legitimate reasons. Chrome extensions are often built around a very small number of concepts, so some repetition is unavoidable.&lt;/p&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would I still write this phrase if search ranking didn't exist?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is no, it probably deserves another look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store Optimization and SEO Are Different Problems
&lt;/h2&gt;

&lt;p&gt;Before this rejection, I treated the Chrome Web Store listing partly like a small landing page.&lt;/p&gt;

&lt;p&gt;Now I separate the two.&lt;/p&gt;

&lt;p&gt;On my own website, I can write detailed articles around problems users may search for.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to check information before sending it&lt;/li&gt;
&lt;li&gt;how to inspect PDF metadata&lt;/li&gt;
&lt;li&gt;how to build a Chrome extension&lt;/li&gt;
&lt;li&gt;mistakes I made during Chrome Web Store review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those pages can provide context and answer broader questions.&lt;/p&gt;

&lt;p&gt;The Chrome Web Store listing can stay focused on the extension itself.&lt;/p&gt;

&lt;p&gt;That division is much cleaner.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Publishing a Chrome extension involves more than getting &lt;code&gt;manifest.json&lt;/code&gt; right.&lt;/p&gt;

&lt;p&gt;The listing itself is part of the product.&lt;/p&gt;

&lt;p&gt;After this rejection, my approach is now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explain exactly what the extension does.&lt;/li&gt;
&lt;li&gt;Avoid unnecessary synonyms and repeated search phrases.&lt;/li&gt;
&lt;li&gt;Keep the description readable for humans.&lt;/li&gt;
&lt;li&gt;Put broader explanatory and search-oriented content on my own site.&lt;/li&gt;
&lt;li&gt;Treat Chrome Web Store review feedback as product feedback, not just a hurdle to get past.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It was a small rejection, but a useful one.&lt;/p&gt;

&lt;p&gt;Building the extension was not the part that caused the problem.&lt;/p&gt;

&lt;p&gt;Trying too hard to help people find it was.&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>I Published a Chrome Extension — Then Found My Home Address on the Store Page</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:50:16 +0000</pubDate>
      <link>https://dev.to/k-wada/i-published-a-chrome-extension-then-found-my-home-address-on-the-store-page-3pg2</link>
      <guid>https://dev.to/k-wada/i-published-a-chrome-extension-then-found-my-home-address-on-the-store-page-3pg2</guid>
      <description>&lt;p&gt;After publishing one of my Chrome extensions, I opened its Chrome Web Store page to check how everything looked.&lt;/p&gt;

&lt;p&gt;The description was there.&lt;br&gt;
The screenshots looked fine.&lt;br&gt;
The listing was live.&lt;/p&gt;

&lt;p&gt;Then I scrolled down.&lt;/p&gt;

&lt;p&gt;And saw an address I recognized immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was my home address.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I had been thinking about the user's privacy, not mine
&lt;/h2&gt;

&lt;p&gt;For the extensions I build under Legacy Tools, I pay a lot of attention to privacy.&lt;/p&gt;

&lt;p&gt;I try to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep processing inside the browser&lt;/li&gt;
&lt;li&gt;avoid unnecessary permissions&lt;/li&gt;
&lt;li&gt;avoid external network requests where possible&lt;/li&gt;
&lt;li&gt;avoid collecting user input or detection results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had reviewed permissions, data handling, and Chrome Web Store disclosures carefully.&lt;/p&gt;

&lt;p&gt;But I had completely missed another category of information:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the developer's own information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had spent so much time thinking about what my extension might expose that I never seriously checked what publishing the extension might expose about me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reason was my trader status
&lt;/h2&gt;

&lt;p&gt;Chrome Web Store asks developers to declare whether they are acting as a trader or a non-trader.&lt;/p&gt;

&lt;p&gt;When I first completed the registration, I selected the trader option.&lt;/p&gt;

&lt;p&gt;Here, "trader" does not mean someone trading stocks.&lt;/p&gt;

&lt;p&gt;It refers to whether you are acting for purposes related to your trade, business, craft, or profession.&lt;/p&gt;

&lt;p&gt;When I reviewed the information again, I realized that verified contact information associated with a trader can be displayed on the Chrome Web Store.&lt;/p&gt;

&lt;p&gt;I had treated the address as information I was providing to Google for verification.&lt;/p&gt;

&lt;p&gt;I had not understood that it could become information visible to users.&lt;/p&gt;

&lt;p&gt;By the time I noticed, the extension was already public.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Just choose non-trader" is not the lesson
&lt;/h2&gt;

&lt;p&gt;My first reaction was obvious:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Then I should just switch to non-trader.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But that is not really the right way to think about it.&lt;/p&gt;

&lt;p&gt;Trader status is not a privacy toggle.&lt;/p&gt;

&lt;p&gt;You should not choose non-trader simply because you do not want your address to appear.&lt;/p&gt;

&lt;p&gt;The declaration needs to match how you actually operate.&lt;/p&gt;

&lt;p&gt;In my case, I reviewed the description and my current way of publishing Legacy Tools extensions, which are currently offered for free, and concluded that non-trader better matched my situation.&lt;/p&gt;

&lt;p&gt;After I changed the setting, the address was no longer displayed on the store page.&lt;/p&gt;

&lt;p&gt;But the important lesson was not the setting itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer identity is part of product design
&lt;/h2&gt;

&lt;p&gt;Before this happened, I thought of developer registration as an administrative step at the end of the publishing process.&lt;/p&gt;

&lt;p&gt;Build the extension.&lt;/p&gt;

&lt;p&gt;Prepare the screenshots.&lt;/p&gt;

&lt;p&gt;Write the description.&lt;/p&gt;

&lt;p&gt;Pass the review.&lt;/p&gt;

&lt;p&gt;Publish.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;That was too simple.&lt;/p&gt;

&lt;p&gt;If you plan to publish extensions as an independent developer, you should think about things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whose name will appear as the publisher&lt;/li&gt;
&lt;li&gt;which address is associated with the developer account&lt;/li&gt;
&lt;li&gt;which email address users will see&lt;/li&gt;
&lt;li&gt;whether you should separate personal and public contact information&lt;/li&gt;
&lt;li&gt;how your trader status affects the information shown to users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these questions change your JavaScript.&lt;/p&gt;

&lt;p&gt;But they absolutely affect what it means to publish software publicly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check your own store page after publishing
&lt;/h2&gt;

&lt;p&gt;Once an extension passes review, it is easy to feel that the job is finished.&lt;/p&gt;

&lt;p&gt;I now think there is one more step.&lt;/p&gt;

&lt;p&gt;Open the public Chrome Web Store listing exactly as a user would.&lt;/p&gt;

&lt;p&gt;Scroll from top to bottom.&lt;/p&gt;

&lt;p&gt;Do not only check the screenshots and description.&lt;/p&gt;

&lt;p&gt;Check what information about &lt;strong&gt;you&lt;/strong&gt; is being published alongside the extension.&lt;/p&gt;

&lt;p&gt;I learned this only after finding my own home address on the page.&lt;/p&gt;

&lt;p&gt;Publishing a browser extension is not only about deciding what your software reveals.&lt;/p&gt;

&lt;p&gt;It is also about deciding what &lt;strong&gt;you&lt;/strong&gt;, as the developer, reveal with it.&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>privacy</category>
      <category>indiedev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>After Shipping 8 Chrome Extensions, These Are the 5 Rules I Always Give AI Agents</title>
      <dc:creator>k-wada</dc:creator>
      <pubDate>Sat, 08 Aug 2026 17:01:20 +0000</pubDate>
      <link>https://dev.to/k-wada/after-shipping-8-chrome-extensions-these-are-the-5-rules-i-always-give-ai-agents-13al</link>
      <guid>https://dev.to/k-wada/after-shipping-8-chrome-extensions-these-are-the-5-rules-i-always-give-ai-agents-13al</guid>
      <description>&lt;p&gt;AI agents can build Chrome extensions surprisingly fast.&lt;/p&gt;

&lt;p&gt;After shipping eight extensions, though, I found that the biggest risks usually do not come from whether the code runs.&lt;/p&gt;

&lt;p&gt;They come from what the agent quietly adds while trying to be helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;another permission&lt;/li&gt;
&lt;li&gt;an external request&lt;/li&gt;
&lt;li&gt;a new dependency&lt;/li&gt;
&lt;li&gt;a refactor I did not ask for&lt;/li&gt;
&lt;li&gt;a change in what user data is read or stored&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of those can affect security, privacy, maintenance, and Chrome Web Store review.&lt;/p&gt;

&lt;p&gt;So before I ask an AI agent to implement anything, I now give it a small set of rules.&lt;/p&gt;

&lt;p&gt;These are the five I use most often.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Do not add or broaden permissions without asking
&lt;/h2&gt;

&lt;p&gt;Chrome extension permissions are part of the product.&lt;/p&gt;

&lt;p&gt;If the agent adds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"storage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"tabs"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or expands &lt;code&gt;host_permissions&lt;/code&gt;, that is not just an implementation detail.&lt;/p&gt;

&lt;p&gt;It changes what the extension is allowed to access and may change what users see during installation or what I need to explain during review.&lt;/p&gt;

&lt;p&gt;So I explicitly tell the agent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not add or broaden permissions without asking me first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a new permission is necessary, I want the agent to stop and explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which permission is needed&lt;/li&gt;
&lt;li&gt;why it is needed&lt;/li&gt;
&lt;li&gt;what feature requires it&lt;/li&gt;
&lt;li&gt;whether there is a narrower alternative&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default should be &lt;strong&gt;minimum permissions&lt;/strong&gt;, not “whatever makes implementation easier.”&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Do not add network communication
&lt;/h2&gt;

&lt;p&gt;A small local extension can easily become something very different if an agent introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an external API&lt;/li&gt;
&lt;li&gt;analytics&lt;/li&gt;
&lt;li&gt;telemetry&lt;/li&gt;
&lt;li&gt;a CDN&lt;/li&gt;
&lt;li&gt;remote configuration&lt;/li&gt;
&lt;li&gt;cloud storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes these are useful.&lt;/p&gt;

&lt;p&gt;But they should never appear accidentally.&lt;/p&gt;

&lt;p&gt;For many of my extensions, I deliberately keep the design simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web page
   ↓
Chrome extension
   ↓
chrome.storage.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No server.&lt;/p&gt;

&lt;p&gt;No account.&lt;/p&gt;

&lt;p&gt;No external transmission.&lt;/p&gt;

&lt;p&gt;That makes both the implementation and the privacy story easier to understand.&lt;/p&gt;

&lt;p&gt;So my second rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not add external network requests, analytics, telemetry, or CDN dependencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If network access is truly required, I want that to become a design decision before it becomes code.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Do not modify unrelated files or features
&lt;/h2&gt;

&lt;p&gt;This one became more important as I started using coding agents for larger changes.&lt;/p&gt;

&lt;p&gt;Suppose I ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add a function that stores selected text in chrome.storage.local.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An agent may notice nearby code and decide to improve it too.&lt;/p&gt;

&lt;p&gt;The result might work.&lt;/p&gt;

&lt;p&gt;But now one small task has changed five files.&lt;/p&gt;

&lt;p&gt;That makes review harder.&lt;/p&gt;

&lt;p&gt;It also becomes difficult to answer a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What exactly changed because of this request?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I usually add:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not modify unrelated files, features, or architecture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For small Chrome extensions, I prefer changes that are easy to understand and easy to reverse.&lt;/p&gt;

&lt;p&gt;I would rather make five small changes than one clever change that touches the entire project.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Do not add dependencies unless they are really necessary
&lt;/h2&gt;

&lt;p&gt;AI agents are very good at finding packages.&lt;/p&gt;

&lt;p&gt;That does not mean I want them.&lt;/p&gt;

&lt;p&gt;If a 20-line utility function can solve the problem, adding another npm dependency may not be worth it.&lt;/p&gt;

&lt;p&gt;Every dependency creates more things to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;supply-chain risk&lt;/li&gt;
&lt;li&gt;updates&lt;/li&gt;
&lt;li&gt;licenses&lt;/li&gt;
&lt;li&gt;bundle size&lt;/li&gt;
&lt;li&gt;build complexity&lt;/li&gt;
&lt;li&gt;future maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not add new dependencies unless they are necessary. If you think one is needed, explain why before adding it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is especially useful for browser extensions because many features can be implemented with the browser APIs and plain JavaScript.&lt;/p&gt;

&lt;p&gt;Small tools benefit from staying small.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Stop before changing the data flow
&lt;/h2&gt;

&lt;p&gt;This is the most important rule.&lt;/p&gt;

&lt;p&gt;If an implementation changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what data is read&lt;/li&gt;
&lt;li&gt;where data is stored&lt;/li&gt;
&lt;li&gt;how long it is stored&lt;/li&gt;
&lt;li&gt;whether data leaves the browser&lt;/li&gt;
&lt;li&gt;which pages the extension can access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do not want the agent to decide that silently.&lt;/p&gt;

&lt;p&gt;I tell it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your change affects what data is read, stored, or transmitted, stop and explain the change before implementing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This turns data flow into an explicit design decision.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Selected text
    ↓
Content script
    ↓
chrome.storage.local
    ↓
Extension UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the agent wants to change that into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Selected text
    ↓
Content script
    ↓
External API
    ↓
Extension UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that is not a small implementation change.&lt;/p&gt;

&lt;p&gt;It is a different product architecture.&lt;/p&gt;

&lt;p&gt;I want to know before the code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt I actually reuse
&lt;/h2&gt;

&lt;p&gt;Here is the short version I give coding agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When modifying this Chrome extension:

- Do not add or broaden permissions without asking me first.
- Do not add external network requests, analytics, telemetry, or CDN dependencies.
- Do not modify unrelated files or features.
- Do not add new dependencies unless they are necessary.
- If your change affects what data is read, stored, or transmitted, stop and explain the change before implementing it.
- Keep the implementation compatible with Manifest V3.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I usually add the task itself underneath this block.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task:

Add the ability to save selected text to chrome.storage.local.

Do not change the list UI or reordering behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that the agent receives both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;what I want it to do&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;what it is not allowed to decide on its own.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I still verify everything myself
&lt;/h2&gt;

&lt;p&gt;These rules reduce surprises.&lt;/p&gt;

&lt;p&gt;They do not replace review.&lt;/p&gt;

&lt;p&gt;Before publishing, I still check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Are all permissions necessary?
[ ] Did any host permissions become broader?
[ ] Are there unexpected network requests?
[ ] Did the agent add a dependency?
[ ] Do I know exactly what data is read?
[ ] Do I know exactly what data is stored?
[ ] Does any data leave the browser?
[ ] Does the Chrome Web Store declaration match the implementation?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also load the extension through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chrome://extensions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use it on real pages before submitting it.&lt;/p&gt;

&lt;p&gt;An extension can pass tests and still feel annoying, request too much access, or behave differently from the store description.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed after eight extensions
&lt;/h2&gt;

&lt;p&gt;AI has definitely made implementation faster for me.&lt;/p&gt;

&lt;p&gt;But after shipping eight Chrome extensions, I spend less time asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the agent build this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and more time asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What decisions should the agent not be allowed to make?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction has become one of the most useful parts of my workflow.&lt;/p&gt;

&lt;p&gt;AI agents are good at completing tasks.&lt;/p&gt;

&lt;p&gt;My job is to define the boundaries around those tasks.&lt;/p&gt;

&lt;p&gt;For Chrome extensions, those boundaries are especially important because permissions, network access, dependencies, and data handling affect not only the code, but also what users are being asked to trust.&lt;/p&gt;

&lt;p&gt;I am building and documenting these experiments as part of &lt;strong&gt;Legacy Tools&lt;/strong&gt;, a collection of small browser tools.&lt;/p&gt;

&lt;p&gt;The full development workflow I use — from choosing an idea to Chrome Web Store review — is also available on the Legacy Tools site.&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>webdev</category>
      <category>agents</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
