惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
博客园 - 三生石上(FineUI控件)
S
Securelist
U
Unit 42
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Simon Willison's Weblog
Simon Willison's Weblog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
T
Tenable Blog
The Hacker News
The Hacker News
The Register - Security
The Register - Security
IT之家
IT之家
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
P
Privacy & Cybersecurity Law Blog
博客园_首页
T
Tailwind CSS Blog
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
T
Tor Project blog
C
CERT Recently Published Vulnerability Notes
Apple Machine Learning Research
Apple Machine Learning Research
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
A
Arctic Wolf
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
V2EX
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
V
Visual Studio Blog
月光博客
月光博客
爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
G
GRAHAM CLULEY
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Heimdal Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
The YAML bug that taught me what bidirectional sync between Claude Code and Codex actually costs
MAXX · 2026-05-12 · via DEV Community

The Codex agent had no name

The sync ran clean. Exit code 0. The skill file I'd authored on the Claude side showed up at the matching path on the Codex side, byte-for-byte where I expected it. I opened the Codex agent picker and the entry was there, but its name was the empty string. Just a blank row.

I assumed I'd mis-named something on disk. I hadn't. The file had name: code-review at the top, in plain YAML frontmatter, exactly the way Claude writes it. The string was right there. The Codex parser was just refusing to see it.

The culprit was one line three rows down: globs: **/*.{js,ts}. Claude's YAML loader is lenient. It reads the value as a string and moves on. Codex uses a strict YAML 1.2 parser, which sees the leading * as an alias anchor, fails to parse the scalar, and silently drops the entire frontmatter block. Every field, including name, goes empty.

The fix is one substitution. The file had an inline helper that decided whether to quote a frontmatter scalar:

function serializeFrontmatterScalar(value) {
  const text = String(value);
  if (/[:#"\n]/.test(text)) return JSON.stringify(text);
  return text;
}

Enter fullscreen mode Exit fullscreen mode

Four characters. That regex covers four of the nineteen YAML 1.2 c-indicators. The other fifteen, including the * from my glob, sail through unquoted and the strict parser breaks. The replacement is a single shared module at bin/util/yaml-scalar.mjs and a one-line call site. The relevant rule in CLAUDE.md now reads, in parentheses, (this has actually happened). I added that parenthetical when I wrote the rule, because by then it had.

This isn't a YAML quirk story. It's what bidirectional sync between two parsers actually costs, and the cost shows up in the most boring place possible.

What "bidirectional" actually means

I keep having to explain this to people who hear "config sync" and picture a one-shot migration wizard. That isn't the shape of the problem.

Both tools are running. I edit a Claude skill on Monday, I edit a Codex MCP server config on Tuesday, and by Wednesday the two surfaces have drifted in independent directions. Neither side is the source of truth. Each side needs to keep being valid on its own parser. The job isn't "export from A, import to B." The job is "keep A and B in agreement, in both directions, on a config surface that overlaps but doesn't match."

That surface is wider than people think. Instructions (CLAUDE.md and AGENTS.md). Skills with frontmatter. MCP servers. Permissions. Hooks. Same concepts, different file paths, different vocabularies (Read and Bash on one side, spawn_agent and codex exec on the other). The CLI I built treats this as a diff problem first and a translation problem second:

ai-config-sync status
ai-config-sync sync --dry-run
ai-config-sync sync --apply

Enter fullscreen mode Exit fullscreen mode

No wizard. No magic. You look at the diff, you decide.

Two parsers, one frontmatter

Here is the rule I wrote into CLAUDE.md after the bug, copied verbatim from the project doc:

Forbidden to write your own quote/escape logic. Forbidden to judge indicators directly with regex.
Reason: guarantee Claude (lenient YAML) ↔ Codex (strict YAML 1.2) round-trip. If even one site uses its own quoting, the strict parser fails to parse the entire frontmatter and fields like name go missing (this has actually happened).

That rule reads strict because it has to. The whole reason the bug existed was that the file had grown a one-off serializeFrontmatterScalar function tucked next to a frontmatter writer, and nobody (including me) noticed it didn't cover the full c-indicator set. The next time someone, possibly an AI assistant editing the file, reaches for the same convenience, the rule needs to stop them.

The shared utility lives at bin/util/yaml-scalar.mjs. Forty-two lines. Two exported functions. Here are the three regexes that do the work:

const RESERVED_INDICATOR_PREFIX = /^[-?:,[\]{}#&*!|>'"%@`]/;
const YAML_BOOL_NULL = /^(?:null|Null|NULL|~|true|True|TRUE|false|False|FALSE|yes|Yes|YES|no|No|NO|on|On|ON|off|Off|OFF|y|Y|n|N)$/;
const YAML_TIMESTAMP = /^\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}(?::?\d{2})?)?)?$/;

Enter fullscreen mode Exit fullscreen mode

The first one is the c-indicator set: nineteen characters, every one of them a structural sentinel in YAML 1.2. That's the regex the old four-character version was a draft of. The second covers YAML 1.1 boolean and null coercion, including the single-letter forms y, Y, n, N that strict parsers will quietly turn into true/false if you leave them bare. The third catches ISO timestamps, because 2014-12-31 as an unquoted scalar becomes a Date object in some parsers and a string in others, and that disagreement is its own class of bug.

The trigger frontmatter for the original bug was this:

---
name: code-review
globs: **/*.{js,ts}
---

Enter fullscreen mode Exit fullscreen mode

Claude reads it. Codex sees **, classifies * as an alias anchor, and discards the block. After the fix, the writer wraps **/*.{js,ts} in double quotes and both parsers agree the value is a string.

The split between the two exported function names matters to me. yamlScalarRequiresQuoting answers a yes/no question. serializeYamlScalar does the wrap. Callers can query without serializing, which is how tests/yaml-scalar.test.mjs gets to assert directly on the predicate. One of the test cases there is the https://x case: a colon followed by a slash (not whitespace) stays plain-safe per YAML 1.2, and the utility correctly does not over-quote it. That's the kind of edge the four-character regex never knew it was missing.

One 8,803-line file

Yes, 8,803 lines in one file is a smell by every standard rubric I'd apply to someone else's code. If a junior eng handed me this in review I would ask, with feeling, why.

Here's what's in it: a diff engine, a plan/apply loop, the paraphrase engine that rewrites Claude-strict tokens into Codex-strict tokens and back, a TOML patcher for ~/.codex/config.toml, a connect installer that wires the host-launcher into either side's plugin path, a reference generator, an agent mapper, a rule loader. All cross-cutting. All sharing state. All built on top of zero external runtime dependencies, which is the constraint that holds the rest of the structure.

That constraint is load-bearing. The full import surface of the main file is node:fs, node:child_process, node:crypto, node:os, node:path, node:readline, node:url, plus the one internal util. There's no bundler in the build. npm run build:dist copies files and injects a thin launcher; it doesn't transpile or bundle anything. Splitting the monolith into ten files means either (a) shipping ten files in the npm package and managing the import graph by hand across them, or (b) adding a bundler, which adds a devDependency and a build step that has to keep producing byte-identical output. The single file makes install trivially flat, the audit surface trivially small, and the diff against any prior version trivially readable.

That's the frame. Now back to why two parsers disagreeing is the part that actually bites.

bin/util/yaml-scalar.mjs is the first extraction. Forty-two lines, two functions, the smallest possible first step out of the monolith. CLAUDE.md says it directly: Splitting bin/ai-config-sync.mjs is on hold. That's not "we'll get to it later." That's "the next extraction has to earn its own file, the way the YAML one did, by being a real shared contract."

The honest cost: parts of the TOML and rule parser are regex-based and hand-rolled. The architecture notes in .claude/docs/repo-analysis/ already flag this. Regex parsing of mostly-structured input works until it doesn t, and when it doesn t, the failure mode looks exactly like the **/*.{js,ts} story above. That's the price of "zero deps" applied to parsing, and I'm paying it knowingly. If I had to guess where the next yaml-scalar.mjs-shaped extraction comes from, it's the TOML side, and it'll be because some real config in the wild produces a parse mismatch I didn't anticipate. The trigger for the YAML extraction was a real bug, not a refactoring mood. I expect the next one to arrive the same way.

I might be wrong about all of this. There's a version of the project where the monolith gets split into a dozen files now, before any more cross-cutting state piles up, and that version is probably easier to onboard contributors to. But it would buy that ease by adding a bundler or a multi-file ship, and neither of those changes makes the YAML bug go away. The bug was in the contract between two parsers, not in the file layout.

Where this lands

The project is v0.1.0. Two known debts are named explicitly in the repo's own architecture notes: the monolith hasn't been split, and the Codex plugin installer has been corrected several times because the plugin spec on that side is still moving. Neither one is solved. Both are the kind of debt you accept when you're trying to ship a usable CLI against two tools that are themselves changing under you.

What the YAML fix actually showed me is that the hard part of bidirectional sync is not the diffing. The diffing is the easy part. The hard part is making serialized output survive both parsers without either one quietly eating a field. bin/util/yaml-scalar.mjs isn't a refactor of old code. It's the first shared contract between the two parse environments, written down as forty-two lines that both sides have to agree on. Every future extraction from the monolith will probably look like that one: small, ugly, named for the bug that made it necessary.

The first extraction took 42 lines. The next one will probably take longer.

https://github.com/slash9494/ai-config-sync-manager