You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This week’s aroma profile is burnt abstractions, stale config handling, and a top note of “just one more special case, bro.” 🤮 The repo is not beyond saving, but it is doing that charming thing where every new feature appears to have been installed with a shovel instead of a design. Delightful.
💩 Broken config files get treated like optional fan fiction, which risks silently overwriting real user state with empty defaults.
When ruler.toml, native MCP JSON, or firebender.json is malformed, the code often shrugs, returns {} or { rules: [] }, and carries on. That is spectacularly forgiving in the worst possible way: a user typo can turn into “merge with empty config and write it back,” which is how software politely vandalizes files while pretending to help.
This is a robustness problem and a trust problem. Missing files (ENOENT) are fine; invalid files are not. Right now those cases are blurred together like someone spilled error handling into the carpet and called it resilience.
}catch(err){if(errinstanceofError&&(errasErrnoException).code!=='ENOENT'){
...
console.warn(`[ruler] Warning: could not read config file at ${configFile}: ${err.message}`,);}raw={};}
Fail hard on invalid/parsing errors; only treat ENOENT as “missing, start fresh.”
Return structured diagnostics instead of {} fallbacks, and surface them at the CLI boundary.
Refuse to write merged config when the existing file is unreadable unless the user explicitly opts into overwrite.
Centralize config-read semantics so every agent doesn’t invent its own adorable little disaster.
Skills Propagation Is a Copy-Paste Swamp
🤮 SkillsProcessor.ts is a giant repetition factory where every new agent demands another sacrificial function.
This file is doing the same job over and over with slightly different constants: cleanup logic repeated per target, propagation logic repeated per target, error cleanup repeated per target. It is the software equivalent of photocopying the same bug thirteen times so nobody gets lonely.
The bad news: this is hard to maintain. The worse news: there is already a sibling subsystem (SubagentsProcessor) doing its own table-driven-ish version, so the repo contains two competing patterns for nearly the same problem. Chef’s kiss of inconsistency. 🫠
Replace per-agent functions with a single table-driven pipeline: [{ target, path, identifiers, copyMode, transform? }].
Extract shared helpers for:
existence check,
temp-dir atomic swap,
cleanup,
dry-run message generation.
Make skills and subagents use the same propagation architecture so fixes land once instead of in twelve miserable places.
Agent Metadata Is Smeared Everywhere
🧟 Adding one agent currently means updating a small committee of registries, switches, maps, and documentation tables like it’s 2009.
The source of truth is not a source of truth; it’s a scavenger hunt. The supported agents list lives in the README, instantiated objects live in allAgents, MCP locations live in a switch, skills routing lives in a map, and subagent routing lives in a different map. This is how drift sneaks in wearing a fake mustache.
The code works today, mostly because someone has been manually herding cats with discipline and caffeine. But every new agent increases the chance of forgetting one surface and shipping a half-supported feature with a confident README. Very enterprise. 💀
Create a single agent manifest describing identifier, display name, rule path(s), MCP path(s), skill target, subagent target, and capabilities.
Generate allAgents, CLI help, MCP routing, and README tables from that manifest.
Move per-agent quirks behind typed adapters, not scattered switch statements and side maps.
Add a test that asserts every documented agent exists in the registry and vice versa.
Nested Discovery Brute-Forces the Repo
🐢 Nested .ruler discovery walks the whole tree and only skips hidden directories, which is a hilariously bad bargain in large repos.
The code recursively descends every non-hidden directory, which means it will happily spelunk through node_modules, build output, vendored junk, giant monorepo packages, or whatever other industrial landfill the repo contains. The comment says “skip hidden directories like .git,” which is cute, because the really expensive directories are usually not hidden.
This is a straight-up performance footgun. The feature most useful in big repos is implemented in a way that gets slower exactly where it matters most. Outstanding symmetry. 🥴
Skip common heavy directories explicitly: node_modules, dist, build, coverage, vendor, .next, etc.
Consider a fast walker with ignore rules instead of handwritten recursive readdir.
Let nested mode accept include/exclude globs or a max-depth knob.
Cache discovery results per run so follow-up operations don’t re-tour the entire museum of regrets.
Test Tooling Is Babysitting Dead Artifacts
🪦 The repo contains compiled .js test corpses while lint/typecheck mostly ignore tests, which is peak “works on my machine” feng shui.
Jest only runs .ts tests, ESLint only lints src/**/*.{ts,tsx}, and TypeScript excludes tests entirely—yet committed compiled .js tests are sitting in the tree like haunted leftovers. So the repo gets the worst of both worlds: extra noise in version control and weaker quality gates over the actual test suite.
This is a developer-experience tax. Dead files confuse diffs, weak test linting lets bad test code rot, and the setup encourages accidental divergence between what developers edit and what the repo stores. Gorgeous little mess. ✨💩
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
This Codebase Smells!
This week’s aroma profile is burnt abstractions, stale config handling, and a top note of “just one more special case, bro.” 🤮 The repo is not beyond saving, but it is doing that charming thing where every new feature appears to have been installed with a shovel instead of a design. Delightful.
Table of Contents
Corrupt Configs Are Quietly “Handled”
💩 Broken config files get treated like optional fan fiction, which risks silently overwriting real user state with empty defaults.
When
ruler.toml, native MCP JSON, orfirebender.jsonis malformed, the code often shrugs, returns{}or{ rules: [] }, and carries on. That is spectacularly forgiving in the worst possible way: a user typo can turn into “merge with empty config and write it back,” which is how software politely vandalizes files while pretending to help.This is a robustness problem and a trust problem. Missing files (
ENOENT) are fine; invalid files are not. Right now those cases are blurred together like someone spilled error handling into the carpet and called it resilience.Files
src/core/ConfigLoader.tssrc/paths/mcp.tssrc/agents/FirebenderAgent.tssrc/core/apply-engine.tsCode
src/core/ConfigLoader.ts— lines 196-220: https://github.com/intellectronica/ruler/blob/main/src/core/ConfigLoader.ts#L196-L220src/paths/mcp.ts— lines 80-89: https://github.com/intellectronica/ruler/blob/main/src/paths/mcp.ts#L80-L89src/agents/FirebenderAgent.ts— lines 98-118: https://github.com/intellectronica/ruler/blob/main/src/agents/FirebenderAgent.ts#L98-L118src/core/apply-engine.ts— lines 900-914: https://github.com/intellectronica/ruler/blob/main/src/core/apply-engine.ts#L900-L914Suggestions
ENOENTas “missing, start fresh.”{}fallbacks, and surface them at the CLI boundary.Skills Propagation Is a Copy-Paste Swamp
🤮
SkillsProcessor.tsis a giant repetition factory where every new agent demands another sacrificial function.This file is doing the same job over and over with slightly different constants: cleanup logic repeated per target, propagation logic repeated per target, error cleanup repeated per target. It is the software equivalent of photocopying the same bug thirteen times so nobody gets lonely.
The bad news: this is hard to maintain. The worse news: there is already a sibling subsystem (
SubagentsProcessor) doing its own table-driven-ish version, so the repo contains two competing patterns for nearly the same problem. Chef’s kiss of inconsistency. 🫠Files
src/core/SkillsProcessor.tssrc/core/SubagentsProcessor.tsCode
src/core/SkillsProcessor.ts— lines 177-206: https://github.com/intellectronica/ruler/blob/main/src/core/SkillsProcessor.ts#L177-L206src/core/SkillsProcessor.ts— lines 683-716: https://github.com/intellectronica/ruler/blob/main/src/core/SkillsProcessor.ts#L683-L716src/core/SubagentsProcessor.ts— lines 58-73: https://github.com/intellectronica/ruler/blob/main/src/core/SubagentsProcessor.ts#L58-L73Suggestions
[{ target, path, identifiers, copyMode, transform? }].Agent Metadata Is Smeared Everywhere
🧟 Adding one agent currently means updating a small committee of registries, switches, maps, and documentation tables like it’s 2009.
The source of truth is not a source of truth; it’s a scavenger hunt. The supported agents list lives in the README, instantiated objects live in
allAgents, MCP locations live in a switch, skills routing lives in a map, and subagent routing lives in a different map. This is how drift sneaks in wearing a fake mustache.The code works today, mostly because someone has been manually herding cats with discipline and caffeine. But every new agent increases the chance of forgetting one surface and shipping a half-supported feature with a confident README. Very enterprise. 💀
Files
README.mdsrc/agents/index.tssrc/paths/mcp.tssrc/core/SkillsProcessor.tssrc/core/SubagentsProcessor.tsCode
README.md— lines 57-76: https://github.com/intellectronica/ruler/blob/main/README.md#L57-L76src/agents/index.ts— lines 38-70: https://github.com/intellectronica/ruler/blob/main/src/agents/index.ts#L38-L70src/paths/mcp.ts— lines 10-35: https://github.com/intellectronica/ruler/blob/main/src/paths/mcp.ts#L10-L35src/core/SkillsProcessor.ts— lines 140-154: https://github.com/intellectronica/ruler/blob/main/src/core/SkillsProcessor.ts#L140-L154Suggestions
allAgents, CLI help, MCP routing, and README tables from that manifest.Nested Discovery Brute-Forces the Repo
🐢 Nested
.rulerdiscovery walks the whole tree and only skips hidden directories, which is a hilariously bad bargain in large repos.The code recursively descends every non-hidden directory, which means it will happily spelunk through
node_modules, build output, vendored junk, giant monorepo packages, or whatever other industrial landfill the repo contains. The comment says “skip hidden directories like.git,” which is cute, because the really expensive directories are usually not hidden.This is a straight-up performance footgun. The feature most useful in big repos is implemented in a way that gets slower exactly where it matters most. Outstanding symmetry. 🥴
Files
src/core/FileSystemUtils.tsCode
src/core/FileSystemUtils.ts— lines 264-304: https://github.com/intellectronica/ruler/blob/main/src/core/FileSystemUtils.ts#L264-L304Suggestions
node_modules,dist,build,coverage,vendor,.next, etc.readdir.Test Tooling Is Babysitting Dead Artifacts
🪦 The repo contains compiled
.jstest corpses while lint/typecheck mostly ignore tests, which is peak “works on my machine” feng shui.Jest only runs
.tstests, ESLint only lintssrc/**/*.{ts,tsx}, and TypeScript excludestestsentirely—yet committed compiled.jstests are sitting in the tree like haunted leftovers. So the repo gets the worst of both worlds: extra noise in version control and weaker quality gates over the actual test suite.This is a developer-experience tax. Dead files confuse diffs, weak test linting lets bad test code rot, and the setup encourages accidental divergence between what developers edit and what the repo stores. Gorgeous little mess. ✨💩
Files
package.jsonjest.config.jseslint.config.mjstsconfig.jsontests/unit/core/FileSystemUtils.test.jstests/unit/core/RuleProcessor.test.jsCode
package.json— lines 6-13: https://github.com/intellectronica/ruler/blob/main/package.json#L6-L13jest.config.js— lines 1-6: https://github.com/intellectronica/ruler/blob/main/jest.config.js#L1-L6eslint.config.mjs— lines 20-22: https://github.com/intellectronica/ruler/blob/main/eslint.config.mjs#L20-L22tsconfig.json— lines 113-114: https://github.com/intellectronica/ruler/blob/main/tsconfig.json#L113-L114tests/unit/core/FileSystemUtils.test.js— lines 1-4: https://github.com/intellectronica/ruler/blob/main/tests/unit/core/FileSystemUtils.test.js#L1-L4Suggestions
.jsfiles appear undertests/.All reactions