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 bouquet is burnt config files, fermented boilerplate, and a top note of “it passed on my machine” 🤮.
I went spelunking through the repo so you don’t have to, and wow — this thing isn’t broken so much as aggressively committed to making future-you miserable 💩.
revert treats a generic root-level config.toml like disposable trash, which is the sort of confidence usually reserved for malware.
Open Hands explicitly writes MCP config into the project’s root config.toml, and revert later unlinks config.toml if there’s no backup. That is wildly optimistic for a file name this generic.
Translation: one unlucky repo with a legitimate config.toml gets “cleaned up” by your tool, and congratulations, you’ve invented config-based vandalism ☠️.
case'Open Hands':
// For Open Hands, we target the main config file, not a separate mcp.jsoncandidates.push(path.join(projectRoot,'config.toml'));
Concrete suggestions
Only delete config.toml when:
a .bak exists, or
the file contains a Ruler provenance marker / known Open Hands MCP section.
Record created files during apply and use that manifest during revert.
Treat generic filenames as restore-only, not delete-by-default.
Nested Discovery Crawls the Repo Like a Feral Raccoon
Nested mode recursively walks basically the whole tree, which is how you end up indexing fixtures, junk, and whatever other cursed debris lives under the repo.
findAllRulerDirs() skips hidden directories and nested git repos, but nottests, tmp-fixtures, coverage, out, or any other landfill. That’s a performance problem and a correctness problem.
In this repo, there are real fixture .ruler directories under test data, so nested discovery can absolutely hoover up things that are test scaffolding, not user config. Gorgeous. No notes. 🦝🔥
Add an explicit directory ignore set for common non-source trees: tests, tmp-fixtures, coverage, dist, build, out, etc.
Respect .gitignore or allow a config-level ignore list for nested discovery.
Prefer a bounded/project-aware traversal instead of “walk everything that isn’t dot-prefixed”.
Broken Configs Get Silently “Handled”
When config loading goes wrong, the code shrugs, mutters “defaults are fine,” and drives off a cliff with remarkable composure.
loadConfig() warns and falls back to {} for non-ENOENT read/parse failures, and applyHandler() separately swallows load failures when resolving nested. So a busted config can quietly degrade behavior instead of failing fast.
That is not resilience; that is error laundering. Users get mystery behavior, and maintainers get bug reports written in blood. 🤡
}catch(err){if(errinstanceofError&&(errasErrnoException).code!=='ENOENT'){if(err.message.includes('[ruler]')){throwerr;}console.warn(`[ruler] Warning: could not read config file at ${configFile}: ${err.message}`,);}raw={};}
Fail hard on invalid or unreadable explicitly requested config files.
Reserve default fallback for true “file missing” cases only.
Return typed diagnostics from config loading and let the CLI decide whether to warn or abort.
Your Quality Gates Are Wearing a Blindfold
The repo’s test/lint setup leaves chunks of code completely unverified, which is a bold strategy if your goal is surprise explosions.
eslint only covers src, Jest only matches *.ts tests, and TypeScript excludes tests entirely. Meanwhile, there are committed *.test.js files and random root-level JS experiment scripts just vibing outside the safety rails.
So yes, there are tests here; no, that does not mean they run. Spectacular bit of performance art 🎭.
// Test if we can manually construct TOML strings to get desired formatfunctionbuildInlineArray(items){
Concrete suggestions
Expand lint/typecheck/test coverage to include tests/**/* and root JS scripts, or delete/archive the junk.
Convert stray JS tests to TS or explicitly include JS test patterns in Jest.
Move ad hoc experiment scripts into a non-committed scratch area or scripts/experimental/ with ownership.
The Agent Zoo Is All Boilerplate, No Plan
You have a small safari park of near-identical agent classes plus a hand-maintained registry, because apparently data tables were too mainstream.
Many adapters are tiny subclasses whose entire personality is “return identifier, return name, return path.” Then src/agents/index.ts manually instantiates the whole herd.
This is pure maintenance tax: every new agent means new file, new class, new imports, new registry entry, new opportunity for someone to typo themselves into oblivion. Delightful 🐒💥
Replace metadata-only subclasses with a declarative agent registry object.
Keep custom classes only for agents with truly unique apply/MCP behavior.
Generate CLI help and capability tables from the same registry source.
SkillsProcessor Is a Copy-Paste Landfill
SkillsProcessor.ts is 38KB of duplicated directory shuffling, which is not a subsystem so much as a cry for help.
Cleanup repeats the same access / dry-run / rm / catch pattern for every target, and propagation repeats the same temp-dir-copy-rename sequence again and again. The file is huge because it keeps retyping the same idea with different folder names like a very tired intern.
Bonus points for temp dirs named with Date.now(), because nothing says “robust file operations” like millisecond collision roulette 🎰.
// Clean up .claude/skillstry{awaitfs.access(claudeSkillsPath);if(dryRun){logVerboseInfo(`DRY RUN: Would remove ${CLAUDE_SKILLS_PATH}`,verbose,dryRun);}else{awaitfs.rm(claudeSkillsPath,{recursive: true,force: true});}}catch{}
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 bouquet is burnt config files, fermented boilerplate, and a top note of “it passed on my machine” 🤮.
I went spelunking through the repo so you don’t have to, and wow — this thing isn’t broken so much as aggressively committed to making future-you miserable 💩.
Table of Contents
config.tomlRevert Plays Russian Roulette with
config.tomlreverttreats a generic root-levelconfig.tomllike disposable trash, which is the sort of confidence usually reserved for malware.config.toml, andrevertlater unlinksconfig.tomlif there’s no backup. That is wildly optimistic for a file name this generic.config.tomlgets “cleaned up” by your tool, and congratulations, you’ve invented config-based vandalism ☠️.Files
src/core/revert-engine.tssrc/paths/mcp.tsCode
src/core/revert-engine.ts#L311-L318src/core/revert-engine.ts#L333-L347config.toml:src/paths/mcp.ts#L33-L36Concrete suggestions
config.tomlwhen:.bakexists, orapplyand use that manifest duringrevert.Nested Discovery Crawls the Repo Like a Feral Raccoon
Nested mode recursively walks basically the whole tree, which is how you end up indexing fixtures, junk, and whatever other cursed debris lives under the repo.
findAllRulerDirs()skips hidden directories and nested git repos, but nottests,tmp-fixtures,coverage,out, or any other landfill. That’s a performance problem and a correctness problem..rulerdirectories under test data, so nested discovery can absolutely hoover up things that are test scaffolding, not user config. Gorgeous. No notes. 🦝🔥Files
src/core/FileSystemUtils.tstests/integration/fixtures/unified/.ruler/AGENTS.mdtmp-fixtures/unified-basic/.ruler/AGENTS.mdCode
src/core/FileSystemUtils.ts#L264-L300.rulercontent:tests/integration/fixtures/unified/.ruler/AGENTS.md#L1-L2# Primary Rules Line Atmp-fixtures/unified-basic/.ruler/AGENTS.md#L1-L2# AGENTS MainConcrete suggestions
tests,tmp-fixtures,coverage,dist,build,out, etc..gitignoreor allow a config-level ignore list for nested discovery.Broken Configs Get Silently “Handled”
When config loading goes wrong, the code shrugs, mutters “defaults are fine,” and drives off a cliff with remarkable composure.
loadConfig()warns and falls back to{}for non-ENOENT read/parse failures, andapplyHandler()separately swallows load failures when resolvingnested. So a busted config can quietly degrade behavior instead of failing fast.Files
src/core/ConfigLoader.tssrc/cli/handlers.tsCode
src/core/ConfigLoader.ts#L202-L225nested = false:src/cli/handlers.ts#L95-L105Concrete suggestions
Your Quality Gates Are Wearing a Blindfold
The repo’s test/lint setup leaves chunks of code completely unverified, which is a bold strategy if your goal is surprise explosions.
eslintonly coverssrc, Jest only matches*.tstests, and TypeScript excludestestsentirely. Meanwhile, there are committed*.test.jsfiles and random root-level JS experiment scripts just vibing outside the safety rails.Files
package.jsonjest.config.jstsconfig.jsontests/unit/core/FileSystemUtils.test.jstests/unit/core/RuleProcessor.test.jstest_manual_toml.jsCode
src:package.json#L6-L14jest.config.js#L3-L6tsconfig.json#L113-L114tests/unit/core/FileSystemUtils.test.js#L1-L5,tests/unit/core/RuleProcessor.test.js#L1-L5test_manual_toml.js#L1-L4Concrete suggestions
tests/**/*and root JS scripts, or delete/archive the junk.scripts/experimental/with ownership.The Agent Zoo Is All Boilerplate, No Plan
You have a small safari park of near-identical agent classes plus a hand-maintained registry, because apparently data tables were too mainstream.
src/agents/index.tsmanually instantiates the whole herd.Files
src/agents/AbstractAgent.tssrc/agents/ClaudeAgent.tssrc/agents/KiroAgent.tssrc/agents/TraeAgent.tssrc/agents/index.tsCode
src/agents/AbstractAgent.ts#L13-L27src/agents/ClaudeAgent.ts#L7-L18src/agents/TraeAgent.ts#L8-L19src/agents/index.ts#L38-L71Concrete suggestions
SkillsProcessor Is a Copy-Paste Landfill
SkillsProcessor.tsis 38KB of duplicated directory shuffling, which is not a subsystem so much as a cry for help.access / dry-run / rm / catchpattern for every target, and propagation repeats the same temp-dir-copy-rename sequence again and again. The file is huge because it keeps retyping the same idea with different folder names like a very tired intern.Date.now(), because nothing says “robust file operations” like millisecond collision roulette 🎰.Files
src/core/SkillsProcessor.tsCode
src/core/SkillsProcessor.ts#L177-L236src/core/SkillsProcessor.ts#L557-L619src/core/SkillsProcessor.ts#L683-L731,src/core/SkillsProcessor.ts#L741-L789src/core/SkillsProcessor.ts#L140-L154Concrete suggestions
{ target, identifiers, relPath, logLabel }.cleanupTargetDirectory()loop.propagateSkillsToTarget()usingfs.mkdtemp()orcrypto.randomUUID()for temp dirs.All reactions