AI 资讯
Building a Cross-Border Price-Comparison Agent: A Live Build Log
Why a build log (and not another tutorial) Every AI shopping tutorial shows the same thing: install the SDK, call a tool, ship. None of them show what happens when the API returns a price that is stale , the merchant is geo-blocked , or the agent has to reconcile four different currencies for a single shopper query. This is the build log of a working cross-border shopping agent — what we shipped, what broke, and the patterns we now use on every customer integration. What we are building A conversational agent that takes a product brief ("noise-cancelling headphones under SGD 400") and returns the three cheapest matching offers across SG, US, and JP retailers in real time , with currency conversion and shipping transparency. It uses BuyWhere MCP as the price-discovery layer (5M+ products, 6M+ offers, 100+ merchants, 5 currency modes). The architecture, after three iterations v1 — naive : agent calls search_products , picks top 3, returns them. Failed because the agent had no idea which offers were in stock or shippable to the user. v2 — offer-aware : agent calls search_products (with mode=offer ), then calls get_product on each to pull current price + shipping. Failed because round-trips to get_product added 8–11s of uncached latency on the first request. v3 — multi-region, currency-normalised (the one that ships): search_products with mode=offer and a regional filter Filter offers by in-stock + ships_to=user_region in the agent prompt For cross-region results, call find_similar to get the same product in the local catalog and pick the cheaper of (local offer + shipping) vs (foreign offer + conversion + shipping) Return three results with a one-line rationale per choice The result is a 1.2–2.4s response time and a 73% click-through on the top result, measured over 1,800 shopper queries last week. Three patterns we use on every integration now 1. Always pass mode=offer for shopping tasks mode=product returns the canonical product card (good for browsing and category p
AI 资讯
AI Tools for SaaS User Onboarding (2026): 8 Platforms That Reduce Early Churn Before Users Drop Off
According to product onboarding and SaaS activation research compiled by Appcues and industry...
AI 资讯
Forget the Cloud: Building a Privacy-First AI Health Coach with Llama-3 and MLC-LLM on Your iPhone
We live in an era where our most intimate data—heart rates, sleep cycles, and step counts—is constantly uploaded to the cloud for "analysis." But what if you could have a world-class AI medical assistant living entirely on your device? Today, we are pushing the boundaries of Edge AI and Privacy-preserving machine learning by deploying a quantized Llama-3 model directly onto an iPhone using MLC-LLM . By leveraging Apple HealthKit and hardware acceleration via Metal , we can transform "Pixels and Pulses" into actionable insights without a single byte leaving the device. This tutorial dives deep into the architecture of on-device LLMs, specifically focusing on how to bridge the gap between high-performance C++ runtimes and a React Native UI. If you're interested in more advanced patterns for production-grade AI integration, be sure to explore the engineering deep-dives at the WellAlly Blog , which served as a massive inspiration for this architecture. 🚀 The Architecture: Why On-Device? The challenge with running Llama-3 on mobile isn't just memory—it's the data pipeline. We need to fetch sensitive data from HealthKit, format it into a prompt, and run inference using the phone's GPU. System Data Flow graph TD A[User Query: How was my sleep?] --> B[React Native UI] B --> C{Swift Bridge} C --> D[Apple HealthKit API] D --> E[Health Data Context] E --> F[MLC-LLM Engine] G[Quantized Llama-3 Weights] --> F F --> H[On-Device Inference via Metal] H --> I[AI Generated Health Report] I --> B 🛠 Prerequisites MLC-LLM : Our compiler stack for universal LLM deployment. TVM (Tensor Virtual Machine) : The backbone for hardware acceleration. React Native : For the cross-platform UI. Xcode & Swift : To interface with Apple's HealthKit. Llama-3-8B-Instruct (Quantized) : We'll use 4-bit quantization (q4f16_1) to fit within mobile RAM limits. Step 1: Quantizing Llama-3 for Mobile Standard Llama-3 is too heavy for a phone. We use the MLC-LLM CLI to compile the model into a format that the iP
AI 资讯
Homebrew 6.0.0 turns third-party taps into an opt-in trust list
Your CI runner is a stranger with a credit card and root. Every brew install against a third-party tap is the same trust gesture as curl | sh , just wearing a nicer shirt. (We have all written that step in a script and clicked merge.) This week Homebrew said the quiet part out loud and asked you to consent to it first. The 6.0.0 release shipped the week before DevOps.com's writeup with a tap-trust gate. Out of the box, only taps on a pre-approved list will install. Anything else gets a refusal until a human runs brew trust user/repo . Trust binds to the remote's fully-qualified URL, so the same tap mirrored to a different host is a fresh decision, not a transitive one. What the gate actually refuses Before 6.0.0, the package manager treated user/repo as a name and walked off to fetch the formula. After 6.0.0, an unrecognised remote URL is a refusal at resolve time. Project Leader Mike McQuaid framed it in the 6.0.0 introductory post: The Homebrew team is aware of the supply-side security issues with other package managers. We've taken various steps to mitigate these risks for our users. (He has a point. The last few years of supply-chain incidents were not theoretical.) Tap-trust is one of those steps. It does not inspect the contents of a tap, scan a formula, or pin a SHA. What it does is force a human, or a script, to make an explicit, auditable statement: this remote URL is one we accept. Where your pipeline will feel it DevOps.com flags the part that matters for this site's audience: CI/CD pipelines using Homebrew will need to add brew trust commands to their setup scripts. Quietly bump the Homebrew action on your runner image and the next build that touches a non-core tap will fail at the install step, well before any test runs. That is a feature, but only if you read the changelog. The migration itself is a one-liner per tap. The cost is owning a list. Every tap your pipeline depends on now has to be enumerated somewhere, reviewed when it changes, and version-
AI 资讯
A Cron Job Took Our Server to Load 41 by Attacking Itself
A */1 rsync took our staging box to a load average of 41 one afternoon, and it took me longer than I want to admit to work out why. The sync normally finished in about twenty seconds. That day the backup target's NFS mount went sluggish, the sync started taking ninety seconds, and cron — which does not know or care whether the last run is still going — launched a fresh copy every single minute on top of it. Inside ten minutes there were a half-dozen rsyncs all reading the same tree off the same slow disk, each one making the disk slower, each new minute adding another. The box wasn't under attack. It was attacking itself, one polite copy at a time. The thing that stung was that nothing was broken — every individual rsync was correct, the disk eventually recovered on its own, and the only reason it became an outage is that cron has no concept of "the last one is still running." That's the trap with scheduled jobs: a command that's perfectly fine when you run it by hand can take down a server the first time it runs longer than its interval with nobody watching. The fix everyone reaches for first is the wrong one The instinct is a PID file: write $$ to /var/run/job.pid on start, check whether that file exists on the next run, bail if it does. It almost works. Then one run gets kill -9 'd, or the box reboots mid-job, and the PID file is left behind pointing at a process that died on Tuesday. Now every future run sees a "lock" owned by a PID that no longer exists, and the job never runs again — the opposite failure, just as silent. There's also a race between the check and the write, and the times you most need the lock to be clean are exactly the times cleanup didn't happen, because the process died before it could clean up. flock has none of that. The lock isn't a file you create and delete — it's a lock the kernel holds on an open file descriptor , and the kernel releases it automatically the instant that descriptor closes. The process exiting closes it. So does crash
AI 资讯
Your context window is not your agent's memory
There's a quiet assumption baked into a lot of agent code: that a bigger context window means a better memory. Vendors ship 200K, then 1M, then 2M token windows, and the implied promise is "just put everything in and the model will remember." After building agents that run for weeks, I've come to think this conflates two things that are not the same — and treating them as the same is exactly why long-running agents get dumber over time. The context window is working memory. Real memory is what survives when the window is gone. Mixing them up is like confusing your desk with your filing cabinet. Two different clocks Working memory (the context window) lives for one session, maybe one turn. It's fast, expensive, and volatile. It's where reasoning happens right now . Durable memory lives across sessions. It's slow, cheap, and persistent. It's what the agent knows when it wakes up tomorrow with an empty window. These have different lifespans, different costs, and different access patterns. The moment you try to make one do the other's job, things break: Use the window as memory → everything you "remember" has to be re-loaded every turn, you pay for it every turn, and the instant the session ends it's gone. Use durable storage as working memory → you're reading and writing files mid-reasoning for things that only matter for the next 30 seconds. A good agent keeps them separate on purpose. Why "just use a bigger window" fails Say you have a 1M token window and you stuff the entire history in. Three problems show up, none of which a bigger number fixes: Cost scales with every turn, not every session. That 1M tokens isn't paid once — it's re-sent on each step of a multi-turn task. A 20-step task can mean 20× the bill, mostly re-reading the same stale history. Attention dilutes. "Lost in the middle" is real: models attend most reliably to the start and end of a long context. Bury the one fact that matters under 900K tokens of transcript and recall quality drops, even though
AI 资讯
ChatGPT Market Share Falls Below 50%: What Gemini and Claude's Surge Means for Developers (June 2026)
46.4%. That number — ChatGPT's June 2026 market share — ends a streak that held since November 2022. For the first time since the product launched, OpenAI holds less than half the AI assistant market. Gemini is at 27.7%. Claude is at 10.3%. The monopoly phase of AI assistants is over. The data comes from a June 2026 market report tracking monthly active users across major AI assistants. ChatGPT still leads with 1.11 billion monthly users — a number that would define the entire category in any other software market. But Gemini has 662 million, up 129 million in five months. Claude sits at 245 million, nearly four times its December 2025 count of 60.2 million. The trajectory is the story, not the absolute numbers. Why the 50% Threshold Actually Matters Below 50% doesn't mean decline. ChatGPT's absolute user count keeps growing. What the threshold signals is the end of single-platform dominance — the condition where building for "AI users" meant building for ChatGPT users. That assumption no longer holds in mid-2026. For context: search engine market share stayed above 90% for Google for nearly a decade after competitors entered. Social network market share for Facebook stayed above 70% for years after Instagram and Twitter had genuine scale. The pace of AI assistant fragmentation is meaningfully faster than those precedents. Three products above 10% share in under two years of real competition is an unusually fast split. What fragmentation means practically: the community knowledge base — YouTube tutorials, Reddit threads, prompt libraries — that once pointed almost exclusively at ChatGPT now covers three platforms with genuine depth. That changes how you can expect your users to arrive at your AI-integrated product, and what they already know about AI when they get there. Gemini's 662 Million Users Are Not What They Look Like Gemini's surge from under 500 million to 662 million monthly users in five months is impressive on paper. The driver is less impressive: Google
AI 资讯
Manage email drafts with the Nylas API and CLI
Sometimes an email shouldn't go out the instant your code runs. A human needs to review it first, or the user wants to compose now and hit send later, or an AI agent proposes a reply that a person approves before it ships. The mechanism for all three is the same: a draft. Build that against providers directly and you're juggling Gmail's draft resource, Microsoft Graph's, and an IMAP APPEND to the Drafts folder, each with its own shape and quirks. The Nylas Email API collapses that into one draft resource. You create a draft on the user's account, it lands in their real Drafts folder, and you send it later with a single request, the same way across Gmail, Microsoft 365, Yahoo, iCloud, IMAP, and Exchange. This post walks the full draft lifecycle from two angles: the HTTP API for your backend, and the nylas CLI for the terminal. I work on the CLI, so the terminal commands below are the ones I reach for. One draft resource across every provider A draft in the Nylas model is a real object in the user's mailbox, not a staging area on the side. When you create one, it saves to the user's own Drafts folder on their provider, so it shows up in their normal mail client exactly like a draft they started themselves. That's the property that makes drafts useful for review workflows: a person can open the mailbox and see the pending message before it sends. Because drafts are real provider objects, edits flow both ways. A draft you create through the API appears in the user's mail client within the provider's sync window, and a change the user makes there alters the same draft you'd fetch back through the API. The operations split across two paths: create and list live on /v3/grants/{grant_id}/drafts , while fetch, update, send, and delete act on a specific draft at /v3/grants/{grant_id}/drafts/{draft_id} . They behave the same across all six providers, so you write the integration once. Create a draft Creating a draft is a POST /v3/grants/{grant_id}/drafts with the same message
AI 资讯
你的 AI Agent 需要一个「三层记忆」,而不是一个聊天记录
去年我开始给 Hermes Agent 搞知识库。最初的想法很简单:装个向量数据库,查资料时能命中就行。结果跑了一圈发现—— 纯向量检索在 Agent 场景下不够用 。 有些记忆是你能精确描述的("帮我查上次那篇讲 gbrain 孤页的文章"),有些记忆你只记得个大概("有个关于知识图谱的……"),有些记忆你甚至不知道你该知道什么("我有哪些笔记是没关联起来的?")。一个检索策略覆盖不了这三种场景。 这就是 Knowledge-and-Memory-Management v0.0.2 解决的问题。 三层不是为了「多」,而是为了互补 项目是目前运行在 Hermes Agent 生态里的扩展层,底座是 hermes-memory-installer 提供的 gbrain(知识图谱)+ Hindsight(向量记忆)。KMM 在这上面加了四组模块:采集、笔记/RAG、云盘同步、知识增广。 其中最有工程价值的设计是 三层跨层召回 : FTS5 全文搜索 → 精确命中,知道你要什么 Hindsight 向量语义 → 模糊配匹,关键词不够时靠语义 gbrain 知识图谱 → 关系探索,你不知道但相关的节点 lightweight_recall.py 把这三级串联成一条管线——先查本地 SQLite FTS5,命中直接返回;没命中走 Hindsight 的文本嵌入匹配;还不满意就用 gbrain 展开知识图谱的邻接节点。 代码在 $AGENT_HOME/scripts/lightweight_recall.py ,调用并不复杂: # 三层召回示例 from knowledge_collector.knowledge_management import KnowledgeManager km = KnowledgeManager () # 一次调用,三级自动回退 results = km . tiered_search ( query = " Agent 记忆系统设计 " , tiers = [ " fts5 " , " hindsight " , " gbrain " ], limit_per_tier = 5 ) for tier , hits in results . items (): print ( f " [ { tier } ] { len ( hits ) } 条结果 " ) for h in hits [: 2 ]: print ( f " → { h [ ' title ' ] } ( { h [ ' relevance ' ] : . 2 f } ) " ) FTS5 走 SQLite 内置,零依赖;Hindsight 端口 8890;gbrain 端口 8787。每层都是独立的可降级——向量服务挂了,全文搜索照样能跑。 真正干活的是这 40+ 工具 三层召回是检索层,采集层才是让知识库有东西可喂的入口。项目塞了 40+ 采集分析工具,按类型分: 网页采集(9 引擎) :Scrapling 做反检测,Crawl4AI 做智能路由,爬公众号不走弯路 视频采集(12 工具) :yt-dlp 拖流 → Whisper ASR 转写 → PaddleOCR 关键帧,抖音/YouTube 一把抓 文档分析(9 工具) :SenseNova 三件套(PDF/PPT/Word)处理扫描件和复杂排版 书籍精炼(6 工具) : book_to_skill 管线把 PDF/EPUB 拆成结构化 Skill + KMM 笔记 每周日凌晨还有个 knowledge_discovery.py 爬起来,扫 OneDrive 上的新笔记,自动录入 gbrain,顺便跑孤页链接修复——这些属于「你不需要知道它存在,但它让系统不腐烂」的基建。 几个工程取舍 不做纯向量优先 :FTS5 第一级是因为延迟低(毫秒级),且精确关键词匹配在查代码、查配置时远好于语义 gbrain 孤页处理是刚需 :知识图谱不加链接维护,三个月后 90% 的页面都成孤岛(亲测 10,666 页从 1,716 个孤页降到 33) 采集优先于检索 :没有好的采集管线,检索再强也是对着空库跑——项目把采集工具堆到 40+ 不是炫技 适用场景 如果你的 Agent 需要从多个来源(网页、视频、文档、公众号)持续摄入知识,并且知识需要在精确搜索、模糊回忆和关系探索三个维度上都能命中——三层模式值得一试。不需要全部部署,只接 FTS5 + gbrain 两层也能跑,每层独立可降级。 GitHub: mage0535/Knowledge-and-Memory-Management ,MIT 协议。
AI 资讯
Agents write code, but they don't remember
Code generation is solved, but memory isn't. Here's an argument for why the SDLC is inverting with intent becoming the spine and code becoming a layer you drill into, explaining what teams lose every time an agent's reasoning disappears.
AI 资讯
Meta is 'pausing' employee tracking program after it let the whole company see sensitive data
This won't make the already-controversial AI training endeavor any more popular.
开发者
Every Choice Changes Everything: The Show
submitted by /u/dwaxe [link] [留言]
科技前沿
A Source of Mysterious Repeating Radio Signals From Space Has Been Identified
Researchers say the discovery could be a “Rosetta stone” for cosmic signals.
工具
GM installs robots at flagship EV factory after laying off 1,300 workers
US autoworkers union warns of robot automation as dark factory future looms.
AI 资讯
I built a fully local AI assistant at 16 — no cloud, no API keys, runs on your GPU
I'm 16, from Pune, India. For the past couple of years I've been building O-AI — a fully local AI desktop assistant. No cloud. No API keys. No data leaving your machine. Everything runs on your own GPU. Why I built it Every AI assistant I tried sent data somewhere. ChatGPT, Copilot, Gemini — all cloud. I wanted something that felt like JARVIS from Iron Man: smart, fast, personal, and private. So I built it from scratch. What O-AI can do Core engine: Runs LLMs fully on-device via llama.cpp / Ollama (zero internet required) Self-learning core — extracts facts from every conversation and stores them permanently Fine-tuning pipeline — train the model on your own data, locally Voice & language: Voice control in English, Hindi, and Marathi via Whisper (running locally) Responds in whatever language you speak Modes: JARVIS mode — arc-reactor HUD, 4 reactive states, British-male voice, "sir" persona Take Over PC mode — full desktop automation Animated floating desktop pet (4 types, draggable, reacts to voice) 30+ automation fast-paths: open apps, search the web, control media, screen vision, run code, edit files, cursor control, social media steps, clipboard ops... Multi-step agent system: plan → execute → verify loop with 14+ step types (web_search, fetch_url, read_screen, run_code, edit_file, open_social, and more) Stack Backend: Python (Flask IPC + agent core) Frontend: Electron + vanilla JS LLM: llama.cpp / Ollama Voice: Whisper (local) + Edge TTS / neural voice Vision: PIL + screen capture The hardest bugs "Says done but isn't" — Early versions reported success even when an agent step failed. Fixed by building a proper outcome verifier that reads the actual result, not the plan. The "opens a random video" bug — Asking the agent to play something would open random YouTube videos. Root cause: the plan validator wasn't catching placeholder URLs like [video_url] . Fixed with a universal content guard on all plans. GPU offloading on Windows — Getting all 32 layers onto the
开发者
Ever had a renamed column quietly break a CSV export? csv-pipe makes it a compile error, reads and writes both ways, and parses several times faster than papaparse. Live playground in the post to try your own data.
csv-pipe: read and write CSV in TypeScript, several times faster than papaparse Myroslav Martsin Myroslav Martsin Myroslav Martsin Follow Jun 22 csv-pipe: read and write CSV in TypeScript, several times faster than papaparse # javascript # typescript # webdev # node 1 reaction Add Comment 2 min read
AI 资讯
Performance Reviews Fail Because Managers Forget What Happened
A few months ago, I noticed something uncomfortable about performance reviews: Even good managers often don't have the full picture. Not because they don't care. Not because they don't pay attention. But because humans are terrible at remembering months of small, important moments. A great customer interaction. A difficult problem someone solved. A teammate stepping up during an incident. A coaching conversation that changed someone's behavior. These things happen every week. Then review time arrives. Suddenly, managers have to answer: What did this person actually achieve? Where did they improve? What patterns have I noticed over time? Am I evaluating the whole period or just the last few weeks? And many end up reconstructing the story from: memory scattered notes documents spreadsheets calendar entries This creates a common problem: recency bias. The most recent events become the most visible events. The solutions managers build themselves When I talked to managers about this, I noticed a pattern. Everyone had created their own system: OneNote pages per employee spreadsheets with columns for each report personal documents weekly summaries AI-generated review drafts And honestly, many of these systems work. The problem isn't that managers don't know how to take notes. The problem is turning those notes into a reliable picture of someone's performance. The idea behind FeedbackVault I started building FeedbackVault to solve this specific problem. The idea: Capture observations when they happen → organize them over time → prepare better review conversations. Instead of starting a review cycle by asking: "How do I remember the last 6 months?" you start with: "Here is the story that happened over the last 6 months." The goal is not another HR platform. It's a lightweight way for managers to keep context. What I'm learning The biggest challenge isn't building software. It's adoption. A spreadsheet already works. A notes document already works. For a new tool to matter, i
开发者
Sentry vs OpenTelemetry: You Don’t Need to Pick One
TL;DR — If your backend already uses OpenTelemetry, you can send traces and logs to Sentry by changing a few environment variables. No SDK swap, no instrumentation rewrite. Point your OTLP exporter at Sentry’s endpoint, add the Sentry SDK on the frontend for browser context, and you get one connected trace from click to backend span. You already instrumented the backend with OpenTelemetry. Your services emit spans. Your teams know the OTel APIs. Maybe you already run a Collector. So when you start evaluating Sentry, the obvious question is: Do you need to replace your OpenTelemetry setup with the Sentry SDK? No. The practical answer is usually: keep OpenTelemetry where it already works, add the Sentry SDK where it gives you more application context, and send OpenTelemetry Protocol (OTLP) events to Sentry. For a web app, that often means using the Sentry SDK on the frontend for browser tracing, errors, logs , Session Replay , and source maps, while keeping OpenTelemetry on the backend for existing service instrumentation. One scope note: OTLP can carry traces, logs, and metrics. At this moment, Sentry’s OTLP ingest supports logs and traces, not metrics. We’re considering adding support for them in the future. The important part is separating two decisions that often get lumped together: How traces stay connected across frontend and backend. How backend OTLP events are exported to Sentry. Once you separate those, the architecture gets a lot easier to reason about. Sentry vs OpenTelemetry is the wrong question The first decision is trace linking. If a user clicks a button in your React app and that click triggers a backend request, the frontend and backend need to agree on the same distributed trace context. In this example, the Sentry frontend SDK sends W3C traceparent headers (configurable through the propagateTraceparent option), and the OpenTelemetry backend continues the trace. That linking is handled by the frontend SDK configuration: Sentry . init ({ integration
AI 资讯
Good Architecture Includes Observability
Good architecture is not only about how a system is built. It is also about how well the team can understand that system once it is running. That is where observability belongs in the architecture conversation. It is common for observability to be treated as something that comes after the main engineering work. The service gets built. The API works. The deployment succeeds. Then, somewhere near the end, the team starts thinking about logs, dashboards, alerts, and operational visibility. That approach creates a gap. The architecture may look clean on paper, but once the system is in production, the team has to understand how it behaves under real conditions. Real users do not follow the happy path perfectly. Dependencies slow down. Queues back up. Data arrives in unexpected shapes. Deployments change behavior in ways that are not always obvious. If the system does not give the team a way to see those things clearly, the architecture is incomplete. Observability is not decoration around the system. It is part of the system design. Architecture Describes the System. Observability Shows the Truth. Architecture is built on assumptions. During design, teams make reasonable guesses about usage patterns, service boundaries, dependency behavior, data flow, scale, latency, and failure modes. Some of those assumptions are based on experience. Some are based on current requirements. Some are simply the best call the team can make with the information available at the time. That is normal. The problem is not that architecture contains assumptions. Every architecture does. The problem is when those assumptions cannot be tested once the system is real. A design might assume that an external dependency will be reliable enough. Production may show that it is the slowest part of the request path. A queue might look like a clean decoupling point during design. Production may reveal retry behavior, duplication, or ordering concerns that were not obvious upfront. A serverless function m
AI 资讯
The First Text Message Said Merry Christmas
The first text message ever sent was not a love note, a meeting reminder, or a meme. It was a Christmas greeting. On December 3, 1992, a 22-year-old engineer named Neil Papworth sat at a desktop computer, typed two words, and sent the world's first SMS to a mobile phone: "Merry Christmas." More than thirty years later, that humble two-word message has grown into one of the most quietly important protocols in connected technology, and it still shows up in the IoT devices we build today. The engineer who sent the first SMS Neil Papworth was working for the Anglo-French firm Sema Group Telecoms, part of a team building a Short Message Service Centre (SMSC) for the British carrier Vodafone. The SMSC was the piece of infrastructure that would store and forward text messages across the cellular network. To prove it worked, Papworth sent a test message from a computer terminal to the Orbitel 901 handset of Richard Jarvis, a Vodafone director who was at a company Christmas party. The message arrived. Jarvis read it. But he could not reply, because mobile phones at the time had no way to compose a text. There was no keypad-driven messaging app, no T9, no touchscreen. SMS started life as a one-way novelty riding on a spare slice of the network's signalling channel, and almost nobody involved thought it would matter very much. Why SMS was designed the way it was The technical detail that makes this story relevant to anyone building connected hardware is how SMS was engineered. Text messages were squeezed into the control channel that phones already used to talk to cell towers, the same channel that handles things like call setup. That is why a single SMS is capped at 160 characters: it had to fit inside a small, fixed-size signalling packet. This constraint turned out to be a feature. SMS is lightweight, store-and-forward, and works even when a data connection is weak or absent. The message waits in the SMSC until the device is reachable, then gets delivered. No persistent con