AI 资讯
I built Skim: a free open-source Email client for Windows with BYOK AI (MIT)
I built Skim because I tried to find a Windows email client that doesn't suck that hard and couldn't really find one. It's not rocket science to vibecode one, right? Why has nobody done it before? Or is everyone just okay with bloated Outlook or archaic Thunderbird? Skim - free, open-source, MIT-licensed minimalistic offline-first email client with BYOK AI. Quick feature list: Installer under 5 MB Bring Your Own Key to enable AI features: Anthropic/OpenRouter, or any OpenAI-compatible server (including a local one) No menu. Minimalistic and contextual interface - buttons are shown only when you need them Keyboard-first controls: shortcuts for everything, no mouse needed Sweet warm zine design Super modest resource consumption AI features are pretty basic: Cowriter that can scan your recently sent emails, adopt your style, and then write emails and replies that sound like you "Ask this email" - chat with a particular email; it can read attachments and follow links inside it Agentic search across all connected inboxes; the "Ask your inbox" feature can scan your whole inbox One-click summarization and translation A few things I'm actually proud of under the hood The UI part is easy to vibecode. These bits were not. Getting the installer under 5 MB took real work. panic = "abort" alone dropped about 6 MB of unwind tables from the binary, that's 23% off the NSIS installer. I ship a single crypto backend (ring, with aws-lc-rs switched off) so I'm not compiling a second, unused crypto library into the thing. I even wrote a tiny Vite plugin that deletes legacy .woff fonts, since WebView2 always uses woff2 anyway. Pretty much every dependency in Cargo.toml carries a comment justifying its feature flags in kilobytes saved: rustls = { version = "0.23" , default-features = false , features = [ "ring" ] } # aws-lc-rs would compile a second, unused crypto library. ~2 MB of dead weight. No Electron, no bundled Chromium. Tauri 2 uses the system WebView2, so it installs per-user wit
开发者
The World's Oldest Communication Protocol Is Music
This is going to be a very different article from what I usually write. No technical discussions, architecture deep dives, or engineering practices today. Instead, we're talking about something much older than software itself: music. We treat language like it's the default mode of human communication, like it's the real and only thing used to communicate, everything else is secondary, emotional, aesthetic, nice to have. But language is actually the outlier. It's the new protocol layered on top of something much older. Music is the original standard and we've basically forgotten how to read it. The Protocol Stack Think of communication like a network stack. Language is high-level. It's TCP/IP. Built on assumptions, needs learning, breaks the second you cross a boundary. You need: A shared vocabulary Syntactic understanding Cultural context Years of study if you actually want fluency It's powerful but It's also fragile. And it's recent . Written language is a few thousand years old. Spoken language is older, sure, but both are late abstractions compared to the hundreds of thousands of years humans have been syncing bodies to shared sound. Relative to that timeline? Language is yesterday's patch. Music? That's the lower-level protocol. The physical layer everything else runs on. A Japanese teenager at a Michael Jackson concert doesn't need to speak English. She doesn't need to understand what "Man in the Mirror" means as a concept. She also doesn't need a music degree. Music isn't zero -cost. Genre, culture, convention still shape how we hear it. But the entry barrier for emotional communication is way lower. A rhythm can hit urgency, celebration, sadness, or tension long before anyone understands the formal structure behind it. Her nervous system speaks that fluently. And so does everyone else in that stadium. How the Protocol Works Here's what happens when the song starts: 70,000 people stop being individuals and start being a distributed system synchronizing to the
AI 资讯
Bio-Tuning Glasses: Building an Invisible Biofeedback Interface with Edge AI and Adaptive Optics
Bio-Tuning Glasses: Building an Invisible Biofeedback Interface with Edge AI and Adaptive Optics What if smart glasses didn't constantly tell you how healthy—or unhealthy—you are? No step counts. No stress notifications. No endless dashboards. No digital reminders telling you to "sit straight" or "go to sleep." Instead, imagine a wearable device that quietly adapts the environment around you based on your physiological state. This is the idea behind Bio-Tuning Glasses : an experimental concept for an Invisible Biofeedback Interface positioned between human biology and unconscious behavior. The goal is simple: Don't make the user adapt to the technology. Make the environment adapt to the user. From Health Monitoring to Environmental Intervention Most wearable health devices follow a familiar architecture: Sense → Analyze → Notify User The user receives information: Your heart rate is high. You are stressed. You haven't moved enough. Your sleep quality is poor. Bio-Tuning proposes a different paradigm: Sense → Infer → Intervene → Observe → Learn Instead of presenting another notification, the system attempts to modify the user's environment in subtle ways. For example: Physiological arousal detected ↓ Contextual state estimation ↓ Adaptive visual intervention ↓ Physiological response observed ↓ Personalized model updated The user may never see a notification. The intervention simply happens in the background. 1. Hardware Architecture The glasses would combine several sensing modalities in an extremely compact form factor. Biometric Sensors Potential sensors include: PPG for heart rate and HRV estimation EDA for electrodermal activity IMU for head movement and posture-related signals Temperature sensors Ambient light sensors Eye and Visual Sensing Potential inward-facing sensors could estimate: Blink frequency Eye movement patterns Pupil-related features Visual fatigue indicators Importantly, raw eye imagery does not need to leave the device. Instead: Raw Sensor Data ↓
AI 资讯
OhNine: Why I Built a Menu Bar App for Claude Limits
OhNine is a free menu bar app that tracks Claude session and weekly usage limits in real time It sends native alerts at 80%, 91%, and 100% so a session never ends without warning The hard problem was never reading a number, it was making the warning arrive before the cutoff instead of after Building a zero telemetry tool changed how I judge every product I ship after it The Problem: Hitting a Wall You Cannot See For months, my Claude sessions ended the same frustrating way. I would be deep in a conversation, mid thought, actually making progress, and then the reply would just stop. No countdown. No yellow light. No warning that said "you have three messages left, wrap up." One second I was working, the next I was staring at a message telling me to wait for a reset I never saw coming. The frustrating part was not the limit itself. Usage limits exist for a reason, and I understand why they are there. The frustrating part was the total lack of visibility into where I stood. Claude Code and claude.ai will occasionally mention you are close to a cap, sometimes at 97 percent, which is technically a warning and practically useless, because by then you are already mid-thought with no time left to land it cleanly. It got worse once I noticed the layers. There is not one limit to track, there are several stacked on top of each other: a session limit, a rolling weekly cap, and separate caps depending on which model you are running. Switching models mid-session, thinking you had found a workaround, only to hit a wall from a different direction, was its own specific kind of frustrating. None of these layers showed up anywhere. There was no dashboard, no menu bar icon, nothing you could glance at the way you glance at your laptop's battery percentage before deciding whether to plug in. So the wall kept arriving the same way: mid-flow, mid-sentence, with zero warning. Coding sessions got cut off between a question and its answer. Writing sessions lost momentum at the worst possibl
开发者
I Spent 3 Weeks Debugging Rate Limits Before I Realized the Problem Wasn't My Code
Ever chased a bug for days, only to discover the "bug" was actually the platform working exactly as designed? That happened to me building a client reporting pipeline. The lesson stuck. Here's what nobody tells you about pulling marketing data from multiple ad platforms: the hard part was never the dashboard. It was everything underneath it. The Setup That Looked Simple on Paper The brief sounded easy. Pull spend, clicks, and conversions from Google Ads and Meta. Store it. Display it in a chart. A junior dev could knock this out in a sprint, I figured. Reality disagreed. Google Ads API enforces operation quotas per developer token, and those quotas scale differently depending on account tier. Meanwhile, Meta's Marketing API throttles based on a rolling usage score tied to the ad account itself, not your app. Two platforms. Two completely different throttling philosophies. Neither documented in a way that made the actual limits obvious until you hit them in production. Where Things Actually Broke My first version polled every client account every hour. Fine for three clients. Then we onboarded client number twelve, and Meta started returning 429s intermittently. Not consistently — intermittently. That's the worst kind of bug. I initially assumed it was a code issue. Retry logic, maybe a race condition in my job scheduler. I spent three weeks going down that path. Eventually, I found the real cause: cumulative API call volume across all client accounts was tripping Meta's app-level rate limit, not the individual account limit. The fix wasn't more retries. It was a request queue with exponential backoff, plus a priority system so active dashboards refreshed before idle ones. Simple in hindsight. Expensive in dev hours. The Real Architecture Behind Multi-Platform Reporting If you're building this yourself, here's what a production-grade pipeline actually needs, based on what broke for me. A Queue, Not a Cron Job Don't just fire off API calls on a schedule and hope for t
AI 资讯
2 Free Browser-Based Tools I Use Instead of Installing CLI/Desktop Converters
As developers, we end up needing to convert or resize a file constantly — a screenshot that needs to be a PNG for docs, an asset that needs to hit exact social-preview dimensions, a PDF that needs merging before a demo. Reaching for ffmpeg , imagemagick , or a paid SaaS every time is overkill for a one-off task. Here are two free, no-signup web tools that cover most of that day-to-day friction. 1. FreelyConvert — general-purpose file conversion freelyconvert.com A browser-based converter covering documents, images, video, and audio: 500+ formats — PDF, DOC/DOCX, images (JPG/PNG/GIF/BMP/SVG/WEBP), video (MP4/AVI/MOV/MKV), audio (MP3/WAV/FLAC/AAC), spreadsheets, presentations No account/signup — upload, convert, download Batch conversion for multiple files in one pass Auto-delete after 24 hours and SSL encryption in transit Useful specifically for: PDF ↔ image conversions ( pdf-to-jpg , images-to-pdf ) Merging PDFs without touching a CLI tool Compressing video/audio for quick sharing Quick image compression when you don't want to script it 2. ImageResizer.dev — client-side image resizing/conversion imageresizer.dev This one's worth calling out for devs specifically: it runs entirely client-side via the Canvas API — nothing is uploaded to a server. That's a real difference if you're resizing anything you'd rather not send off-device, and it also means it's fast (no upload/download round trip). Features: Exact dimension presets for social platforms (Instagram, LinkedIn, X/Twitter, YouTube, TikTok, Pinterest, WhatsApp) — handy for generating OG images or social preview assets without hardcoding dimensions yourself Format conversion across JPG, PNG, WebP, AVIF, BMP, GIF, SVG Crop, flip, upscale , plus bulk resize/compress for batches Aspect-ratio locking to avoid distortion No account, no watermark Good fit for generating og:image assets, favicon prep, or resizing screenshots for a README without spinning up a script. Why bother mentioning these Neither requires an accoun
AI 资讯
I Built a Self-Hostable URL Shortener Because Bitly Now Charges $10/Month for Basic Links
In 2023, Bitly's free plan gave you 100 links per month with full analytics. In 2025, they slashed it to 5 links per month . Five. And they started showing full-screen interstitial ads before redirecting — even on links you created years ago. In 2026, their cheapest paid plan is $10/month — just to shorten links without ads. I was paying $120/year to turn long URLs into short ones. A problem that takes 3 lines of code to solve. So I solved it myself. For free. Forever. Introducing ZipLink ZipLink is a fast, self-hostable URL shortener built with Next.js and Firebase. Deploy it once, use it forever. No monthly fees. No link limits. No ads. No "upgrade to unlock analytics." Your links. Your data. Your domain. Your rules. https://yourdomain.com/abc123 → https://some-really-long-url.com/path/to/thing?utm=whatever That's it. That's the product. Except you own it completely. The State of URL Shorteners in 2026 (It's Embarrassing) Let me show you what the "industry leaders" are charging for what is essentially a database lookup: The Comparison Table Feature Bitly Rebrandly Short.io Dub.co TinyURL Pro ZipLink Monthly cost $10-$300/mo $13-$349/mo $19-$149/mo $24-$299/mo $9.99/mo $0 Annual cost $96-$2,388/yr $156-$4,188/yr $228-$1,788/yr $288-$3,588/yr $119.88/yr $0 Free tier links 5/month 10/month 1,000 total 25/month Unlimited (no analytics) Unlimited Custom domain Paid only Free (1 domain) Required Paid only Paid only Yes (yours) Click analytics Paid only Paid only Free (basic) Paid only Paid only Full, free Link expiration Paid only Paid only Yes Yes No Yes Password protection Enterprise only Paid only Paid Paid No Yes API access Paid only Paid only Yes Yes Paid Full, free QR codes 2 free, then paid Paid Yes Paid Paid Unlimited Self-hostable No No No Yes (complex) No Yes (simple) Data ownership Their servers Their servers Their servers Their servers Their servers Your Firebase Ads/interstitials Yes (free tier) No No No Yes (free tier) Never Links disappear if you stop pay
AI 资讯
#21 So, What's Your First One?
Before I hand this over, I want to tell you where I'm actually standing right now. I'm looking at the biggest mountain yet: building our hospital's own ERP and EMR — the systems that run the business side and the medical records side of the whole place. That's usually the job of specialized companies, and it's tangled up with outside regulators too. Nobody knows how long it'll take. I'm assuming at least three years. Honestly, it feels overwhelming. The size of the fear hasn't changed. My grip on it has. Here's the strange part. That overwhelmed feeling isn't unfamiliar at all. A year ago, staring at a blank screen and not knowing what code even was, I felt exactly this lost. What's different isn't the size of the fear. It's that I now know what to do with it. Get curious, look it up. Look it up, a direction shows up. See a direction, find a method, and just start. Fail, and you've learned something. Succeed, and you move to the next thing. That loop is the only thing that ever carried me anywhere , and it's the same loop I'm running at the foot of this much bigger mountain. Right now the wall isn't technical The thing I don't know isn't code. It's other departments. I moved from the treatment room to the planning office not long ago, and I still don't really know how the other departments do their work. You can't automate what you don't understand. So before anything else, I'm doing the one thing that actually comes first: listening. Hearing what people in the field actually need, what's grinding on them, and figuring out the shape of a fix together, one conversation at a time. I've noticed something before, more than once: problems that look completely different from the outside — counting a stack of forms, tracking down misplaced supplies, sorting a pile of ID cards — usually reduce to the exact same shape underneath. Make the pile of things findable. I suspect the same pattern is waiting inside every other department too. I just haven't looked yet. That's how I
AI 资讯
AI Agents Inside CI/CD: How We Automated PR Triage and Reduced Review Bottlenecks
Over the past few months, I've been exploring how AI agents can fit into a modern CI/CD pipeline—not to replace engineers, but to eliminate repetitive work that slows teams down. Here's what worked well: ✅ Automatically categorized incoming pull requests ✅ Flagged potential security and dependency issues ✅ Suggested fixes for linting and test failures ✅ Generated review summaries for faster code reviews ✅ Reduced context switching for reviewers The biggest lesson? AI is most valuable before the human review begins. The Problem Every engineering team eventually runs into the same issue. Developers submit pull requests faster than reviewers can process them. A typical PR often goes through several repetitive steps: CI builds Unit tests Linting Dependency checks Security scanning Style comments Reviewer assignment Documentation validation None of these tasks require deep architectural thinking, yet they consume valuable engineering time. I started wondering: What if an AI agent handled the first round of triage automatically? The Workflow Instead of waiting for a human reviewer, the pipeline lets an AI agent inspect every pull request immediately after CI starts. Developer │ ▼ Pull Request Created │ ▼ CI Pipeline Starts │ ▼ AI Agent ├── Analyze changed files ├── Review commit summary ├── Detect risky changes ├── Check coding standards ├── Explain failing tests ├── Suggest fixes └── Generate PR summary │ ▼ Human Review By the time a reviewer opens the PR, much of the routine analysis is already complete. Example GitHub Actions Workflow A simplified workflow might look like this: name: AI Pull Request Review on: pull_request: types: [opened, synchronize] jobs: ai-review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Tests run: npm test - name: Run Linter run: npm run lint - name: AI PR Analysis run: ./scripts/ai-review.sh The AI step can analyze: Test failures Lint violations Changed files Security findings Dependency updates before publishing a r
AI 资讯
How to Convert Bank Statements to CSV (Without Losing Data Accuracy)
If you've ever tried converting a bank statement PDF to CSV and ended up with a jumbled mess of merged cells, missing rows, or split transaction descriptions — you're not alone. This is one of the most common data pain points for accountants, bookkeepers, and anyone who does their own finances. In this post, I'll walk through why this happens, what the right approach looks like, and how to get clean, analysis-ready CSV output from any bank statement. Why Bank Statement PDFs Are So Hard to Parse Bank statements aren't structured documents — they're designed for printing, not data extraction. Here's what generic converters run into: Merged cells : PDF renderers often group date + description + amount into a single visual block. Naive converters pick one cell boundary and split it wrong. Multi-line transactions : A single transaction entry (especially with memos) can span 2–3 lines in the PDF, but gets split into separate rows in the spreadsheet. Negative vs. positive amounts : Debit/credit columns vary by bank.Chase uses a single "Amount" column with negatives for debits. BoA uses two separate columns. A generic converter treats them identically and produces wrong signs. Running balance drift : If even one row is misaligned, every balance figure below it is off. Method 1: Manual Copy-Paste (What You're Probably Doing Now) The baseline. Open the PDF, select all, paste into Excel, then spend 30 minutes fixing column alignment. Pros: Free, no tools required. Cons: Slow (20–40 minutes per statement), error-prone, completely unscalable if you have multiple accounts or months to process. Method 2: Python + pdfplumber For developers who want a scriptable solution: import pdfplumber import csv with pdfplumber . open ( " statement.pdf " ) as pdf : rows = [] for page in pdf . pages : table = page . extract_table () if table : rows . extend ( table ) with open ( " output.csv " , " w " , newline = "" ) as f : writer = csv . writer ( f ) writer . writerows ( rows ) This works reas
AI 资讯
Sovereign Lemmings Released
I have released the Sovereign package on Github. It deploys Lemmings into up to 3 cloud regions for your choice in configuration flavor with cost estimations through dry-runs and aggregating the report into one final report as lemmings come and go in the result of the load test. I built it for organizations that plan on using AI to build something, not hire somebody like me who helped write The Library to do it for them. You can hire me in consulting if you need help, but it's available now. But, before you spend $50,000 on a television ad driving people to your new app that you just built after spending $50,000 on tokens, why not run Lemmings and Sovereign first? It's 100% free and does not involve me at all in order for you to read through the extensive README.md files and comments in the code for you to understand what to do to run it and adapt to its results. Enjoy using it! There - that is the post. Now - 🙌🏻 - Ask me anything 🙇🏻 👇🏻
AI 资讯
Python's Object Model in Depth: Why Two Lines That Look the Same Behave Differently
Two lines of code. Same variable. Same operator. Completely different behavior. a = [ 1 , 2 , 3 ] b = a b += [ 4 ] # line A print ( a ) # [1, 2, 3, 4] x = 1 y = x y += 1 # line B print ( x ) # 1 Line A changes a . Line B does not change x . The only difference is whether the variable holds a mutable or immutable object. To understand why this happens, you need to understand how Python actually represents variables internally. Variables Are Not Boxes The box metaphor is how most introductory programming courses explain variables: a variable is a box that holds a value. You put 5 into the box called x . Later you can replace it with 10. In Python this metaphor is accurate for immutable types and dangerously misleading for mutable types. The more accurate model: a Python variable is a name that is bound to an object. The object exists independently of the name. Multiple names can be bound to the same object. Binding a name to a new object does not affect the old object or other names that reference it. You can inspect this directly: a = [ 1 , 2 , 3 ] b = a print ( id ( a ) == id ( b )) # True -- same object, two names x = 5 y = x print ( id ( x ) == id ( y )) # True -- both point to integer object 5 Both cases start the same: two names pointing to the same object. What happens next depends on whether you mutate the object or rebind the name. Two Fundamental Operations Every operation on a Python object falls into one of two categories. Mutation : the object at a given memory address is modified. All names pointing to that address see the change. Rebinding : a name is pointed at a different memory address. Other names pointing to the original address are unaffected. List methods like .append() , .extend() , .sort() , and item assignment lst[i] = x are mutations. Assignment with = is rebinding. The += operator is either mutation or rebinding depending on whether __iadd__ is implemented and the object is mutable. Tracing Through the Object Graph a = [[ 1 , 2 ], [ 3 , 4 ]]
AI 资讯
I ran 3 months of spec-driven development without ever reading the code
I'm a scrum master. I was a developer ten years ago. I have enough background to discuss design and trade-offs with an LLM — but three months ago I made a deliberate bet on my solo project: I would never read the code. The specs define the tests. The tests control the code. The code is a black box. I'm not claiming this is what everyone should do. But it's my bet, and it forced a system into existence: when nobody reads the code, the process has to carry the trust that a code-reading human normally provides. I've just published that system as a reference implementation: backlog-as-data — the full writeup, the Claude Code skills translated to English, and the CLI source, verbatim from my daily setup. Here's the short version. The backlog is git data, not a document Most agent task-management tools store tasks in a dedicated place — a tasks.json , a database, a backlog/ folder. My bet is different: the backlog is the YAML frontmatter of my spec files. One file per ticket, and the ticket's status is a field — never a location in a document. --- id : PARSE-07 title : Tolerate CRLF in decklist import type : ticket status : todo priority : should exec : model : sonnet effort : think review : light matured : 2026-07-22 --- # PARSE-07 — Tolerate CRLF in decklist import The spec body: design, contracts, test cases. The ticket file IS the spec. Everything below the frontmatter is the spec — written by the LLM, after it has challenged the need I expressed in conversation. The frontmatter is data — owned by a small CLI, mutated only through it. Same file, so they can never drift apart. Why it matters: "move it to Done" is not an operation. LLMs (and humans) mangle documents when a state change means relocating text. Making status a field makes every transition a one-line, idempotent, testable mutation. The board I look at (a small web page on my server, with GitHub deep links to each spec) and the readable markdown view are generated projections , locked by a do-not-edit sentin
AI 资讯
citesure 0.2: CourtListener case law and CJK title matching
LLM-written bibliographies do not stop at arXiv preprints. Law review drafts invent reporter cites; multilingual papers mangle Chinese titles. citesure 0.2 extends the integrity gate into those failure modes. US case law via CourtListener References that look like court cases — @jurisdiction entries, Plaintiff v. Defendant titles, or reporter strings such as 347 U.S. 483 — are resolved against Free Law Project CourtListener. Ranking prefers an exact reporter cite over companion orders, so Brown lands on 347 U.S. 483 rather than a later procedural listing. @jurisdiction { brown1954 , title = {Brown v. Board of Education} , year = {1954} , howpublished = {347 U.S. 483} , } citesure check examples/packs/us-case-law.bib citesure warm-cache cases.bib Optional COURTLISTENER_TOKEN for higher rate limits. Law-review CI: templates/journal/law-review.yml . CJK-aware matching NFKC + fullwidth folding; character-level similarity for CJK-heavy titles; CJK bigrams in claim scoring so Chinese claims are not silently empty. Evidence Integrity bench 242/242 (US cases + Chinese titles + multi-domain set) Claims mini-bench 29/29 Eight domain packs including us-case-law Install pip install "git+https://github.com/SybilGambleyyu/citesure.git[pdf]" Source: github.com/SybilGambleyyu/citesure · Demo: workers.dev
AI 资讯
I built SwiftNotch: a productivity dashboard for the MacBook notch
The notch on a MacBook is strange real estate. It is always there. It sits at the top of the screen, close to the menu bar, close to system controls, close to whatever you are doing. But most of the time it is treated like a cutout to design around instead of a place software can use. That felt like a missed opportunity. So I built SwiftNotch , a macOS menu bar app that turns the notch area into an expandable productivity dashboard. Hover near the notch or press Option + Space , and the quiet black shape becomes a small command center for widgets, files, media, shortcuts, developer tools, and window actions. Website: swiftnotch.xyz Demo video: Launch note: SwiftNotch 1.x is free during beta . I want early Mac users to try the full experience, share feedback, and help shape the app before SwiftNotch 2.0 introduces paid plans. The idea I did not want to build another large dashboard that asks you to leave your current app. The goal was the opposite: make useful tools available in the smallest possible space, without breaking flow. The notch is perfect for this because it already behaves like a visual anchor. You know where it is without thinking. If it can expand only when needed, it becomes a temporary interface layer instead of another permanent panel. SwiftNotch starts collapsed. When activated, it opens into a compact dashboard with the widgets and actions you choose. What SwiftNotch does The current app includes 31 built-in widgets across productivity, system utilities, media, automation, and developer workflows. Some examples: Media Control for Spotify, Apple Music, VLC, YouTube, and browser players Shelf for drag-and-drop file staging, quick sharing, paths, iCloud actions, and zip workflows Clipboard History for snippets, links, and quick paste Calendar Events , Reminders , Notes , Weather , World Clock , and Pomodoro Quick Toggles for Wi-Fi, Bluetooth, Dark Mode, and volume Window Snapping with layouts for halves, thirds, quarters, and custom grids Developer H
AI 资讯
One folder shape for every course: a lifecycle monorepo convention
TL;DR I merged several training courses into one monorepo and gave every course the same numbered folder shape : 00-planning → 04-post-training . A _TEMPLATE/ you copy to start the next one, an _ARCHIVED/ you park old stuff in, and a CLAUDE.md that makes the convention machine-readable. The trick that makes it stick: templates use <angle-bracket-slots> , and "done" is a grep that returns nothing. I had course material scattered across repos — planning notes here, marketing copy there, facilitator run-sheets in a third place. Every new course started from a blank page, and I re-invented the folder layout each time. So I collapsed everything into one monorepo with a single rule: every course has the identical shape. The lifecycle, as folders The insight isn't "use folders" — it's that a course has a lifecycle , and numbered folders make that lifecycle the primary axis instead of file type. Plan it, sell it, teach it, run it, follow up. Five stages, always in order: Folder Stage What lives here 00-planning/ Prepare Syllabus (source of truth), specs 01-marketing/ Sell Positioning master + channel assets 02-content/ Teach Modules, one file each 03-delivery/ Run Run-sheet, pre-flight checklist, fallback plan 04-post-training/ Follow up Feedback form, follow-up email, post-mortem The numeric prefix isn't decoration. It forces sort order to match the actual workflow, so the folder listing reads like the process itself. Same reason migration files are timestamped — order is information. <course>/ 00-planning/ -> derives everything below 01-marketing/ 02-content/ 03-delivery/ 04-post-training/ --. post-mortem findings | ^------------------' feed back into 00..03 That loop at the end matters: the post-mortem doesn't sit in a graveyard folder. Its findings flow back into the syllabus, the run-sheet, the marketing. The structure runs the same feedback loop it's supposed to teach. _TEMPLATE/ : a course starts as a copy Starting a new course is one line: cp -r _TEMPLATE my-new-cou
AI 资讯
#02 – Encapsulation & Abstraction in Python
Welcome to Day 2! Today we focus on two core pillars of Object-Oriented Programming: Encapsulation: Hiding internal state and requiring all interaction to go through performing validation or controlled methods. Abstraction: Hiding complex implementation details and exposing only a clean, simplified interface to the user. 1. Access Modifiers: Public, Protected, & Private 🛡️ Python does not have strict enforcement keywords like public or private found in Java or C++. Instead, it uses naming conventions and name mangling to communicate intent and protect internal data. ┌─────────────────────────────────────────────────────────────────────────────┐ │ ACCESS MODIFIERS IN PYTHON │ ├──────────────┬───────────────┬──────────────────────────────────────────────┤ │ Level │ Syntax │ Scope / Intended Access │ ├──────────────┼───────────────┼──────────────────────────────────────────────┤ │ Public │ self.name │ Accessible anywhere (inside & outside class) │ │ Protected │ self._balance │ Internal & subclasses only (Convention) │ │ Private │ self.__pin │ Class internal only (Triggers Name Mangling) │ └──────────────┴───────────────┴──────────────────────────────────────────────┘ Public ( self.name ): Fully accessible from anywhere. Protected ( self._balance ): Single leading underscore. Signals to developers: "This is internal—do not mutate or access outside this class or its subclasses." Private ( self.__pin ): Double leading underscore. Triggers name mangling ( _ClassName__attribute ), making it hard to accidentally access or override outside the class. 💻 Code Example: Access Modifiers & Name Mangling class SecureVault : def __init__ ( self , owner : str , balance : float , pin_code : str ): self . owner = owner # Public self . _balance = balance # Protected (convention) self . __pin = pin_code # Private (name mangled) def verify_pin ( self , pin : str ) -> bool : return self . __pin == pin vault = SecureVault ( " Alice " , 50000.0 , " 9876 " ) # Public access works as expected
AI 资讯
whoimports: who still imports this Python module?
Before you rename, move, or delete a Python module: who still imports this? Grepping hits strings and comments. Importing the package can run side effects. whoimports walks the tree with the AST and prints every matching import / from … import line. Install pip install git+https://github.com/SybilGambleyyu/whoimports.git Usage whoimports src/auth/session.py whoimports auth.session -f json whoimports pkg.util -f md Notes Zero dependencies, Python 3.10+ File paths and dotted module names Understands src/ layouts text / markdown / JSON output Pairs with gitchurn and redactx for safe refactor context. Source: github.com/SybilGambleyyu/whoimports · MIT
AI 资讯
logsnip: cut CI noise, keep the stack traces
Cut the noise. Keep the stack traces. CI logs are mostly package installs. The failure is a few dozen lines buried under thousands of Downloading… lines. Scrolling for the real stack trace is a tax paid on every red build. logsnip is a zero-dependency Python CLI that extracts those failure regions and collapses the rest. Install pip install git+https://github.com/SybilGambleyyu/logsnip.git # or the whole toolkit: curl -fsSL https://raw.githubusercontent.com/SybilGambleyyu/devkit/main/install.sh | bash One-liners # Last failure from a GitHub Actions run gh run view --log-failed | logsnip --last # Headlines only logsnip ci-full.log --summary # Safe to paste into an AI assistant gh run view --log-failed | logsnip --last | redactx What it matches Built-in patterns cover pytest E lines and AssertionError , npm ERR! , rustc error[E…] , TypeScript error TS… , GitHub Actions ##[error] , make failures, and common exit-code messages. Stack frames after a hit are pulled in automatically. Design No network, no config files, no dependencies — pipe-friendly --check exits 1 when error-like lines appear (CI gate) --json for machines; --summary for humans in a hurry Pairs with redactx before anything leaves your machine Source: github.com/SybilGambleyyu/logsnip · MIT
AI 资讯
The Language Barrier That Made Me Use AI Better
I came to dev.to to translate. I stayed to steal. I mean that as the compliment it is here. On this site, "I'm stealing that line" is something you say to an author's face and they thank you for it. Ideas are meant to be lifted, reused, carried home. It took me a while to understand that culture — because I didn't arrive as a thief. I arrived as a tourist who couldn't read the signs. Here's the setup. I'm Korean. My English is workable but slow, and writing a comment good enough to earn a real reply from a stranger — in a second language, in a technical field I never trained in — is more than I can do alone at a speed I'd tolerate. So when I started reading and commenting here, I opened an AI beside me and used it the obvious way: as a translator. Read the post, get the gist, draft a reply, fix my English, post it. That was the whole plan. It lasted about a week. The moment the tool changed jobs What broke the plan was that the posts were good . Not content-farm good — actually good. People writing honestly about the thing that broke at 3am, the assumption that quietly rotted, the fix they were embarrassed they'd missed. I'd come for a translation and I'd leave with an idea lodged in my head that had nothing to do with the words. At some point — I don't remember deciding it — I stopped asking my AI to just translate the post, and started asking it something else: "Is there anything in here we should actually be using?" That question changed what the tool was. A translator turns one language into another. What I'd started doing was turning someone else's hard-won lesson into a change in my own system — and the AI wasn't a dictionary for that job. It was the thing that read the post, understood my setup, found the overlap, and then — the part that still surprises me — built it and tested it. That's the theft this series is named for. Not the words. The lessons. From translator to research partner, in three steps Looking back, the tool climbed through three jobs, and I